OmniAICreator/Qiita-1.07M huggingface dataset:
正規表現　アンカー

アンカーは幅0の文字列にマッチするメタ文字列です。 幅0とは文字と文字の間、文字列の先頭、文字列の末尾、 などを意味します。 ある特定の条件を満たす「位置」にマッチします。

^ 行頭にマッチします。行頭とは、文字列の先頭もしくは改行の次を 意味します。
$ 行末にマッチします。 行末とは文字列の末尾もしくは改行の手前を意味します。
\A 文字列の先頭にマッチします。
\Z 文字列の末尾にマッチします。 ただし文字列の最後の文字が改行ならばそれの手前にマッチします。
\z 文字列の末尾にマッチします。
\b 単語境界にマッチします。 単語を成す文字と単語を成さない文字の間にマッチします。 文字列の先頭の文字が単語成す文字であれば、文字列の先頭 の位置にマッチします。
\B 非単語境界にマッチします。 \bでマッチしない位置にマッチします。
 # 文字列中の real にマッチする
/real/.match("surrealist") # => #< MatchData "real">
 # 先頭に real とないとマッチしない
/\Areal/.match("surrealist") # => nil
 # 単語境界がrealの前にないのでマッチしない
/\breal/.match("surrealist") # => nil
単語を成す文字、成さない文字の定義はエンコードによって 異なります。以下の例で「全角」括弧は EUC-JP では 単語を成す文字と見なされますが、UTF-8 では見なされません。 その結果、以下のような挙動をします。

 # -*- coding:utf-8 -*-
 # デフォルトは UTF-8
/foo\b/.match("あいうfoo%") # => #< MatchData "foo">
/\bfoo\b/.match("あいうfoo%") # => nil
/\bfoo\b/e.match("（foo）".encode("EUC-JP")) # => nil
/\bfoo\b/.match("（foo）") # => #< MatchData "foo">
Unicode の規格では、単語を成す文字を Word というプロパティで 定義しています。

先読み、後読み(lookahead, lookbehind)
ある位置から続く文字列が ある部分式にマッチするならばその位置にマッチする という正規表現を書くことができます。

「ある位置から続く文字列(先読み、lookahead)/ある位置の手前までの文字列(後読み、lookbehind)」 と「マッチする(肯定、positive)/マッチしない(否定、negative)」 の組み合わせで4つのパターンがあります。

(?=pat) 肯定先読み(positive lookahead)
(?!pat) 否定先読み(negative lookahead)
(?<=pat) 肯定後読み(positive lookbehind)
(?<!pat) 否定後読み(negative lookbehind)
\K 後読みの別表記、このメタ文字列の手前までを後読みします。 つまり /pat1\Kpat2/ は /(?<=pat1)pat2/ と同様の意味となります。
 # 以下の例では、後読みと先読みを使って < b> と
 # </b> に挟まれているという条件を正規表現中に記述しつつ
 # <b> </b> 自体にはマッチさせていない。
/(?<=< b>)\w+(?=<\/b>)/.match("Fortune favours the < b>bold< /b>")
 # => #< MatchData "bold">
 # 以下は上の正規表現と同じものを表す
/< b>\K\w+(?=<\/b>)/.match("Fortune favours the < b>bold< /b>")
 # => #< MatchData "bold">
vi/vim と editorconfig

#背景
プロジェクトが大きくに連れて、ソースの統一性が出てくる。しかし、メンバーでは様々なエジターをつかっている（vi（自分）、vscodeなど）。最近、editorconfig (https://editorconfig.org) もよく聞かれ、サポートするエジターも多い。そのため、プロジェクトに editorconfig を入れようと思っていた。

ここで２つ課題が出てきた
1. 自分のvi環境はplugin管理ソフトが入っていない（使いたくない）
2. 既存のソースはどのように editorconfig を適用する

ここで、自分の解決方法を簡単にまとめる

#環境
以下は自分の環境

```
OS: CentOS Linux release 7.5
VIM - Vi IMproved 7.4
```

# editorconfigをインストール・設定
vim-editorconfigのgithub(https://github.com/editorconfig/editorconfig-vim) からarchive (https://github.com/editorconfig/editorconfig-vim/archive/master.zip) をとってくる

ファイルを展開したフォルダにある `autoload` `doc` `plugin`の内容を全てそれぞれ `~/.vim`の配下に該当のフォルダーにコピーする

```:shell
$ cd editorconfig-vim-master
$ cp -r ./autoload/* ~/.vim/autoload/
$ cp -r ./doc/* ~/.vim/doc/
$ cp -r ./plugin/* ~/.vim/plugin/
```
これで editorconfigのpluginのインストールが完了した。

vim を実行して、以下のコマンドで plugin一覧が確認でき、そこに editorconfigがあるかどうか確認できる

``` :vim
:help local-additions
```


# 既存のソースをeditorconfigの設定を適用する
色々探して、このようなもの (https://github.com/jedmao/eclint) を見つけたが、複雑そうで、やりたいことよりはるかに機能が多いいのでやめた。

手動でviを持ちファイルを開けたら、強制的に保存 `:wq` すれば、ルールが適用できるようにわかったので、vimのbatchmodeで実施すれば、やりたいことができるはずである。

実際このようにテストした。

## テストの準備
テストフォルダーに以下の test.py を作成する

``` test.py:python
def test()$
    echo "This is a test"   $
$
```
echo 行にわざとスペースと最後にスペースのみの行を追加した。


## ソースをeditconfigルールを適用
同じテストフォルダーに .editconfigファルを作る

``` text:editorconfig
# top-most EditorConfig file
root = true

# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = false
max_line_length = 0
trim_trailing_whitespace = true

# Python
[*.py]
indent_size = 4
indent_style = space
max_line_length = 120
```

この状態で、viにeditoconfigを正しくインストールできれば、新しいファイルや既存ファイルの編集するあと、保存すると editconfigで決めたルールに変形されている。

試したいのはコマンドラインだけで、既存んのファイルを整形できるかどうか。以下のように test.pyをtest.py.orgを保存して、コンマンドラインでviを適用してみる

```:shell
$ cp test.py test.py.org
$ vi -c ":wq" test.py
```

すると、test.py ファイルが変形されたことが確認できる

```:shell
$ diff test.py test.py.org | cat -A
2c2$
<     echo "This is a test"$
---$
>     echo "This is a test"   $
```

このように、フォルダー全体の .py ファイルに適用したい場合、以下のように実行できる

```:shell
$ find -name <対象のフォルダー> -exec vim -c ":wq" {} ¥;
```

または、ファイル全体を`reindent`をしたいときに

```:shell
$ find -name <対象のフォルダー> -exec vim -c ":bufdo normal gg=G:wall" -c ":wq" {} ¥;
```

#まとめ
vi に plugin managerなしで、editorconfigのインスとる仕方を説明した。また、既存フォルダーにたいして、新しいeditorconfigで決めた整形のルールを適用する方法を説明した。

参考になれば嬉しいと思います。
正規表現　キャプチャ

丸括弧 ( ) によってキャプチャをすることができます。 括弧に囲まれた部分正規表現にマッチした 前からn番目の開き括弧によって囲まれた部分式にマッチした 文字列を後で参照することができます。

正規表現内では \1, \2, ... という記法で後方参照できます。 また、\k<1>, \k<2>, ... や \k'1', \k'2', ... という記法を使うこと もできます(10を越える数字を渡すことができます)。 また、Regexp#match で得られた MatchData からは MatchData#[　]で取り出せます。

また、$1, $2, ... という特殊変数によって n 番目の括弧にマッチした 部分文字列を参照できます。これらの特殊変数はマッチ処理が終わったあとで しか使えないことに注意してください。

　# (..) に at がマッチしたのを \1 で参照し、マッチが成功している。
m = /[csh](..) [csh]\1 in/.match("The cat sat in the hat")
　# => #< MatchData "cat sat in" 1:"at">
　# Regexp#match でマッチしたテキストは MatchData#[] で参照できる
m[1] # => "at"
1,2,... ではなく、名前を付けることができます。 (?< name>pat)もしくは(?'name'pat)と記述します。キャプチャした文字列は MatchData#[ ] に Symbol を渡すことで参照できます。 これは名前付きキャプチャと呼ばれます。

m = /\$(?<dollars>\d+)\.(?< cents>\d+)/.match("$3.67")
 # => #< MatchData "$3.67" dollars:"3" cents:"67">
m[:dollars] # => "3"
m[:cents] # => "67"
名前付きキャプチャは正規表現内で \k<name>、\k'name' という記法で参照できます。

/(?< vowel>[aeiou]).\k< vowel>.\k< vowel>/.match('ototomy')
 # => #< MatchData "ototo" vowel:"o">
注: 名前付きキャプチャと数字によるキャプチャは併用できません。

リテラル正規表現内に名前付きキャプチャがあり、 =~ の左辺で用いた 場合には、その名前のローカル変数にキャプチャした文字列を代入します。

/\$(?< dollars>\d+)\.(?< cents>\d+)/ =~ "$3.67" # => 0
dollars # => "3"
cents # => "67"
注: ローカル変数への代入が行われるのは、左辺の正規表現リテラルが#{}による式展開を含んでいない場合に限られます。

数字による後方参照では、負の数による、 \k<-1>, \k<-2>, ... や \k'-1', \k'-2', ... という記法での 相対的な指定が可能です。-1 は後方参照が書かれた位置の1つ手前の 位置にあるキャプチャを表し、-2, -3, で2つ手前、3つ手前を表します。 これは非常に多くのキャプチャを持つような正規表現を記述するためや、 正規表現に別の正規表現を式展開で埋め込む場合などに便利です。

/(.)(.)\k<-2>\k<-1>/.match("xyzyz") # => #< MatchData "yzyz" 1:"y" 2:"z">
Treasure Dataでcsvファイルをimportする方法（Mac）

## 背景
Treasure Dataにcsvファイルをimportする際にかなり手こずったのでここに書いておきます。
検索しても一連の流れを書いていてパッとわかりやすいものがなかったので、、、

## 目的
Treasure Dataにcsvファイルをimportする方法を説明。
今回は自分のやり方を書き記します。

## やること
1. JDKのインストール
2. embulkのインストール（←今回のやり方では必要ありませんでした。）
3. TDコマンドのインストール
4. TDコマンドの実行
5. 終わり

## JDKのインストール
- JDKが入っているかチェック

ターミナルを開き`java -version`と打ち込みます。
![デスクトップ_—_-bash_—_80×24_と_「MACでTreasure_Dataでcsvファイルをimportする方法」を編集_-_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510375/7846f929-1d83-7a31-4a70-b17070d207d0.png)
↑の場合はインストールされていません。

- JDKのインストール

ちなみに、バージョン8より上はまだ対応していないので気をつけましょう。
バージョン：Java SE 8
Product：Mac OS X x64
を選択しましょう。
https://www.oracle.com/technetwork/java/javase/downloads/index.html?ssSourceSiteId=otnjp


![Java_SE_Development_Kit_8_-_Downloads.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510375/f66a9872-a3ca-e65f-2a41-1dd3acf48003.png)

クリックするとアカウント認証を求められるので持ってなければ作成しましょう。
過去バージョンをインストールする際には必要みたいです。

![Oracleログイン_-_シングル・サインオン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510375/2db1aa92-0798-ec74-922b-76dde72f2055.png)

- では、インストールされていることを確認しましょう。

![デスクトップ_—_-bash_—_80×24_と_「MACでTreasure_Dataでcsvファイルをimportする方法」を編集_-_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510375/5f726754-19c9-fd93-e61d-c0ee23656be9.png)

## embulkのインストール
下記のコマンドをターミナルに打ち込めばOKです。
`curl --create-dirs -o ~/.embulk/bin/embulk -L "http://dl.embulk.org/embulk-latest.jar"
chmod +x ~/.embulk/bin/embulk
echo 'export PATH="$HOME/.embulk/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
embulk gem install embulk-output-td`
詳細は公式ドキュメントにあるのでどうぞ。
https://support.treasuredata.com/hc/en-us/articles/360001495428-Bulk-Import-from-CSV-files

## TDコマンドのインストール
↓TDコマンドを使用するためにはこちらをインストールして初期設定が必要です。（初期設定はここでは割愛）
https://toolbelt.treasuredata.com/


## TDコマンドの実行
↓TDコマンドの公式ドキュメントになります。
https://docs.treasuredata.com/articles/td-cli

では一気に駆け抜けてコマンドだけ書いてしまいます。
1. `td table:partial_delete <DB名> <Table名> --from <UDF形式のtime> --to <UDF形式のtime>`
　　→テーブルに余分なデータがある時はtimeを指定して削除します。
2. `td import:list`
　　→いま登録されているsession一覧を見ることが出来ます。
3. `td import:create <session名> <DB名> <Table名>`
　　→これでsessionを作成します。
4. `td import:prepare <csvファイル> --format csv --columns <カラム名>,<カラム名>,・・・ --time-value  <UDF形式のtime> -o parts/`
　　→ファイルを圧縮分割してmsgpackに変換する。timeカラムがない場合はベタ打ちで指定する。
5. `td import:upload <session名> <分割ファイルのパス>`
　　→先程の変換したファイルをアップロードする。
6. `td import:perform <session名>`
　　→TDで処理を実行します。
7. `td import:commit <session名>`
　　→successになったらcommitをします。
8. `td import:delete <session名>`
　　→commitまで完了したらsessionを削除しましょう。

初めて触る際は`td import:list`を使って都度確認することで現状のステータスが把握しやすいのでおすすめです。

## 終わり
個人的な躓きポイントだったのは
1. JDKのバージョン8までしか対応していなかったこと。
　　→そうとは知らずに最新バージョンをインストールして動かずあわあわしてました。
2. いい感じに情報がまとまっているブログなどが少ないこと。
　　→ただcsvファイルをimportしたいだけだったのに、かゆい所に手が届かない。。。
3. csvファイルにtimeカラムがないパターン。
　　→今回はuser_idをテーブルにimportしたかっただけなので、指定の仕方がよくわからず苦労しました。

ということでcsvの限定的な話をしてしまいましたが、どこかのだれかの役に立つことができれば幸いです。
はてなブログのRSSフィードのURLを取得する方法

## 目的

- RSSについて調べた時のこととRSSフィードのURLを取得する方法を書く
※本方法を取らなくてもRSSを取得したいサイトのURLの末尾に`/rss`をつければいいらしいです。。。すいません。

## RSSとは？(調べたことを殴り書く)

- データを取得するためのフォーマットらしい。
- 略さない正式名称は「Rich Site Summary」「Really Simple Syndication」「RDF Site Summary」である。
- 主にブログなどの更新情報を公開する時に使用される。
- 自分がよく見るブログのRSSさえ取得できれれば、そのブログのtopまで行かずとも更新可否がわかる。
- RSSリーダーと呼ばれるツールを使用すると複数のブログの更新状況を管理することができる。

## 筆者の環境
1. PC
    1. OS: macOS High Sierra 10.13.6
    1. 機種: MacBook Pro (15-inch, Early 2011)
    1. CPU: Intel(R) Core(TM) i7-2675QM CPU @ 2.20GHz
1. ブラウザ
    1. Google chrome
1. RSSフィードURLを取得するリンク先
    1. [miriwoのブログ](https://miriwo.hatenablog.com/)

## はてなブログでのRSSフィードのURLを取得する概要

1. RSSフィードURLを取得したいページをブラウザで開く
1. Google chromeの開発者用の機能を使いRSSフィードURLを調べる

## はてなブログでのRSSフィードのURLを取得する詳細

1. RSSフィードURLを取得したいページをブラウザで開く
    1. RSSフィードを取得したいページへ移動する。  
    筆者は自分のはてなブログに記載をしたかったため[miriwoのブログ](https://miriwo.hatenablog.com/)をブラウザで開いた。
1. Google chromeの開発者用の機能を使いRSSフィードURLを調べる
    1. RSSフィードURLが欲しいサイトがブラウザで表示されている時にブラウザを右クリックする。
    1. 「検証」をクリックする。  
        ![スクリーンショット 2019-11-24 19.39.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/0917b35a-4518-0516-f307-eaf32f4302b7.png)
    1. 下記の画像の様な開発者用画面が開く  
        ![スクリーンショット 2019-11-24 19.40.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/83165dbe-5de6-64a2-23c5-8947a743c467.png)
    1. 開発者用画面の右上にあるHTMLのコードが記載されている部分(下記画像)のクリックするなどしてアクティブにする。  
        ![スクリーンショット 2019-11-24 19.41.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/720dd9dd-c482-ce8c-3ccf-c6b0a5715931.png)
    1. 「command」+「f」を押してコードを検索する窓を表示する。(Find by string...って書いてある部分のこと)※windowsだと「Ctrl」+「f」  
        ![スクリーンショット 2019-11-24 19.47.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/73d955f2-16d5-eee8-8381-e040f600faf1.png)
    1. 検索窓に`rss`と入力する。
    1. ヒットした部分のコードを見る。

        ```html
        <link rel="alternate" type="application/rss+xml" title="RSS2.0" href="https://miriwo.hatenablog.com/rss">
        ```

        ![スクリーンショット 2019-11-24 20.34.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/9bdb77d8-0f54-a768-d211-13884f5e8261.png)

    1. コードの内容の`href=`の後ろの部分に記載されている部分がRSSフィードのURLである。

        `href="https://miriwo.hatenablog.com/rss"`
正規表現　繰り返し

以下のメタ文字列は繰り返しを表現します。 直前の部分式を何回繰り返すかを指定します。このような繰り返しを 表すメタ文字列を量指定子(quantifier)と呼びます。
　
* 0回以上
+ 1回以上
? 0回もしくは1回
{n} ちょうどn回(nは数字)
{n,} n回以上(nは数字)
{,m} m回以下(mは数字)
{n,m} n回以上m回以下(n,mは数字)
以下の例で、量指定子の基本的な使いかたを示しています。

　# 以下の正規表現は 最初に大文字が1文字以上(H)で、小文字が1文字以上(l)、
　# lが2文字(ll)の後ろにoが続く文字列にマッチします。
"Hello".match(/[[:upper:]]+[[:lower:]]+l{2}o/) # => #< MatchData "Hello">
これらは「欲張り(greedy)」にマッチします。 マッチが成功する、最長の文字列にマッチしようとします。 そのため、これらの量指定子は特に最大量指定子(greedy quantifier) と呼ばれます。

最小量指定子(reluctant quantifier)
一方、以下のメタ文字列(普通の繰り返しメタ文字列に ? を付加したもの) はマッチが成功する、最短の文字列にマッチします。そのため、これらの 量指定子は特に最小量指定子(reluctant quantifier)と呼ばれます。

*? 0回以上
+? 1回以上
?? 0回もしくは1回
{n,}? n回以上(nは数字)
{,m}? m回以下(mは数字)
{n,m}? n回以上m回以下(n,mは数字)
以下の例では、最小量指定子を使うことで、(\d+)がマッチする場所を変えています。

/^.*(\d+)\./.match("Copyright 2013.")  # => #< MatchData "Copyright 2013." 1:"3">
/^.*?(\d+)\./.match("Copyright 2013.")  # => #< MatchData "Copyright 2013." 1:"2013">
また、ネストしていない括弧の対応を取るためにも使えます。

 # ここでは < b> と < /b> の対応を取る
%r{< b>.*< /b>}.match("< b>x< /b>y< b>z< /b>") # => #<MatchData "< b>x< /b>y< b>z< /b>">
%r{< b>.*?< /b>}.match("< b>x< /b>y< b>z< /b>") # => #< MatchData "< b>x<  /b>">
絶対最大量指定子(possessive quantifier)
以下のメタ文字列は、最大量指定子のように最長のマッチをしますが、 一度マッチすると、その後マッチに失敗してもバックトラックしません。 つまりマッチ済みの文字列を手放さずにマッチに失敗します。 これらの量指定子は絶対最大量指定子と呼ばれます。

*+ 0回以上
++ 1回以上
?+ 0回もしくは1回
アトミックグループを用いることで同じことができます。
DockerでRails環境を構築するときに発生したエラー

#Webpacker configuration file not found 
Rails6.0を使う場合、webpackerが標準になっているので,webpackerをインストールしていない場合,以下のエラーが出ます。

```ruby:
Webpacker configuration file not found /app_name/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /app_name/config/webpacker.yml (RuntimeError)
```

webpackerを使うためにはYarnが必要です。
そこでDockerfileに以下を追加してYarnをインストール必要があります。

```ruby:Dockerfile
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y yarn
```

Yarnをインストールした後、以下でwebpackerをインストールすれば大丈夫。

```ruby:
docker-compose run web bundle exec rails webpacker:install
```


#Error: Cannot render console from Allowed networks
docker compose upした時に以下のエラーがlogに出ました。

```ruby:
 Cannot render console from 172.20.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
```


どうやら、アクセス元のIPアドレスが 127.0.0.1の場合だけ使えるというセキュリティがかかっているようですが、http://localhost でアクセスしても間にDockerが挟まっているため、Railsからみたときのアクセス元が127.0.0.1にならないためこのエラーが出ているようです。

ですので、以下をdevelopment.rbに追記することで、172.20.0.1をホワイトリストに登録すれば対処できます。

```ruby:development.rb
 config.web_console.whitelisted_ips = '172.20.0.1'
```
よくわからなかった用語

#ホスト名
ネットワーク上でのコンピュータの名前
#ローカルホスト
ネットワーク上での自分のPCのこと
#リモートホスト
ネットワークで繋がっているPCのうち自分ではないPCのこと
#アドレス,URL,ドメインの違い
アドレス：インターネット上の住所
URL　 ：アドレスを表すフォーマットのことだがアドレスもURLも似たような意味で使われている
ドメイン：URLだとわかりにくいのでhogehoge.comなどわかりやすくURLを置き換えたもののこと
PostgreSQLのコマンド

#PostgreSQLを起動する

**sudo service postgresql start**
※sudoコマンド：一般ユーザーでログインしている時に、スーパーユーザーでないと実行できないコマンドを実行するために使用する、１つのコマンドだけをスーパーユーザー権限で実行する
※suコマンド：exitするまではずっとスーパーユーザーである点がsudoコマンドとの違い

#psqlを使用してPostgreSQLに接続する

**psql -h ホスト名 -p ポート番号 -U ロール名 -d データベース名**

・ホスト名  ：PostgreSQLが起動しているマシンのIPかホスト名。
　　　　　　デフォルトではlocalhostになっている
・ポート番号：使用するポート番号。デフォルトでは5432になっている
・ロール名　：省略した場合はローカルホスト名が使用される
・データベース名：省略した場合はロール名と同じデータベースに接続される

#psqlを終了する

**\q**

#データベース一覧を表示する

**\l**

#データベースを切り替える

**\c データベース名**

#テーブル一覧を表示

**\dt**

#テーブルの構造を確認する

**\d テーブル名**

#テーブル内のデータを全て表示する

**select * from テーブル名;**

#ユーザー(ロール)の一覧を表示する

**\du**

#パスワード付きでユーザー(ロール)を作成する

**create role [ユーザー(ロール名)] with [権限] login password [パスワード];**


# スーパーユーザーにする

**alter role [ユーザー名(ロール名)] with superuser;**

# スーパーユーザーを剥奪する

**alter role [ユーザー名(ロール名)] with nosuperuser;**
LIKE句（演算子）を使用したあいまい検索について

LIKE句（演算子）を使用したあいまい検索について、完全に忘れていたため、備忘録もかねて以下にまとめます。

#LIKE句（演算子）とは
SQLの検索条件に指定される文字列比較演算子である。
ちょっと難しいですが、SQLに対して、LIKE句を使用するとあいまい検索ができるようになるということです。

#LIKE句（演算子）の使い方<Rails>
Railsでは基本的にWhereと一緒に使用し、以下のように使います。

```:例
model名.where('検索するカラム名 LIKE(?)', "検索ワード")
```

**検索の取得件数の指定方法**
.limited(数)と記載しましょう

```:例
>>先ほどのコードと組み合わせると以下のようになります。
model名.where('検索するカラム名 LIKE(?)', '検索ワード').limited(数)
```
**不要な情報を除外する時**
.where.not(不要な情報)

```:例
>>先ほどのコードと組み合わせると以下のようになります。
model名.where('検索するカラム名 LIKE(?)', '検索ワード').where.not(不要な情報)
```


#ワイルドカードについて
一部を一致させて検索したい時、以下のワイルドカードが使用できます。

| ワイルドカード | 意味 |
|:-:|:-:|
| % | 任意の0文字以上の文字列 |
| _ | 任意の1文字 |

```:例
>>前に１文字だけ記載あり＋後方に０文字以上の記載あり
model名.where('検索するカラム名 LIKE(?)', '_検索ワード%').limited(数)

>>前後ともに0文字以上の記載あり
model名.where('検索するカラム名 LIKE(?)', '%検索ワード%').limited(数)

>>前後ともに1文字の記載あり
model名.where('検索するカラム名 LIKE(?)', '_検索ワード_').limited(数)
```

##具体例
上記を活用して、user名をキーワード入力された際に、検索できるようにします。
[条件]
モデル名:User
あいまい検索機能：キーワードを含んでいればOK
検索取得件数：10件
不要な情報：current_user.id=>ログイン中のユーザーIDを除外します。

上記条件を全てコードに入れると以下のようになります。

```:例
User.where(['name LIKE ?', "%#{params[:keyword]}%"]).where.not(id: current_user.id).limit(10)

```

以上となります。
最後まで閲覧いただき、ありがとうございました。
何か修正の必要な点などございましたら、コメントもしくは編集リクエストいただけますと幸いです。


###参照
【Rails入門】where likeであいまい検索！複数条件やOR条件も解説
https://www.sejuku.net/blog/71189
正規表現　文字

正規表現内では、「\」の後に文字列を置くことで、 ある特定の文字を表現することができます。 これは、改行のように Ruby の文法で特別な意味を持つ文字を埋め込む ためなどに用いられます。 文字列リテラルの記法とほぼ同様(リテラル/バックスラッシュ記法)で、 以下の記法が利用可能です。


\t           水平タブ            horizontal tab (0x09)
\v           垂直タブ            vertical tab   (0x0B)
\n           改行                newline        (0x0A)
\r           復帰                return         (0x0D)
\b           バックスペース      back space     (0x08)
\f           改ページ            form feed      (0x0C)
\a           ベル                bell           (0x07)
\e           エスケープ文字      escape         (0x1B)
\nnn         符号化バイト値の8進数表現 (nnn の8進数3文字で表現)
\xHH         符号化バイト値の16進数表現 (HH の16進数2文字で表現)
\cx, \C-x    制御文字 (x は a から z までのいずれかの文字)
\M-x         メタ (x|0x80)
\M-\C-x      メタ制御文字
\uHHHH       ユニコード文字 (HHHH の16進数4桁)
\u{HHHHHH HHHHHH ....} ユニコード文字列 (HHHHHH は16進数1桁から6桁まで指定可能)


\b は文字クラス内でのみ有効な表現です。文字クラスの外では 単語の区切りを表すメタ文字列と解釈されます。
「\s」は文字列では空白(0x20)を意味しますが、正規表現では タブなどを含む空白文字全般にマッチするメタ文字列です。
正規表現　式展開

正規表現内では、#{式} という形式で式を評価した文字列を埋め込むことが できます。

place = "東京都"
/#{place}/.match("Go to 東京都") # => #< MatchData "東京都">
埋め込んだ文字列にメタ文字が含まれているならば、それは メタ文字として認識されます。

number = "(\\d+)"
operator = "(\\+|-|\\*|/)"
/#{number}#{operator}#{number}/.match("43+291") # => #< MatchData "43+291" 1:"43" 2:"+" 3:"291">
埋め込む文字列をリテラルとして認識させたい場合は Regexp.quote を 使います。
正規表現　メタ文字列とリテラル、メタ文字とエスケープ

正規表現の文法には、正規表現内で特別な働きをする文字列と、それ以外の その文字列そのものにマッチするような文字列があります。 前者をメタ文字列(meta string)、後者をリテラル(文字列)(literal string)と呼びます。

/京都|大阪|神戸/
という正規表現においては、「京都」「大阪」「神戸」がリテラルで、 2つの「|」がメタ文字列です。

以下の文字は「メタ文字」(meta character) と呼ばれる、正規表現内で特殊な働きをする文字です。

( ) [ ] { } . ? + * | \
これらの文字をリテラルのようにその文字としてマッチさせるためには、 バックスラッシュ「\」を前に付けます。「\\」はバックスラッシュ1文字に マッチします。

メタ文字以外の文字も、メタ文字に続けて置くことで特別な働きをするよう になる場合があります。つまりメタ文字列を構成します。例えば

/[a-z]/
/\Axyz\Z/
という正規表現において "[a-z]", "\A", "\Z"はメタ文字列です。
Qiita APIを使って記事一覧を取得する

# アクセストークンを発行する

アクセストークンで認証しないとAPI上限が1時間で60回しかないため、発行しておく。
アクセストークンで認証した状態ではAPI上限は1時間で1000回。

[アクセストークンの発行ページ](https://qiita.com/settings/tokens/new)からアクセストークンを発行する。
今回は記事一覧を取得できればいいため、スコープは`read_qiita`のみチェックしておく。

![Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349145/3bff33bb-b516-356d-093a-d07fa8513f60.png)

発行するとこんな感じでアクセストークンが表示される。
このアクセストークンは再表示できないため、控えておく。

![Qiita (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349145/5bd858ec-1bb3-52f7-ec8c-c9799622cd8e.png)

# APIを叩いてみる

記事一覧を取得するエンドポイントは以下。

```
[GET] https://qiita.com/api/v2/items
```

試しに`curl`コマンドで叩いてみる。
アクセストークンは`Authorization`ヘッダに`Bearer`をつけて指定する。

```bash
$ curl -H 'Authorization: Bearer 1c4f9fd3c9082815b0be1c1fbbc48cb2ae035855' 'https://qiita.com/api/v2/items'
```

レスポンスの形式は[APIドキュメント](https://qiita.com/api/v2/docs#get-apiv2authenticated_useritems)を参照してください。

# オプション

|オプション名|説明|
---|---
|`page`|ページ番号(1~100)|
|`per_page`|1ページあたりに含まれる要素数|
|`query`|検索クエリ<br>参考: [検索時に利用できるオプション \- Qiita:Support](https://help.qiita.com/ja/articles/qiita-search-options)|

## オプションを指定した例

2019年11月11日10日以降10ストック以上されている記事3件を取得する例。
`query`パラメータには`created:>2019-11-11 stocks:>10`をURIエンコードした状態で指定している。

```bash
$ curl -H 'Authorization: Bearer 1c4f9fd3c9082815b0be1c1fbbc48cb2ae035855' 'https://qiita.com/api/v2/items?page=1&per_page=3&query=created%3A%3E2019-11-11+stocks%3A%3E10
```

# まとめ

簡単だし使いやすいしAPIドキュメントもわかりやすいし、便利ですね。

# 参考

- [Qiita API v2ドキュメント \- Qiita:Developer](https://qiita.com/api/v2/docs#get-apiv2items)
- [検索時に利用できるオプション \- Qiita:Support](https://help.qiita.com/ja/articles/qiita-search-options)
LaravelでSNSの雛形デザイン作成してみた(user_tableまで)

今回SNSの雛形デザインを作成してみましたので、オープンソースとして共有いたします。

# 目的
・汎用的データ作成
|- デザイン
|- ソース

# 実装した機能
|- user側のテーブルの編集機能

# 作成物
![スクリーンショット 2019-11-24 19.32.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/f8aef19e-8af4-c915-3265-7979dc1eaa4a.png)
![スクリーンショット 2019-11-24 19.32.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393193/5ef70e20-5ac7-6dde-490b-ed14cc4ec378.png)

# 環境構築
Mac High sierra
Laravel 5.8
VirtialBox+Vagrant+Homestead環境

※こちらはチートシートにまとめてありますので
このURLを参照してください。
　|- [Laravel環境構築 チートシート](https://qiita.com/ProgramingDai/items/6fe5f678bf5a05e27c05)

チートシートの「vagrant ssh」まで完了すれば大丈夫です。

# 1.データクローン
まずどこでもいいので下記コマンドをターミナルに入力してデータをクローンしてください

```console:ターミナル
$ git clone https://dai570415@bitbucket.org/dai570415/laravel-sns-master.git
```

# 2.クローンデータを解凍して環境に入れる
先ほど環境構築した際に「code」フォルダを作成しているかと思いますので、その中にクローンしてきたファイル（中身のみ）をごそっと入れてください。

下記アドレスにアクセス
192.168.10.10

Topページが表示されるはずです。

# 3.DB関係を設定する

マイグレート

```console:ターミナル
$ php artisan migrate

* こちらでDB周りが構築できました
```

# 最後に
汎用性を重視した雛形作成を目的にしているので
投稿側はあえて実装していません。以下URLから実装してください。

[Laravelで投稿アプリの機能を作成 ~CRUD編~](https://qiita.com/ProgramingDai/items/cf6944f9cd0ac08f4e3e)
[Laravelで投稿アプリの機能を作成 ~リレーション編~](https://qiita.com/ProgramingDai/items/249acc8894079ee58268)
Pythonで自由群を作ってみる

# 群とは
なにか「2項演算」ができる、空集合でない集合$G$であって、
(つまり、$g, h \in G$とすると、2項演算$g\cdot h$があり、演算結果もGの元、つまり$g\cdot h\in G$となるものであって)
次の条件を満たすもののことを群といいます。

- (単位元) 単位元と呼ばれる元$e\in G$があり、任意の元$a \in G$に対し、$e\cdot a = a \cdot e = a$が成り立つ
- (逆元) 任意の元$a\in G$に対し、ある元$b \in G$が存在し、$a\cdot b = b \cdot a = e$が成り立つ。$b$は$a$の逆元と呼ばれ、$a^{-1}$と書く
- (結合法則) 任意の元$a, b, c \in G$に対し、$(a\cdot b)\cdot c = a \cdot (b \cdot c)$が成り立つ

# 群の例
- 足し算ができる整数は、群です(単位元→$0$, $a$の逆元→$-a$, 結合法則→足し算は結合法則が成り立つことが知られている)
- 足し算ができる有理数も群です(同上)。また、掛け算ができる、有理数から0を除いたもの、も群です。(0も含む有理数だと、0の逆元が定義できないので群ではありません)

# 自由群
群の定義以外、何も制約がないのが自由群です。

ここでは、自由群の中でも2つの元から生成される$F_2$について考えます。つまり、単位元と、2つの元$a, b \in F_2$と、その逆元$a^{-1}, b^{-1}$から、好きなのを選んで演算して、を好きなだけ繰り返してできるものを考えます。

$F_2 = \\{e, a, b, a^{-1}, b^{-1}, aa, ab, ab^{-1}, ba, ba^{-1}, bb, a^{-1}b, a^{-1}a^{-1}, a^{-1}b^{-1}, \dots\\}$

## 逆元は?
$a$の逆元が$a^{-1}$なのは分かりましたが、では、$ab^{-1}aab$など、組み合わさったものの逆元はどうなるでしょう?
実はこれは、それぞれの元の逆元を取って、さらに、順番を逆転させたもの、つまりこの場合は$b^{-1}a^{-1}a^{-1}ba^{-1}$が逆元になります。
実際、これらを演算してみると

```math
\begin{eqnarray}
ab^{-1}aab\cdot b^{-1}a^{-1}a^{-1}ba^{-1} & = & ab^{-1}aa \cdot a^{-1}a^{-1}ba^{-1}\\
& = & ab^{-1}a \cdot a^{-1}ba^{-1}\\
& = & ab^{-1} \cdot ba^{-1}\\
& = & a \cdot a^{-1}\\
&=&e\\
\\
b^{-1}a^{-1}a^{-1}ba^{-1}\cdot ab^{-1}aab & = & b^{-1}a^{-1}a^{-1}b\cdot b^{-1}aab\\
& = & b^{-1}a^{-1}a^{-1}\cdot aab\\
& = & b^{-1}a^{-1}\cdot ab\\
& = & b^{-1}\cdot b\\
& = & e
\end{eqnarray}
```

確かに、逆元になっていることが分かります。

# Pythonでやってみよう

Pythonは演算子オーバーロードが簡単なのでやりやすいですね。
早速やってみます。

実装方針として、$a$とか$ab$とかを、文字列で持つことにします。
また、逆元は大文字のA, Bで持つことにします。

逆元計算のためには、`str.swapcase`メソッドを使い、文字列をひっくり返します。
長年Pythonを使っていましたが、`swapcase`を使ったのは人生で初めてです。
なんと、このメソッドは、大文字は小文字に、小文字は大文字にする、というメソッドです。

```py
'heLLo woRLd, ゎぃゎ ヵッォ ゃ ωπ'.swapcase() # => 結果は次行
'HEllO WOrlD, ゎぃゎ ヵッォ ゃ ΩΠ'
```

残念ながら(?)、小さいひらがなは大きくなりませんが、ASCII文字じゃなくてもギリシャ文字は変換されるらしいです。まぁ、そんなことはどうでもいいので実装しましょう。

大事なことは大体考えたので、コードをガーッと書きましょう。

```py
from collections import namedtuple

FreeGroupBase = namedtuple('FreeGroupBase', 's')
class FreeGroup(FreeGroupBase):
    def __init__(self, s: str):
        if s.lower().replace('a', '').replace('b', ''):
            # a, bのみから生成されているか確認
            raise ValueError('Unexpected element is contained')

    # 逆元を ~a のように取ることにします
    def __invert__(self) -> 'FreeGroup':
        return FreeGroup(self.s.swapcase()[::-1])

    # 演算を * で行うことにします
    def __mul__(self, other: 'FreeGroup') -> 'FreeGroup':
        return FreeGroup(self._mul_impl(self.s, other.s))

    @classmethod
    def _mul_impl(cls, lhs: str, rhs: str) -> str:
        '演算の実装'
        if not lhs: # lhsが単位元
            return rhs
        if not rhs: # rhsが単位元
            return lhs
        if lhs[-1].swapcase() == rhs[0]: # ...a * ~a... の形だと、a * ~aを打ち消せる
            return cls._mul_impl(lhs[:-1], rhs[1:])
        return lhs + rhs # そうでなければ、文字列を単にくっつけたもの

    def __repr__(self) -> 'str':
        if not self.s:
            return 'e'
        return ' * '.join(e if e.lower() else '~' + e.tolower() for e in self.s)

a = FreeGroup('a')
b = FreeGroup('b')
e = FreeGroup('')

g = a * b * b * a * ~b * ~b * ~a * a * b * (a * a * b)
print(g)
print(g * ~g)
print(~g * g)
```

うん、なんかいい感じにできてますね。
Amazon Transcribeを試してみた

twitterで「Amazon Transcribeがリリースされた」との情報をゲットしたため使ってみた。

#Amazon Transcribeとは？
AWSの音声認識のサービス。音声ファイルをS3にアップロードすると、数分で自動で文字起こししてくれるサービス。

#検証環境など
- iphoneのボイスメモを利用。
- 静かな部屋（周りに人がいないかつテレビ等も消した状態）でボイスメモの録音を実施。
- iphoneと発言者の距離は十数cm。
- つまり録音時の環境は良好。

#結論
- 上記環境で利用する分には文字起こしの精度は非常に高い。（認識率100％）

#検証方法
- 音声を録音する。
    - iphoneの「ボイスメモ」機能を利用し音声を録音する。
    - 音声ファイルをiphoneからPCに転送する。
    
- PCでAWSマネジメントコンソールにログインする。　
    - 省略。
 
- 録音した音声ファイルをS3にアップロードする。
    - バケットを作成する。（もちろん既存の物があればそれでOK。）
    - 音声ファイルをバケットにアップロードする。
    - アップロード完了したらバケットのバスをコピーしておく。

- Amazon Transcribeのジョブを新規作成する。
    - マネジメントコンソールのトップページで「Amazon Transcribe」と入力する。
    - 当該ページが表示されたら、「Create job」をクリックする。
    - 「Job settings」「Input data」の各項目を入力する。
        - 「format(音声ファイルの形式)」に制限あり。mp3、mp4、wav、flacのみ対応。
        - 「Audio sampling rate」は音声ファイルのプロパティで確認可能なので、そこの情報をもとに記入する。※ここ間違うと、文字起こしに失敗する。
![iOS の画像.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279180/631dfc1e-b6c8-d15d-95ba-bf9e1e406a5d.jpeg)

　　　　- 「Output Data」は今回すべてデフォルトのままにする。（よくわかんない）
　　　　- 「Create」を押下。
![iOS の画像-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279180/b30b31df-ad57-06a0-5e95-75c732730457.jpeg)



- 「Status」が「In progress」から「Complete」になるまで待つ。
![iOS の画像-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279180/21aeeabe-9a40-2621-88ab-fc259933b7d8.jpeg)

  - 「Status」が「Complete」になったら文字起こしの結果を確認する。
![iOS の画像-5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279180/a62cee5c-56c0-be43-17d8-66165858da55.jpeg)
        - 今回は音声ファイルも小さかったせいか１分ほどで文字起こし完了。ちゃんと認識されていますね。


#今後の課題ややってみたいこと
- 議事録作成に応用できないか実験する。
    - 職場のがやがやした環境の中で、どのくらいの精度を発揮できるか実験する。
    - もちろん、文字起こしされたテキストを構造化し直すタスクは自身でやらないといけないが…）
- コールセンター業務に活用できないか考える。
    - コールセンター業務で音声データの録音をやってるはず。これを「Amazon Transcribe」で文字起こししして、テキストマイニングかけて、チャットボットの精度向上に役立てるとか   
    - Amazon Connectと連携できないか。

#つぶやき
音楽ファイルでやってみたけど、だめだった笑（あわよくば歌詞をすべて文字起こしして欲しかった）
[Jquery] Validation

フォームの入力体験を向上するため、
フォームのバリデーションを `Jquery Validation` を使って正しい入力へ誘導します。

最新版が1.19.5となったのでドキュメントも更新します。

# URL

こちらが本家サイトになります。
[jQuery Validation Plugin | Form validation with jQuery](https://jqueryvalidation.org/)
ドキュメントは[こちら](https://jqueryvalidation.org/documentation/)から


# 利用方法

## Hotlink

今回はこちらを使います。

```
https://cdn.jsdelivr.net/npm/jquery-validation@1.19.5/dist/jquery.validate.min.js

https://cdn.jsdelivr.net/npm/jquery-validation@1.19.5/dist/additional-methods.min.js
```

## パッケージ経由

パッケージマネージャー経由で利用する人は下記を参照してください。

### Nuget

```
https://www.nuget.org/packages/jquery.validation
```

### Npm
```
https://www.npmjs.com/package/jquery-validation
```

# メソッド

jquery.validate.jsには3つのメソッドがあります。

## validate()

指定したフォームを`validate"します。

## valid()

指定したフォームまたはエレメントを`validate`します。

## rules()

指定したエレメントに対して`rule`を読み込み、追加、削除

# カスタムセレクター

3つのセレクターが用意されています

## :blank

入力されてないエレメントを選択します

## :filled

入力済みのエレメントを選択します

## :unchecked

チェックされていないエレメントを選択します

# Build-inされているValidation メソッド

- required
- remote
- minlength
- maxlength
- rangelength
- min
- max
- range
- step
- email
- url
- date
- dateISO
- number
- digits
- equalTo

# サンプル1 

本家にあるサンプルは下記

```html
<form class="cmxform" id="commentForm" method="get" action="">
  <fieldset>
    <legend>Please provide your name, email address (won't be published) and a comment</legend>
    <p>
      <label for="cname">Name (required, at least 2 characters)</label>
      <input id="cname" name="name" minlength="2" type="text" required>
    </p>
    <p>
      <label for="cemail">E-Mail (required)</label>
      <input id="cemail" type="email" name="email" required>
    </p>
    <p>
      <label for="curl">URL (optional)</label>
      <input id="curl" type="url" name="url">
    </p>
    <p>
      <label for="ccomment">Your comment (required)</label>
      <textarea id="ccomment" name="comment" required></textarea>
    </p>
    <p>
      <input class="submit" type="submit" value="Submit">
    </p>
  </fieldset>
</form>
<script>
$("#commentForm").validate();
</script>
```

# Ruleを作る

基本的な使い方はRuleを作っていきます。各Ruleに沿ってValidateしていきます。

## 例

```javascript
$("#myform").validate({
  rules: {
    // simple rule, converted to {required:true}
    name: "required",
    // compound rule
    email: {
      required: true,
      email: true
    }
  }
});
```

上のサンプルでは`rules`の名前を `required` とし、`email`というフィールド名をもつフィールドに対して`required`(必須)であること、メールタイプであることを`rule`としています。


# 次　

サーバーサイドでのチェック、エラーメッセージの表示場所の指定などをカバー
Laravelでクロージャを使った自作バリデーションの作成

Laravelのバリデーションでチェックボックスの特定の組み合わせを不可にするために、
自作バリデーションを作成してみました。
自作バリデーションはRulesを作る方法がありますが、
調べた所、バリデーションでもクロージャが使えるようでした。

簡単なサンプルを作ってみました。
まずフォームを作ります。

```
<h1>果物を選んで下さい。</h1>
@if ($errors->any())
    <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
@endif
<form action="{{ route('check') }}" method="POST">
    @csrf
    <input type="checkbox" name="fruits[]" value="apple">りんご
    <input type="checkbox" name="fruits[]" value="orange">みかん
    <input type="checkbox" name="fruits[]" value="banana">バナナ
    <input type="submit">
</form>
```

りんごとバナナに同時にチェックがある時にエラーにするために、
コントローラーに以下のバリデーションを追加します。
fruitsのバリデーションの１つとしてクロージャを組み込んでます。
$attributeにフォーム名、$valueにフォームの値が入り、
$failにエラーメッセージ入れて返すという形になります。

```
public function check(Request $request)
{
    $request->validate([
        'fruits' => [
            'required',
            function ($attribute, $value, $fail) {
                if (in_array('apple', $value) && in_array('banana', $value)) {
                    return $fail('りんごとバナナは同時に選べません。');
                }
            }
        ],
    ]);
    return view('input');
}
```

少し可読性は悪いですが、別クラスを作らなくてすむのは便利です。
Twigで拡張子が２つある理由

Twigのファイル名は、「index.html.twig」と「html」＋「twig」と拡張子が2つついています。

これは「twig」というのが、Twigのテンプレートファイルということを示し、「html」は、twigファイルをレンダリングして生成されるものが、「HTML」ファイルであることを示している。

これは、[Template Naming](https://symfony.com/doc/4.4/templates.html#template-naming)に記載されていました。
CentOS8にSFTP接続できるようにする

## まえがき

SFTP接続できるサーバを構築する機会があったのでそのときにやったことを書いておきます。



## 環境

| OS        | CentOS 8.0.1905 64bit |
| --------- | --------------------- |
| webサーバ | Apache/2.4.37         |
| OpenSSH   | OpenSSH_7.8p1         |
| クラウド  | さくらクラウド        |



## 前提

- ApacheまたはNginxなどのwebサーバをインストール済み。
- ドキュメントルートは/var/www/vhostsとする



## 新規ユーザ作成

SFTP接続専用のユーザを作成します

管理ユーザになる

```shell
sudo su -
```

ユーザ作成

```shell
useradd sftp-user
```

パスワードを設定

```shell
passwd sftp-user
```





## SFTPユーザのグループ指定

SFTP専用ユーザーをApacheのグループに追加します。

Apacheユーザを確認

```shell
 id apache
 uid=48(apache) gid=48(apache) groups=48(apache)
````

SFTP専用ユーザをグループに追加

```shell
usermod -g 48 sftp-user
```

グループIDを確認

```shell
id sftp-user
uid=1001(sftp-user) gid=48(apache) groups=48(apache)
```



## ssh鍵設定

SFTPで接続するための鍵を作成する。

sftp-userのホームディレクトリに移動

```shell
cd /home/sftp-user
```

.sshディレクトリを権限700に指定して作成

```shell
mkdir -pm 700 .ssh
```

所有者をsftp-userに変更

```shell
sudo chown sftp-user:sftp-user .ssh
```

sftp-userにログイン

```shell
su - sftp-user
```

.sshに移動

```shell
cd .ssh
```

鍵を作成

```shell
ssh-keygen -t rsa -b 4096
```

生成された鍵ファイルを確認

```shell
$ ls -la
合計 20
drwxr-xr-x 2 sftp-user sample-sftp 4096 12月  4 22:43 .
drwxr-xr-x 3 root        root        4096 12月  4 22:37 ..
-rw------- 1 sftp-user nginx       3247 12月  4 22:40 id_rsa
-rw-r--r-- 1 sftp-user nginx        754 12月  4 22:40
id_rsa.pub
```

id_rsa.pubをauthorized_keysというファイルに転記する。 

```shell
cat id_rsa.pub
vi authorized_keys
```

authorized_keysの権限を変更

```shell
chmod 600 authorized_keys
```

最終的にこうなっていればOK

```shell
$ ls -la
drwx------ 2 sftp-user sample-sftp 4096 12月  4 22:43 .
drwxr-xr-x 3 root        root        4096 12月  4 22:37 ..
-rw------- 1 sftp-user nginx        754 12月  4 22:43 authorized_keys
-rw------- 1 sftp-user nginx       3247 12月  4 22:40 id_rsa
-rw-r--r-- 1 sftp-user nginx        754 12月  4 22:40 id_rsa.pub
```

sftp-userからexit

```shell
exit
```



## SFTPできるディレクトリを制限

SFTPアカウントで接続した際、ルートからなんでも見れて更新できては何かと困るので制限をかける。

.sshディレクトリに移動

```shell
cd /etc/ssh
```

バックアップを作成

```shell
cp -p sshd_config sshd_org_config
```

ユーザの制限事項を追加

```shell
vi sshd_config
```

```shell
#sshd_configの一番下に追加
Match group apache
  ChrootDirectory /var/www/
  ForceCommand internal-sftp -u 0002
```

ログインするディレクトリの所有者をrootにする

```shell
chown root:root /var/www
```



vhost以下の所有者を全てapacheにする

```shell
chown -R nginx:nginx /var/www/vhosts
```



vhosts以下のファイルの権限を664にする

```shell
#カレントディレクトリ以下全てに適用
find ./ -type f -exec chmod 664 {} \; 
```



vhosts以下のディレクトリの権限を775にする

```shell
find ./ -type d -exec chmod 775 {} \;
```



## トラブルシューティング

- アップロードできない

アップロードするディレクトリは権限と所有者を以下の権限にする。それでもできない場合はログインするディレクトリにアップロードしようとしてないか確認する。ログインするディレクトリはrootの権限なのでアップロードできないです

```shell
権限: 775
所有者: apche(webサーバの実行ユーザ)
```

- ログインできない

SFTPでログインするディレクトリは所有者と権限を以下に変更する

```shell
権限: 755
所有者: root:root
```
[Elm] Msg に更新後の値を含めるのは要注意

「`Msg` が来たら値を更新する」というのが普通の Elm アーキテクチャですが、一捻りして「`Msg` に更新後の値を含める」と思わぬハマり方をすることがあるので注意しましょう。タイミングによっては上手く更新されないことがあります。

## 例

こちら何の変哲もないカウンターです。

**Counter V1**

```elm
module Counter exposing (main)


import Browser
import Html exposing (..)
import Html.Events exposing (..)



main : Program () Model Msg
main =
    Browser.sandbox
        { init = initialModel
        , view = view
        , update = update
        }



type alias Model =
    { count : Int }


initialModel : Model
initialModel =
    { count = 0 }


type Msg
    = Increment
    | Decrement


update : Msg -> Model -> Model
update msg model =
    case msg of
        Increment ->
            { model | count = model.count + 1 }

        Decrement ->
            { model | count = model.count - 1 }


view : Model -> Html Msg
view model =
    div []
        [ button [ onClick Increment ] [ text "+1" ]
        , div [] [ text <| String.fromInt model.count ]
        , button [ onClick Decrement ] [ text "-1" ]
        ]
```

ここで、「もっと `Msg` シンプルにしたくね？」と思いつき、`Increment` と `Decrement` を `Update Int` という一つの `Msg` にまとめましたとしましょう。ここまでは特に問題ありません。

**Counter V2**

```elm
type Msg
    = Update Int


update : Msg -> Model -> Model
update msg model =
    case msg of
        Update amount ->
            { model | count = model.count + amount }


view : Model -> Html Msg
view model =
    div []
        [ button [ onClick (Update 1) ] [ text "+1" ]
        , div [] [ text <| String.fromInt model.count ]
        , button [ onClick (Update -1) ] [ text "-1" ]
        ]
```

さらに、「`update` もっと簡単に書きたくね？」ということで、 `Msg` に**更新後の値を入れてしまう**ことにしましょう（V3）。 UI ライブラリとしてはこの方が使い勝手が良さそうです。実際、 かつて [evancz/elm-sortable-table](https://github.com/evancz/elm-sortable-table) もそうしていました。

**Counter V3**

```elm
type Msg
    = Update Int


update : Msg -> Model -> Model
update msg model =
    case msg of
        Update count ->
            { model | count = count }


view : Model -> Html Msg
view model =
    div []
        -- ここで新しい値を計算する
        [ button [ onClick (Update (model.count + 1)) ] [ text "+1" ]
        , div [] [ text <| String.fromInt model.count ]
        , button [ onClick (Update (model.count - 1)) ] [ text "-1" ]
        ]
```

さて、一つ前とあまり変わらないように見えますが、こちらのコードは**少々危うさがあります**。


## 何が危ういのか

問題は高速にイベントを発火させた時です。V2 と V3 の違いを明らかにするために、次の JavaScript をコンソールで実行してみましょう。

```javascript
// + ボタンを 100 回押す
for (let i = 0; i < 100; i++) {
  document.querySelector("button").click();
}
```

V2 ではカウンターの値が `100` になりますが、 V3 の方では `1` にしかなりません。なんということでしょう。
これは Virtual DOM が更新される前にイベントが 100 回発生しているためです。すると `model.count` は常に `0` なので `Update 1` が 100 回 `update` に届くということになります。

では、Virtual DOM の更新を待つとどうでしょう。今度はクリックの直後に 20ms ずつ待ってみます。

```javascript
(async () => {
  for (let i = 0; i < 100; i++) {
    document.querySelector("button").click();
    await new Promise(resolve => setTimeout(resolve, 20));
  }
})();
```

今度は期待通り `100` と表示されます。そんなに高速に操作する人間はいないはずですが、ヘッドレスブラウザの操作（puppeteerなど）では十分起こり得ます。
さらに `update` に HTTP などの非同期処理を挟むと人間でも簡単に再現可能になります。「１秒待ってからカウンターを更新する」[こちらのサンプル](https://ellie-app.com/7nVqPxjrXKSa1)で確かめてみましょう。


## まとめ

イベントハンドリングするときは **Virtual DOM がいつ更新されるのか（特に古い値への参照を握っていないか）**に注意しましょう！
CameraXでImageProxyを扱おうとすると 'Image is already closed' でクラッシュする

## はじめに
CameraXで撮影した画像をBitmapに変換しようとした時に以下のエラーで苦しめられたのでメモっておきます。

```
java.lang.IllegalStateException: Image is already closed
```

## かいけつ
撮影時のリスナーである `onCaptureSuccess` 内でコンストラクタを呼んでたのが原因でした。

#### failed

```kotlin
override fun onCaptureSuccess(image: ImageProxy?, rotationDegrees: Int) {
    super.onCaptureSuccess(image, rotationDegrees)
    // do
}
```

#### success

```kotlin
override fun onCaptureSuccess(image: ImageProxy?, rotationDegrees: Int) {
    // do
}
```

## なんでか
`onCaptureSuccess` の内部の実装を見ると中で `ImageProxy` を `close` させていたためでした。

```ImageCapture.java
public void onCaptureSuccess(ImageProxy image, int rotationDegrees) {
            image.close();
        }
```

## おわりに
ちゃんと使うなら標準ライブラリ使えよってことですかね・・・
【unix】ゾンビプロセス・孤児プロセスって何。

自分の記録用

## 環境
さくらレンタルサーバー
Flask 1.1.1
Werkzeug 0.16.0

## やりたいこと
クライアントからリクエストがあった際に、

- 親プロセス
    - forkで子プロセスを生成
    - クライアントに、responseを返す
    - 子の終了を待たずに、消滅
- 子プロセス
    - クライアントから渡された処理を行う
    - 処理終了後、消滅
   
## 疑問点
親が先死ぬとゾンビだ孤児だが出ちゃって邪魔らしい？
double fork？みたいなことしなきゃいけないらしい？
といった記述があったので、実際に調べてみた。

## 結果

### ゾンビプロセスとは
処理の終了した子プロセスで、親プロセスのwaitを待っている状態のプロセス。
子プロセスがforkされた段階でプロセステーブルに子プロセスが追加され、親プロセスのwaitをもって子プロセスはプロセステーブルから削除される。
つまり、処理は終了しているが親にwaitで引き取られていないプロセスのこと。

### 孤児プロセスとは
親プロセスが先に終了してしまい、親のwaitにより引き取られなくなった子プロセスのこと。親プロセスが先に死んでしまった子プロセスは、initプロセスにre-parentingされ、以後initプロセスが親プロセスとなる。
initプロセスは積極的にwaitを実施し、孤児プロセスを終了させる。

### まとめ
つまり、親プロセスが常駐プロセスで、いろんなタイミングで子を作り、どのタイミングでwaitを呼べばわからないような場合に、ゾンビプロセスが大量にできてしまいシステムを圧迫する、ということっぽい。

今回実現したい機能では、先に親プロセスがさっさと死ぬため、子プロセスはinitにきちんと引き取られrて終了するだろうから、double forkとかしないでよさげ。


## 参考ページ
用語のイメージが掴みやすい
>[孤児プロセス](https://wa3.i-3-i.info/word14951.html)
>[ゾンビプロセス](https://wa3.i-3-i.info/word11035.html)

まとめとしてわかりやすい
>[yahoo知恵袋](https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1152001996)

double forkが必要な場合やその理由について
>[HATENA Blog : Double forkによるプロセスのデーモン化と、ファイル変更時の自動サーバーリロードの実装 (Python)](https://nwpct1.hatenablog.com/entry/python-daemonize-auto-reload)
リングフィットアドベンチャーを買いたかった話

# 背景
みなさん運動してますか？
引きこもりにはもってこいの[リングフィットアドベンチャー](https://www.nintendo.co.jp/ring/)が最近任天堂から発売されました！！
私も買いたかったのですが、どこも品切れらしくて辛いです。かと言って、メルカリとかヤフオクで転売ヤーから高値で買うのも腹立つので、なんとか正規ルートで買おうと頑張ってみました。


# やったこと
色々ググってるとどうも時々通販で、商品が入荷され在庫が復活するということを聞きました。ただ、ずっと通販サイトの前で張り付いているわけには行かないので、在庫が復活したら通知してくれないかなーと考えていました。
そこで、[こういう便利なサイト](https://www.net-zaiko.com/item/4902370543278)をつかって、ここで在庫が復活していたらLineで通知するアプリを作りました。

成果物はこちら！
https://github.com/aitaro/inventory-notification

ちなみにitemcodeを変えたら他の商品でも使えます。

# 環境構築
正直言語はなんでもいいです。個人的にRubyが好きなのですが、なんとなくPythonにしました。
開発はローカルでやりますが、在庫通知という特性上、どこかにデプロイすることを念頭において開発しましょう。
### フォルダ構造

```
.
├── README.md
├── main.py
└── requirements.txt
```

```requirements.txt
line-bot-sdk
selenium
chromedriver-binary
```

# 実装
基本的には2ステップです。

1. net-zaiko.comからスクレイピング
2. lineへ送信

これを適当なサーバにデプロイします。(今回はheroku)

スクレイピングはseleniumを使う方法とbeautifulsoup4を使う方法がありますが、このサイトではアクセスしてから他のサイトの在庫情報を取りに行くので、ブラウザの挙動をそのまま再現するseleniumを使います。また、lineは[ここ](https://developers.line.biz/ja/)からbotを作成し、アクセストークンを発行します。コード中の`GOOGLE_CHROME_SHIM`はchromeの実行ファイルの場所です。

```main.py
from linebot import LineBotApi
from linebot.models import TextSendMessage
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import chromedriver_binary
import re
import time
import os

# 在庫情報取得

# リングフィットアドベンチャー
item_id = '4902370543278'
# item_id = '4988013097025'

# ブラウザーを起動
options = Options()
options.binary_location = os.getenv('GOOGLE_CHROME_SHIM')
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)

# net-zaikoにアクセス
url = 'https://www.net-zaiko.com/item/' + item_id
driver.get(url)
time.sleep(10)
targetElements = driver.find_elements_by_css_selector("#sl0 .siSa,.siSb,.siSc,.siSd,.siSe")
title = driver.find_element_by_id("itmH0").text

# それぞれのネットショップで在庫があるか確認
flag = False
for el in targetElements:
    # amazonはマケプレでぼったくってくるから除外
    pattern = r'Amazon\.co\.jp'
    result = re.search(pattern, el.text)
    if not result:
        flag = True
        print('在庫あり')
    print(el.text)
    print(title)

# ブラウザーを終了
driver.quit()


# Lineに通知

line_bot_api = LineBotApi(os.getenv('LINE_CHANNEL_ACCESS_TOKEN'))

if flag:
    messages = TextSendMessage(text=f"{title}の商品在庫があります！\nこちらよりアクセスして下さい{url}")
    line_bot_api.broadcast(messages=messages)
```

### 工夫した点
- サイトによって在庫ありの表記に揺れがあったので、緑枠(siSa 〜 siSe)で在庫ありを判定
- Amazonはマケプレボッタクリ詐欺がひどいので除外

### デプロイ
chromeが入って、定期実行できる必要があったので、その条件で色々検討したのですが、herokuが無料で行けそうだったのでherokuにしました。
herokuでのアプリに作り方は割愛しますが、add-onでheroku schedulerを入れるのと、buildpackでchromeとchromedriveを入れるといけます。[ここらへん](https://qiita.com/sho7650/items/8fe07126f00c8e94e13b)参照。


# 感想
2時間ぐらいかけてつくりました。まだ買えてません。早くほしいです。
スクレイピングは迷惑にならない範囲でやりましょう。
Java11インストール後にEclipseが起動しなくなる現象

# はじめに

職場でJava11をインストールしたところ、Eclipseが起動しなくなりました。
当初は原因が全く分からずに苦戦したので、記録として記事を書くことにしました。

# 状況

## 当初の状態

以下のように古いJavaであったため、空いた時間でJavaのバージョンを上げることにしました。
なお、Eclipseは[Pleiades](https://mergedoc.osdn.jp/)の日本語化版を使っています。

* OS：Windows 10 Pro
* Java：Oracle Java 8
* Eclipse：Eclipse 4.6（Neon）

## Javaのバージョンアップ後の状態

無償で使えて簡単にインストールできる「Amazon Corretto」をインストールしました。

* OS：Windows 10 Pro
* Java：[Amazon Corretto 11](https://docs.aws.amazon.com/ja_jp/corretto/latest/corretto-11-ug/downloads-list.html)
* Eclipse：Eclipse 4.6（Neon）

## 発生した不具合

Eclipseのスプラッシュ画面が表示された後、`An error has occurred. See the log file ...`というダイアログが出てしまい、Eclipseが起動しませんでした。

![eclipse_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/312166/511c2a89-b6a7-f012-e0a0-a0c2e82c5512.png)

# 対応策

* 以下の記事を参考にして、最新版のEclipseをインストールしたところ、無事にEclipseが起動しました。
 * [Java11以上でEclipse-Oxygenが起動しない](https://www.gwtcenter.com/eclipse-oxygen-doesnt-invoke-on-java11-or-later)
* ちなみに、今回インストールしたEclipseのバージョンは「リリース 2019-09」の最新版です。

# まとめ

* Java 7からJava 8にバージョンアップした時には、Eclipseが起動しないという症状はなかったと思うので、今回はかなり驚きました。
* 当初はAmazon Correttoに不具合があるのでは...と思いましたが、色々調べていくうちにJava10以降で同様の症状が出ていると分かり、最終的に比較的簡単な方法で解決できて良かったです。
* バージョン管理に載せていないちょっとしたプログラムが幾つかありましたが、既存のワークスペースからコードを簡単にインポートできたので助かりました。
【Unity】UIで押させたいボタンだけフォーカスさせる

追記(2020/1/20)
Buttonが反応しない不具合を解消するため、Canvasに加えてGraphicRaycasterを追加するようにしました。
追記(2020/1/21)
Focus()にて1F待機を追加しました。UniTaskを使用してますが1F待機できればCoroutineなどでも問題ないはずです。

## 背景
デジゲー博に展示して試遊してる様子を見て気づいたんですが、押させたい場所にポップを表示させるだけでは人は押してくれませんでした（見ててまじかよと思った）。

そこで、押させたい場所しか押せない仕組みが必須と分かり実装してみました。

## 概要

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">UIで押させたいボタンだけフォーカスさせる実装方法<br>①Stopper用Canvas(+Image)を通常のUIのCanvasより前に表示させる<br>②押させたいボタンにAddComponentで動的にCanvasを追加し、SortOrderをStopperCanvasより前に表示させる。<br>③するとUIのレイヤー関係を壊さずに最前面に表示できる。 <a href="https://t.co/TRnADbzk1L">pic.twitter.com/TRnADbzk1L</a></p>&mdash; アズマゴロー@デジゲー博B-03a (@azumagoro) <a href="https://twitter.com/azumagoro/status/1198534250158379009?ref_src=twsrc%5Etfw">November 24, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## コードとか

```C#:StopperController.cs
using UniRx.Async;
using UnityEngine;
using UnityEngine.UI;

public class StopperController : MonoBehaviour
{
    [SerializeField] private Canvas _stopperCanvas;

    public static FocusController Instance;

    private Canvas _addedCanvas;
    private GraphicRaycaster _addedRaycaster;
    
    private void Awake()
    {
        Instance = this;
    }

    public async void Focus(GameObject go)
    {
        _stopperCanvas.gameObject.SetActive(true);
        _addedCanvas = go.AddComponent<Canvas>();
        _addedRaycaster = go.AddComponent<GraphicRaycaster>();
        // たまに動作しない時があるため1F待機する
        await UniTask.DelayFrame(1);
        _addedCanvas.overrideSorting = true;
        _addedCanvas.sortingOrder = _stopperCanvas.sortingOrder + 1;
    }

    public void RemoveFocus()
    {
        // 依存関係のため_addedRaycasterから先に削除する
        Object.Destroy(_addedRaycaster);
        _addedRaycaster = null;
        Object.Destroy(_addedCanvas);
        _addedCanvas = null;

        _stopperCanvas.gameObject.SetActive(false);
    }


#if UNITY_EDITOR
    [SerializeField] private GameObject testGameObject;

    [ContextMenu("TestFocus")]
    void TestFocus()
    {
        Focus(testGameObject);
    }
    
    [ContextMenu("TestRemoveFocus")]
    void TestRemoveFocus()
    {
        RemoveFocus();
    }
#endif
}
```

### StopperCanvas
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237014/3cd127b1-44d9-7420-efb9-d143fa661028.png)

### StopperController
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237014/b830b915-60a1-0997-d7cd-e58befabf145.png)




参考になった場合はよろしければいいねお願いします😊

おわり
VScode＋Pyrightで新バージョンのPython文法の混入を防ぐ

# Pyrightって何？
![PyrightLarge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40987/374bdfc1-e722-6273-2882-5e891949118d.png)

[Pyright](https://github.com/microsoft/pyright)はMicrosoft謹製のPython向け静的解析ツールです。
もともと型チェックが得意な同ツールですが、型チェックの他にもコード内に意図せず未サポートの文法（Python 3.8の[セイウチ演算子](https://qiita.com/Nipper1357/items/446923f67e03d646be36)など）が使われていないかチェックする機能も備えています。
このチェック機能があれば、*Python 3.8の新機能盛り沢山のコードを配布したら配布先で動かなかった！（Python 3.4 (2014年) のままだった）*、といったトラブルを未然に防ぐことができます。
このようにPyrightは型チェックだけでなくコード側でPythonの対象バージョンを絞ることもでき非常に強力な静的解析ツールと言えるでしょう。

PyrightはVScodeの拡張機能として利用可能です。

**余談:**　名称の「Pyright」は[パイライト鉱石](https://ja.wikipedia.org/wiki/黄鉄鉱)（Pyrite; 黄鉄鉱）とかけているようです。ロゴのデザインも素敵ですね。

# やり方

さて本題です。設定の手順は以下の通りです。

1. VScodeの拡張機能**Pyright**をインストールする。
2. 自身のプロジェクトのルートディレクトリに`pyrightconfig.json`（下記参照）を用意する。
3. VScodeを再起動する（設定を反映させるため）。

```json:pyrightconfig.json
{
    "pythonVersion": "3.4"
}
```

**コメント:**　上記の設定では、自身のプロジェクトの中でPython **3.4**でサポートされていない文法（ex. [セイウチ演算子](https://qiita.com/Nipper1357/items/446923f67e03d646be36)、[f記法](https://qiita.com/Nakamurus/items/9171a37014d9b25eece0)）が**Problem**として検出されます。

# サンプル
実際に未サポートの文法（f記法）を使用した場合の結果を見てみます。下記のサンプルコードをご覧ください。

```python:test_pyright.py
a = 3.14
print(f"a = {a}")
```
見ての通りPython 3.4では未サポートのf記法が使用されています。
このときVScode上では、下のスクリーンショットのとおり、該当箇所に赤い下線が引かれて**Problem**として強調されていることがわかります。またパネル部分にも**Problem**として表示されます。

**▼ VScodeの画面（上：エディタ部分、下：パネル部分）**
<img width="809" alt="スクリーンショット 2019-11-24 1.36.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40987/527013b7-a429-5a0e-e958-9d8d841250b2.png">
<img width="585" alt="スクリーンショット 2019-11-24 18.23.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40987/64fc9e64-0e0f-1981-4007-a2c6267a1bc9.png">

**コメント:**　赤い下線の箇所にカーソルを乗せることで「 *f記法はPython 3.6以上が必要です* 」と書かれたツールチップが表示されます。

このチェック機能があれば、「○○○はPython 3.8からだっけな？ △△△は〜」と呟きながらその都度リファレンスを確認せずに済みますのでとっても快適です。

**Pyright、すごい。**

# 参考リンク
- [microsoft/pyright: Static type checker for Python](https://github.com/microsoft/pyright)（GitHubのページ）
- [pyright/configuration.md at master · microsoft/pyright](https://github.com/microsoft/pyright/blob/master/docs/configuration.md)（**pyrightconfig.json**の書き方について）
- [Pyrightで型チェックしたいのにimportで怒られるときの対処法 - Qiita](https://qiita.com/tenajima/items/81e0ea8ef70b954f7f0f)（**pyrightconfig.json**の存在を知るきっかけになった記事です。感謝😆）
10進数でも2進数でも8進数でも逆から読んで同じになる回文数（Ruby）

##回文とは
世の中ね、顔かお金かなのよ...
（よのなかねかお か おかねかなのよ）
のように上から読んでも下から読んでも同じ言葉を回文と言います。


|    １０進数   |    ２進数  |    ８進数  |
|:----------:|:---------:|:--------:|
|     0      |      0    |    0     |
|     1      |      1    |    1     |
|     2      |      10   |    2     |
|     3      |      11   |    3     |
|     4      |      100  |    4     |
|     5      |      101  |    5     |
|     6      |      110  |    6     |
|     7      |      111  |    7     |
|     8      |      1000 |    10    |
|     9      |      1001 |    11    |
|     10     |      1010 |    12    |

例えば、上の表では１０進数で９が２進数、８進数共に回文数となっています。

今回は１０以上の数で１０進数、２進数、８進数共に回文となる最初の数を探してみます。

##考え方
まず２進数で一番右が"０"の数を考えてみます。10101010とか。
回文でなければならないので、一番右が"0"だど一番左も"0"にならなければいけないのですが、そのような２進数は存在しません。（例えば、00101010は存在しない）
なので右も左も"1"から始まる２進数になるはずですが、これは必ず奇数になります。なので奇数だけ順番に探していけば良いことになります。


###10進数の回文数
ある10進数が回文数となっているかどうかは、reverseメソッドを使って、

```ruby:qiita.rb
num.to_s == num.to_s.reverse
```
を使えば分かります。

###その10進数が2進数でも回文数になっているか
またある10進数の、その数の2進数が回文数になっているかどうかは、.to_sメソッドを使えば

```ruby:qiita.rb
num.to_s(2) == num.to_s(2).reverse
```
で分かるようになります。
to.s()のカッコの中に数字を入れると、その進数に変換することが出来ます。


##あとは10以上の10進数で2進数、8進数共に回文数になっている数をif文とwhileループで探すだけです！


```ruby:qiita.rb
num = 11
border = "-------"
while true
  if num.to_s == num.to_s.reverse &&
     num.to_s(8) == num.to_s(8).reverse &&
     num.to_s(2) == num.to_s(2).reverse
    puts num
    puts num.to_s(2)
    puts num.to_s(8)
    puts "we found it!"
    break
  end
  puts num
  puts num.to_s(2)
  puts num.to_s(8)
  puts "not this one."
  puts border
  num += 2
end
```

計算してみると、

```ruby:qiita.rb
585
1001001001
1111
```
になりました！

##ちなみに
これに16進数でも回文数となるような数を探そうと思って、条件を付け足してプラグラムを走らせてみたのですが、何分待っても計算が終わりませんでした、、、