OmniAICreator/Qiita-1.07M huggingface dataset:
PostgreSQL 8.4からECU-JPのデータベースを10.18に移行しようとしたら文字化けした話


古いPostgresだと機種依存文字はSJISで持ってるのが原因で、リストアできてもエラーが出たり、取り込めても文字化けしてたり手間かかりました。
#前提条件
- Windows環境
- 旧環境：PostgresSQL 8.4
- 新環境：PostgresSQL 10.18
- 旧環境のデータべースの文字エンコーディング：EUC-JP

#試してみたこと
- ECU_JPのまま移行　→　機種依存文字が文字化け
- SJISに変換して移行　→　`createdb --locale=C --encoding=sjis --template=template0 hogehog`が失敗
- SJIS指定で出力したdmpファイルをUTF-8に変換してpsqlでリストア　→　機種依存が変換できないとのエラー

#成功した手順
結局UTF-8で移行することになりました。

### 旧環境でdumpを取る
    pg_dump -E SJIS -v --inserts [対象のデータベース] > [出力ファイルパス]
-EスイッチでSJISを指定して出力（文字化けを防ぐ）

###出力ファイルを編集する

1. 出力ファイルを開く
1. 一行目に`\encoding UTF8;`を追加
1. `SET client_encoding = 'SJIS';`という記述があった場合`SET client_encoding = 'UTF-8';`に変更
1. 文字エンコーディングをUTF-8に変更して保存
    
###新環境でデータべースを作成
    createdb --locale=C --encoding=UTF8 --template=template0 [データベース名]

###ダンプファイルからデータをリストア
    psql -f [dmpファイルパス] [データベース名]
Firebaseのホスティング-デプロイしたい。

#はじめに
制作したサイトをfirebaseで公開しようと利用したので、その手順や注意を忘れないよう自分なりにまとめた記事です。


##準備
・ Googleアカウント
・ デプロイするサイト
・ firebaseのプロジェクト作成(公開するサイト1つにつき1つ作る。)
・ node.jsをインストール(推奨版)



ターミナルでnode.jsがインストールされているか確かめる。

```
$ node -v
```

続いてnpmも一緒にインストールされているか確認してみる。

```
$ npm -v
```


##firebase-toolsのセットアップ

firebaseのコマンドラインツールのインストール

```
$ sudo npm install -g firebase-tools
```

インストールされているか確認する。

```
$ firebase -V
```

インストールが終わったら、firebaseにログイン

```
$ firebase login
? Allow Firebase to collect anonymous CLI usage and error reporting information?(Y/n)
  ↓Yを選択後
✔  Success! Logged in as <mail address>
```
Success! が出たらログイン完了。


##プロジェクトの初期化

アップしたいファイルに移動し、初期化する。

```
$ cd <アップしたいファイルまで移動>
<ファイル名>$ firebase init
```

矢印キーで移動、スペースキーで選択、リターンで決定。
Hostingを選択。

```
? Which Firebase CLI features do you want to setup for this folder?
❯◉ Hosting: Configure and deploy Firebase Hosting sites
```

どのフォルダを公開用のフォルダにしますか?
publicディレクトリを使用するので、Enter。

```
? What do you want to use as your public directory? (public)
```

publicフォルダの中のHTMLを上書きしますか?
Nを選択。<strong>絶対No。注意!!!!</strong>
complete!と出たら、初期化ができました。

```
? File public/index.html already exists. Overwrite? (y/N)
↓Nを選択
✔︎ Firebase initialization complete!
```

続いてファイルの中身を確認。
・ firebase.jsonが作成されている。
・ publicフォルダの中に404.htmlが作成されている。


##サイトを公開(デプロイ)

デプロイするときに、初期化したファイルに移動しているか確認してから行う。

```
<ファイル名>$ firebase deploy

Hosting URL: <公開したかったサイトのURL>
```

URLをコピーしてブラウザに貼り付けると、https:で表示される。


##ログアウト
firebaseにログインしている状態なので、ログアウトして終了。

```
<ファイル名>$ firebase logout
```


##デプロイしているサイトを更新したい。
編集したファイルに移動し、firebaseにログインした後、そのままデプロイすればOK!

```
$ cd <アップしたいファイルまで移動>
$ firebase login
<ファイル名>$ firebase deploy
```




##メモ

プロジェクトの一覧を確認

```
<ファイル名>$ firebase projects:list
```

ターミナルのクリア
``control + l``

firebaseサイトの自分のダッシュボードに行くと現在公開しているサイトと履歴を確認できる。ロールバックもダッシュボードでできる。
※ロールバック:以前公開したサイトに戻す事。

##参考

https://qiita.com/hiroki-harada/items/ca22ac177db68e3c3796#fn1

https://www.topgate.co.jp/firebase04-firebase-hosting-deploy-website

https://www.skyarch.net/blog/?p=17078#3
1分で、macのjavaバージョンを切り替え

> 会社では定期的に欲しいノートパソコンに交換してくれますが、私はMac Proに交換してもらいました。openjdkを使うので問題ないと思っていたのですが、legacy案件の中ではjavaが1.7や1.8でないと動かない場合がありました。その時、バージョン切り替えしながら分かった近道を皆さんと共有したいと思います。

#環境
シェルはzshで設定・確認します。

#実施
##javaバージョン確認する
javaのバージョンを確認してみましょう。
zshでは-v, --version , -V , --VERSIONなどはNGです。

```zsh
java -version
where java # 居場所を確認
```
##javaのパスを通しましょう
Windowsではパス登録が簡単だったが、なんだかMacでは環境変数が保存されない
それで見つけたのが下記の方法でした。ちなみにRCはRun Commandの略語です。
一言で、シェルで設定ファイルです。


### 1. エディターが開く

```zsh
open ~/.zshrc
```

### 2. javaの指定しよう

記載はこんな感じ

```
export JAVA_HOME=`/usr/libexec/java_home -v "1.8"`
PATH=${JAVA_HOME}/bin:${PATH}
```

### 3. 修正をシステムに反映
sourceはbash系でも使われるコマンドでして、現在の設定の即時で適用するコマンドです。
RCファイルの設定後には一度シェルを閉めて開き直すように案内される場合もありますが、
基本的にはこれで開かなくてもいいはずです。

```zsh
source ~/.zshrc
```

### 4. 結果確認
-versionです。忘れないで…。

```zsh
java -version
```

#結論
基本中の基本ですが、たまにしか行わないのでハマる場合があります。
今後は記事の内容を補足して他の言語や設定も追加していきたいと思います。
CSS コンテンツ量が少ない時にフッターをしたに表示させつつ、フッターを固定させない

#はじめに
![スクリーンショット 2021-09-06 21.10.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/17046508-71b4-1243-4878-0256648a1843.png)

**なんでフッターがコンテンツに被ってるねん！！！**

フッターを`position:fixed`で固定したからか？

でも下で固定しとかな、コンテンツが少ない時フッターが上にあがってきてしまう。。。

**・コンテンツ量が多い時、スクロールしたら下にフッターがある**
**・コンテンツ量が少ない時、常に下にフッターがある**
👆を同時に実現するにはどうしたらいいか・・・

Webのcssを触るのが久々で、結構な時間こんな問題と格闘してしまった。。:cold_sweat:

#cssだけで解決してみせます

```html
<body>
    <div class="wrapper">
        <header>
            <!--グローバルナビなど-->
        </header>
        <main>
            <!--ここにコンテンツの内容-->
        </main>
        <footer>
            <p>Copyright © 2021</p>
        </footer>
    </div>
</body>
```

```css
.wrapper{
    min-height: 100vh; /* ←コンテンツの高さの最小値＝ブラウザの高さに指定 */
    position: relative;/* ←相対位置 */
    padding-bottom: 60px; /* ←フッターの高さを指定 */
    /* ↑ヘッダーやフッターを含むすべての要素の高さ＝min-height:100vhになるように指定 */
}

footer{
    position: absolute;/* ←絶対位置 */
    bottom: 0;
    text-align: center;
}
```

![スクリーンショット 2021-09-06 21.10.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/4b27a28f-8cc1-6306-fcb2-0dff5a28f21e.png)

か、解決した。。。！！

#コメントより
###別のやり方も教えてもらいました！①

>headerとfooterのheightが分かっているならmainのmin-heightをcalc(100vh - var(--header-height) - var(--footer-height))と言う感じに設定してあげればfooterのpositionをabsoluteにする必要はなくなりますよ。
mainの中に下方向マージンが大きく取られたものが入るとfooterが押しやられるので、mainに適当な幅で下方向paddingを入れてやると崩れにくくなります。

@felis さん、ありがとうございます！

###別のやり方も教えてもらいました！②

>`wrapper`をフレックスブロックの`min-height: 100vh; flex-direction: column`で縦積みにし、`main`を`flex: 1 1 auto;`にするとmainがフレックスアイテムになって良い具合に伸びます。
というやり方もできます:point_up:

@right714 さん、ありがとうございます！
パスを通す？環境変数とは…？？command not findに打ち勝ちたくて調べたこと

入れたはずのPythonが`command not find`と出力されて使えない…
入っているはずなのにnvmコマンドを打っても`command not find`と出力されて使えない…

などなど、入れたはずのツール、言語がチュートリアル通りにターミナルへ入力しても`command not find`と出力される問題。

こんなことがあった時に偉い人からよくいただくアドバイスが**「どうせパスが通ってないんでしょ？」**
いやいや、パスってなんじゃい！と思って重い腰を上げて調べました。

ちなみに私は使っているmacOSが古く、bashを使ってます。
新しいmacOS(確かCatalina以降？)の人はzshなので、編集するファイルが違ったり、ちょこっと違うみたい(使った事ないからわからない)のでご了承ください。


# パスを通すとはコマンドを探す先を教えてあげること
インストールしたツールや言語を使うためには、そこまでのファイルパスを環境変数に設定して、文字通り道を作ってあげないと召喚できない、使えない。
パスはそのコマンドなどの情報が保存されているファイルまでの道のことらしい。
Linuxやmac、多分Winも新しい言語とかツールとかをインストールした時にこのパスを通す作業をしないとそのコマンドが使えないことがあるみたい。



# 「パスが通ってない」とは
コマンドを入力したのに、command not found(コマンド見つからなかった)と出る状態。

例えば仮にアイウエオがあって、アイウエオとコマンドを打つとする。
そうすると以下になったりする。

```terminal
$ アイウエオ
-bash: アイウエオ: command not found
```



そんなコマンド知らないよ。(=そんなんどこにあるの？)となる。
実際にはインストールしたのに！コマンドのファイルがあるのに！って思っても、そこまでのパスが通っていないので、そのファイルがどこにあるのかPCは分からず、見つからない時もこれが出る。

お使い行って、お店がわからなくて、そのまま帰ってきたみたいな感じ。。


# いざパスを通す(一時的ver.)
パスを通すとは、具体的には`$PATH`という変数に、そのコマンドが入っているファイルへのファイルパスを登録して道を教えてあげることです。
ということで、まずはその`$PATH`の中に何が入っているのか、`$ echo $PATH`コマンドを入力して見てみましょう。

```terminal
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```

出力された`/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin`が`$PATH`の中身です。
`:`までで1区切りとして読み、左側にいくにつれて優先順位が高くなります。

そのため、上記出力例でいくと、以下の様になります。

**優先順位ランキング**
*1位* `/usr/local/bin`さん
*2位* `/usr/bin`さん
*3位* `/bin`さん
*4位* `/usr/sbin`さん
*5位* `/sbin`さん


`$PATH`という変数の中身を確認したら、追加したいコマンドのファイルパスをFinderとかを使って予め調べておいて、ターミナルに以下を入力します。

```terminal
$ export PATH=$PATH:加えたいコマンドのファイルパス
```

けれども、**これだとターミナルを閉じるとまた初期化されて元どおり**になってしまい、再度開いてコマンドを入力するとcommand not foundになってしまいます。。


# いざパスを通す(永遠にver.)
恒久的にパスを通す、つまりPCを立ち上げ、ターミナルを開いたらいつでも使える状態にしておくためには`.bash_profile`や`.profile`, `.bsh`, `.zshrc`みたいなファイルへパスを書いて保存します。

`.bash_profile`や`.profile`, `.bsh`, `.zshrc`などはホーム(macだとユーザー名のディレクトリ直下)に入っているみたいなので、今ターミナルで開いている階層がホームではない人は、何も考えずにターミナルウインドウを×ボタンで消して、また立ち上げるか、別にターミナルウインドウを新しく開いてそこでやるとか、`cd`とだけターミナルに打ち込むとかして、ホームに移動しましょう。

そこで、以下の`ls -a`コマンドを入力してどんなドットファイルが入っているのか、確認しましょう。

```teriminal
$ cd
$ ls -a
```

`ls -a`をすると今いる階層(ちゃんとホームにいますよね？)にある、ドットファイルを含めた、そこの階層にあるもの全てが一覧表示されます。

あとはviコマンドでそれらを開いて、編集しましょう。

```terminal
$ vi 編集するファイル名
```

viコマンドを打ったら、少し変わった表示になったと思います。
viはターミナル上でそのまま使えるテキストエディタです。なので、実はこの作業は全部ターミナルでやらなくても、ドットファイルを直接VS Codeみたいなエディタで開いて編集するのでもいいです。

今回はあっちこっち移動するのも面倒なので全部ターミナルで終わらせます。ちょっとプロっぽい瞬間です。

viコマンドでファイルを開いただけでは、入力ができないので、`I`キーを押してインサートモードにして入力ができる状態にし、先に何か書いてあったら最終行にさっきの追加したいコマンドのファイルパスを入力します。

↓こういつやつを書き込む。
`PATH=$PATH:加えたいコマンドのファイルパス
`

入力が終わったら、`Esc`キーでインサートモードを解除し、`:`キーと、`w`キーと、`q`キーを、順番にキー入力して、編集内容を保存してエディタを閉じます。

ここまでくれば、あとはターミナルのウインドウを消して、ターミナルを立ち上げ直せば再起動したことになり、先ほどの編集内容が反映されるはずです。

再起動が面倒であれば以下のコマンドで編集内容を反映させる方法もあります。

```terminal
$source ~/.bash_profile
```


# 「コマンドの情報が入っているファイルの場所を調べるコマンド」でパスが反映されてるか確認
先ほど通したパスが、きちんと通っているか確認します。

そのために、コマンドのパス情報がどこのファイルに入っているのか確認する以下のコマンドを入力してみましょう。


```terminal
$ which コマンド名
```

実行例

```terminal
$ which pyenv
/usr/local/bin/pyenv
```
OracleのデータベースでSQL実行したら、「ユーザー～は存在しません」と言われた場合の対処

## 経緯
テーブル作成やinsertするsql実行しようとしたら、そのようなエラーメッセージが出た。
MySQLに慣れていると、Oracleってクセが強く感じる。
ググってもいまいち分かりやすい記事が無かったので、1つ1つ調べていくことにした。

## 解決方法
調べていくと、ユーザーっていうのはスキーマのことらしい。

なら、まずはスキーマを作成する。
今回は仮で、パスワードも全て同じ名前にする。

```
CREATE USER 【スキーマ名】 IDENTIFIED BY 【スキーマ名】;
GRANT ALL PRIVILEGES TO 【スキーマ名】;
```

次に、必要なテーブルとか入れたり必要な設定をする

```
create table～
```

A5M2で、ホスト名とか色々入力してテスト接続が成功したら、OK

## 感想
うーん、oracleよりMySQLのほうがやっぱりすこなんだが、、、
Oracleってローカルの環境構築で絶対ハマる
「アダプティブ カードを投稿して応答を待機する」アクションで動的なコンテンツに回答が表示されないときの対処法

入力フォームつきのアダプティブカードを投稿し、その返答結果を受け取りたい場合があると思います。

今回、私の環境で「アダプティブ カードを投稿して応答を待機する」アクションにおいて、回答に入力するべき動的なコンテンツが表示されなかったため、対処法を記載しておきます。


## もし「動的なコンテンツ」に回答結果の変数が表示されなかった場合
※今回、「アダプティブ カードを投稿して応答を待機する」アクションは名前が長かったので、以下のように名前を変更しました。
【デフォルト】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464309/3993a042-fc96-0d25-8e6e-39d36138c85c.png)
【「・・・」ボタンより名前変更後】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464309/f7b2b4c0-eb72-2642-bfab-998c2a33ac29.png)


「動的なコンテンツ」→「**式**」に以下のような式を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464309/ee5deb4b-500a-b319-9044-877690bcae53.png)

式の中身
```outputs('応答待機')?['body/data/thoughts']
```

このようにするとアダプティブカードから入力された返答を受け取ることができます。
embulkでTreasureDataにデータをアップロードする


OpenJDK8をインストール

https://adoptopenjdk.net/?variant=openjdk8&jvmVariant=hotspot

コマンド実行でembulkのインストール

https://www.embulk.org/

windows

```
PowerShell -Command "& {[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::TLS12; Invoke-WebRequest http://dl.embulk.org/embulk-latest.jar -OutFile embulk.bat}"
```

pluginsからインストール

- embulk-input-td
- embulk-output-td

https://plugins.embulk.org/

```
embulk gem install embulk-input-td
```

環境変数にpath設定

ymlファイル

```
in:
  type: file
  path_prefix: XXXXX.tsv
  parser:
    charset: UTF-8
    newline: CRLF

out:
  type: td
  apikey: api_key
  endpoint: api.treasuredata.com
  database: db
  table: tab
  auto_create_table: true
  mode: append
```

実行

```
embulk run filename.yml
```
[SpringMVC]値を正規表現でバリデーションする

Tipsです。手短に。



`@Pattern`アノテーションを利用して、クラスプロパティの値を正規表現でチェックする方法を紹介します。
よかったら いいね だけお願いします。


## 手順
1. build.gradleにライブラリを追記
1. フィールドにアノテーションを追記



## build.gradleにライブラリを追記
```gradle:build.gradle
dependencies {
    implementation 'org.hibernate.validator:hibernate-validator'
}
```


## フィールドにアノテーションを追記
```java:Sample.java
import javax.validation.constraints.Pattern;

public class Sample {

    @Pattern(regexp="^[a-zA-Z0-9]{3}", message="3文字でおねシャス")  
    String value;
...
```



## 他のアノテーションも知りたい
こちらの投稿が大変参考になります。
[Spring Frameworkで使用できるBean Validationアノテーション一覧 - ぺんぎんらぼ]( https://penguinlabo.hatenablog.com/entry/springframework/validator)




## 参考
- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator/6.2.0.Final


## タグ
- Spring
- SpringBoot
- アノテーション
- Annotation
- Bean Validation
- バリデーション
- 正規表現
- チェック
- 方法
- フォーマット
- 検証
- プロパティ
- フィールド
Workato：現在の日時を日本時間(JST)で取得するには

WorkatoのFormulaやConnector SDK, Rubyコネクターで利用可能な `now` 関数の戻り値は、太平洋標準時で返されます。

https://docs.workato.com/developing-connectors/sdk/sdk-reference/ruby_methods.html#pre-defined-ruby-methods

> now
> Returns timestamp of the moment that the formula was executed, in Pacific time (UTC-8/UTC-7).

日本時間で現在日時を取得したい場合は、Formulaに次の通り入力します。

```ruby
now.in_time_zone("Asia/Tokyo")
```
mayaがエラー・ワーニングを吐く時の対処 4　~不死身の亀~


TurtleDefaultBakeLayerというノードが何もしてないのに出来てしまっいて、
「削除してくだい」と言われたので削除しようとしたけれども、deleteボタンを押すと

    // Error: file: C:/Program Files/Autodesk/Maya2019/scripts/others/doDelete.mel line 111: Cannot delete locked node 'TurtleDefaultBakeLayer'.

と断られる。

TurtleDefaultBakeLayerは　レンダリング設定で render using を turtleにすると生成されるturtleの為のノード。
ワーニングの通り、ノードがロックされているので通常の手順では削除できない。

1,カメなのにウサギ殺しのボタンを押す
--
![kamegorosi.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/e251edbd-da4a-508e-dd78-cd9af9c7f512.png)
シェルフのturtleに登録されているこのボタン。
（カメを削除したいのに、ウサギにバッテン・・・・）
これを押すとTurtleDefaultBakeLayerは削除される。他のturtle由来のノードも削除される。

2,プラグインをunloadする。
---
プラグインをunloadすると
特にシーンに対して何も影響がなければ、turtle由来のノードは削除されプラグインをunloadしてくれる。


ロードされていると何かの拍子に出てきてしまうので、プラグインマネージャーからload/autoLoadをoffにしておく。

それでもTurtleDefaultBakeLayerが存在しているデータが回ってくるとプラグインはloadされるし、TurtleDefaultBakeLayerはまた出てくるしで面倒なので上記2点を一括処理にして見つけたら即処理にしてしまうのがお勧め。

ただし、Turtleを実際に使用している場合は消すとより面倒になるのでその辺はしっかり確認してください。



ノードのlock
----

"locked node" とあるように、ノードが lock状態にあるとmayaではノードを削除できない。

    cmds.lockNode("pSphere1", lock =True)
でノードをlockできる。

    cmds.lockNode("pSphere1", lock =False)

でlockを解除できる。

が、無暗に解除して削除するとデータが容易に壊れるので注意が必要。
例えば　referenceノードもシステム上は lockNodeでlockされてるだけなので、lockを外せば削除できる。
必要な物を保護するためにlockしていることが多いので、何も考えずに

    nodes = cmds.ls()
    cmds.lockNode(nodes , lock =False)

みたいなことをやるのはダメ、絶対。
unkownノードもロックを外せば削除できるが、そもそもunkownノードが生成されるという事はシーンが正確に再現できていない可能性が高いので
これも何も考えずに削除すると、正しいシーンを再現することができなくなる可能性が非常に高い。
コントローラー内の処理のカテゴリー

#####自分でもあやふな部分があるので復習も兼ねて！

###まずコントローラーとは？

・リクエストに対する処理をする場所
・処理をした後クライアントにレスポンスとして返す場所

###コントローラー内での処理のカテゴリー

・コントローラー内での処理のカテゴリーをアクションと言います！
　基本的な7つのアクションが、、、
　
・index→一覧表示（トップページ）
・new→新規投稿ページ
・create→データの投稿
・show→個別詳細ページ
・edit→投稿編集ページ
・update→データの編集
・destroy→データの削除

例えば、クライアントからトップページが見たああああああい！！とリクエストが来た場合はコントローラー内のindexアクションが動きます！

トップページの表示がリクエストで来ていた場合の記述の仕方↓

```rb
def index
end
```

以上！！
OpenCVを使って緑被を抽出する

Pythonで使えるライブラリの1つとしてOpenCVがありますが、活用例として特定の色の抽出がよく紹介されます。
今回は、OpenCVと緑被分布図を使って、駅から半径1.5km以内の範囲にある緑被の抽出・緑被率の計算を行うプログラムを作成してみました。

#緑被分布図の準備
緑被分布図は下記のリンクから。
首都圏と近畿圏のものがあるようです。

緑被分布図の公開 - 大都市圏整備（国土交通省）
https://www.mlit.go.jp/crd/daisei_ryokuhi_index.html

##駅から半径1.5km以内の範囲を示す緑被分布図の作成
現時点では**気合いで**作成します（いずれは自動化していきたい…）。
例えば新宿駅なら次のような図になります。
![shinjuku.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418323/1379042f-829f-c0ca-988f-f9ac8430c85b.jpeg)


#コード
下記のサイトを参考に、コードを書いてみました。

OpenCV 入門 (10) - 色の抽出
https://note.com/npaka/n/nc6764b99dbe0

【Python+OpenCV】特定の色を検出するプログラム
https://craft-gogo.com/python-opencv-color-detection/

今回は「緑被地（主に樹林地）」・「緑被地（主に草地）」の2種類を抽出します。


```py
import cv2
import numpy as np

#パスを指定
path = ""  #適宜パスを指定する

#駅を指定
station = "shinjuku"  #上記パスの下に作成した円形の緑被分布図を置き、駅名を付けて保存しておく

#画像の読み込み
img = cv2.imread(f'{path}{station}.jpg')

#周囲の余白を除去・計測・図示
img_array = np.asarray(img)
white_min = np.array([235, 235, 235])
white_max = np.array([255, 255, 255])
mask_white = cv2.inRange(img, white_min, white_max)
cv2.imwrite(f'{path}white_mask_{station}.png', mask_white)
white_array = np.asarray(mask_white)
white_count = np.count_nonzero(white_array == 255)

#HSVに変換
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# 緑色のHSVの値域
hsv_min = np.array([30, 64, 0])
hsv_max = np.array([90, 255, 255])
mask = cv2.inRange(hsv, hsv_min, hsv_max)
masked_img = cv2.bitwise_and(img, img, mask = mask)

#緑色のピクセル範囲を図示
cv2.imwrite(f'{path}green_mask_{station}.png', mask)
cv2.imwrite(f'{path}green_masked_img_{station}.png', masked_img)

#緑色のピクセル比率を算出
hsv_array = np.asarray(mask)
chi = np.count_nonzero(hsv_array == 255)
mot = np.count_nonzero(hsv_array > -1) - white_count
prob = chi / mot * 100

print(prob, "%")
```

#出力
![white_mask_shinjuku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418323/fff15886-b884-51f5-2a59-387874c81520.png)
余白の判定図

![green_mask_shinjuku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418323/baa60341-c59e-1939-37df-b2d709d15c3d.png)
緑被の判定図

![green_masked_img_shinjuku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418323/750784a5-8b46-8174-e1e4-aa0ccbb39bc6.png)
緑被の抽出図

緑被率は下記の通り。

```
10.700869741784832 %
```

#参考文献
緑被分布図の公開 - 大都市圏整備（国土交通省）
https://www.mlit.go.jp/crd/daisei_ryokuhi_index.html

OpenCV 入門 (10) - 色の抽出
https://note.com/npaka/n/nc6764b99dbe0

【Python+OpenCV】特定の色を検出するプログラム
https://craft-gogo.com/python-opencv-color-detection/
起動時のbashファイルの読み込み順

## 起動時のbashファイルの読み込み順

Ubuntu起動時に、`~/.bashrc`が読み込まれるため、カスタマイズしたい場合は、基本的に、`~/.bashrc`を触ればいいことになる。

環境変数を追加したい場合は、`~/.bashrc`に書いてもいのだが、`~/.profile`に書くのが慣例となっているので、`~/.profile`に書くことになる。個人の環境であれば、どこに書いてもいいだろうが。

`~/.profile`の中身を見ると分かるのだが、`~/.bashrc`は、`~/.profile`の中から読み込まれている。

そして`~/.profile`は、`/etc/profile`から読み込まれる。これのファイルが存在している場所は、ホームディレクトリではないので、ログインした全ユーザーに対して、共通で実行されることになる。一番最初に、読み込まれるファイルがこれになる。

`/etc/profile`から読み込まれるファイルは、`~/.profile`だけでなく、読み込まれる順番がある。その順番が、

>
1. ~/.bash_profile
- ~/.bash_login
- ~/.profile

上記３ファイルのうち、１つしか存在してはいけないことになる。Debian系には、`~/.profile`しか存在していないが、RedHat系には、`~/.bash_profile`が存在している。`~/.bash_login`はどうでもいいだろう。

`/etc/profile`のどこから、`~/.profile`を読み込んでいるのか、確認が取れなかった。ファイルの中身を見ると、`/etc/bash.bashrc`を読み込んでいのは分かる。これも全ユーザー共通で実行される。

そして、次に、`/etc/profile.d`配下にある、拡張子がshになっているファイルをfor文で回して`全て`読んでいる。`ls -l /etc/profile.d`で中身を見ると、複雑な名前のスクリプトファイルが、6個程存在している。このファイルの中で何をやっているかはぱっと見は複雑だ。この6ファイル全て実行されていることになる。流したいスクリプトファイルを追加したい場合は、`/etc/profile`を触らなくても、このディレクトリ配下に新規ファイルをおくだけで、自動で流してくれることになる。
作成したEC2にWebサーバー（nginx）を立ち上げるまで。

作成したEC2にWebサーバー（nginx）を立ち上げるまでの簡易的なメモです。

## 1.EC2にログイン
SSHでログイン。

```bash
# XX.XXX.XX.XXXはパブリックアドレスを入力。
ssh -i ~/.ssh/xxx.pem ec2-user@XX.XXX.XX.XXX
```

## 2.EC2にnginxをインストール
amazon-linux-extrasを使ってnginxをインストールします。

```bash
# マニュアルの確認
man amazon-linux-extras

# 利用可能なリストを表示
amazon-linux-extras

# 管理者権限でインストール
sudo amazon-linux-extras install nginx1

# nginxを起動
sudo systemctl start nginx.status

# nginxのステータスを確認(起動されていることを確認)
systemctl status nginx.status

# ポート80番の状態を確認
sudo lsof -i:80
```

## 3.Webサーバーの動作確認
EC2セキュリティグループのインバウンドルールを編集。ルールを追加。
![SS 2021-09-08 10.08.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140048/ac4481cb-5dae-1514-1706-88b5dc9fda60.png)
今回は確認用なので以下に編集。保存。
タイプ→「HTTP」　
ソース→「マイ IP」

ブラウザにてアドレスバーにパブリックアドレスを入力し、nginxの表示を確認。
![SS 2021-09-08 9.40.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140048/218c7ad3-6782-4aac-9c3a-3aa3ac99beaf.png)
AWS DVAの勉強 2021/8一発合格済み

#AWS DVAで覚えること
###・AWS COGNITO
ユーザー認証。IDフェデレーション、ユーザープール/IDプールの違い
###・AWS Elastic BeanStalk
###・AWS S3
SSE、バージョニング、
###・AWS RDS,AURORA,Elastic Cashe
###・AWS Lambda
###・AWS API Gateway
###・AWS DynamoDB
###・AWS SQS,SNS,SES
これらをテキスト・問題演習でやればOK。
使用したテキスト：[ポケットスタディ AWS認定 デベロッパーアソシエイト (アソシエイト試験ポケットスタディ)](https://www.amazon.co.jp/gp/aw/d/4798063401?psc=1&ref=ppx_pop_mob_b_asin_title)
Djangoでsync_to_asyncを使ってみる

Djangoで先にリスポンスを返してから重い処理を継続する簡単な方法を見つけたので紹介します。理解できていない部分も多いので、誤り等あればご指摘いただければ幸いです。

### asyncioを使った非同期処理
Django 3.1より非同期処理的にリスポンスを返す非同期Viewが導入されました。例えば、標準ライブラリasyncioを使って次のような非同期Viewを書くと、スリープしている間に非同期的にリスポンスを返してくれます。

```python:views.py
import asyncio
async def async_func():
    for i in range(5):
        await asyncio.sleep(1.0) # 1秒待機
        print(i+1)

async def async_response(request):
    task = asyncio.create_task(async_func())
    task
    return HttpResponse('Asyncronous Response')
```
上では、非同期関数`async_func`を定義し、非同期Viewの`async_response`で呼び出しています。`async_response`では`asyncio.create_task`を使って同時並行でコルーチンを実行しています。これをuvicornで実行してブラウザからアクセスすると以下のようなログが出ます("Project"はプロジェクト名で置き換えてください)。

```terminal
$ uvicorn Project.asgi:application
INFO:     Started server process [15308]
INFO:     Waiting for application startup.
INFO:     ASGI 'lifespan' protocol appears unsupported.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     127.0.0.1:49470 - "GET /myapp/async_response HTTP/1.1" 200 OK
1
2
3
4
5
```
スリープの完了を待たずにResponseが返されているのが分かります。

### sync_to_asyncによる非同期化
一方で、次の`sync_func`のような同期関数に適応したい場合、コルーチンを返す非同期関数に変換する必要があります。ここで、ASGIの`sync_to_async`を使うことができます。

```python:views.py
import time, asyncio
from asgiref.sync import sync_to_async
def sync_func():
    for i in range(5):
        time.sleep(1.0) # 1秒待機
        print(i+1)

async def async_response(request):
    async_func2 = sync_to_async(sync_func, thread_sensitive=False)
    task = asyncio.create_task(async_func2())
    task
    return HttpResponse('Asyncronous Response')
```
実行すると、先ほどと同様のログが出力されます。これにより、自分で定義した任意の処理を開始しつつ先にリスポンスを返すことができました。
　以上を応用すると、バックエンド側で機械学習や数値計算などの重い処理を開始しつつ、リスポンスを先に返すといったことにも使えるかと思います。

### 参考
* https://docs.python.org/ja/3/library/asyncio-task.html#coroutine
* https://docs.djangoproject.com/en/3.2/topics/async/
【エンジニア】初めて転職活動した話し

# はじめに
Qiitaに登録するキッカケは、転職活動を始めたことです。
転職活動を始めて、アウトプットの大切さを痛感しました。。そしてキッカケとなった転職活動のことを書いていこうと思います。
私と同じように「初めての転職活動」を不安に感じてる方々は沢山いると思いますし、エンジニアとして働き始めたばかりという方でも、常に準備しておいて損は無いので、少しでも私の経験がそのような方の助けになればと思い、可能な範囲で詳細に書いていこうと思います！！

# 自己紹介
- 2013年〜 ソフトウェア会社にて働き始める  

### 技術スキル
- OS：`Windows` `Mac` `Linux`
- 言語：`VB.Net` `C#.Net` `PHP` `Java` `C++` `HTML5` `jQuery`
- FW：`Spring Boot` `Laravel` `Smarty` `OnsenUI` `Cordova`
- DB： `SQL Server` `Oracle` `MySQL`
- その他：`Apache` `Git/GitHub` `Docker` `Jenkins` `Backlog` `AWS`

### マネジメントスキル
- プロジェクトリーダーとして、  
検証案件では最大10名規模のマネジメントを経験（工程管理/進捗管理/品質管理）  
開発案件では4名規模のマネジメントを経験(工程管理/進捗管理/品質管理）

# 転職を考えたキッカケ
1. 今の会社では、成長に限界を感じたから。
2. 自分の可能性に挑戦してみたくなった。
3. 頑張りを評価してくれる会社に行きたいと思った。

# 今後は何をしたい？
- 今後はマネジメントの力を付けたいとは思いつつ、技術スキルが不足していることも自覚しています。  
現職では経験年数の浅い頃からリーダー業務のようなことをすることが多かったが、「自分はまだスキルが足りてないんじゃないか」と
モヤモヤしながら過ごす日々。。  
まずは技術を全力で磨こうかなと！！（技術を磨いてる中で、やっぱり技術が好きでその道に。。となるかも？）  
- 人に必要とされるプロダクトを作っていきたい。
- チーム作りでは、誰が抜けても品質を落とすことの無い「属人化」の無いプロジェクト作りをして行きたい。

# まず転職活動で行ったこと
1. 右も左も分からず、とりあえず転職サイトに登録してみる。
私が主に使用したのは、`BIZREACH` `openwork` `ミドルの転職` など。
2. 登録した転職サイトで、エージェントの方から沢山のメッセージが届く。  
沢山スカウトが届くため、「自分は優秀な人間なのか？」と勘違いしそうになる（笑）  
ただ驚いたのは、人材紹介の会社ってこんな沢山あるんだ！ということ。
3. 職務経歴書を作成し、エージェントの方々に添削してもらう。

# ぶち当たった壁
- **個人活動/アウトプットの大切さ**  
エンジニアとして転職する上で、GitHubやQiita等ブログやSNSなど、今までどれだけの個人活動、自己学習、アウトプットしてきたか？が求められます。← 私が無知すぎて、これを全く知らなかった  
でも普通に考えて、企業側も採用する上でエンジニアの能力を知りたいわけで、職務経歴書などから測れる能力なんて高が知れてます。自分の能力を示せるモノを残しておくことは当たり前です。。（今まで学習してきた内容など、なぜ残してないんだと、転職活動を始める上で一番後悔しました）
- **各技術の経験の浅さ**  
現職はSESメインであるため、案件によっては全く新しい言語に触れる。ということや、開発以外の案件ということも珍しくありません。  
そのため「この言語・技術は自信がある！！」というくらい熟練できる環境に身を置ける機会がほぼありませんでした。
求人によっては「PHPの開発歴3年」という必須スキルがあったりしますが、私は長くて2年ほど。。ということもありました。  
ただ色々な案件・技術をこなしてる分、「キャッチアップするスキル」はかなり付いたと思うので、私はそれで勝負することになりますが、私の可能性をどれだけ伝えられるか？が鍵になるわけです。

# 私が経験して感じたこと/感じていること
まだ採用を頂いてない私が書くのも恐縮ですが！笑
**※ 1人のエージェントだけとやりとりするのではなく、数名の方にお願いする方がいいです。正直、エージェントによって熱量も違えば、職務経歴書に対する指摘も違います。あまり多いと紹介いただく求人を捌ききれないので5名ほどかなと。**
**※ エージェントの方は基本的に、前向きなことを言って頂けます。ただ私個人の意見としては、「エージェントの経験上、私が課題になりそうな点は何か？」を聞いたほうが良いかなと思ってます。自分の課題を知っておけば、それを前もって補うような職務経歴書の記載もできますすし、面接の準備もできます。** 

# 結局、転職活動の状況はどうなってるの？
**※2021/09/07：現在進行中**
各エージェントに紹介して頂いた10社ほどにエントリーし、数社のカジュアル面談を控えてる状況。

#### 応援していただけると幸いです！！
GCC 11.2.0 - x86 SIMD: emmintrin.h の _mm_loadu_si32 と _mm_loadu_si16 のバグ

GCC 11.2.0 で、_mm_loadu_si32 を使うと下位32ビットではなく、上位32ビットに値が入っている。

(Clang 12.0.5 では下位32ビットに値が入っていました)

そこで emmintrin.h を覗くと、パラメータが逆順になっていた。

直下の _mm_loadu_si16 の実装も同じミスをしているっぽい。

修正するなら _mm_loadu_si32 と _mm_loadu_si16 から呼び出す関数を

_mm_set_epi32 → _mm_setr_epi32
_mm_set_epi16 → _mm_setr_epi16

に変更するか、関数はそのままで引数の順番を変更するか。
logrotateが動かない (備忘録)


# logrotate とは

各種アプリケーションが吐き出すlogファイルを圧縮したりローテーションしたり古いものを削除したりするアプリケーション。

# 環境

* Fedora Server 31 (5.8.18-100.fc31.x86_64)



# 何が起こったのか

**ログファイルのローテーションが行われない。**

logrotateの設定ファイル（`/etc/logrotate.conf`,`/etc/logrotate.d/*.conf`）の記述内容は正しく、
`sudo logrotate -d /etc/logrotate.conf`でデバッグしても問題ない。
また、`sudo logrotate -f /etc/logrotate.conf` で手動で強制的に実行すると正常にローテーションされるにもかかわらず、自動でローテーションされない。


# 解決方法

## `logrotate.timer` サービスが動作していなければ動かす。

```bash
$ sudo systemctl status logrotate.timer 
● logrotate.timer - Daily rotation of log files
   Loaded: loaded (/usr/lib/systemd/system/logrotate.timer; disabled; vendor preset: disabled)
   Active: inactive (dead)
  Trigger: n/a
     Docs: man:logrotate(8)
           man:logrotate.conf(5)

$ sudo systemctl start logrotate.timer 

$ sudo systemctl status logrotate.timer 
● logrotate.timer - Daily rotation of log files
   Loaded: loaded (/usr/lib/systemd/system/logrotate.timer; disabled; vendor preset: disabled)
   Active: active (waiting) since Wed 2021-09-08 09:18:15 JST; 3s ago
  Trigger: Thu 2021-09-09 00:00:00 JST; 14h left
     Docs: man:logrotate(8)
           man:logrotate.conf(5)

$ sudo systemctl enable logrotate.timer 
```

## 次はいつ動くか知りたい

```bash
$ sudo systemctl list-timers
NEXT                         LEFT          LAST                         PASSED    UNIT                         ACTIVATES
Wed 2021-09-08 09:47:13 JST  14min left    Wed 2021-09-08 08:47:13 JST  46min ago dnf-makecache.timer          dnf-makecache.service
Wed 2021-09-08 11:25:13 JST  1h 51min left Tue 2021-09-07 11:25:13 JST  22h ago   systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.s>
Thu 2021-09-09 00:00:00 JST  14h left      n/a                          n/a       logrotate.timer              logrotate.service
Thu 2021-09-09 00:00:00 JST  14h left      Wed 2021-09-08 00:00:13 JST  9h ago    mlocate-updatedb.timer       mlocate-updatedb.service
Thu 2021-09-09 00:00:00 JST  14h left      Wed 2021-09-08 00:00:13 JST  9h ago    unbound-anchor.timer         unbound-anchor.service

5 timers listed.
Pass --all to see loaded but inactive timers, too.
```

上記例では`Thu 2021-09-09 00:00:00 JST`にキックされる


## タイマーの設定はどこ？

`/etc/systemd/system/timers.target.wants/logrotate.timer`で設定されています

```ini:logrotate.timer
[Unit]
Description=Daily rotation of log files
Documentation=man:logrotate(8) man:logrotate.conf(5)

[Timer]
OnCalendar=daily
AccuracySec=1h
Persistent=true

[Install]
WantedBy=timers.target
```




# なぜ起きたのか

* logrotateは`cron.daily`で動くものだと思い込んでいた。（実際、ググると「`cron`で動く」と記載のあるサイトが多数ヒットする）
* そして、設定に問題があるものと思い設定ファイルをこねくり回していた。


# 参考資料

[ArchLinux Wiki - logrotate](https://wiki.archlinux.org/title/Logrotate)
[windows][visual studio2019]「次/前のタブ」のショートカットキーが効かない！？

visual studioで、ソースコードを複数開いて開発することよくありますよね。
で、タブの移動に、Ctrl+PgDn/Upを使用するのですが、全く反応しません。
その直し方です。

# 結論: Ctrl+PgDn/Upの他の割当てを、削除する。

##方法
###1.VSのデフォ設定で、Ctrl+PgDn/Upに「ウィンドウ.次/前のタブ」が割り当てられているのを確認。
visual studio起動 -> ツール -> オプション -> 環境 -> キーボード
-> "以下の文字列を含むコマンドを表示"の欄に、"のタブ"を入力。

Ctrl + PgDn(全体)が設定されているのを確認。
![aaaaaaaa次のタブ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723966/ee125fda-d0df-6055-e1a6-051b32e6d328.png)

同様に、Ctrl + PgUp(全体)が設定されているのを確認。
![aaaaaaaa前のタブ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723966/d151dff4-ad77-1de2-1bbc-f1daa4ae21e1.png)

なのに、Ctrl + PgUp/Dnを入力してもタブが移動しない。


###2.Ctrl+PgDn/Upの他の割当てを削除する。
(今回は、"編集.下端に移動","編集.上端まで移動"にあった。)

"以下の文字列を含むコマンドを表示"の欄に、"端"を入力。
"編集.下端に移動"を選択 -> 削除
![aaaaaaaaaaa下端に移動.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723966/01d2949c-ddbc-1fdc-4369-141fb92b39f5.png)

"編集.上端まで移動"を選択 -> 削除
![aaaaaaaaaaa下端まで移動.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1723966/5157c953-b905-c921-70ac-5e59860fb30d.png)

これで、Ctrl + PgDn/Upで、タブの移動できる様になったはず。
ActiveStorageにバリデーションを設定する方法

## はじめに

Ruby on Railsにおいて、ActiveStrageは画像投稿機能を実装する際、
とてもシンプルで使いやすく、重宝しています。
ただ、**バリデーション**の設定が**デフォルトでできない**ようです。
どうにかしてバリデーションの設定ができないか調べてみると、
オリジナルでファイルを作成している方々がたくさんいらっしゃり、
尊敬と憧れを抱きつつも、ズボラな自分はもっと簡単に設定する方法ないの？
と探してたどり着いた方法です。

それは`activestorage-validator`という`gem`を導入する方法です。

個人的に、普通にモデルに設定するバリデーションとほぼ同じやり方で設定できる点が使いやすいなと感じ、他の初学者の方にもオススメできると思い記事にした次第です。

導入から使い方を下記にまとめて見ました。

（今回は`Rails 6.0` 、`MySQL`を使用しています。)

## 導入方法

まず、`Gemfile`に下記を記述します。

```ruby
gem 'activestorage-validator'
```
コンソールで

```ruby
% bundle install
```
これで導入は完了です。

## 使い方
### ファイル添付必須
入力フォームでファイルの添付を必須にしたい時の記述方法です。
'activestorage-validator'では、`presence: true`で指定できます。

#### 配置例

```ruby
class User < ApplicationRecord
  has_one_attached :avatar

  validates :avatar, presence: true, blob: { content_type: :image }
end
```

- `blob:`と記述するのは、ActiveStorageは`Blob`と`Attachment`モデルを使うからです。
- `content_type:`で添付ファイルの型を指定します。今回の例では画像なので、`:image`となります。
（オプションは`:image`の他に、`:audio`、`:video`、`:text`を指定可能です。）

### 拡張子など、もっと細かく指定したい場合
#### 配置例

```ruby
class User < ApplicationRecord
  has_many_attached :photos
  validates :photos, presence: true, blob: { content_type: ['image/png', 'image/jpg', 'image/jpeg'], size_range: 1..5.megabytes }
end
```
- 拡張子を細かく指定したい場合は`content_type:`で上記のように記述すれば、より細かく指定できます。
- 保存できるファイルの容量を指定したい場合は、`size_range:`で指定します。上記だと1〜5MBのファイルのみ保存可能にしています。

## 終わりに
以上で現時点で私が理解している機能についての説明を終わります。
まだ試していませんが、`message:`を使えば表示されるエラー文の指定もできるのではないかと考えたり、まだまだ細かいバリデーションを設定できる可能はあります。
`active_strage_validations`という`gem`も似た感じでバリデーションの設定ができるようですが、
なんとなく'activestorage-validator'の方が直感的にわかりやすかったので、個人的にはこちらを使用させていただいております。
もっと詳しく知りたい方は下記参考文献よりご確認ください。

初学者ですので、理解不足な部分があると思いますが、間違いなどあれば
ご指摘していただけると幸いです。

## 参考文献
- [ActiveStorageのバリデーション](https://qiita.com/ken1flan/items/76dcdd4971d26b4fb13d)
- [【Rails 5.2】 Active Storageの使い方](https://qiita.com/hmmrjn/items/7cc5e5348755c517458a)
- [activestorage-validator](https://github.com/aki77/activestorage-validator)
- [Active Storage Validations](https://github.com/igorkasyanchuk/active_storage_validations)
Windows Terminal でベルを抑制する

Windows Terminal のベルは Windows のサウンド設定が使われるんですが、Windows 10 のデフォルトでは「ピロん」って感じでわりとドキッとする音がします。警告音としてはドキッとするのは正しいのですが、TAB補完で複数候補が出てきたときなどにいちいちベル音が鳴っていると少々うっとおしいです。

この音を消す方法をググったところ、`~/.inputrc` に `set bell-style none` を書くという方法が複数ヒットします。それでも確かにベル音は消えますが、Windows Terminal の設定でなんとかならないのかなと更に調べたところありました。

1. 設定画面を表示する
  タブの並びにあるメニューボタンから"設定" を選択するか、Ctrl+,で設定画面が開きます。

1. 設定したいプロファイル(この場合 Ubuntu)の詳細設定を開く
  ![setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/95bd00bc-8b5a-cfa9-50f8-febb5e3f6f52.png)

1. 「ベル通知スタイル」の「音によるチャイム」のチェックを外して保存する。

以上です。

いつの間にか GUI の設定画面なんて出来てたんですね。4月にリリースされた 1.7 から使えるようになっていたんでしょうか。気が付いてませんでした。

なお、従来通り settings.json による設定も可能です。

[Bell notification style](https://docs.microsoft.com/ja-jp/windows/terminal/customize-settings/profile-advanced#bell-notification-style)

## 音を変更する

(2021.10.1追記)

ベルを抑制するのではなく別の音に変更したい場合、Windows Terminal 単体では設定できません。Windows のサウンドコントロールパネルから「システムエラー」の割り当てを変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86075/952d6eb0-829f-d191-1897-9b93feb89ce0.png)
`go install` で、コマンドのパッケージパスとバージョンを保持しておきたい

どうも。昨日初冠雪した富士山を眺めつつ記事を書いている、アユタヤドットコムの那賀です。

go 1.16 から、グローバルへのツールのインストールには `go install` を使い、開発中のライブラリの管理には `go get` を使うということで、きっちり分かりやすくなりました（参考: [Go1.16からの go get と go install について - Qiita](https://qiita.com/eihigh/items/9fe52804610a8c4b7e41) ）

しかしこの `go install` は、 `$GOPATH/bin` にパッケージ末尾の名前でコロンと実行ファイルを転げてくれるだけというとても思い切りの良い仕様なので、いくつかの情報が落ちます。 // [go command - cmd/go - pkg.go.dev](https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies)

具体的には、以下がやや辛い。特に、今入っているコマンドが最新なのかを確認したい場合や、バージョンアップを検討したい時などに。まあ、定期的に全部のコマンドを、問答無用で `@latest` で上書きするような `go install` を列挙したスクリプトを実行するのでも、運用上は特に困らないとは思うんですけども。

* パッケージ名のフルパスが分からなくなるので、どこから入れたか分からなくなる
* どのバージョンを入れたか分からなくなる

簡易的にそれらの情報をファイル名として保持し、コマンド名へシンボリックリンクを張るようなシェルスクリプトを書いてみました。

```shell-session:
$ go-install github.com/ericchiang/pup@v0.3.8
$ ls -l ~/go/bin/pup*
pup -> pup-github.com%2Fericchiang%2Fpup@v0.3.8
pup-github.com%2Fericchiang%2Fpup@v0.3.8
$ go-install github.com/ericchiang/pup@latest
$ ls -l ~/go/bin/pup*
pup -> pup-github.com%2Fericchiang%2Fpup@v0.4.0
pup-github.com%2Fericchiang%2Fpup@v0.3.8
pup-github.com%2Fericchiang%2Fpup@v0.4.0
```

要点としては、パッケージ名を後ろ側から切り詰めながらモジュール名を探すところと、 `go list -m --versions` で対象のモジュールのバージョン情報を取り寄せているところだけです。簡易なものなので、複数指定に対応していない、インポートパスのワイルドカードを扱えない等の問題がありますが、ひとまず用をなすのでこのまま使ってみます。

<!-- mdppcode src=/Users/knaka/bin/go-install -->

```bash:go-install
#!/bin/bash
set -o nounset -o errexit -o pipefail

: ${bindir:=$(go env BINDIR)}
: ${bindir:=$(go env GOPATH)/bin}
: ${bindir:=$HOME/go/bin}
read -r package target_ver <<< $(echo "$1" | sed -nEe 's/^([^@]+)(@(.*))?/\1 \3/p')
module="$package"
while true
do
  modversions=($(go list -m --versions "$module"))
  test ${#modversions[@]} -gt 1 && break
  module=$(echo "$module"| sed -nEe 's@/[^/]+$@@p')
done
latest_ver="${modversions[${#modversions[@]}-1]}"
test -z "$target_ver" -o "$target_ver" = "latest" && target_ver=${latest_ver}
basename=$(basename ${package})
rm -f ${bindir}/${basename}
go install ${package}@${target_ver}
name=$(echo "${basename}-${package}@${target_ver}" | sed -Ee 's@/@%2F@g')
mv -f ${bindir}/${basename} ${bindir}/${name}
ln -sf ${name} ${bindir}/${basename}
```

<!-- /mdppcode -->

本当は、Golang のライブラリでパッケージ情報を問い合わせることができれば Go でツールを書こうかと思ったのですが、それらは軒並み Go 本体の internal の機能なので、呼べないんですよね…どこかに良いライブラリは無いかしら。

では。
GitHubを使いやすくするChrome拡張をリリースした【個人開発】

**GitHubのIssueを業務や個人開発でもっと使いやすくする**Chrome拡張**「Mokuren」**を作りました。
エンジニアやプロジェクトマネージャーの方に使っていただけると、劇的に変わると思います。

https://chrome.google.com/webstore/detail/mokuren-for-github/nikennffbfoadbajdgnhlngjahofhdef?utm_source=qiita

仕事の隙間時間を使いながらコツコツ開発してきましたが、無事公開できました。
開発は半年くらいかかったと思います。友人との開発だったので感謝でいっぱいです。

今回は、**Mokurenの紹介と技術周りの話を書いていきます。**
個人開発をしている人のモチベアップにでも繋がれば嬉しいです。

その前にさくっとMokurenについて紹介させてください。

# Mokurenを使ってる人のGitHubの画面

こちらはGitHubのIssue一覧の画面です。画面右側と下に普段見ないような表示があります。
これがMokurenの機能です。

![FireShot Capture 271 - Issues · tinp-lab_Mokuren-on-boarding - github.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195882/d0ecf50a-5bb3-6504-fa53-7b1a228d7036.png)

# 機能紹介

### (画面右側)サイドバー

これはIssue一覧画面からIssueの詳細情報をサイドバーで開けるようにした機能です。
Issue一覧ページから離れずに、詳細情報を見たりコメントしたりラベルも変えられます。
動画でのが伝わりやすいかと思うので、Twitterにあげたやつですが再生してみてください。

https://twitter.com/imasirooo/status/1434850438361145344


### (画面下)ピン

次はピンです。ピンはIssueやPull requestをピンしておけばGitHub上の全てのページからアクセスできる機能です。
エンジニアだったら実装に関係するIssueやPull request。Issueを管理する立場の方なら、後で確認するIssueをサクッとピンしておくなどの使い方ができると思います。

こちらも動画があるのでよかったら再生してください！

https://twitter.com/imasirooo/status/1434858749638758402

# 技術周りの話

ここからは技術周りについてです。

### Mokurenの動作環境

* Vue.js
* typescript
* Firebase Realtime database
* GitHub API V4
* Apollo
* sass


### Chrome拡張でVue.jsを使うには

Webアプリケーションを作るならvue cliやnuxtを選択する手もありましたが、今回はGitHubページのDom操作をしないといけないため、
Vueインスタンスを直接埋め込む方式にしました。
以下は例です。

```js
new Vue({
  store: store,
  render: (h) => h(App),
}).$mount("#id");
```

ビルドにはこちらのpackageを使用しました。ここら辺需要があれば別記事で詳しく書こうと思います。
https://github.com/adambullmer/vue-cli-plugin-browser-extension


### GitHub V4を選んだ理由

GitHub APIのv4はGraphQLなのですが、今まで使ったことがありませんでした。
それでも使用した理由は、Mokurenの仕組み上、GitHub内の複雑な情報を取得しないといけなく
REST APIだとリクエスト数が半端ないことになってしまいました。

GraphQLは取得するデータをフロント側が操作できるので、普通であれば10回リクエストしないといけないところを1回で済み、パフォーマンス的にも向上しました。

### リリースした後

ProductHuntといった海外の、プロダクト投稿サイトに載せました。
毎日ランキングが走るサービスで、Mokurenはその日の8位になりました。
この時の記事は[noteに書きましたが](https://note.com/inasirooo/n/n567859a68d9a)、多くのユーザー流入がありました。個人開発だと作って使われずに終わるケースになりがちですが、いろんな人に使ってもらえるのでProductHuntはお勧めです。

<img width="500" alt="picture_pc_d5feb654b6b53544facff057638f0d58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195882/dfcf8a57-9dd8-cc2e-eba2-eb84ccebdc8e.png">


# よかったこと

* まだユーザー数はそんなの多くないですが、毎日使ってくださるユーザーやフィードバックをくださるユーザーがいて嬉しい
* はじめてtypescriptを使ったがもうjavascriptには戻れない


# 大変だったこと

* 初めてのtsだったのでインプット大変だった
* リリース前にテストユーザーにいろいろフィードバックもらったが、初期は全然使われないものだった
* 使ってくれる人がいるのかの不安との戦い


正直多変なことの方が数では多いです。
でも使ってくれる人がいるだけで、その辛さはどこかへ消えてしう瞬間があります。
とはいえまだまだ改善の余地があるのでコツコツと続けていきたいです。

ここまで読んでいただきありがとうございます。
もしよかったらMokurenを使ってみてフィードバックをいただけると嬉しいです

https://chrome.google.com/webstore/detail/mokuren-for-github/nikennffbfoadbajdgnhlngjahofhdef?utm_source=qiita
[React] [Amplify] Audioでmp3を読み込めず「DOMException: Failed to load because no supported source was found.」が発生する

# はじめに
Reactで開発しているWebページ上で音楽を再生しようとしたところ
ローカル環境では再生が可能であるのに、Amplifyでホストしている開発環境でタイトルのエラーが発生して再生できませんでした。
原因を調査しましたので、備忘録として記載していきます。

# 事象


以下コードのように音声を再生しようとしたところ
コンソール上にエラーが表示されてしまいました。

``` ts
import AudioSource from './assets/AudioSource.mp3';

~中略~

const audio = new Audio(AudioSource);
audio.play();
```

以下のようなエラーが発生。サポートしてないソースだからロードできないそうな。なぜ？

```
DOMException: Failed to load because no supported source was found.
```

# 解決策

普通にエラーメッセージでググるといかにもそれっぽいaudioやvideoタグを使用した際の内容が引っかかりますが、私には当てはまりませんでした。

私の場合はAmplifyの設定に問題がありました。
と言ってもSPAの設定時にAWS公式の以下の指定に沿って、SPAを機能させるためにリダイレクトの設定をしていただけです。
https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/redirects.html#redirects-for-single-page-web-apps-spa

ふと気になって正規表現を見てみると、「mp3」が存在しません。
構築時に何となく設定をしていただけでしたので、全く気づきませんでした。

```
</^[^.]+$|\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|woff2|ttf|map|json)$)([^.]+$)/>
```

というわけで、mp3をリダイレクトの対象外に追加してあげて解決しました。

```
</^[^.]+$|\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|woff2|ttf|map|json|mp3)$)([^.]+$)/>
```

以上です。
【Ruby on Rails】バリデーションが効かなかったときの原因追求をした話


#対象者

* バリデーションを使っている方
* バリデーションが効かない不具合が発生している方


#目的

* バリデーションを使って投稿が失敗するようにすること

#実際の手順と実例
###1.前提

https://post-output.com/185/

上記記事を参考に実装

* Articleモデル（記事の投稿）、Tagモデル、ArticleTagモデル（中間テーブル）実装中
* title,bodyはArticleのカラム、tag_nameはTagのカラム

　下記のようにバリデーションを設定したが投稿ができてしまう、、、

````model/tag.rb
class Tag < ApplicationRecord
  has_many :articles, through: :article_tags
  has_many :article_tags

  validates :tag_name, presence: true
end
```

###2.結論（解決策）

下記のようにコントローラーを変更

before

```app/tags_controller.rb
def create
    @article = Article.new(article_params)
    @article.user = current_user
    tag_list = params[:article][:tag_name].split("/")
    if @article.save
      @article.tags_save(tag_list)
      flash.now[:notice] = "投稿されました"
      redirect_to article_path(@article)
    else
      @user = current_user
      flash.now[:alert] = "投稿に失敗しました"
      render :new
    end
  end
```

after

```app/tags_controller.rb
def create
    @article = Article.new(article_params)
    @article.user = current_user
    tag_list = params[:article][:tag_name].split("/")

      #下記の部分を追加
    if tag_list == []
      tag = Tag.new()
      tag.tag_name = ""
      tag.save
      @user = current_user
      flash.now[:alert] = "投稿に失敗しました"
      render :new
      #上記の部分を追加

    elsif @article.save
      @article.tags_save(tag_list)
      flash.now[:notice] = "投稿されました"
      redirect_to article_path(@article)
    else
      @user = current_user
      flash.now[:alert] = "投稿に失敗しました"
      render :new
    end
  end
```

※上記のコントローラーで使用している**tags_save(tag_list)**はArticleモデルで定義したものです。

```app/model/articles.rb
 def tags_save(tag_list)
    if !tags.nil?
      article_tags_records = ArticleTag.where(article_id: id)
      article_tags_records.destroy_all
    end
    
    tag_list.each do |tag|
      inspected_tag = Tag.where(tag_name: tag).first_or_create #①
      tags << inspected_tag
    end
  end
```


###3.原因

**@article.saveで保存が行われてしまっている**

beforeの書き方だと先にarticleの内容が保存されてしまっており、
tag_saveも””空欄が保存され、そのまま通過してしまっている

````Terminal
[7] pry(main)> tag.tag_name = ""
=> ""
```

空欄だと投稿は失敗ですよということを表すために、
下記の記述を追加

```app/tags_controller.rb
    if tag_list == [] #タグが空欄だったときの条件付け
      tag = Tag.new()
      tag.tag_name = ""　#タグ名が空欄であることを定義
      tag.save　#セーブされ、ここでバリデーションが作動する
      @user = current_user
      flash.now[:alert] = "投稿に失敗しました"
      render :new 
    elsif
      (中略)
　　　　　　　end
```

バリデーションが作動するのは.saveされたとき！ということを学びました、、！
Rails enumの使い方

#enumとは
enumは列挙型でカラム(列)で文字列を順番に出力していくものです。

そしてそれぞれに数字を割り当てて意味を持たせます。

例えばある処理をして処理の流れを表現できます。

0が「未入力」、1が「入力中」、2が「処理中」、3が「処理済」
というように　処理の流れを表現できます。


⚫︎補足
Rubyにはenumはなくrails　4.１以降から導入されたみたいです。

#enumを使うと?

Enumを使うことにより数値で修正が簡単になり、module側で変更するだけで
全体に変更が反映されます。
意味を持った文字を入れて、DB は数字で管理し保存しておくことができます。
そして値を決めることによって不正なアクセスが入らないようにします。

データベースの中身が見れるschema.rbで見てみましょう。


```schema.rb

ActiveRecord::Schema.define(version: 2021_01_17_095549) do

  create_table “staffs", fcharset: "utf8", force: :cascade do |t|
    t.string “name”
    t.string “job”
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    end

```

これをenumにすると

```app/models/staff.rb

class Staff < ApplicationRecord
enum name: {
Taro: 0,
Jiro: 1,
Saburo: 2,
Yonro: 3
}

```
みたいになります。

nameカラム(integer型)の中の４人の名前をそれぞれ紐づけます。
nameカラムにtaroを入れたら0がデータとして入ります。


#シンボルと文字列で定義
enumはシンボルと文字列で定義ができます。

```rb

class Student < ApplicationRecord
  # シンボルで定義
  enum school_class: [ :A, :B, :C, :D ]

  # 文字列で定義
  enum blood_type: [ "A", "B", “C”, “D” ]
end


```

Rubyの配列と同じで添字と定数が紐付きます。

```rb
Student.create(school_class:  ‘A’)      データベースに0が保存される

Student.create(school_class: ‘B’)      データベースに1が保存される

```




#型による使い方
integer,boolean,型による使い方、　確認、検索、更新メソッド
など他にもいろいろな使い方があります。

この資料から確認してみてください。
https://pikawaka.com/rails/enum


⚫︎参考資料
https://pikawaka.com/rails/enum
https://techacademy.jp/magazine/31545
https://web-camp.io/magazine/archives/16862
https://qiita.com/kitsunecat/items/ddc13b95814650c4471e
Swift　デコレータパターン

デコレータパターン
--
The Decorator（デコレータ)とはデザインパターンの一つ。
既存のクラスに存在しなかった追加機能を実装するために用いる。クラス内のゴニョゴニョせずに追加機能を実装できるデザインパターンと覚えれば良さげ、、

extension
--
extensionがあるから必要なくない？
よくextensionをつかって関数を作成したり、Delegateパターンを追加するのが王道な気がする。。
可読性も上がるし、実際僕自身もたくさん使用する。
ただ、既存のクラスをあくまで拡張するのがextensionなのでoverrideはできないし、ストアドプロパティをゴニョゴニョすることはできない。

例コード

```swift
// 全ての親クラス
class Living {
    func bark() -> String {
        return "live"
    }
}

// 動物クラス
class Animal: Living {
    override func bark() -> String {
        return "animal"
    }
}

// 各動物の種類の親クラス
class Kind: Living {
    let living: Living
    
    init(living: Living) {
        self.living = living
    }
}

//🐩クラス
class Dog: Kind {
    override func bark() ->String {
        return "wanwan"
    }
}



```
自分用 MVCアーキテクチャ

#MVCの概略
設計思想の話で、要はコードを整理していく指針。
目的は保守性を上げたり、コードの再利用性を上げたりすること。
これにならってコーディングしていくと拡張もしやすい。

#登場人物（に置き換える）

###Model氏
データの管理を担当

###View氏
画面の入出力を担当
画面に表示するものや、画面からクライアントの入力を受け取るもの

###Controller氏
アプリの主な制御（ビジネスロジック）を担当
####補足：ビジネスロジックとは
*画面を出し分ける際の判定するか
*ユーザーがログインしたときにこのログイン情報でログインさせるか


#登場人物の相関関係
最低限、以下View起点の3つを抑えとく。


1.Viewで入力
⇒Controllerに伝え
⇒その値をModelとして保持

2.Viewで入力
⇒Controllerに伝え、その値によって
⇒Viewを呼ぶ

3.Viewで使用する変数は
⇒Modelから取得する


##補足
そのほかにModelの値を変更すればその変更がそのままDBに反映される高度な実装、や
MVVM(Model・View・ViewModel)アーキテクチャなどがある。
mailcatcherが特定の環境で落ちる

UnitTestでmailcatcher使っていたところなぜか落ちるようになりました。

いろいろ調べたところ
`bento/amazonlinux-2` >= 1.2.0 && mailcatcher == 0.8.1(現時点の最新)
で落ちるようです

大人しくバージョンダウンしましょう

```
 gem install mailcatcher -v 0.7.1
```
自分のローカルだけに保存したいコードがあるとき

M1のMacを使い始めて、追加のコードを書かないとM1では実装できないことがありました。
しかしそのコードをpushするとステージングで、エラーになってしまう。。
そんな時に使ったのがこれ！

```
git update-index --assume-unchanged '無視するファイル名'
```
※GitHubにpushしたくないファイル名はそのファイルの上で右クリック→Copy Relative Pathでコピーできます。

これでGitHubにpushされず、自分のローカルだけに反映されます。
【Next.js】 Vercelビルド時のエラー解決方法  'Page Without Valid React Component'

## 使用環境
・MacOS BigSur（11.5.2）
・VScode（1.59.1）
・Node.js   (16.1.1）
・React（17.0.2）
・Next.js（11.1.0）

## はじめに

Vercelのビルド時に出たエラー’Page Without Valid React Component’の解決方法です。

![スクリーンショット 2021-09-08 5.14.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/711874/0572dcca-ea59-77e9-13a7-956dea4ba674.png)


```bash
04:50:30.440  	> Build error occurred
04:50:30.442  	Error: Build optimization failed: found pages without a React Component as default export in 
04:50:30.442  	pages/editPage
04:50:30.442  	pages/profile
04:50:30.442  	pages/search
04:50:30.442  	pages/userAuth
04:50:30.443  	See https://nextjs.org/docs/messages/page-without-valid-component for more info.
04:50:30.443  	    at /vercel/path0/node_modules/next/dist/build/index.js:597:19
04:50:30.444  	    at processTicksAndRejections (internal/process/task_queues.js:95:5)
04:50:30.444  	    at async Span.traceAsyncFn (/vercel/path0/node_modules/next/dist/telemetry/trace/trace.js:60:20)
04:50:30.473  	error Command failed with exit code 1.
04:50:30.474  	info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
04:50:30.493  	Error: Command "yarn run build" exited with 1
```

## 結論/解決策

Vercelビルド時のエラーログだけではよく分からなかったので、エラーログに表示されていたNext.jsの公式ドキュメントのURLに飛んだら方法が書いてありました。

pagesの配下のReactコンポーネント（ページとして表示させたいコンポーネント）は`export`ではなく、`export default` を使用しなければいけないそうです。

> If the file is meant to be a page, **double check you have an export default with the React Component instead of an export.** If you're already using export default, make sure the returned value is a valid React Component.
- [公式DOC][1]より


（後々、エラーログみたらちゃんと書いてありました:yum: `Error: Build optimization failed: found pages without a React Component as default export in`）

## 最後に

default exportだとimportする際のクラス名や関数名が一致していなくても呼び出せることから、予期せぬエラーが生じるのを回避するためにexportを使った方がいいという情報をどこかでみたので慣習的にそうしていました。

しかし今回のようにNext.jsでpagesのコンポーネントとして読み込ませる時など、`default export`でなければValid React Componentとしてみなされないケースもあるみたいです。

なぜそうなのか気になって公式ドキュメントのPagesの解説をみましたが、詳しくは書いてありませんでした。これ以上深堀まではしてませんが、そういうものだと思っておきます。

もし詳しい方がいたら情報いただけると幸いです 🙇

## 参考資料

- Next.js 公式ドキュメント[Page Without Valid React Component][1]
- Hatena Blog [【React/ES6】named exportsとdefault exportsの使い分け][2]

[1]:https://nextjs.org/docs/messages/page-without-valid-component#why-this-error-occurred
[2]:https://bonoponz.hatenablog.com/entry/2020/06/11/%E3%80%90React/ES6%E3%80%91named_exports%E3%81%A8default_exports%E3%81%AE%E4%BD%BF%E3%81%84%E5%88%86%E3%81%91
xrdpのHomebrew Formulaを作った

既にいくつかの記事でビルドや設定方法は語られているが、車輪の再発明をする必要もないので、HomebrewのFormulaにして、今後xrdpをmacOSで利用したいユーザがいちいちビルド環境を整えてビルドしなくてもするようにしておく。

## TL;DR

```sh
brew tap eru/tap
brew install eru/tap/xrdp
```

## 解説

```ruby
class Xrdp < Formula
  desc "Open source RDP server"
  homepage "http://www.xrdp.org/"
  url "https://github.com/neutrinolabs/xrdp/releases/download/v0.9.17/xrdp-0.9.17.tar.gz"
  sha256 "56b913dd6d0f15b60f7a53963b30ad905f00669c91701db35bb4410be262a77e"
  license "Apache-2.0"
  head "https://github.com/neutrinolabs/xrdp.git"

  depends_on "autoconf" => :build
  depends_on "automake" => :build
  depends_on "libtool" => :build
  depends_on "nasm" => :build
  depends_on "pkg-config" => :build
  depends_on "libxfixes"
  depends_on "libxrandr"
  depends_on "openssl@1.1"

  def install
    ENV.prepend_path "PKG_CONFIG_PATH", Formula["openssl@1.1"].opt_lib/"pkgconfig"

    system "./bootstrap"
    args = %W[
      --prefix=#{prefix}
      --sysconfdir=#{etc}
      --localstatedir=#{var}
      --disable-dependency-tracking
      --disable-silent-rules
      --enable-strict-locations
    ]
    system "./configure", *args
    system "make"
    system "make", "install"
  end

  test do
    system "#{bin}/xrdp", "--version"
  end
end
```

よくある雑なFormulaだが、特筆する点としては、macOSではLibreSSLが標準になっているため、[OpenSSLのFormula](https://github.com/Homebrew/homebrew-core/blob/dfa45b3a40d3675c1eaf5d3db98ffaf5f5861888/Formula/openssl%401.1.rb#L24)にも記載がある通り、OpenSSLをHomebrewでインストールしてもパスが通らないので、明示的に`PKG_CONFIG_PATH`に追加を行っている。

また、`--sysconfdir=#{etc}`, `--localstatedir=#{var}`で、それぞれのパスをHomebrewのprefix(`brew --prefix`で確認できる)以下に指定している。
これらのオプションは、`--enable-strict-locations`のオプションも合わせて指定しない限り、autoconfの標準ディレクトリで上書きされてしまう。[^1]

## 謝辞

参考にさせていただいた記事。ありがとうございます。（順不同、執筆時点でのタイトル）

- [macOS(10.14.6)でXRDP(0.9.10)インストール - Qiita](https://qiita.com/KKZ@github/items/c707c2a9d72f23956d70)
- [macOS へ RDP でリモートデスクトップ接続する - Qiita](https://qiita.com/zakkied/items/4071e58fd43233c298af)
- [Mac mini(M1)でもWindowsからRDPでリモートデスクトップしたい！ - Qiita](https://qiita.com/ChujoHiroto/items/76012b5847be04e5acee)

[^1]: これを行わないと`/etc`, `/var`が利用されるため、`make install`時にroot権限が必要になる。
ShellScript で MySQL の実行結果を変数に格納する

# 概要

ShellScript で簡易的な処理を書いていた際、MySQLの結果を変数に格納したくなったことがあった。
その際にやったことをメモしておく。

### 前提

- ここで記載するのはMySQLの実行結果が1行の場合の方法。2行以上の場合はさらに工夫が必要。

# 結論

```shell
result=`mysql --defaults-extra-file=mysql.cnf -u user -e "SELECT id, title, description FROM table WHERE id = 123" -E | sed -e "1d" | sed -e 's/: /="/g' | sed -e 's/$/"/'`
eval ${result}
# 結果出力
echo ${id}
echo ${title}
echo ${description}
```

# 解説

ワンラインでゴリゴリ書いているので分解しながら解説する。

### mysqlコマンド

```shell
mysql --defaults-extra-file=mysql.cnf -u user -e "SELECT id, title, description FROM table WHERE id = 123" -E
```

MySQLコマンドの最後の`-E`オプションをつけることで以下のように実行結果が縦出力される。

```
*************************** 1. row ***************************
 id: 123
 title: タイトル
 description: 説明文
```

### sedで置換

まずは上記の実行結果から邪魔な1行目を取り除く

```shell
sed -e "1d"
```

続いて「: 」を「="」に置換し…

```shell
sed -e 's/: /="/g'
```

さらに行末に「"」を追加する。

```shell
sed -e 's/$/"/'
```

すると最終的に以下のような出力結果になる。

```
 id="123"
 title="タイトル"
 description="説明文"
```

### evalでコマンドとして実行

上記の結果を eval で実行すると、もうお分かりの通り、カラム名と同じ変数「id」「title」「description」にそれぞれ値を代入する式となる。

```shell
eval ${result}
```

# 1カラムのみ取得したい場合

上記は複数カラムを一気に変数に格納する方法だが、1カラムのみの場合はもっとシンプルに書ける。

```shell
title=`mysql --defaults-extra-file=mysql.cnf -u user -e "SELECT title FROM table WHERE id = 123" -BN`
# 結果出力
echo ${title}
```

# まとめ

シェルでゴリゴリ書くのは楽しいのだが、ここまでくるとそろそろ他の言語を使ったほうが書きやすいと思う。
でも途中までシェルで書いたし、ここで他の言語にいくのも癪なので、意地というか、どうしてもシェルで完成させたくなってしまう。
そんなときに使ってほしい。