読者です 読者をやめる 読者になる 読者になる

LINE BOT 正式リリース! 新機能、Beaconを早速試してみた!!

みなさんこんにちは、久保田です。

さて、僕は9/29(木)渋谷で開催されたLINE DEVELOPER DAY 2016に参加してきました!
http://linedevday.linecorp.com/jp/2016/

f:id:AdwaysEngineerBlog:20160930014416j:plain

感想を先に言うと、LINEはこれから益々技術の会社として世に力を示していくんだろうな、、、
と感じました。
OSSへの意気込みや技術者の環境がとてもうらやましい、と感じました。

そして様々なセッションがありましたが、
今回は、LINEのBOTがBeta版を経てついに正式公開という発表が一番盛り上がったのではないでしょうか。

そして正式公開に伴い、新機能だけでなく、APIがさらに使いやすくなったり、SDKの発表もありました。
さらに優勝賞金1,000万円の「LINE BOT AWARDS」も開催するらしく、開発意欲が溢れ出そうでした!
僕はこのAWARDに本気で取り組みたいと思います!

さて、色々楽しいお話はありましたが、以前Betaの頃LINE BOTを作った僕としましては、
LINE BOTの新機能やSDKは試したくてしょうがなかったので、早速試してみました!

今回僕が試した新機能は、
「Beacon」 です!

なんと新しいLINE BOTでは、Beaconからイベントを受け取り、Botに喋らせることが可能になりました!

つまりBeaconの近くを通った時に、Botを通じて何かアクションを起こせる、ということです。

このBeaconはアンケートに答えればもらえたので、参加者のみなさんが持っているのではないでしょうか。

というわけで今回は、公開されたRubyのSDKを使い、このBeaconを通じて、Botに喋らせたいと思います!

Botの用意

まずはBotの用意です。
こちらを参考にすればできるはずです。 https://developers.line.me/messaging-api/getting-started

こちらに沿えば、LINE@として作ったアカウントを通してmessage APIを使えるようにしたり、
Botのweb hook URLの設定なども行えます。

動画つきで優しいですね。

Beaconとの連携

さて次はBeaconデバイスと先ほど作ったLINE BOTを紐付けます。
こうすることで、Beaconからのイベントが先ほど登録した Web Hook URLを通してサーバーに送られてきます。

まず、Beaconデバイスの入っている箱からBeaconデバイスを取り外します。

f:id:AdwaysEngineerBlog:20160930013244j:plain

するとURLが書いてあります。

このURLにアクセスすると、LINEのIDとパスワードが求められます。

この認証が終わると、BeaconデバイスとLINE BOTを紐付けられる画面がでてきます。

ここで任意のBotを選択、すると次はBeaconデバイスのシリアル番号とパスワードが求められます。

f:id:AdwaysEngineerBlog:20160930013511p:plain

これはBeaconデバイスの後ろ、電池を外すと書いてあります。

ここまでやったら紐付け完了、Beaconのイベントが先ほど登録したWeb Hook URLを通してサーバーに渡ってきます。

実装

ついにサーバー側の実装です。

前提として、リクエストはHTTPSで受け取る必要があります。
なので、HTTPSの環境で実装してください。

まず、RubyのSDKとsinatraをインストールします。

# frozen_string_literal: true
# A sample Gemfile
source "https://rubygems.org"

gem 'sinatra'
gem 'line-bot-api'

そして、僕のRubyの実装はこんな感じです。(ほぼREADMEのままです。)
(LINE_CHANNEL_SECRETとLINE_CHANNEL_TOKENは管理画面で取得可能です。)

require 'sinatra'
require 'line/bot'
set :bind, '0.0.0.0'

def client
  @client ||= Line::Bot::Client.new { |config|
    config.channel_secret = ENV["LINE_CHANNEL_SECRET"] 
    config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
  }
end

post '/callback' do  # botの設定時にWeb Hook URLに登録したパス。
  body = request.body.read

  signature = request.env['HTTP_X_LINE_SIGNATURE']
  unless client.validate_signature(body, signature) # signatureの確認
    error 400 do 'Bad Request' end
  end

  events = client.parse_events_from(body)
  p events
  events.each { |event|
    case event
    when Line::Bot::Event::Beacon
      message = {
        type: 'text',
        text: 'おかえり!'
      }
      client.reply_message(event['replyToken'], message)
    end
  }
end

いやー、かなり書きやすくなっていますね。
Betaの頃はjsonの扱いやパラメータが多くてめんどくさかったですからね。笑

ひとまず、僕はこのBeaconを家で便利に使いたいので、近づいたら「おかえり!」と喋るようにしました。

注意すべきなのは、僕はEC2上でコーディングしてそのままSinatraを動かしていたのですが、Sinatraは普通に動かすとローカルのリクエストしか受け付けません。
なので3行目にset :bind, '0.0.0.0'と書いています。

そして、実行。(一旦3000ポートで受け付けます。僕の構成ではHTTPSのリクエストをELBで3000に流すようにしています。)

bundle exec ruby main.rb -p 3000

テスト

さて実際にBeaconを起動して、スマホを近づけます。

f:id:AdwaysEngineerBlog:20160930013844j:plain

ドキドキ、、、

f:id:AdwaysEngineerBlog:20160930015849p:plain

動きました!

LINEのトークルームにも、、、

f:id:AdwaysEngineerBlog:20160930015941p:plain

きました!!!!(色々試しているのはお許しください。)

まとめ

これはかなり夢が広がるなーと感じました。
なによりも、楽しいです!!

気になった点は、
テストで動かしている時、Beaconからイベントが送られているかわからないという点がありました。
僕のiPhoneが悪いのか、Beaconとの距離がずっと近いからなのか、 BlueToothを一度offにしてonにしないとうまくイベントが送られませんでした。
そうすると、僕の設定が間違っているのか、iPhoneの方が悪いのかデバックが難しいな、と感じました。

しかし一度うまくいけばなんとなくコツがつかめるので、楽しいの一言です!
仕事の前日なのに日付が変わるまで遊んでいました。

今回は以上です。 僕はこれからAWARDに向けて色々考えたいと思います。では。

Faradayのmiddlewareの作り方

こんにちは、久保田です。 今回はRubyのHTTPクライアント、Faradayのmiddlewareの作り方をご紹介しようと思います。
RubyKaigi2016のToru KawamuraさんのWeb Clients for Ruby and What they should be in the future の発表に触発されました。

FaradayはRack同様、middlewareを作り独自の機能を追加することができます。
このmiddlewareの機能を作ることで、リクエスト、レスポンスの処理をFaradayの中に隠蔽することが可能になります。

middlewareの作り方

middlewareの作り方は、

  • Faraday::Middlewareを継承したクラスを実装
  • register_middlewareメソッドを使ってmiddlewareとしてクラスを登録する。

この2ステップで作ることができます。

そしてFaradayのインスタンスを作る時に宣言することで使用することができます。

Faraday::Middlewareを継承したクラスを実装

まず、リクエストをhookするためには、

class Foo < Faraday::Middleware
  def call(req_env)
    # リクエスト時に動く
  end
end

最低限これだけあればOKです。
callの引数にリクエスト時にFaradayが生成した変数のセットが入っており、それを書き換えることなどができます。

そして、レスポンスをhookするためには、

class Foo < Faraday::Middleware
  def call(req_env)
    # リクエスト時に動く
    ...

    @app.call(req_env).on_complete do |res_env|
      # レスポンスが返ってきたらコールバックされる
    end
  end
end

これでOKです。 @app.call(req_env).on_completeにブロックを渡すことで、レスポンスが返ってきた時にコールバックされるブロックを定義できます。
@appはFaradayが定義しています。

register_middlewareメソッドを使ってmiddlewareとしてクラスを登録する。

middlewareができたらmiddlewareとして、Faradayに登録します。

この時の登録の方法でmiddlewareをリクエスト時に使えるものにするか、レスポンスが返ってきた時に使えるものにするか、両方で使うかが決まります。
そしてmiddlewareの使用時に使うメソッドも変わってきます。
正しいものを選びましょう。

リクエスト時のみ

Faraday::Request.register_middleware(foo: Foo)

使用時

connection = Faraday.new('http://example.com') do |conn|
  conn.request :foo
end

レスポンス時のみ

Faraday::Response.register_middleware(foo: Foo)

使用時

connection = Faraday.new('http://example.com') do |conn|
  conn.response :foo
end

両方

Faraday::Middleware.register_middleware(foo: Foo)

使用時

connection = Faraday.new('http://example.com') do |conn|
  conn.use :foo
end

以上になります。 この機能を使って綺麗なAPI用のクライアントや、スクレイピングする機能を開発していきたいですね。

今回参考にしたのは、こちらのGemです。
https://github.com/lostisland/faraday_middleware

Elixirでフィボナッチ数

こんにちは、エンジニアの渡部です

最近、Elixirの本(プログラミングElixir)の日本語訳が出版されましたね。

その中でフィボナッチ数を分散処理で解決するコードが書かれていたのが面白そうだったため試してみました。

フィボナッチ数計算コード

コードは全部で3つのモジュールで構成されています。

  1. メインモジュール・・・プロセス数1から10までで同じ問題を解き、各々どれくらい時間がかかるかを表示する
  2. スケジューラ・・・手が空いたフィボナッチサーバプロセスに計算させるマン
  3. フィボナッチサーバ・・・ひたすらフィボナッチ数を計算をするナイスガイ。計算が終わったらすぐにスケジューラに次の仕事を要求する仕事中毒者

メインモジュール

defmodule Fibonacci do
  def main do
    to_process = [37, 37, 37, 37, 37, 37]

    # 1から10のプロセス数で実験する
    Enum.each 1..10, fn num_processes ->
      {time, result} = :timer.tc(
        Scheduler, :run,
        [num_processes, FibSolver, :fib, to_process]
      )

      if num_processes == 1 do
        IO.puts inspect result    # 計算結果を表示する
        IO.puts "\n #       time (s)"
      end

      :io.format "~2B       ~.2f~n", [num_processes, time / 1000000.0]
    end
  end
end

スケジューラ

defmodule Scheduler do
  # num_processes数のプロセスを生成し、to_calculateリスト内のフィボナッチ数を全て計算していく
  def run(num_processes, module, func, to_calculate) do
    (1..num_processes)
    |> Enum.map(fn(_) -> spawn(module, func, [self]) end)
    |> schedule_processes(to_calculate, [])
  end

  defp schedule_processes(processes, queue, results) do
    receive do
      # まだ計算するフィボナッチ数が残っている場合は、サーバプロセスに計算を要求する
      {:ready, pid} when length(queue) > 0 ->
        [next | tail] = queue
        send pid, {:fib, next, self}
        schedule_processes(processes, tail, results)
      # 全てのフィボナッチ数を計算し終わった場合は、サーバプロセスをシャットダウンする
      {:ready, pid} ->
        send pid, [:shutdown]
        if length(processes) > 1 do
          schedule_processes(List.delete(processes, pid), queue, results)
        else
          # 全てのプロセスを終了したら、結果リストを並び替えたリストを生成し返す
          Enum.sort(results, fn {n1, _}, {n2, _} -> n1 <= n2 end)
        end
        
      # サーバプロセスが計算し終わった値を結果リストに格納する
      {:answer, number, result, _pid} ->
        schedule_processes(processes, queue, [{number, result} | results])
    end
  end
end

フィボナッチサーバ

defmodule FibSolver do
  # フィボナッチ数を計算して生成元に送る関数
  def fib(scheduler) do
    send scheduler, {:ready, self}
    receive do
      {:fib, n, client} ->
        send client, {:answer, n, fib_calc(n), self}
        fib(scheduler)
      {:shutdown} ->
        exit(:normal)
    end
  end

  # わざと非効率的にする
  defp fib_calc(0), do: 0
  defp fib_calc(1), do: 1
  defp fib_calc(n), do: fib_calc(n - 1) + fib_calc(n - 2)
end

実行結果

実行環境

  • OS: Ubuntu 16.04.1 LTS (64bit)
  • CPU: Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz
  • CPU数: 2 (コア数は各1個)
  • メモリ: 1GB

結果

実行結果は下の画像のようになりました。

#の列が使用したプロセス数、timeは計算にかかったリアルタイム(現実時間)です。

f:id:AdwaysEngineerBlog:20160923171231p:plain

このときのtopコマンドの出力ですが、きちんと分散処理がなされていて画像のようにCPU使用率200%となりました!

日常的に使っていてCPU使用率200%という数値を見たことがなかったので、少し感動しました。

f:id:AdwaysEngineerBlog:20160923171224p:plain

せっかくなのでRubyと比較

業務でRubyのThreadを使いたいと思っているので、RubyのThreadはどんな結果になるか興味があります。

というのも、RubyのThreadはネイティブスレッドですが、Giant VM Lock(GVL)というVMでネイティブスレッドの数を一つに制限する機構があると見聞きしたためです。これがどのようにパフォーマンスに影響するのか実験してみます。

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'benchmark'

def fib(n)
  if n == 0
    0
  elsif n == 1
    1
  else
    fib(n - 1) + fib(n - 2)
  end
end

def main()
  to_calculate = [37, 37, 37, 37, 37, 37]

  thread_list = to_calculate.map do |n|
    Thread.new { fib(n) }
  end

  result = Benchmark.realtime { thread_list.each(&:join) }

  puts ' #       time (s)'
  puts "%02d       %.2f" % [thread_list.length, result]

  thread_list.each(&:join)
end


main if $0 == __FILE__

計算すべきフィボナッチ数は6個(to_calculateの要素数)あるので6スレッド生成して、実験してみました。

結果は、6スレッドで28.83秒(リアルタイム)となりました。

topコマンドの出力を見てみると、CPU使用率が100%以上あがりません。

f:id:AdwaysEngineerBlog:20160923175206p:plain

やはり、GVLの効果でネイティブスレッド数が限定されて、コア数分の分散処理になっていないようです。

GVLがあるのは、Ruby自体がスレッドセーフでなく、他サードパーティーモジュールなどもスレッドセーフではないからというのが理由として挙げられているようです。

しかし、IO処理などはGVLの制限がはずれるらしく、実際に以下のコードを試すとCPU使用率128%となりました。

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

def f()
  1_000_000_000.times { STDERR.puts "Hello" }
end

def main()
  thread_list = 6.times.map do |i|
    Thread.new { f }
  end
  
  thread_list.each(&:join)
end


main if $0 == __FILE__

まとめ

Elixirの分散処理はとてもすごいですね。コード自体に慣れることができればとても素早い処理をすることができそうです。

でも普段使いならRubyのほうが私の脳に優しいかなと思いました(^^;)

Elixirの日常使いを増やして色々と作っていきたいです。 (RubyはRubyistでPythonはPythonista、Elixirを使う人はなんていうんだろう?)

はてなブログに引っ越しました!

こんにちは、久保田です。

さて、我々Adwaysエンジニアブログですが、デザインリニューアルも兼ねて、
実はこっそりライブドアブログからはてなブログに移行致しました。

今回はこの移行に至るまでの軌跡をお話したいと思います。

まず、前提として、ブログ移行に関して以下のような課題がありました。

- ドメインは「blog.engineer.adways.net」から変えない。  
- 過去のブログの記事は捨てない。  
- ドメインは変わらないが、パスがどうしても変わってしまうので、過去のリンクを辿ってきた人をリダイレクトさせる。  

以上を踏まえて、やるべき作業は以下のようになりました。

- デザインの決定   
- 記事、画像の移動  
- 過去のリンクを踏んだユーザーをリダイレクトをさせるjsの用意  
- ドメインの移管  

今回は、デザインの決定、ドメインの移管以外の2つのお話をさせていただきます。

- 記事、画像の移動    
- 過去のリンクを踏んだユーザーをリダイレクトをさせるjsの用意    

のお話をさせていただきます。

記事、画像の移動

まず、旧ブログに投稿した記事を全て新ブログに移動させます。

ブログは、大抵の場合記事データのエクスポート機能とインポート機能があり、フォーマットに従っていれば簡単に移動ができます。

しかし、問題になるのは、画像です。

旧ブログにいつまでも画像を残しておくわけにはいかないので、画像を新ブログにアップロードし直す必要があります。
そうなると、記事データに書かれた画像のパスも書き換えてあげないといけないわけです。
しかし、画像をすべて手動でアップロードし、手動でパスを書き換えるというのは現実的ではないので、幾つかのプログラムを通して、新しいブログにインポートする記事のデータを作ります。

その点を踏まえた上で、作業は以下のような手順で行います。
1, 旧ブログから記事データをエクスポート
2, 旧ブログから全画像をダウンロード
3, 新ブログに全画像をアップロード&新画像パスの取得
4, 1でエクスポートした記事の画像のパスを3でアップロードした画像のパスに置換
5, 4で画像のパスを置換した記事データを新ブログにインポート

このステップをこなせば、画像も一緒に移動できるはずです。

旧ブログから記事データをエクスポート

これはブログの管理画面でできるはずです。
ライブドアブログでは、設定 > エクスポート と画面を辿っていくと、エクスポートができました。

旧ブログから全画像をダウンロード

画像のダウンロードは、先ほど取得した記事データを使用します。
記事データから画像のパスを抜き出し -> ダウンロードする
という手順です。
この作業は、PythonのBeautiful Soapというモジュールがうまくはまりそうだったので採用しました。

from bs4 import BeautifulSoup
from urllib import request
import re
import os.path
import wget
from urllib import request

# 画像のダウンロード
def downloadImageFromInternet(source, output):
    try:
        response = request.urlopen(source)
        if response.code != 200:
            return -1
        with open(output, "wb") as fout:
            fout.write(response.read())
        return 11
    except Exception as err:
        print("NotFoundError!!! : ", source)

# main処理
f = open("backup.txt") # 記事データをopenする
blogs = f.read().split("-----\n--------") # 記事データを一つの記事ごとに分ける
n = 0
for i, blog in enumerate(blogs):
    imgs = BeautifulSoup(blog).find_all('img') # omgタグを探す
    print("blog No,{}: ".format(i + 1))
    if not os.path.exists('./images/{}'.format(i+1)):
        os.mkdir('./images/{}'.format(i+1))
    for img in imgs:
       m = re.match("http://livedoor.blogimg.jp/adways04/imgs/.*/.*/(.*)", img["src"]) # 対象の画像かを確認
       if m:
           n += 1
           src = img['src']
           print("{} -> ./images/{}/{}".format(src, i + 1,m.group(1)))
           downloadImageFromInternet(src, './images/{}/{}'.format(i + 1, m.group(1))) # 記事ごとに分けて画像を保存しておく

新ブログに全画像をアップロード&新画像パスの取得

次は新ブログに画像をアップロードします。 これを行うために、はてなフォトライフのAPIを使用しました。

はてなフォロライフAPI経由で画像をアップロードするには、OAuthを行う必要があります。(WSSEは使えなくなっていました。)
なので、OAuthの勉強も兼ねて、OAuthのクライアントサイドを実装してみました。
せっかくなので、ドキュメントは RFC5849しか見ない、という縛りも加えました。
辛かったですが、これくらいできないとダメだと感じ、頑張りました。

流れとしましては、 http://developer.hatena.ne.jp/ja/documents/auth/apis/oauth/consumer このページの通りですが、

アプリをはてなに登録、consumer_key と consumer_secretを取得  
↓  
consumer_key と consumer_secretを使って、access_tokenを取得  
↓  
access_tokenを使って、https://www.hatena.ne.jp/oauth/authorize?oauth_token={access_token}にアクセスして、verifierを取得  
↓  
verifierを使って、oauth_tokenとoauth_token_secretを取得  
↓  
oauth_tokenとoauth_token_secretを使って、はてなフォロライフAPIにアクセス、画像のアップロード  

と、なります。

少し長めなので、gistをはっておきます。

oauth_tokenの取得

画像のアップロード

一つ目のgistを動かしてoauth_tokenとoauth_token_secretを取得、
二つ目のgistで取得したoauth_tokenとoauth_token_secretを使ってapiアクセス、画像アップロードをしています。

幾つかはまりどころがあったので、お話しします。

はまりどころ

oauth_tokenの取得

苦労した点としては、毎回signatureを作る必要があるのですが、少しでも間違えるとsignatureエラーが出るだけで、何が間違っているのかわからない、という点でした。
例えば、すでにエンコード済みのoauth_tokenなどはエンコードする必要がありません。なので、oauth_tokenを再度エンコードすると、エラーになります。

画像のアップロード

こちらは一つだけハマったのは、僕の実装だと、OauthCli.newした時にタイムスタンプを作ってそれをヘッダーに乗せていたのですが、それだとアップロードの最中にタイムスタンプが有効期限切れになってしまった点です。

そしてアップロードした後は、アップロードした画像と新パスの対応付けのため、redisにデータを保存しています。

後の詳細はコードを見ていただければわかると思います。

1でエクスポートした記事の画像のパスを3でアップロードした画像のパスに置換

次はエクスポートした記事の中の画像パスを新しい画像のパスに置換します。
ここで先ほどredisに保存したデータを使います。
大まかな流れは、

ブログを1つずつ分ける  
↓   
redisのデータから、画像のパスを置換  
↓   
配列に入れておく  
↓  
配列に入れた記事をすべてつなげて、ファイルに書き込む
require 'redis'

redis = Redis.new
f = File.open('./backup.txt')
blogs = f.read().split("-----\n--------")
new_blogs = []

blogs.each.with_index(1) do |blog, i|
  img_srcs = blog.scan(/img.*?src=\"(.*?)\"/)
  img_srcs.flatten.each do |src|
    dst_src = redis.get("#{i}/#{src.match(/.+\/([\w-]+\..+)$/)[1]}")
    if dst_src
      p "#{i}: #{src} => #{dst_src}"
      blog = blog.sub(src, dst_src)
    end
  end
  new_blogs << blog
end


File.open("backup-1.txt", "w") do |f|
  f.puts(new_blogs.join("-----\n--------"))
end

特に難しいところはありません。正規表現が大変だったなーくらいです。
これで新しいブログにインポートする記事のデータが完成しました。

4で画像のパスを置換した記事データを新ブログにインポート

ここまできたら後ははてなブログの管理画面で先ほど作った記事データをインポートします。
これが完了すると、画像のパスも書き換わった状態の記事が新ブログに反映されます! これで新ブログが完成です。

過去のリンクを踏んだユーザーをリダイレクトをさせるjsの用意

僕らのブログは、Adways Engineers Diaryなど、外部に幾つかリンクを持っています。
それらの外部リンクには、過去のブログのパスがはってあります。
しかし新ブログに移行するにあたり、パスが変わってしまったので、それらのリンクがリンク切れを起こしてしまいます。 (http://blog.engineer.adways.net/archive/4444444.html -> http://blog.engineer.adways.net/entry/4444444.html という形になります。)

なので今回は、エラーページにjsを仕込んでおき、エラーページのURLと対応した記事ページがあったら、リダイレクトさせることにしました。

そのために、

- 旧記事と新記事のパスの対応表の作成  
- エラーページで発火するjsの実装  

が必要になります。

旧記事と新記事のパスの対応表の作成

この処理で、対応表をjson形式で吐き出すようにして、jsに渡します。
対応表を作るために、旧記事と新記事の記事データがまた必要になります。
両方の記事データからパスの部分を抜き出す必要があるからです。

なのでまた記事データをブログからエクスポートして用意します。
そして以下のRubyプログラムに食わせます。

require 'json'

key_paths   = File
                .open('./backup-livedoor.txt')
                .read
                .scan(/PATH: (.*)\n/)
                .flatten
                .map do |path|
                  "http://blog.engineer.adways.net/#{path}"
                end

value_paths = File
                .open('./backup-hatena.txt')
                .read
                .scan(/BASENAME: (.*)\n/)
                .flatten
                .reverse
                .map do |path|
                  "/entry/#{path}"
                end

table = key_paths.zip(value_paths).to_h.to_json

p key_paths.size
p value_paths.size
File.open("table.json", "w") do |f|
  f.puts(table)
end

こうするとルーティングを管理する対応表ができます。
後はここでできたjsonをjsにはって、

<script>
  if(document.querySelectorAll('.no-entry').length){
      // route_tableにjsonを貼る   
      route_table = {"http://blog.engineer.adways.net/archives/5094288.html":"/entry/5094288","http://blog.engineer.adways.net/archives/14407148.html":"/entry/14407148","http://blog.engineer.adways.net/archives/5441933.html":"/entry/5441933",

…snip…

,"http://blog.engineer.adways.net/archives/49447083.html":"/entry/2016/09/03/014433"}
      
      url = location.protocol + "//" + location.host + location.pathname;
      if(route_table[url]) {
        location.href = "http://blog.engineer.adways.net" + route_table[url];
      }
  }
</script>

はてなブログの管理画面のデザイン > フッタのところにコピペして保存すればOKです!

これで昔のリンクを踏んできたユーザーが移行した記事にリダイレクトされます。

まとめ

これでDNSの設定を変え、ドメインをはてなブログに設定すれば、移行は完了です。
OAuthの実装がかなり山だったな・・・と感じております。

いろいろとありましたが、無事我らAdwaysEngineersBlogは、はてなブログに移行が完了しました。

今後も更新頑張っていくので、よろしくお願いいたします。

RubyKaigi2016まとめ

RubyKaigiの僕が聞いたセッションのスライドまとめです。(随時更新)

Ruby3 Typing by Yukihiro "Matz" Matsumotoさん

dRuby in the last century. by Masatoshi SEKIさん

https://speakerdeck.com/m_seki/druby2016

Welcome to haconiwa - the (m)Ruby on Container by Uchio KONDOさん

https://speakerdeck.com/udzura/mruby-on-container

A proposal of new concurrency model for Ruby 3 by Koichi Sasadaさん

http://www.atdot.net/~ko1/activities/2016_rubykaigi.pdf

Unifying Fixnum and Bignum into Integer by Tanaka Akiraさん

http://www.a-k-r.org/pub/2016-09-08-rubykaigi-unified-integer.pdf

Scalable job queue system build with docker by Takashi Kokubun

https://speakerdeck.com/k0kubun/scalable-job-queue-system-built-with-docker

How to create bindings 2016 by Kouhei Sutouさん

https://slide.rabbit-shocker.org/authors/kou/rubykaigi-2016/

How DSL works on Ruby by SHIBATA Hiroshiさん

http://www.slideshare.net/hsbt/how-dsl-works-on-ruby

Learn Programmming essence from Ruby patches by Mitsutaka Mimuraさん

https://speakerdeck.com/takkanm/learn-programming-essence-from-ruby-patches

Ruby Reference Manual 2016 Autamn by okkezさん

http://slide.rabbit-shocker.org/authors/okkez/rubykaigi2016/

Modern Black Mages Fighting in the Real World by Satoshi "moris" Tagomoriさん

http://www.slideshare.net/tagomoris/modern-black-mages-fighting-in-the-real-world

SciRuby Machine Learning Current Status and Future by Kenta Murataさん

https://speakerdeck.com/mrkn/sciruby-machine-learning-current-status-and-future

Ruby Committers vs the World

Web Clients for Ruby and What they should be in the future by Toru Kawamuraさん

http://www.slideshare.net/tkawa1/rubykaigi2016-web-clients-for-ruby

Recent Advances in HTTP and Controlling them using ruby by Kazuho Okuさん

http://www.slideshare.net/kazuho/recent-advances-in-http-controlling-them-using-ruby

Optimizing Ruby by Urabe, Shyouheiさん

https://speakerdeck.com/shyouhei/optimizing-ruby

Dive into CRuby by NARUSE, Yuiさん

https://speakerdeck.com/naruse/dive-into-cruby