Rubyと筋肉とギターとわたし

筋トレが仕事です

【Rails】unicornの謎エラー

どうもてぃです。

unicornの設定でかなり手間取りました。

環境

起きたこと

とある記事を参考にunicornを設定し、ローカルでbundle exec rails unicorn:startしたところ以下のエラーでハマりました。

I, [2019-01-15T16:48:10.401826 #1790]  INFO -- : Refreshing Gem list
I, [2019-01-15T16:48:11.349098 #1790]  INFO -- : unlinking existing socket=/home/user/project/tmp/unicorn.sock
I, [2019-01-15T16:48:11.349216 #1790]  INFO -- : listening on addr=/home/user/project/tmp/unicorn.sock fd=14
E, [2019-01-15T16:48:11.349315 #1790] ERROR -- : unsupported signal SIGTEAM (ArgumentError)
/home/user/project/config/unicorn.rb:11:in `trap'
/home/user/project/config/unicorn.rb:11:in `block in reload'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:543:in `spawn_missing_workers'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:142:in `start'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/bin/unicorn:126:in `<top (required)>'
/home/user/project/vendor/bundle/ruby/2.5.0/bin/unicorn:23:in `load'
/home/user/project/vendor/bundle/ruby/2.5.0/bin/unicorn:23:in `<main>'

おそらく ERROR -- : unsupported signal SIGTEAM (ArgumentError)これが原因かと。

ローカル環境でやったのがまずかったのかなと思い、GCEのCentOS7上で環境を作ってやってみたのですが、同じエラーが出ました。

やったこと

最初もいいましたが、まず、以下の記事を参考にファイルを作成し設定をしていきました。

qiita.com

bundle exec rails unicorn:startで作成したタスクを実行したのですが、上記のエラー。

そして、どれだけ探しても同じエラーで詰んでる人がいないという。

と思っていたところ、以下の記事が出てきた。

doruby.jp

記事を参考にconfig/unicorn.rbを変更してみました。

#  unicron.rb
# set lets
$worker  = 2
$timeout = 30
$app_dir = "/home/user/project/" #アプリの場所
$listen  = File.expand_path 'tmp/unicorn.sock', $app_dir
$pid     = File.expand_path 'tmp/unicorn.pid', $app_dir
$std_log = File.expand_path 'log/unicorn.log', $app_dir

# set config
worker_processes  $worker
working_directory $app_dir
stderr_path $std_log
stdout_path $std_log
timeout $timeout
listen  $listen
pid $pid

# loading booster
preload_app true

# before starting processes
before_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
  old_pid = "#{server.config[:pid]}.oldbin"

  if old_pid != server.pid
    begin
      Process.kill "QUIT", File.read(old_pid).to_i
    rescue Errno::ENOENT, Errno::ESRCH
    end
  end
end

# after finishing processes
after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

これで一旦はbundle exec rails unicorn:startが動くようになりました。

終わりに

今回の解決策には全くなってないですが、プロジェクトの関係で早く本番環境を作らないといけないので、一旦この方法で落ち着けます。

時間のあるときにもうすこし調査してみます。

誰か解決してくれるといいんだけど。

【Ubuntu】apt update時winehqでGPGエラー

f:id:rdwbocungelt5:20190116114707p:plain

どうもてぃです。

apt-keyの更新とか設定とかメンドイですね。今回身をもって知りました。

環境

  • Ubuntu 16.04.5 LTS(elementary OS 0.4.1 Loki)

現象

$ sudo apt update

無視:1 http://dl.google.com/linux/chrome/deb stable InRelease
ヒット:2 http://dl.google.com/linux/chrome/deb stable Release                                                                                             
ヒット:3 https://dl.yarnpkg.com/debian stable InRelease                                                                                                   
ヒット:4 https://download.docker.com/linux/ubuntu zesty InRelease                                                    
ヒット:5 https://cli-assets.heroku.com/apt ./ InRelease                                                              
ヒット:8 http://packages.elementary.io/appcenter xenial InRelease                                                      
ヒット:9 http://ppa.launchpad.net/elementary-os/stable/ubuntu xenial InRelease                                         
エラー:7 https://dl.winehq.org/wine-builds/ubuntu xenial InRelease                                                     
  公開鍵を利用できないため、以下の署名は検証できませんでした: NO_PUBKEY 76F1A20FF987672F
ヒット:10 http://archive.ubuntu.com/ubuntu xenial InRelease                                                            
ヒット:11 http://ppa.launchpad.net/gregory-hainaut/pcsx2.official.ppa/ubuntu xenial InRelease
ヒット:12 http://archive.ubuntu.com/ubuntu xenial-updates InRelease                                                     
ヒット:13 http://archive.ubuntu.com/ubuntu xenial-backports InRelease                                                  
ヒット:14 http://ppa.launchpad.net/noobslab/pcsx2/ubuntu xenial InRelease                   
ヒット:15 https://packagecloud.io/slacktechnologies/slack/debian jessie InRelease                                       
ヒット:16 http://archive.ubuntu.com/ubuntu xenial-security InRelease                                                    
ヒット:17 http://ppa.launchpad.net/elementary-os/os-patches/ubuntu xenial InRelease                                     
ヒット:18 http://ppa.launchpad.net/philip.scott/elementary-tweaks/ubuntu xenial InRelease 
ヒット:19 http://ppa.launchpad.net/ubuntuhandbook1/audacity/ubuntu xenial InRelease       
ヒット:20 http://ppa.launchpad.net/webupd8team/java/ubuntu xenial InRelease               
パッケージリストを読み込んでいます... 完了                    
W: GPG エラー: https://dl.winehq.org/wine-builds/ubuntu xenial InRelease: 公開鍵を利用できないため、以下の署名は検証できませんでした: NO_PUBKEY 76F1A20FF987672F
E: リポジトリ https://dl.winehq.org/wine-builds/ubuntu xenial InRelease は署名されていません。
N: このようなリポジトリから更新を安全に行うことができないので、デフォルトでは更新が無効になっています。
N: リポジトリの作成とユーザ設定の詳細は、apt-secure(8) man ページを参照してください。

winehqで公開鍵がないんかな、と予想。

やったこと

まずはwikiを参照。

wiki.winehq.org

そしたらtopに書いてありました。

$ wget -nc https://dl.winehq.org/wine-builds/winehq.key

$ sudo apt-key add winehq.key

$ sudo apt update

これだけだったなんて。

終わりに

しばらくエラーが出てて更新できてなかったので、その後apt upgradeやりました。

やはり一時情報を確認するのが大切ですね。

めでたしめでたし。

【Ubuntu】apt updateで404 not found

f:id:rdwbocungelt5:20190116114707p:plain

どうもてぃです。

いろいろ環境構築してる時にタイトルの子が出てくるとかなり困る。

なんとか解決してみました(解決できたかどうか微妙だが)。

環境

  • Ubuntu 16.04.5 LTS(elementary OS 0.4.1 Loki)

やったこと

いろんな記事を試しました。

が、メインは以下の記事の手順。

qiita.com

今回公開鍵のエラーも出てたので以下も参考にした。

www.trifields.jp

公開鍵エラーの方はなんとか直ったんですが、404 not foundエラーの方が直らない。

リポジトリはこの子。

エラー:44 http://ppa.launchpad.net/hunter-kaller/ppa/ubuntu xenial Release
  404  Not Found

E: リポジトリ http://ppa.launchpad.net/hunter-kaller/ppa/ubuntu xenial Release には Release ファイルがありません。
N: このようなリポジトリから更新を安全に行うことができないので、デフォルトでは更新が無効になっています。
N: リポジトリの作成とユーザ設定の詳細は、apt-secure(8) man ページを参照してください。

なので一旦リポジトリを取り直してやってみたが、、、

$ sudo add-apt-repository ppa:hunter-kaller/ppa

$ sudo apt -y update


・
・
・
・
・
・
・
エラー:44 http://ppa.launchpad.net/hunter-kaller/ppa/ubuntu xenial Release
  404  Not Found

E: リポジトリ http://ppa.launchpad.net/hunter-kaller/ppa/ubuntu xenial Release には Release ファイルがありません。
N: このようなリポジトリから更新を安全に行うことができないので、デフォルトでは更新が無効になっています。
N: リポジトリの作成とユーザ設定の詳細は、apt-secure(8) man ページを参照してください。

だめだなこれは。

対処法

Releaseファイルがないということはリポジトリの更新がそもそも止まってるんじゃね?と思い、なら必要ないんじゃないかという結論に至ったので消しました。

/etx/apt/sources.list.d/配下にhunter-kaller-ubuntu-ppa-xenial.listがいるので、削除してしまう。

けど、もしエラーになったら面倒なので、一応バックアップとして取っておく方法にする。

$ sudo mkdir /etc/apt/backup

$ sudo mv /etc/apt/sources.list.d/hunter-kaller-ubuntu-ppa-xenial.* /etc/apt/backup/

$ sudo rm -rf /var/lib/apt/lists/*

$ sudo apt update

これで一旦問題なくupdateできました。

【Rails】unicorn.rbでRails.rootが使えない

どうもてぃです。

本番環境を作ってます。環境ってすごく大事ですよね。

今回何も考えずデフォルトのサーバーpumaを使っていたので、unicornに移行しようと設定していたところ起きた問題です。

環境

起きたこと

worker_processes Integer(ENV['WEB_CONCURRENCY'] || 3)
timeout 15
preload_app true

listen Rails.root.join('tmp', 'unicorn.sock')
pid    Rails.root.join('tmp', 'unicorn.pid')

before_fork do |server, worker|
  Signal.trap 'TEAM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill('QUIT', Process.pid)
  end

  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothind. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

stderr_path File.expand_path('log/unicorn.log', Rails.root)
stdout_path File.expand_path('log/unicorn.log', Rails.root)

上記がunicornの設定ファイルです。

これを元にサーバー起動をしてみたところ、以下のエラーが発生。

# lib/tasks/unicorn.rake を実行する
$ bundle exec rails unicorn:start

unicorn -c /home/user/project/config/unicorn.rb -E development -D
Traceback (most recent call last):
    9: from /home/user/project/vendor/bundle/ruby/2.5.0/bin/unicorn:23:in `<main>'
    8: from /home/user/project/vendor/bundle/ruby/2.5.0/bin/unicorn:23:in `load'
    7: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/bin/unicorn:126:in `<top (required)>'
    6: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/bin/unicorn:126:in `new'
    5: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:77:in `initialize'
    4: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/http_server.rb:77:in `new'
    3: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:77:in `initialize'
    2: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:84:in `reload'
    1: from /home/user/project/vendor/bundle/ruby/2.5.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:84:in `instance_eval'
/home/user/project/config/unicorn.rb:5:in `reload': uninitialized constant #<Class:#<Unicorn::Configurator:0x000055a569137798>>::Rails (NameError)
master failed to start, check stderr log for details
rails aborted!
Command failed with status (1): [unicorn -c /home/user/projec...]
/home/user/project/lib/tasks/unicorn.rake:5:in `block (2 levels) in <main>'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands/rake/rake_command.rb:23:in `block in perform'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands/rake/rake_command.rb:20:in `perform'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/command.rb:48:in `invoke'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/railties-5.2.1/lib/rails/commands.rb:18:in `<main>'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `block in require_with_bootsnap_lfi'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/loaded_features_index.rb:65:in `register'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:20:in `require_with_bootsnap_lfi'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/bootsnap-1.3.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:29:in `require'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `block in require'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:253:in `load_dependency'
/home/user/project/vendor/bundle/ruby/2.5.0/gems/activesupport-5.2.1/lib/active_support/dependencies.rb:287:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => unicorn:start
(See full trace by running task with --trace)

たいていどこのファイルでも問題なくRailsを使えるので何も疑ってなかったのですが、色々調べたところ使えないようです。

やったこと

require 'rails'をやってみたんですが、Rails.rootnilで返ってくる。

故に、joinメソッドでNoMethodErrorが起きるという事態。

そのため、大人しく絶対パスを使って書き直すことにした。

worker_processes Integer(ENV['WEB_CONCURRENCY'] || 3)
timeout 15
preload_app true

# listen Rails.root.join('tmp', 'unicorn.sock')
# pid    Rails.root.join('tmp', 'unicorn.pid')
listen '/home/user/project/tmp/unicorn.sock'
pid '/home/user/project/tmp/unicorn.pid'

before_fork do |server, worker|
  Signal.trap 'TEAM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill('QUIT', Process.pid)
  end

  defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothind. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

stderr_path File.expand_path('log/unicorn.log', '/home/user/project/')
stdout_path File.expand_path('log/unicorn.log', '/home/user/project/')

これで解決。

おわりに

環境変数を設定すればいいのかもなーと思いました。

本番環境ではそれで行こうかな。

【Git】現在のブランチを取得して、git branchを打たないようにする

どうもてぃです。

皆さん開発してますか?僕は全然出来てません。

時に開発すると、自分が異常にgit branchをしていることに気づき、もうどうしようもないくらい同じコマンドを打ちたくない気持ちでいっぱいだったので、今回それを解決しました。

参考

すでに神がいました。

blog.penginmura.tech

こちらを参考にさせていただきます、ありがとうございます。

やったこと

aliasを作成して、push時、pull時にbranchを打たなくていいようにします。

alias.bashrcへ記載します。それぞれの環境で.bash_profileなどに書き換えてください(alias書いてるとこならどこでもいいんじゃないすか)。

alias push="git rev-parse --abbrev-ref HEAD | xargs git push origin"
alias pull="git rev-parse --abbrev-ref HEAD | xargs git pull origin"

git rev-parse --abbrev-ref HEAD で取得したブランチ名をxargsコマンドで渡してあげる。これだけ。

終わりに

pushするときに多用していたgit branch、その後にコマンドラインにあるブランチ名をコピーしてペーストする手間をなくしました。

これでbranchの煩わしさから逃れられますね。

…checkoutするときにはgit branchが必須なんですけど。

【備忘録】Railsでcheck_box_tagがfalseのときもパラメータを飛ばしたい

Rails速習実践ガイドめっちゃいいね、どうもてぃです。

さて、昔実装したのに、しばらくやってないと忘れることよく有りますよね。

今回は備忘録として忘れてたことを書きたいと思います。

環境

やったこと

check_box_tagでパラメータを飛ばす場合、デフォルトではチェックのついたものしか飛びません。ということを完全に忘れていて、軽く30分くらい悩みました。

なので、適切な対処が必要。

まずはcheck_box_tagのリファレンスを確認。おなじみのrailsdocです。

<%= check_box_tag 'page[freezeflag]', true, false, {} %>
# <input id="page_freezeflag" name="page[freezeflag]" type="checkbox" value="true" />

これ使ってみます。

check_box_tagの第一引数はパラメータのkey名 & 属性のIDとname、第二引数は渡す値、第三引数は初期値、第四引数は状態を表してます。

チェックがついていると、strongparameterの中に

{ "page" => <ActionController::Parameters { "freezeflag" => "true" } permitted: false> }

という形で入ります。チェック無しだとそもそも、params["page"]nilになります。

これはデータを更新する上で不便。チェックがあるかどうかで無駄な処理を書かなきゃいけないのはスマートじゃないです。

それを解消するのがhidden_field_tag

必ずcheck_box_tagの前に設置しましょう!

それが以下。

<%= hidden_field_tag 'page[freezeflag]', false %>
<%= check_box_tag 'page[freezeflag]', true, false, {} %>
# <input id="page_freezeflag" name="page[freezeflag]" type="checkbox" value="true" />

check_box_tagにチェックが入らなければ同じ名前のhidden_field_tagの値(false)がパラメータとして飛ぶ。

逆にチェックがついていればcheck_box_tagの方で値が上書きされるという感じ。

必ずnameは同じにしないといけないことに注意。あと最初に言ったけど、hidden_field_tagの位置にも注意。

これで今回の要件を満たせます。

番外編(おまけ)

素晴らしいメソッドを見つけました。

ActiveRecord::Type::Boolean.new.castです。

以下の記事に書いてありました。素晴らしいです。ありがとうございます。

qiita.com

なので、今回飛ばしている値を変更します。

<%= hidden_field_tag 'page[freezeflag]', 0 %>
<%= check_box_tag 'page[freezeflag]', 1, false, {} %>
# <input id="page_freezeflag" name="page[freezeflag]" type="checkbox" value="true" />

これで、パラメータとしてチェック済みの時は文字列の1、チェック無しだと文字列の0が飛びます。

上の記事のように、models/applilcation_record.rbへ専用のメソッドを書いておくと。。。

def checked?(data)
  ActiveRecord::Type::Boolean.new.cast(data)
end

checked?の引数に飛んできたチェックボックスのパラメータを渡すとtrue or falseを判定してくれます。

すばらしい。感動しました。

【Ruby】スクレイピングに精度を求めるならNokogiriではなくSeleniumだ

どうもてぃです。

とある巨大ECサイト(通称熱帯雨林)をスクレイピングして遊んでいます。

今回は nokogiri で問題が発生したので記事にしました。

nokogiriのスクレイピング精度はあんまり良くないのを実体験で痛感しましたね。

environment

issue

ページネーション要素の取得です。

Nokogiriだと4〜6割の確率でページネーションを取得できない場合があります。

問題なのが、Seleniumだとページを読み込み終わるまで待つSelenium::WebDriver::Waitがあるのに対して、Nokogiriにはwaitが存在しません。

あと、NokogiriではJS等で動的に表示しているページは上手く取得できないことがあるとのこと。

だからSeleniumブラウジングしてスクレイピングする方が成功確率は高いと。

最初からSelenium使えばよかったですわ。PythonSeleniumだし。

solution

試しに、一番お手軽なスクレイピングサイト、巨大ECサイト熱帯雨林を使ってみます。

ここだと、ページネーションもありますので。

最近switchのスマブラが販売されて転売ヤーさんが乱立しているGCコンをスクレイピングしてみます。

require 'selenium-webdriver'
ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36"

# headlessモードのoptionをつける
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument("--user-agent=#{ua}")

driver = Selenium::WebDriver.for(:chrome, options: options)
driver.get('https://www.amazon.co.jp/gp/offer-listing/B07HC2F97Q/ref=dp_olp_new?ie=UTF8&condition=new')

# ページ読み込みのwaitを設定
wait = Selenium::WebDriver::Wait.new(timeout: 10)

# find_elementで単数取得
wait.until { driver.find_elements(:xpath, "//h3[@class='a-spacing-none olpSellerName']/span/a") }
seller_info = driver.find_elements(:xpath, "//h3[@class='a-spacing-none olpSellerName']/span/a")
wait.until { driver.find_elements(:xpath, "//ul[@class='a-pagination']/li/a").map { |el| el.attribute(:href) } }
pagination = driver.find_elements(:xpath, "//ul[@class='a-pagination']/li/a").map { |el| el.attribute(:href) }

# ページネーションの最後までクリックする
loop.with_index(1) do |_, i|
  puts "==================================#{i}回目==================================="
  puts driver.find_elements(:xpath, "//h3[@class='a-spacing-none olpSellerName']").map(&:text)

  break if driver.find_elements(:xpath, "//ul[@class='a-pagination']/li/a").last[-1] == '#'
  driver.find_elements(:xpath, "//ul[@class='a-pagination']/li/a").last.click
end

# 二回目のget urlも問題ない
driver.get('https://www.amazon.co.jp/sp?_encoding=UTF8&seller=A2W8UAZHGIMLV7')

driver.close

上記ソースを超簡単に説明。

# headlessモードのoptionをつける
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument("--user-agent=#{ua}")

Selenium::WebDriver::Chrome::Options.newSeleniumのオプションを設定するインスタンスを生成します。

AWSGCPで動かすことも想定にいれて、ヘッダレスでブラウザを起動しないようなオプションをつけています。

ついでにユーザーエージェントも設定してます。

# ページ読み込みのwaitを設定
wait = Selenium::WebDriver::Wait.new(timeout: 10)

スクレイピングをした際にページが全て表示されるまで待つ必要が有ります。

その設定を上記でやっています。使い方は

wait.until { driver.find_elements(:xpath, "//h3[@class='a-spacing-none olpSellerName']/span/a") }
seller_info = driver.find_elements(:xpath, "//h3[@class='a-spacing-none olpSellerName']/span/a")
wait.until { driver.find_elements(:xpath, "//ul[@class='a-pagination']/li/a").map { |el| el.attribute(:href) } }
pagination = driver.find_elements(:xpath, "//ul[@class='a-pagination']/li/a").map { |el| el.attribute(:href) }

のように、要素を取得する前にwait.utilを設定します。簡単です。

残りは要素の取得の処理がメインですね。

loopの部分でページネーションのリンクをクリックし続ける処理をやっています。そんな大したことはやってないです。

最後に

やはり、困った時はrubydocが役に立ちます。

Class: Selenium::WebDriver::Driver — Documentation for selenium-webdriver (0.0.28)

是非参考にしてみてください。

なにかあればコメント欄で〜。

ではでは。