OmniAICreator/Qiita-1.07M huggingface dataset:
Railsのnokogiriでスクレイピングしてactiverecord-importで配列をDBに保存する

# スクレイピングしてDBに保存したい人向けです
外部からデータ取ってくることに憧れてたので、初めてスクレイピングやった忘備録です。
初めてスクレイピングしたのでおてやわらかにお願いします笑

# 何をスクレイピングしたの？
[paypayのキャンペーンwebページ](https://paypay.ne.jp/notice/20200604/01/)から店舗名を取得しました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314481/9df6c72a-b76a-3bac-2a26-9826b2fc69f9.png)

# スクレイピング前のDB
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314481/79615757-a8da-4e0d-386b-bc7460054dbc.png)

# スクレイピング後のDB
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314481/5f31561f-b0db-4282-280f-1b5571e9511a.png)

# 手順
1. nokogiriでweb上のテキストを配列形式で取得する
2. ↑の配列をactiverecord-importで一度のクエリで保存する


# 環境
- sqlite3
- ruby 2.6.3
- Rails 6.0.2.1

```Gemfile.
gem 'activerecord-import'
gem 'nokogiri'
```
`bundle install`しといてください！

# まずはスクレイピングしてみる
今回はcontrollerから呼び出したかったので、moduleとして作成します。

```app/controllers/concerns/paypay_scrapes_concern.rb
module PaypayScrapesConcern
  require 'open-uri'
  require 'nokogiri'

  def scrape_paypay_shops
    url = 'https://paypay.ne.jp/notice/20200604/01/'

    charset = nil
    html = open(url) do |f|
      charset = f.charset
      f.read
    end

    doc = Nokogiri::HTML.parse(html, nil, charset)

    @shops = doc.xpath('//div[@class="article__contents post"]').css('tr').map do |node|
      @shops << node.css("td[1]").text
    end.drop(1)
  end
end
```

結果を確認してみます。

```
$ ruby paypay_scrapes_concern.rb

=> ["あさひ", "味千ラーメン 掛川インター店", "遠州屋", "株式会社縁 開縁ダイニング縁や", "大石農場ハム工房", "大手門うおそう", "OZ", "KAKEGAWA 1番地", "掛川グランドホテル", "華月苑", "インド・ネパール料理レストラン GANESHA", "かねきや旅館", "カレー・ザ・ロック", "喜縁旬菜 ZIKAN", "喬菜 まさ吉", "餃子と串カツ 遠州誠家", "串&Bar FuQ(ふく)", "琴菊", "ことのや", "魚処 粋", "椎の木茶屋", "真味楼", "寿し処 八幡", "タナカ", "中国料理四川", "戸塚屋", "巴屋", "ナムズ", "にんちゃんち ", "ひいらぎや", "ファニーファーム", "Food Labo 房’s", "ふらっと", "ベル・エポック", "MAX'S DINER", "まるましらすや", "麺屋 RiQ", "八咫烏", "ラーメン 男前", "らーめん若虎", "LA MAREA 1980 DAN"]
```

# controllerに新しくメソッド追加

```shops_controller.rb
def create_paypay_shops
   @shops = scrape_paypay_shops
   shops = []
   @shops.each do |shop|
     shops << Shop.new(name: shop)
   end
   # DBアクセス一回で配列を保存できるgem activerecord-import
   Shop.import shops
 end
```
こんな感じで保存できると思います。

今後はDBのバリデーションとかもやりたいですね。笑

# 2021.03.09 追記 Activerecord-importの書き方について 
Activerecord-importの公式ドキュメントによると、[columns-and-arrays](https://github.com/zdennis/activerecord-import#columns-and-arrays)が一番早いそうですね。

```shops_controller.rb
def paypay_save
   @shops = scrape_paypay_shops
   shops = []
   @shops.each do |shop|
     shops << Shop.new(name: shop)
   end
   # DBアクセス一回で配列を保存できるgem activerecord-import
   Shop.import shops
end

# ↑をリファクタリングしてみましょう

def paypay_save
  # eachの中でShop.newをしないことでパフォーマンス改善
  Shop.import [:name], [scrape_paypay_shops]
end
```
重複していたらupdateしたりignoreするコマンドもあるみたいなので試してみてください！


# 参考
https://morizyun.github.io/blog/ruby-nokogiri-scraping-tutorial/index.html
https://qiita.com/superman9387/items/1981a24664b260e77238
https://qiita.com/makicamel/items/b6d4f3d2661fc66103ed
要件定義について考える


# はじめに

上流工程の業務に携わる機会が増えてきたので
ちょっとした用語整理です。

ベストプラクティスや間違いがあれば
書き直していく予定です。
今回は要件定義についてまとめます。

--------------------------------
# 要件定義とは

> 要求分析の結果を基に
実装すべき制約を明確にして
「要件」として確定すること

--------------------------------
# 要するに

システム開発をする上で重要なことを
仕様作成、設計に落とし込めるまで
内容を精査する。

精査した内容で
ステークホルダーと合意を取る。


--------------------------------
# 要求と要件
「要求」 = 本当に欲しいもの
「要件」 = 本当に要るもの

--------------------------------
# 要求
ビジネス要求や業務要求など種類がありますが
共通して言えることとしては

クライアントがやりたいこと
クライアントが実現したいこと

これらが要求になります。

--------------------------------
# 要件

ざっくり言えば
**要求を実現する為に必要なこと**が
要件となる。

要件は作り手が考えることで
考える為に何が必要かをクライアントにヒアリングする。

--------------------------------
# まとめ
要求 ＝ やりたいこと
要件 = やらなければならないこと

要件定義フェイズでは
要求を聞き入れ
システムを設計する為の要件を作成する。

要件を作成する場合は
クライアントにヒアリングして
必ず、合意を取る。

--------------------------------
# おわり
C++によるプログラミング技法_スマートポインタに独自のデリートコードを実装しリソースの開放漏れを防ぐ

#1 はじめに
　C++では基本的には、デストラクタによってクラスのオブジェクトが使用したリソースを開放する処理が定義される場合が多いが、現実的にはすべてのクラスがそのように設計されているわけではなく、ユーザーによって明示的に開放させる作業を要求するものがあります。しかし、明示的な開放は時としてリソースリークする恐れがあります(解放する前に例外が発生するよ、開放忘れの場合など)、今回は、このような明示的な開放を要求するクラスに対してスマートポインタを用いて、確実に開放する手法を紹介をしたいと思います。

#2 動的に確保したリソースがリークするようなケース
　下記にリソースがリークするようなケースを示します。
　

``` conn.cpp

struct destination{}; //接続先
struct connection{}; //接続を使用するための必要な情報
connection connect(destination* dst); //接続を開く
void disconnect(connection conn); //接続を閉じる

void test(destination &d)
{
   connection c = connect{d}  //接続を取得
　 //接続を使用するコード
   //関数testを終了するまえにdisconnectを呼ぶのを忘れた場合
}
```

　上記のように短い処理なら注意深くコードを書けばリークは防げるかもしれませんが、try-catchやブロックを用いた多重にネストされたコードだと開放の処理を忘れやすくなる可能性があります。

#3 スマートポインタに独自のデリータを定義しリソースの開放漏れを防ぐ
　STLに存在する、スマートポインタは特に何も指定しなければ、破棄された際に所有しているポインタに対してdeleteが実行されます。この規定の動作はユーザーが独自に設定できます。ことのきdeleteの代わりに用いる関数をデリータと呼びます。以下に簡単な例を示します。

```use_share_ptr.cpp
struct destination{}; //接続先
struct connection{}; //接続を使用するための必要な情報
connection connect(destination* dst); //接続を開く
void disconnect(connection conn); //接続を閉じる
auto end_connection = [](connection* p) { disconnect(*p); }; //デリータとして定義するラムダ式
void test()
{
   connection* c = ・・  //接続を取得
   std::shared_ptr<connection> sp(&c, end_connection); //独自のデリートコードを実装した
　 //接続を使用するコード
   //関数testが例外によって終了したり、disconnectを呼ぶのに忘れた場合でも関数testの終了時にend_connectionが実行されリソースの開放漏れを防げる。
}

```
上記は、関数testの終了時にポインタspのデリータによりend_connectionが実行されリソースが確実に開放されます。
また、std::unique_ptrも同様にデリータを定義できます。以下に示します。

```use_unique_ptr.cpp
//接続関連の処理
auto end_connection = [](connection* p) { disconnect(*p); }; //デリータとして定義するキャプチャなしのラムダ式
void end_connection2(connection* p)  { disconnect(*p); };　//関数のカスタムデリータ
void test()
{
   connection* c = ・・  //接続を取得
   std::unique_ptr<connection, decltype(end_connection)> sp1(&c, end_connection); //独自のデリートコード(ラムダ式を使用)を実装した
 　std::unique_ptr<connection, decltype(end_connection2)*> sp2(&c, end_connection2); //独自のデリートコード(関数オブジェクト)を実装した
　 //接続を使用するコード
   //関数testが例外によって終了したり、disconnectを呼ぶのに忘れた場合でも関数testの終了時にend_connectionが実行されリソースの開放漏れを防げる。
}

```

上記はsp1にラムダ式を用いた場合と、sp2に関数オブジェクトを使用したパターンを示しました。デリータとして関数ポインタを与えるとstd::unique_ptrのサイズは1ないし2ワード増加するのが一般的です。またキャプチャをともわないラムダ式の場合サイズは変化しないため、カスタムデリータを関数とキャプチャをともわないラムダ式
のどちらかを選択できるのならラムダ式を採用するべきです。またshared_ptrと違いdecltypeというキーワードを使用していますが、これはunique_ptrはデリータをコンパイル時にバインドする必要があり、shared_ptrは実行時にバインドするためだからです。
Fintechについてまとめた

Yuheiです。

時々聞くIT関係の用語で「Fintech」について、何の事で、どう言う時に使うのかが理解が合間だったので、まとめてみました。

# Fintechとは？
「Finance(金融)」と「technology(技術)」の言葉を組み合わせたもので、

「IT技術を駆使した金融サービス」のことです。

ITによる金融サービスは、「Fintech」と言う言葉が出てくる以前から、ATMのお金の出し入れや、クレジットカードの利用などで使われていましたが、

ここ数年で、消費増税のポイント還元や、キャッシュレスサービスの発展により、注目されるようになりました。


#Fintechのサービス事例
現在、Fintechで使われるサービスに何があるのかを調べてみました。

下記はその一部分です。
・マネーフォワードなどの家計簿アプリ
・PayPayなどのキャッシュレスアプリ
・仮想通貨
・クラウドファウンディング
・確定申告サービス
・ロボアドバイザーなどの資産運用
・SNS上の決済サービス
などです。

# 日本での普及率
最近では、消費増税やコロナショックにより、キャッシュレス決済を使う人が増えたりして、Fintechへの関心が高まっていますが、
それまでの普及率はあまり高くなかったみたいです。

日本は元々「円」に対する信用度も高く、かつカード決済があまり普及していなかったこともあり、普及率はあまり高くなかったそうです。

また、日本では、大手金融機関とスタートアップが提携してサービスを開発するといった事例が少ない上、法律なども絡んで、普及率が高くないと言った結果となっているみたいです。

#Fintechの今後
送金、決済、融資、ロボアドバイザー、会計、仮想通貨など様々なカテゴリーを持つFintechですが、現在では、誰もが気軽にスマホで扱ええるサービスとなりました。

これらは、高度な技術を持つIT企業があったからこそ実現したことであり、今後も沢山のサービスが生まれてくると思います。

#最後に
Fintechについてまとめようと思ったのは、今日たまたまFintechについての書籍を購入したのもあり、少し勉強しようと思い、本を読みながら、ググったりして調べ、自分なりにまとめてみました。

今後も何か気になることがあれば気軽にまとめていきたいと思います。

本日はありがとうございました。

#参考文献

[・60分でわかるFintechフィンテック最前線](https://www.amazon.co.jp/dp/4774188808/ref=cm_sw_em_r_mt_dp_U_Dsl-Eb9ZJCKRR)
WindowsでPyAudioがPython 3.7, 3.8, 3.9 にインストールできない場合の対処法

2020年6月現在PyAudio公式版はWindowsのPython 3.6.Xまでしか対応していません。
https://pypi.org/project/PyAudio/#files

3.7以上でインストールしようとすると
"Microsoft Visual C++ 14.0 is required."
というエラーが出ますが、エラーに従ってMicrosoft C++ Build ToolsをインストールしてもPyAudioの依存関係の設定が上手くいっておらず、インストールできません。

3.7以上でPyAudioを使うには非公式版ですが
https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio
からバージョンに対応したwhlファイルをダウンロードしてインストールすれば使えます。例えばPython 3.8 on x86-64なら

```py -m pip install PyAudio‑0.2.11‑cp38‑cp38‑win_amd64.whl```

でインストールできます。動作は問題ありませんでした。
公式版ならWindows版Python3.6.Xを使うのが無難です。
Microsoft C++ Build Toolsをインストールしても結果には関係ありませんのでご注意ください。そのような誤った記事が多くありました。
360度回転対応ワンワイヤー（１Wire）シリアルサーボ TS-315を使う

今回は，シリアルサーボTS-315を使ってみましょう．

##TS-315とは？
そもそもTS-315とは何か？
TS-315は1Wire，1本の通信線でシリアル接続可能な360°回転対応のサーボモーターです.
何がすごいのか？
360度回転可能なサーボモータは，最近よく目にするようになりました．
しかし，PWM駆動が主流です.
##1Wireシリアル通信
TS-315は１Wireシリアル接続であることが特徴です．
1Wireにするメリットは，数珠繋ぎすることが可能なことが挙げられます．
PWM接続の場合，各サーボモータとは，1対1で接続する必要があります.
しかし、１Wireシリアルにすれば，数珠つなぎにすることが可能です．
この結果，通信ボードに，サーボモータの台数分の通信コネクタを用意する必要がなくなります．

ルネサスエレクトロニクスのがじぇるねブランドでGR-ROSEという製品があります．
GR-ROSEはROS2での使用を目的としており，近藤などの１Wireシリアルのサーボモータ向けに作られました．
ROSはROBOTIS社の製品を中心にこの1Wireシリアル接続のサーボモータが多くつかわれているようです．
しかし，高いのです，
1個5千円のサーボモータをふつうは買えません・・・
オムニホイールだと，３個で１５０００円を超えてしまいます．

##価格
しかしTS-315は1個千円前後です，
送料含めても2000円以下で購入可能です．
よって，オムニホイールであれば3軸６千円でフルセット用意可能です．
Aliexpressで５４２８円でした．(２０２０年６月２８日現在）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/9ce2816b-83e2-717e-cb5e-5c0fde9cae92.png)

それでは，TS-315の実物を見てみましょう．
ケーブルと，ホーン，ネジ類が付属しています．
![DSC_0178 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/0917651d-74fd-f85d-5b09-98c8b8183e9c.jpeg)

接続は，USB接続の変換基板を使用しました．
現在売られているものとは違う形です.
電圧は，5~8.4Vです．
![DSC_0182 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/29bbf1da-d605-3438-10ce-3243bd3895cc.jpeg)
##GUIでコントロール
ServoTestというアプリケーションでID設定や各サーボのテストが行えます，
![ServoTest.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/523e5aec-62e6-7c0a-749f-7f40c4a02d68.jpeg)

各サーボモータにIDを振る事で個別操作が可能になります.

##シリアル通信
TeraTerm等のターミナルエミュレータで操作します．
360度回転の場合，1500が停止で，500と2500が最大値です．

###コマンド例

```
#IDコマンドT速度(ms)
```

###初期コマンド 位置確認

     #1PRAD\r\n
返答　

     001P0000

###停止

```
#1P1500T100
```

###回転

```
#1P500T100
```
###3サーボ全回転

```
#1P500T100#2P500T100#3P500T100
```
といった形でコントロール可能です.

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">TS-315 ワンワイヤーサーボ実験中<br><br>8.4Vまで入力可能<br>動画は7.7Vでテスト <a href="https://t.co/PKZXBtAube">pic.twitter.com/PKZXBtAube</a></p>&mdash; usashirou (@usashirou1) <a href="https://twitter.com/usashirou1/status/1277169571057635328?ref_src=twsrc%5Etfw">June 28, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
has_and_belongs_to_manyメソッドを使用してモデルを関連付けする

has_and_belongs_to_manyメソッドを使って多対多のモデルの関連付けからレコードを作成するまでの手順を書いていきます。

記事執筆時のRailsとRubyのバージョンは以下のとおりです。

```bash
$ rails -v
Rails 6.0.3.1
$ ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin18]
```

## has_and_belongs_to_many関連付け
has_and_belongs_to_many関連付けでは、多対多のモデルをつなぐ中間テーブルを作成します。has_many :through関連付けのように中間モデルは作成しません。

モデルの関連付けのイメージ図（Railsガイドから引用）
[Active Record の関連付け - Railsガイド](https://railsguides.jp/association_basics.html#has-and-belongs-to-many%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392897/36d79e50-0bcd-9567-dba6-40a289566928.png)

assembliesとpartsが多対多で関連付けるモデルで、assemblies_partsがそれらの中間テーブルです。

## モデルの関連付け
上記のモデルを以下のように具体化して説明します。
assembliesモデル→Userモデル
partsモデル→Bookモデル
assemblies_parts→books_usersテーブル

ユーザー(User)が読んだ本(Book)を登録するアプリを作成するとします。
1人のUserは複数のBookを登録でき、同じBookは複数のUserから登録されるため、多対多の関係になります。

UserモデルとBookモデルを関連づけるために、それぞれのモデルに以下の定義を追加します。

```ruby
class User < ApplicationRecord
  （中略）
  has_and_belongs_to_many :books
end
```

```ruby
class Book < ApplicationRecord
  （中略）
  has_and_belongs_to_many :users
end
```

UserとBookを紐づけるために中間テーブルを作成します。モデルは作成しないので、マイグレーションファイルのみ作成します。

```bash
rails g migration create_books_users book:references user:references
```

マイグレーションファイルが作成されるので、`rails db:migrate`を実行します。

```ruby
class CreateBooksUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :books_users do |t|
      t.references :book, null: false, foreign_key: true
      t.references :user, null: false, foreign_key: true
    end
  end
end
```

## レコードの作成
本（Book）を登録するアクションをコントローラーに作成します。

以下の例ではbuildメソッドでBookオブジェクトの作成、saveメソッドでBookオブジェクトをDBに保存、<<メソッドで中間テーブルにレコードを作成しています。
buildメソッド、<<メソッドはhas_and_belongs_to_manyで宣言したことにより使えるようになるメソッドです。
Bookオブジェクトの作成とDBへの保存の処理を分ける必要がない場合は、buildメソッドと<<メソッドの代わりにcreateメソッドを使ってオブジェクトの作成から保存までまとめて実行することもできます。
[has_and_belongs_to_manyで追加されるメソッド - Railsガイド](https://railsguides.jp/association_basics.html#has-and-belongs-to-many%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%95%E3%82%8C%E3%82%8B%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89)

```ruby
class BooksController < ApplicationController
  （中略）
  def create
    # 登録するBookのレコードに紐づけたい任意のUserオブジェクトをインスタンス変数に設定
    @user = User.first
    # Userと紐づくBookオブジェクトを作成（book_paramsはストロングパラメーター）
    @book = @user.books.build(book_params)

    # DBに保存
    if @book.save
      # 中間テーブルにレコードを作成
      @user.books << @book 
      redirect_to @book
    else
      render :new
    end
  end
  （中略）
end
```
GCP Ubuntu Server で GUI(Ubuntu Desktop )をインストール成功したの話

# SSH でコネクト

1. keyfileを生成
`ssh-keygen -t rsa -b 4096 -C username`
2. keyfile.pub を開けで中の文字をコピーして
3. VM インスタンス　=> 編集　=> SSH 認証鍵 項目を追加 でペスト
4. `ssh -i keyfile username@xx.xxx.xxx.xxx` でコネクト

hint
* WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
`ssh-keygen -R xx.xx.xxx.xxx` で解決出来ます


## Swap
```
sudo fallocate -l 1G /swapfile
sudo dd if=/dev/zero of=/swapfile bs=1024 count=1048576
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo "/swapfile swap swap defaults 0 0" | sudo tee -a /etc/fstab
sudo mount -a
```

## Gui
```
sudo apt-get update && sudo apt-get upgrade -y
sudo apt-get install --no-install-recommends ubuntu-desktop -y
sudo apt-get install gnome-core -y
sudo apt-get install -y gnome-panel
sudo reboot now -h
```

## VncServer
```
sudo apt install tightvncserver -y
```
```
vncserver
vncserver -kill :1

echo -e"
unset SESSION_MANAGER /n
metacity & /n
gnome-settings-daemon & /n
gnome-panel &
" > '.vnc/xstartup'

vncserver 
```

#  ファイアウォール 
| vnc-server |
|:--|
| 上り |
| http-server |
| IP 範囲: 0.0.0.0/0 |
| tcp:5901 |
| 許可 |
| 1000 |
| default |
| オフ |

## Vnc Viewer をダウンロード　
https://www.realvnc.com/en/connect/download/viewer/

外部 IP
xx.xxx.xxx.xxx:5901 でコネクト

## chrome リモートデスクトップをインストール
```
sudo apt install  xbase-clients -y
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb; \
wget https://dl.google.com/linux/direct/chrome-remote-desktop_current_amd64.deb; \
sudo dpkg -i google-chrome-stable_current_amd64.deb; \
sudo dpkg -i chrome-remote-desktop_current_amd64.deb; \
sudo apt install -f -y
```
```
sudo usermod -a -G chrome-remote-desktop $USER
sudo reboot
```

```
cd /opt/google/chrome-remote-desktop; ./chrome-remote-desktop --stop; sudo cp chrome-remote-desktop chrome-remote-desktop.orig; sudo sed -i -e 's/FIRST_X_DISPLAY_NUMBER = 20/FIRST_X_DISPLAY_NUMBER = 0/g' chrome-remote-desktop; sudo sed -i -e 's/while os.path.exists(X_LOCK_FILE_TEMPLATE % display):/#while os.path.exists(X_LOCK_FILE_TEMPLATE % display):/g' chrome-remote-desktop; sudo sed -i -e 's/display += 1/#display += 1/g' chrome-remote-desktop; sudo sed -i -e 's/self._launch_x_server(x_args)/#self._launch_x_server(x_args)/g' chrome-remote-desktop; sudo sed -i -e 's/self._launch_x_session()/#self._launch_x_session()\n    display = self.get_unused_display_number()\n    self.child_env["DISPLAY"] = ":%d" % display/g' chrome-remote-desktop; ./chrome-remote-desktop --start

sudo apt-get install lxde -y

sudo apt install xfce4-terminal -y
```
VncViewerでコネクトChrome Remote Desktop　を設定する

完成！！！

# Uninstall none use langpack
```
sudo apt-get install localepurge
```
# 日本語をインストールする
```
sudo apt-get -y install `check-language-support -l ja`
```
Sharpe RatioとSortino Ratioについて

#1 目的
Sharpe RatioとSortino Ratioの意味を説明します。

#2 内容

#2-1 Sharpe Ratioについて

株式投資における銘柄選定においては、期待リターンが高く、リスク（日々の変動率,Volatilityのこと)が低い銘柄を選ぶことが一般的によいとされている。リターンとリスクの関係を示したものがSharpe Ratioである。Sharpe Ratioの計算式は下記で定義されます。

```math
Sharpe Ratio =K \biggl({\frac{R_{n}-R_{f}}{σ_{n}}} \biggl)
```

- $R_{p}:$　期待リターンを表します。

ある株式銘柄の価格について、当日の終値を$S_{i}$と表し、前日の終値を$S_{i-1}$と表すときに
変化率$c_{i}$は下記式(1)で定義する。($1≦i≦n$)

```math
c_{i} = \biggl({\frac{S_i}{S_{i-1}}} \biggl) \tag{1}
```

ここで$R_{p}$は$c_{i}$の平均となります。

```math
R_{n} = \frac{1}{n} \sum_{i=1}^{n} c_{i} \tag{2}
```

- $R_{f}:$　無リスクリターンを示します。何もしなくても得られる利益です。（例：配当、利息)

- $σ_{p}:$　Volatilityを表します。

```math
σ_{n} = \frac{1}{n} \sqrt{\sum_{i=1}^{n} (c_{i}-\bar{c})^{2}}      \tag{2}
```

- $K:$　調整定数を表します。

株価データが日足の場合は、$K=\sqrt{256}$, 株価データが週足の場合は、$K=\sqrt{52}$となります。

上記式より、Sharpe Ratioが大きい=高期待リターン & 低リスク(Volatility)となり一般的によい傾向となります。逆にSharpe Ratioが低い場合は、リスク（Volarility)が高いということですので、損をした場合の損金が大きくなることを示しております。<b>一般的に$Sharpe Ratio > 1 $の銘柄を買うことがよいとされております。</b>


<b>数値は大きいほど好ましいです。</b>

[Sharpe Ratioについてさらに詳しく知りたい場合は、こちらのサイトにまとめられております。](https://money-smart-kyoshitsu.com/toshin/sharperatio.html)

下記に日足の株価に対するsharp rationを計算するpythonコードを載せておきます。

```python:test.py
#Sharp Ratioを計算する関数
def shaperatio(DF):
    df = DF.copy()
    df["daily_ret"] = DF["close"].pct_change() #株価終値の前日との変化率を計算する。
    ret_ave=np.mean(df["daily_ret"])
    vol_sp = df["daily_ret"].std() 
    return  math.sqrt(256)*ret_ave/vol_sp
```

#2-2 Sortino Ratioについて

Sharpe RatioのVolatility $σ_{p}$は、株価の上昇方向の変化と下降方向の変化の両方を対象に計算していますが、Sortino Ratioのolatilityは下降方向の変化のみを取り出してVolatilityを算出します。
銘柄をトレードするときに、最終的に損金が出る場合どの程度損金がでるのか予測したい場合にSortino Ratioを使います。

```math
Sortino Ratio = \biggl({\frac{R_{p}-R_{f}}{σ_{dp}}} \biggl)
``` 

$R_{p}:$　期待リターンを表します。[実際の計算方法はこちらをご覧ください。](https://qiita.com/NT1123/items/096dc41c24751934747e)
$R_{f}:$　無リスクリターンを示します。何もしなくても得られる利益です。（例：配当、利息)
$σ_{dp}:$　下降方向のVolatilityを表します。

<b>数値は大きいほど好ましいです。</b>

ある株式銘柄の価格について、任意の日の銘柄価格を$S_{i}$とするとき、前日との変化率$c_{i}$を下記のとおり定義する。

<b> $σ_{dp}$の計算方法 </b>

```math
c_{i} = \biggl({\frac{S_i}{S_{i-1}}} \biggl)　　
```

ここで$c_{i}<0$となるものを集め、$C_{dp}$を定義します。

```math
C_{dp} = \left\{c_{j} | c_{i}<0 \right\}
```

このとき開始日からn営業日後までの株式銘柄のVolatilityを下記数式で定義する。

```math
σ_{dp} = \sqrt{\sum_{c_{j} \in C_{dp}}^{} {(c_{j}-\bar{c})}^{2}}
```
(ただし、$\bar{c}$は$C_{dp}$の要素の平均とする。)
【1日目】イベントトラッキングの設定方法　by WordPress

初めまして、コーダーです。

よく見かけるのは、HTMLタグにonclick属性をインライン記述する`<a href="" onclick="gtag(...)">` ですよね？
今回は、**WordPress**で、**一つのテンプレートファイルで数十ページ生成する**、しかもaタグではなく**buttonタグ**で
クリックイベントがきちんと設定＆取得できるのか？が、
個人的に少し引っかかったので簡単にまとめてみることにしました！


# 今回やりたかった事
「店舗ページ(20ページ)に設置しているアコーディオンのクリック数をそれぞれカウントしたい。」
「アコーディオンは各店舗ごとに複数設置。」
サイトの内容：レンタルオフィスのサイト
ページ：レンタルオフィス20店舗分のページが存在する。
テンプレート：各オフィスはpage-office-detail.phpで作成する。
管理画面：20店舗登録。それぞれに同じカスタムフィールドを用意して、
各オフィスで所有している備品を入力する形式。
備品アコーディオンをpage-office-detail.phpに出力させる。
イベントトラッキング：アコーディオンにトラッキングを仕掛ける。その際に「event_category」と「event_label」の値を動的に取得する。

# 条件
- gtag.js
- WordPress5.4/PHP7.2  
※プラグインはACFやCustom Taxonomy Orderなどのカスタムフィールドやタクソノミー関連のプラグインのみ導入。  
（Analytics関連のプラグインは入れていません。）  
※Analytics管理画面にて「目標」は設定済みです。

# 結果イメージ
HTMLの時はこれでOKですよね！

```
<head>
//gtag.jsなので<head>タグ開始直後に記述する
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'GA_MEASUREMENT_ID');
</script>
</head>

<button onclick="gtag('event', 'click', { 'event_category': `椅子の種類`, 'event_label': `武蔵小杉` });"></button>
```

# 結論
page-office-detail.phpの各アコーディオンに下記をかけば、とりあえずAnalyticsにデータを送ることができます。

```
<?php
$officeName = get_the_title(); //例：武蔵小杉
?>
<button onclick="gtag('event', 'click', { 'event_category': '椅子の種類', 'event_label': <?php echo $officeName; ?> });">椅子の種類のアコーディオン</button>
```

※Analyticsでは武蔵小杉/椅子の種類、赤羽橋/椅子の種類...などのように店舗分のデータをそれぞれ渡すことができます。
もちろんevent_categoryの値を「技術書の種類」にすれば、武蔵小杉/技術書の種類、赤羽橋/技術書の種類...と取得が可能です。

# しかしこのままだとアコーディオンを閉じた時もカウントしてしまう。。。
今回の目的は、
「閲覧者はアコーディオンをクリックするのか？
（きちんと中身を見てもらえているのか。クリック数が少なければ別の見せ方を検討したい）」
でしたので、少し工夫をします。

# 修正後

page-office-detail.php
インラインで書くのをやめます。

```
<div class="js-toggle-wrapper" aria-expanded="false">
　<button type="button" class="js-analytics-event" data-officeName="<?php echo $officeName; ?>" data-category="椅子の種類">椅子の種類のアコーディオン</button>
　<div>
　　アコーディオンの中身
　</div>
</div>
```
 office.js

```
$('.js-analytics-event').on('click', (event) => {
  let $current = $(event.currentTarget);
  accrodion($current);//処理内容は省いていますが、クリックしたら親要素のdivの「aria-expanded」がtrueになって
コンテンツが開く処理をしています。

  if ($current.parent('.js-toggle-wrapper').attr('aria-expanded') === 'true') {
      let cate = $current.attr('data-category');
      let officeName = $current.attr('data-officeName');
      gtag('event', 'click', { 'event_category': `${cate}`, 'event_label': `${officeName}` });
    }
});
```

これで「アコーディオンを開いた時」のみカウントを取得することができるようになりました。
ちなみに、私の場合はカウントの反映に2時間ほどかかったような気がします。。

**その他**
スマホの場合 `click`イベントや `onclick` だとイベントが取得できない。
というケースを聞きますが、
試しにインラインでonclickを書いた場合・今回の方法両方でAnalyticsにデータは送ることができていました。
（個人的な検証結果）

閲覧ありがとうございました。
Docker + Rails で Bundler v2.X を使う


Gemfile.lock の `BUNDLED WITH` と Docker イメージ内の bundler バージョンに乖離があるとエラーになる。

https://qiita.com/tanakaworld/items/e15ff9dbdd4b628378c2


次の通り対策ができる。

1. イメージ内の gem をアップデート `gem update --system`
1. 任意のバージョンの bundler をインストール `gem install bundler -v <バージョン>`

例:

```docker:Dockerfile
FROM ruby:2.6.2

ENV APP_HOME /app
WORKDIR $APP_HOME

COPY Gemfile $APP_HOME/Gemfile
COPY Gemfile.lock $APP_HOME/Gemfile.lock

ENV BUNDLER_VERSION 2.1.0
RUN gem update --system \
    && gem install bundler -v $BUNDLER_VERSION \
    && bundle install -j 4

COPY . $APP_HOME
```
Node.jsのコードを定期実行する（crontabを利用）

# これまでのおさらい
- [Raspberry piにNode.jsをインストールする](https://qiita.com/takashi53/items/69d4395c70d76ddbb0ab)
- [Node.jsでrequestモジュールを使ってHTTPリクエストを実行する](https://qiita.com/takashi53/items/76c5987b73b76ba9ea96)
-  [Node.jsでIFTTTのWebhooksを使う（requestモジュール利用）](https://qiita.com/takashi53/items/7f1679c52edd741c3ed8)
-  [Node.jsからobnizでBME280(気温、湿度、気圧)センサーを動かす](https://qiita.com/takashi53/items/49ce6686df961df9001e)

# 今回のお話
- node.jsをcrontabで定期実行する。

前回書いたコードは、「BME280センサーの値を読み取り、Google スプレッドシートに書き込む」というものでした。
これは一回だけ実行する作りになっています。
このままでは、毎回手動で実行する必要があります。

```javascript
// デバイスに接続
const Obniz = require("obniz"); // デバイスに接続
var obniz = new Obniz("****-****"); //Obnizの番号を指定
var webclient = require("request");


obniz.onconnect = async function () {
  const ifttt_event = "Record"; //イベント名
  const ifttt_secret_key = "あなたのキーを書く"; //キー
  const IFTTT_URL_GoogleSheets = 'https://maker.ifttt.com/trigger/' + ifttt_event + '/with/key/' + ifttt_secret_key;

  const bme280 = obniz.wired("BME280", {vio:0, vcore:1, gnd:2, csb:3, sdi: 4, sck: 5, sdo:6 });
  await bme280.applyCalibration();
  await bme280.setIIRStrength(1);

  val = await bme280.getAllWait();


  //obniz画面表示
  obniz.display.clear();
  obniz.display.print("temperature:" + val.temperature.toFixed(1)) //気温
  obniz.display.print("humidity:" + val.humidity.toFixed(1)) //湿度
  obniz.display.print("pressure:" + val.pressure.toFixed(1)) //気圧



  //送信データ作成
  const p1 = val.temperature.toFixed(1);
  const p2 = val.humidity.toFixed(1);
  const p3 = val.pressure.toFixed(1);

  //IFTTTリクエスト
  webclient.post({
    url: IFTTT_URL_GoogleSheets,
    headers: {
    "content-type": "application/json"
    },
    body: JSON.stringify({'value1': p1, 'value2':p2, 'value3':p3})
    }, function (error, response, body){
    console.log(body);
  });

  obniz.close();//Obniz切断
}
```
# Node.jsのコードを定期実行する方法

- crontabで定期実行する方法 ⇒ 参考：[crontabの書き方](https://www.server-memo.net/tips/crontab.html)
- node-cronを使う方法 ⇒ 参考：[Node Cron](https://www.npmjs.com/package/node-cron)

今回は、crontabで試してみます。


# crontabの設定

crontabでは、コマンドのフルパスが必要です。

whichコマンドで、nodeコマンドのフルパスを調べます。
`/home/pi/.nodebrew/current/bin/node` の部分を使います。
`~/myapp/BME280.js` の部分が実行するファイルです。

```shell-session
pi@raspberrypi:~/myapp $ which node
/home/pi/.nodebrew/current/bin/node
```

crontabは、-eオプションが編集です。

```shell-session
pi@raspberrypi:~/myapp $ crontab -e
```

先程調べたnodeのフルパスを指定し、実行するファイルを指定します。
以下の設定を登録しました。
`*/10` の部分が、10分周期で実行の意味となります。
参考：[crontabの書き方](https://www.server-memo.net/tips/crontab.html)

```shell-session
*/10 * * * * /home/pi/.nodebrew/current/bin/node ~/myapp/BME280.js
```

-lオプションがリスト表示です。

```shell-session
pi@raspberrypi:~/myapp $ crontab -l

（略）

*/10 * * * * /home/pi/.nodebrew/current/bin/node ~/myapp/BME280.js
```

# 実行結果

Google スプレッドシートのデータを見てみます。

crontabで実行されたコードによって、10分周期に気温、湿度、気圧が記録されています。

![10minits.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299557/53386676-1e34-fd19-a547-d721ee4e05c7.png)
Docker ディスク容量を圧迫し、docker-compose buildできない時の対処法

# No space left on deviceエラー
docker-compose buildコマンド実行時、

```
OSError: [Errno 28] No space left on device
```

というエラーが発生し、ビルドができなくなってしまいました。

この問題を解決してくれたコマンドは以下になります。

```
docker system prune
```

これは、不要なリソースを全て削除してくれるコマンドです。
自動で使われていないと思われるリソースを削除します。
ローカル開発環境であればこの方法が一番簡単なようです。
[docker system prune | Docker Documentation](https://docs.docker.com/engine/reference/commandline/system_prune/)

[その他、docker環境を掃除してくれるコマンド]
(https://qiita.com/tmiki/items/687f953d3fd649df816e)
ラズパイにAirPodsをつなげる

基本的にはこちらの手順で進める
https://qiita.com/homelan/items/e82b919638d3c458d2ec

が、そのままではscan onした時にAirPodsがリストに表示されない。


/etc/bluetooth/main.conf を編集し下記設定を追加

```
ControllerMode = bredr
```

再起動

```
sudo /etc/init.d/bluetooth restart
```

以上でAirPodsがリストに表示されるようになる。


---

参考
https://askubuntu.com/questions/922860/pairing-apple-airpods-as-headset/1063582#1063582
間違えやすいpathの見極め方

# pathの見極め方
path名を探す時、普段使うのはターミナルでrails routesして、

                   Prefix Verb   URI Pattern                                                                              Controller#Action
        new_admin_session GET    /admins/sign_in(.:format)                                                                admins/sessions#new
            admin_session POST   /admins/sign_in(.:format)                                                                admins/sessions#create
    destroy_admin_session DELETE /admins/sign_out(.:format)                                                               admins/sessions#destroy

prefixからpath名を探す。

# path名がない
しかし、このようにpath名が書かれていない場合がある。

                   Prefix Verb   URI Pattern                                                                              
             edit_product GET    /products/:id/edit(.:format)                                                             products#edit
                  product GET    /products/:id(.:format)                                                                  products#show
                          PATCH  /products/:id(.:format)                                                                  products#update
                          PUT    /products/:id(.:format)                                                                  products#update
                          DELETE /products/:id(.:format)                                                                  products#destroy
                     cart GET    /carts/:id(.:format)                                                                     carts#show

products#destroy、products#updateのpath名が見つからない。この場合、path名はproduct_pathになる。prefixでpath名が出てくるまで上に遡っていけばいい。
Docker で PHP 8.0.0 Alpha 1 環境構築

# 概要

2020年6月25日に [PHP 8.0.0 Alpha 1](https://www.php.net/archive/2020.php#2020-06-25-1) がリリースされました。
[Docker イメージ](https://hub.docker.com/_/php) も公開されていたので最低限の環境を構築してみます。

# 構成

```
$ tree
.
├── docker-compose.yml
├── nginx
│   └── default.conf
└── public
    └── index.php
```

# ファイル

```yml:docker-compose.yml
version: "3.8"

services:
  nginx:
    image: nginx
    ports:
    - "80:80"
    volumes:
    - ./public:/var/www/html
    - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
  php:
    image: php:8.0.0alpha1-fpm
    volumes:
    - ./public:/var/www/html
```

```php:public/index.php
<?php
phpinfo();
```

```conf:nginx/default.conf
server {
    index index.php index.html;
    root /var/www/html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri = 404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}
```

コードは [SnowCait/php8-docker-compose-example](https://github.com/SnowCait/php8-docker-compose-example) にも置いてあります。
さくっと試したい方は `git clone` して使ってください。

# 起動

```bash
docker-compose up -d
```

# ブラウザでアクセスする

http://localhost/ にアクセスすると `phpinfo()` の内容が表示されます。
ポートを変えたい場合は `"80:80"` の部分を `"8080:80"` にすると http://localhost:8080/ でアクセスできます。
![php8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455401/a502c0c8-866f-3b6c-c12b-83fed32ebc7b.png)


# コマンドラインから実行する

```bash
docker-compose exec php php -v
PHP 8.0.0alpha1 (cli) (built: Jun 26 2020 19:56:42) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.0-dev, Copyright (c) Zend Technologies
```

コマンドラインだけあれば良い方は nginx の設定は不要です。

# 停止

```bash
docker-compose down
```

# 拡張

実際にアプリを動かそうとすると今回紹介したコードだけでは足りないと思います。
データーベースや KVS が必要だったり Composer が必要だったり public/ 以外のディレクトリが必要だったり。
Docker Compose であればコンテナや設定を追加するだけなので色々と拡張しやすいです。

Composer を使いたい方は [環境を汚さずに Composer を使いたい - Qiita](https://qiita.com/SnowCait/items/e70ec1a7d365b490c2b2) に書いていますのでもし興味があれば。
docker-compose.yml に 4 ～ 5 行追加するだけで使えるようになります。
ほとんど意味のないコピペ記事はどこから来ているのか

active_hash に関する記事は少ない。
https://kossy-web-engineer.hatenablog.com/entry/2019/01/08/205702
で知って少し調べてみた。

Qiita では
https://qiita.com/haruya_hamasaki/items/3cd0b780fb1f076a9bb8
https://qiita.com/Toman1223/items/8633142312bfa886d50b
という記事が見つかったが、ほとんど追加の内容がない。

`self.data` のインデントは同じ…。まぁ、同じデータを機械整形したら、同じになる気もする。

このような記事を投稿するインセンティブは誰にどのようにあるのだろうか…。

質（しつ）が悪く、質（たち）が悪い記事は、大抵参考文献とかは書いていない。先人から学び、自分も何かを残すという、根本がなっていない。

`[2] pry(main)` と数字が入るのと `pry(main)` を併用しているのって、どこかで自分が書いた部分とコピペが混じっているからではないかと勘繰ってしまう。
Pythonでピラミッドを表示させる

#はじめに
Pythonを学習してみようと思い、参考書をもとに10時間くらい勉強しました。
そのアウトプットとして、Pythonでピラミッドを作成してみました。

#環境
- Windows10
- PyCharm 2020.1.2
- Python3.8

#実行結果
```
> python pyramid.py
Please input number => 6
     *
    ***
   *****
  *******
 *********
***********
```

#コード
```pyramid.py
num=int(input('Please input number => '))
spc=' '*max(0,num-1)

for i in range(1,2*num,2):
    ast='*'*max(1,i)
    out=spc+ast
    print(out)
    spc=spc.replace(' ','',1)
```

##コードの解説
input関数を使用して、num変数にキーボードからの入力した値を代入します。
このとき、取得した値はstr型になるので、このあとのためにint型にしておきます。

spc変数には、空白を代入していきます。

for文を使ってピラミッドを表示していきます。
range関数で1から2ずつ加算させていきます。これによって、*が1つ,3つ,5つ…と増えていきます。
ループの最後に空白を1ずつ取り除いてあげます。

（try、expectを使って数字以外が入力したときの対処も入れても良いかもしれません。）

#まとめ
このプログラムを作成することで

- input関数
- int()
- range関数
- max関数
- for文
- replaceメソッド
- Pythonのお作法

が理解出来ました。
MySQLでINFORMATION_SCHEMA からバッファプールのインデックスのページ数とデータサイズを取得する

タイトルそのまま、


参照は下記です。
行方不明にならないようにメモ書きする

データサイズB表示

```sql
SELECT
    INDEX_NAME,
    COUNT(*) AS Pages,
    ROUND(SUM(IF(COMPRESSED_SIZE = 0,
    @@GLOBAL.innodb_page_size,
    COMPRESSED_SIZE))) AS 'Total Data (B)' 
FROM
    INFORMATION_SCHEMA.INNODB_BUFFER_PAGE 
WHERE
    INDEX_NAME='emp_no' 
    AND TABLE_NAME = '`{スキーマ名}`.`{テーブル名}`';
```

データサイズMB表示

```sql
SELECT
    INDEX_NAME,
    COUNT(*) AS Pages,
    ROUND(SUM(IF(COMPRESSED_SIZE = 0,
    @@GLOBAL.innodb_page_size,
    COMPRESSED_SIZE))) AS 'Total Data (B)' 
FROM
    INFORMATION_SCHEMA.INNODB_BUFFER_PAGE 
WHERE
    INDEX_NAME='emp_no' 
    AND TABLE_NAME = '`{スキーマ名}`.`{テーブル名}`';
```

参照
https://dev.mysql.com/doc/refman/5.6/ja/innodb-information-schema-buffer-pool-tables.html

INFORMATION_SCHEMA.INNODB_BUFFER_PAGEについて
https://dev.mysql.com/doc/refman/5.6/ja/innodb-buffer-page-table.html
ステップ関数

```C#
private void button_Click(object sender, EventArgs e)
{
    var x = np_arange(-5.0, 5.0, 0.1);
    var y = step_function(x);

    var plt = new Chart();
    plt_plot(plt, x, y);
    plt_xlim(plt, -6.0, 6.0);
    plt_ylim(plt, -0.1, 1.1);
    plt_show(plt);
}

private U[] np_arange<T, U>(T start, T end, U step) where T : struct where U : struct
{
    var start_ = (dynamic)start;
    var end_ = (dynamic)end;
    var step_ = (dynamic)step;

    return Enumerable.Range((int)(start_ / step_), (int)((end_ - start_) / step_)).Select(x => (U)(x * step_)).ToArray();
}

private int[] step_function<T>(T[] x) where T : struct
{
    return x.Select(n => ((dynamic)n > 0) ? 1 : 0).ToArray();
}

private void plt_plot<T, U>(Chart plt, T[] x, U[] y) where T : struct where U : struct
{
    plt.Size = new System.Drawing.Size(500, 350);

    plt.ChartAreas.Add("step");
    plt.Legends.Add("step");
    plt.Series.Add("step");

    plt.ChartAreas["step"].AxisX.MajorGrid.Enabled = false;
    plt.ChartAreas["step"].AxisX.LabelStyle.Format = "0.0";
    plt.ChartAreas["step"].AxisX.Minimum = (dynamic)x.First();
    plt.ChartAreas["step"].AxisX.Maximum = (dynamic)x.Last();
    plt.ChartAreas["step"].AxisY.MajorGrid.Enabled = false;
    plt.ChartAreas["step"].AxisY.LabelStyle.Format = "0.0";
    plt.ChartAreas["step"].AxisY.Minimum = (dynamic)y.First();
    plt.ChartAreas["step"].AxisY.Maximum = (dynamic)y.Last();

    plt.Series["step"].ChartType = SeriesChartType.Line;

    foreach (var n in x.Zip(y, Tuple.Create))
    {
        plt.Series["step"].Points.AddXY(n.Item1, n.Item2);
    }
}

private void plt_xlim(Chart plt, double minimum, double maximum)
{
    plt.ChartAreas["step"].AxisX.IntervalOffset = 0.0;
    plt.ChartAreas["step"].AxisX.Minimum = minimum;
    plt.ChartAreas["step"].AxisX.Maximum = maximum;
    plt.ChartAreas["step"].AxisX.Interval = 2;
}

private void plt_ylim(Chart plt, double minimum, double maximum)
{
    plt.ChartAreas["step"].AxisY.IntervalOffset = 0.1;
    plt.ChartAreas["step"].AxisY.Minimum = minimum;
    plt.ChartAreas["step"].AxisY.Maximum = maximum;
    plt.ChartAreas["step"].AxisY.Interval = 0.2;
}

private void plt_show(Chart plt)
{
    Bitmap bitmap = new Bitmap(plt.Width, plt.Height);
    plt.DrawToBitmap(bitmap, new Rectangle(System.Drawing.Point.Empty, plt.Size));
    Cv2.ImShow("plot", BitmapConverter.ToMat(bitmap));
}
```
![000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662099/753ba43d-b774-841f-feb5-58fa87364429.png)

参考文献:
斎藤康毅(2016)『ゼロから作るDeep Learning』オライリー・ジャパン
【Circle CI】"You must use Bundler 2 or greater with this lockfile" エラーとCircle CIのbundlerアップデート

# 0. エラーの発生原因

> bundler 2.X 系で作成された Gemfile.lock ファイルが CircleCI 上で bundle install できないなどが発生する件に対応する．

らしい。
自分の場合、既存のプロジェクトにGemを追加した際、bundlerのバージョンを 1.X 系から 2.X 系に上げたことが原因だった。

## 参考

- ["You must use Bundler 2 or greater with this lockfile" に対応する](https://qiita.com/tanakaworld/items/e15ff9dbdd4b628378c2)

# 1. エラーの対処方法

これも先の記事より引用になるが、
① bundler を以前のバージョンに戻してGemfile.lockを再作成する
あるいは
② Circle CIで bundler 2.X系を使用できるようにする

の二通りの対処方法がある。
今回はプロジェクトのバージョンをできるだけ最新に保っておきたいという点で、せっかくの機会と思い ② の対処方法を採る。


# 2. 修正したコード（.circleci/config.yml）

```config.yml
- test:
# ...
  - restore_cache:
      keys:
      - v1-dep-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
      - v1-dep-{{ .Branch }}-
      - v1-dep-
    - run:
        name: update bundler
        command: |
          gem update --system
          gem install bundler
    - run:
        name: install gem dependencies
        command: |
          bundle config set clean 'true'
          bundle config set path 'vendor/bundle'
          bundle install --jobs=4 --retry=3
    - save_cache:
        key: v1-dep-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
        paths:
        - vendor/bundle
```

別件ではあるが、 `restore_cache` でGemfile.lockのキャッシュも行っている。これによりCircle CIのテストの実行時間を短縮できる。
↑はベストプラクティスっぽいのでやった方が良さそう。


```yml
  - run:
      name: update bundler
      command: |
        gem update --system
        gem install bundler
```

この部分で Circle CI上で bundler のアップデートを行っている。

## 注意点

ローカルあるいはCI上で `bunldr update` を行うと、Gemfile.lockに変更が起きてしまうので、チーム開発時は（bundler updateを行わないように）注意。

## 参考


- ["You must use Bundler 2 or greater with this lockfile" に対応する](https://qiita.com/tanakaworld/items/e15ff9dbdd4b628378c2)
- [Circle CI 2.0を使ってGemfileを新鮮に保つ
](https://tech.recruit-mp.co.jp/server-side/fresh-gemfile-with-circle-ci/)
- [CircleCIで「You must use Bundler 2 or greater with this lockfile.」と出た時の対処法](https://qiita.com/tynmarket/items/f723494c76894cbb596d)
- [bundle install には --clean を指定する (特に Circle CI では)
](https://blog.yuyat.jp/post/bundle-install-clean/)
- [依存関係のキャッシュ - Circle CI Documentation](https://circleci.com/docs/ja/2.0/caching/)
製薬企業研究者がPythonのユニットテストについてまとめてみた

# はじめに

ここでは、`unittest`を用いたPythonのテストについて解説していきます。


# テストの基本

テストは、対処となる関数に対応させるように、以下のように書きます。

```python
import unittest


def average(num1, num2):
    return (num1 + num2) / 2


class AverageTests(unittest.TestCase):
    
    def test_average(self):
        actual = average(1, 2)
        expected = 1.5
        self.assertEqual(actual, expected)
```

`average`という関数に対して、`AverageTests`というclassが用意され、このクラス内のメソッドとして、`test_average`が書かれています。
このように、テスト用の関数は`test_テスト対象の関数名`とすることが多いです。


# `assert`メソッド

上の例のように、テストの判定時には`assert`メソッドが使われます。
よく使われる`assert`メソッドには、以下のようなものがあります。

- assertEqual(actual, expected)：actualとexpectedが等しいかどうか
- assertNotEqual(actual, expected)：actualとexpectedが等しくないかどうか
- assertTrue(bool)：boolが`True`であるかどうか
- assertFalse(bool)：boolが`False`であるかどうか
- assertGreater(num1, num2)：num1がnum2より大きいかどうか
- assertGreaterEqual(num1, num2)：num1がnum2以上かどうか
- assertLess(num1, num2)：num1がnum2より小さいかどうか
- assertLessEqual(num1, num2)：num1がnum2以下かどうか
- assertIn(value, values)：valueがvaluesに含まれるかどうか


# まとめ

ここでは、`unittest`を用いたPythonのテストの書き方について解説しました。
テストを味方につけて、開発効率を上げていきたいところです。
[コード公開]Flutter for webを使いたくて作ったゲームが全く伸びなかったので、情報共有ついでに供養する

# はじめに
`flutter for web`を使って何か作りたいなと思い考えていたところ、『本当に無理ゲーな神経衰弱』を思いつきました。

「全く伸びずでした」で終わりでもいいかなと思ったのですが、Flutter for webを使ってみた記事がそもそもあまりなかったため、せめて情報共有をしようと思いこの記事を書くことにしました。

コードも公開してます(BSD-3)。
https://github.com/yasudadesu/kuso_sinkei

# どんなアプリか
**圧倒的にクリアが難しい神経衰弱です。**

ルールは以下

- 基本ルールは神経衰弱と全く同じ
- 毎回カードの絵柄は自動的に生成される
- 難易度は４段階

ゲーム中の画像は以下のような感じ。
![スクリーンショット 2020-06-27 8.59.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190157/2ab16634-17b5-16ae-d7eb-050ca9a50711.png)

![スクリーンショット 2020-06-27 8.47.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190157/2da5d13b-0c72-c6d2-58d8-791f2604e0bd.png)

どういうこと？と思う方も多いと思いますのでコードを見る前に一度プレイしてみると良いかと思います。

こちらからプレイができます↓
https://muzu-sinkei.firebaseapp.com/#/

# コードを参考する上で注意して欲しいこと
ある程度コード内でコメントなどもしていますが、その他にも色々注意点があるので記しておきます。

### 1. 状態管理はProvider
もはや非常に有名なパッケージであるProviderを使って状態管理をしています。
`notifyListers`を呼ぶべき箇所とそうでない箇所の参考などになるかと思います。

### 2. ランダムの方法
最初は`CustomPainter`の内部で`final rand = Random()`を作って実装をしようとしていたのですが、そのように実装するとリビルドが起こるたびに関数が再実行されてしまいます。

ですので、あらかじめ`ChangeNotifier`クラス内で非常に大きなランダムの配列を作り、その配列の中から初期位置を決めるようにして、Widgetのリビルドと処理を切り離しました。

### 3. firebase関連のファイルは入ってません
そのまんまです。

https://flutter.dev/docs/development/data-and-backend/firebase
いくつかのサイトでfirebase x Flutter for webの記事は上がっていますが、個人的には上のリンクの公式ページからリンクされている以下のページを見ることをお勧めします。

https://medium.com/flutter/must-try-use-firebase-to-host-your-flutter-app-on-the-web-852ee533a469


### 4. リファクタなどはしていない
リファクタなどの作業やディレクトリの整理などはしておりません。


# さいごに

ベッドの上で思いついた瞬間は非常に面白いと思って(個人開発あるある)飛び起きて突貫工事で作ったのですが、その後にTwitterでつぶやいたところ全くインプレッションが伸びず、恥ずかしすぎてツイ消ししました。

個人的には非常に面白いゲームを作れたなと深夜テンションながら思っており、全く伸びなかったのが悔しかったため、一人でも多くの方にプレイしてもらえると嬉しいなと思い本記事を書きました。

よければプレイしてみてください！
また、もっといいプラクティスなどがあればご共有いただけますと幸いです。
C言語のunsigned char型が想像以上に沼だった話

#はじめに
C言語学習者にとっては誰もが一度は疑問に思う、**charとunsigned charとsigned charの使い分けがよくわからないよ！**という悩み。

ことの発端は、memcpyやmemcmp, memsetなどの関数のなかでは、汎用ポインタ(void*)型として渡された引数をunsigned char*型にコピーして操作しているらしい、ということに気づいたところから始まる。

```C:memset.c
void *memset(void *dst, int val, size_t len)
{
    unsigned char *ptr = dst; //unsigned char*型を使用している！
    while (len-- > 0)
        *ptr++ = val;
    return dst;
}
```
※memset : dstに対してlenバイト分だけvalで埋めるための関数。

このときに、「え？なんでunsigned char型なの？char型じゃダメなの？」と疑問に思ったので、いろいろ調べてみた。

#char型には3種類あり、すべて別物
まず、そもそも```char```と```unsigned char```と```signed char```はすべて別物だ。
これこそが初学者が最も陥りやすい第一ポイントではないかと思う。

> 処理系は、char を、signed char または unsigned char のいずれかと同じ値の範囲、同じ表現形式、同じ動作をするものとして定義しなければならない。char はどちらに定義されたとしても、**signed char とも unsigned char とも異なる型であり、これらの型と互換性はない。**
(引用：[JPCERT GC](https://www.jpcert.or.jp/sc-rules/c-str04-c.html))

つまり、charをsinged- かunsigned- とするかは標準として未規定であり、これは処理系（コンパイラ）が定義するように任されている。そのどちらに定義されたとしても、この3種類の型に互換性はないということらしい。

だから、ネットでたまに「char型の範囲は-128〜127だ」と断言しているのを見かけるがそれは誤りである。
この辺は```int```と仕様が異なるところなので注意したい。

|データ型名|バイト|その他の名前|値の範囲|
|:-----|----:|---------:|------:|
|int|2または4|**signed**|-2,147,483,648 ～ 2,147,483,64|
|unsigned int|2または4|unsigned|0 ～ 4,294,967,295|
|**char**|1|-|**0 〜 255 / -128 〜 127**|
|**signed char**|1|-|-128 〜 127|
|**unsigned char**|1|-|0 〜 255|
参考：[データ型の範囲 - Microsoft Docs](https://docs.microsoft.com/ja-jp/cpp/cpp/data-type-ranges?view=vs-2019)


#3種類のcharの基本的な使い分け
結論からいえば、文字集合としての単純な文字データを扱う場合にはcharを、数値として扱う場合にはsigned charかunsigned charを用いるのが基本的な使い分けである。

特に、mem-系の関数のように、操作対象が汎用型(void *など)で、その対象すべてのビットにアクセスしたいような場合にはunsigned charが積極的に使われている（後述）。

## 1. 文字集合を扱う場合
文字列処理系の標準ライブラリの仕様を考慮し、文字データを単純に表す際には**char**を使用するのが好ましい。

## 2. charを数値として扱う場合
この場合はsingned charかunsigned charを使う。
いずれにせよ値の範囲に収まるように注意せねばならず、特にsigned charの範囲は-128 ~ 127と狭いのでいまいち使いどきがピンとこない。

こういうときこそsigned charの出番だよ！という良い事例ないかな...

#unsigned charの特徴
冒頭で、mem-系の関数のなかでは汎用ポインタ(void*)型として渡された引数をunsigned char*型にコピーして操作しているのなんで？という疑問を紹介した。
詳しく調べてみると、どうやらunsigned charの標準仕様となっている表記法に関係があるようだ。

> C標準[ISO/IEC 9899:2011]6.2.6.
>>unsigned char型の[...]オブジェクトに格納される値は純2進表記法で表現される。
...
(純2進表記法とは) バイナリの桁 0 および 1 を使用する整数の位置表現で、連続するビットで表現される値は加算方式をとり、1 から始まり、最上位ビット以外は連続する 2 の整数乗で乗算される。

だから、汎用ポインタ(void *)型などで渡されたオブジェクトの非ビットフィールドに対して、その表現を1バイトずつ検査することが可能になる。

...文系には頭がなかなか追いつかないが、unsigned char型のオブジェクトはパディングビットを持たないことがあるので、mem-系関数のようにメモリ領域そのものを扱うような関数で、操作対象の非ビットフィールドも含めたすべてのビットにアクセスしたいときにはunsigned char型の表記法が最も適する、ということのようだ。

memcpyやmemcmpなどの関数のなかで、void *型で渡される引数をunsigned char型にコピーして操作するのはそのためである。

　
　
unsigned charを完璧に理解するにはまだ道のりが長そう。。
ラズパイでcronがうまく設定できないときのTips

# 概要
ラズパイを買って、なにかしら定期処理させようとしたときにちょっとハマった。
そもそもcron触ったことない場合のcronの注意と
ラズパイだとコマンドちょっと違うよっていう話。

僕と同レベルの初学者向けに書いてます。

# ラズパイ編

## cronの起動、再起動

```
/etc/init.d/cron start
/etc/init.d/cron restart
```
↓は検索するとよく出てくるけど

```
service crond restart
```
debian(ラズパイのOS)だとそんなものないよってなるので注意。

## ログ

### 設定

```/etc/rsyslog.conf(抜粋)
###############
#### RULES ####
###############

#
# First some standard log files.  Log by facility.
#
auth,authpriv.*         /var/log/auth.log
*.*;auth,authpriv.none      -/var/log/syslog
#cron.*             /var/log/cron.log
daemon.*            -/var/log/daemon.log
kern.*              -/var/log/kern.log
lpr.*               -/var/log/lpr.log
mail.*              -/var/log/mail.log
user.*              -/var/log/user.log
```

以下の記述がデフォルトでは、
コメントアウトされてるので、解除。

```
#cron.*             /var/log/cron.log
↓
cron.*             /var/log/cron.log
```

### 確認方法
当たり前だけど、これでいけます。

```
cat /var/log/cron.log
```

# cron
## 設定方法
以下のコマンドでエディターが開きます。
色々書いてるけど、一番下に実行したいコマンド書いたら実行されます。

```
crontab -e
```

## ※PHPを実行したいけどエラーが出たとき
### フルパスで書くのが重要

例えば、
`/var/www/html/cron.php`
を実行したいとき。

このファイル内でなにかしらインクルードしてる場合は、

```cron.php
include("./hogehoge.php")
```
↑こう書くとエラーが出る。

```cron.log
(CRON) error (grandchild #***** failed with exit status 255)
```
なのでフルパスで書いてあげる。

```cron.php
include("/var/www/html/hogehoge.php")
```




また、実行したいファイルでなく、PHPの場所も書いたほうがいい。
僕は書いたら動きました。

```
* * * * * /usr/bin/php /var/www/html/cron.php
```

# 終わりに
間違ってたら指摘ください
一対多モデルでのdjangoデンプレートが表示されない時の確認した方がいい箇所

一対多モデルを制作してhtmlに出力する時につまったところを解説。


今回はモデルに値を渡すことができたけど出力ができない時、確認した方がいいところを記載します。

```html
<div>
{% for comment post.comments.all %}
{{ comment.user }}
{{ comment.text }}
{% endfor %}
</div>
```
今回はこのようなhtmlを出力して見たいと思います。

確認するべき点は三箇所
1.templateに出力するオブジェクトの書き方
2.related_nameをちゃんと定義しているか
3.viewsの設定


###①templateに出力するオブジェクトの書き方

```html
<div>
{% for comment post.comments.all %}
{{ comment.user }}
{{ comment.text }}
{% endfor %}
</div>
```

の```post.comments.all ```

コイツの具体的な書き方がわからなかったので、コイツの説明


post は変数でviewで渡した時の返り値 

```views.py
def Post(request):
    form = PostChatMessage()
    if request.method == 'POST':
       form = PostChatMessage(request.POST, request.FILES)
       if form.is_valid():
           post = form.save(commit=False)
           post.nickname = request.user
           post.save()
           return redirect('chat')
       else:
           form = PostChatMessage()
           return render(request, 'ChatSend.html', コイツ→{'error': 'Please type message'})
    return render(request, 'ChatSend.html', コイツ→{'form':form})
```

commnets はmodels.pyで定義したrelated_name

```model.py

---略---
def Comment(models.Model):
    post = models.ForeignKey(ChatMessage, on_delete=models.CASCADE, related_name='comments')
--------
```

です。
お間違えのないように

###②related_nameをちゃんと定義しているか

related_nameが定義されていなくても
model名_setで同等の使い方ができます。
又related_nameが定義されていても子model名とおんなじ名前だと動かないみたいです。


###③viewsの設定

自分はここで詰まりました。

######正

```views.py
def ShowComments(request, pk):
    post = get_object_or_404(ChatMessage, pk=pk)
    return render(request, 'Comments.html', {'post':post}) 
```

######誤

```views.py
def ShowComments(request):
    post = Comment.object.all()
    return render(request, 'Comments.html', {'post':post}) 
```

下でも表示はされますが、一対多の関連付けが表示されないので子モデルが全て表示されます。
nuxt typescriptをvercel(now)にデプロイしたときにハマった３つのエラーと解決策

#Error: Can not read tsconfig.json from /vercel/xxxxxxxx

tsconfig.jsonが読み込めませんというエラー。
https://github.com/nuxt/now-builder/issues/245 を見て解決。
tsconfig.jsonが間違ってるから、typescriptを使う設定にしたnuxtを新規作成して、tsconfig.jsonをもらってこいとのこと。
で、どこが間違ってたかと言うと・・・

```json:tsconfig.json修正前
    "types": [
      "@types/node",
      "@nuxt/types",
    ]
```

```json:tsconfig.json修正後
    "types": [
      "@types/node",
      "@nuxt/types"
    ]
```

僕の場合、最後の「,」が多かったのでvercelでは読み込んでくれなかった。vscodeでエラーにならなかったので気が付かなかった。
issueの人は最初にコメントが入ってたらしい。


#Property 'component' does not exist on type 'RouteConfig'

https://github.com/nuxt/nuxt.js/issues/7502
nuxtと@nuxt/typesがかみ合ってないエラー？
最新のnuxt（執筆時点では2.13.2）にアップデートすれば修正されている。
僕はnpm updateで直った。

#Error: The Serverless Function "index" is 52.82mb which exceeds the maximum size limit of 50mb.

Functionは50MBまでだけど超えてるからデプロイできないよというエラー。
なんでもかんでもpackage.jsonのdependenciesに入れてるとこうなる。

https://github.com/nuxt/now-builder/issues/30
これとか見ながら開発環境でだけ必要なやつはdevDependenciesに移動した。
sass、sass-loader、node-sassをdependenciesからdevDependenciesに移動したらそこそこ軽くなった。
あと不要なパッケージもいくつかあったので削除。

```json:pakage.json修正前
  "dependencies": {
    ...
    "sass": "^1.26.9",
    "sass-loader": "^8.0.0",
    "node-sass": "^4.14.1",
  },
  "devDependencies": {
    ...
  }
```

```json:pakage.json修正後
  "dependencies": {
    ...
  },
  "devDependencies": {
    ...
    "sass": "^1.26.9",
    "sass-loader": "^8.0.0",
    "node-sass": "^4.14.1",
  }
```

staticフォルダにめっちゃ重い画像とか入ってても上限超えてしまうので、そちらも確認してみてください。

あんまり機能作ってないのにもう上限の50MBにいってしまって辛い。それとも僕の設定がなにかおかしいのだろうか・・・
意外といらないパッケージもありそうだからそのうちダイエットしよう。
【初心者でもわかる】いちょう切り。part1（4つの要素を2×2に並べる方法-flexbox編-）

# どうも、7noteです。今回はflexboxを使っていちょう切り、やって行こうと思います。

どうも7noteです。
この記事は以下へ引っ越しました。

https://naruweb.com/coding/orange01/