【個人開発】通勤時にQiitaのトレンド記事が届くLINE Botを開発した

## はじめに

今回は通勤時間を有効活用することができる、通勤時にQiitaのトレンド記事が届くLINE Botを開発しながら**Railsと外部APIの連携**、**LINE Messaging API SDKの使い方**、**LINE Flex Messageの使い方**を学んでいきます。

チュートリアル形式で実際にLINE Botの開発をしながら開発方法を解説していきます。

## この記事の対象者

- LINE Bot開発に入門したい人
- Railsと外部APIの連携手法を学びたい人
- 個人開発でLINE Botを作ってみたい人

## 目標成果物

LINE側から「出勤なう」と送られてきたタイミングでQiitaのトレンド記事上位5つを返すLINE Bot。

![IMG_7062.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/cd79cc33-f523-2bf8-296f-882f7b242c66.jpeg)


## LINE Botについて

### LINE Botとは

LINE BotとはLINE上のメッセージの返答を自動化できるチャットボットです。

**チャットボット**とはユーザーからのメッセージに、自動で返答するプログラムです。

LINE Botを使うことで、ユーザーに対してカスタマーサポート、商品のクーポン送付、予約機能など様々なアプローチを行うことができますなどをすることができます。

**【LINE Botでできること】**

- ユーザーからのメッセージに対して自動返信
- 返答の出しわけ
- 選択肢の提示
- クーポンの発行や利用
- Webサイトへの誘導

今回の開発ではユーザーへメッセージを自動送信する機能を開発します。

### LINE Botの仕組み

LINE BotはLINEが提供する**Messaging API**を利用して開発をすることができます。

https://developers.line.biz/ja/docs/messaging-api/overview/

この**Messaging API**は**LINE Developersコンソール**という開発者向けの管理上で作成することができる**チャネル**を通信経路として利用する。

ユーザーがLINE Botに対してメッセージを送信してから返信が返ってくる流れは以下のように表すことができます。


![スクリーンショット 2022-07-29 15.18.12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/7bad0b31-523a-dc36-9e20-6e36100c39ce.jpeg)

① ユーザーがスマホアプリでメッセージを送信
② 送信されたメッセージはチャネルを経由しLINEプラットフォームへいきRailsアプリへ
③ Railsアプリで受信したメッセージを解析
④ Railsはユーザーへ送信したいメッセージのリクエストをLINEプラットフォームへ
⑤ LINEプラットフォームからユーザーのスマホへメッセージが送信される

## 簡単なオーム返しアプリを作ってみる

まずは公式ドキュメントの手順に沿って簡易的なオーム返しアプリを開発していきます。

https://developers.line.biz/ja/docs/messaging-api/building-bot/

### Messaging API のチャネルの作成

まずはじめに先ほど紹介したメッセージの経由を行う**チャネル**を**LINE Developersコンソール**を利用して作成していきます。

![スクリーンショット 2022-07-29 16.31.09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/29c04545-0092-976b-28c0-8ed3fec00db8.jpeg)

下記の公式サイトにまずはアクセスします。

https://developers.line.biz/ja/services/messaging-api/

まず初めに、自分の使っているLINEアカウントを用いてログインします。

![スクリーンショット 2022-07-29 16.33.34.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/286c469d-00d4-e5c2-2c8d-568623544928.jpeg)

はじめての人はここから**LINE Developers**に新規のアカウントを登録してください。

登録が完了したらサイドバーより**Providers**を選択し**create**をクリックしてください。

![スクリーンショット 2022-07-29 17.18.38.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/131ee79f-3baa-3c38-0e7e-51442fcdbb4f.jpeg)

登録が完了すると、作成したプロバイダーが表示されています。

![スクリーンショット 2022-07-29 17.20.18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/56e21cbb-7c8b-10f3-38e7-cd81a3c00199.jpeg)

下記より新規チャンネルを作成します。

![スクリーンショット 2022-07-29 17.22.40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/c3ff2b96-e791-f486-14f0-6c4b5fe98699.jpeg)

作成画面に行ったら上から下記の入力を行います。

- チャンネルタイプ - Messaging API
- プロバイダー - 先ほど登録した名前
- 会社または所有の国 - Japan
- チャンネルアイコン - 任意の画像
- チャンネル名 - 任意の名前
- チャンネルの説明 - 任意の説明
- カテゴリー - Webサービス
- サブカテゴリー - Webサービス

登録が完了したら下記のような画面が表示されます。

![スクリーンショット 2022-07-29 17.31.54.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/f10442ca-9194-b86b-4b0e-88dec4c9821c.jpeg)

Messaging APIのタブに切り替えるとQRコードが出てくるのでそこからLINE Botを自分のLINE上で登録することができます(まだ何も動きません)

![スクリーンショット 2022-07-29 17.35.30.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/8533c26b-6bb8-4960-ee6a-17e484f16ff0.jpeg)

これでチャネルの作成はできたので、次にRailsアプリ側の準備をして行きます

### LINE Messaging API SDKの準備

#### Railsの環境構築

該当のディレクトリ内で以下のコマンドを実行しRailsアプリを作成します。

```
rails new . --api
```

なおRubyおよびRailsの環境構築はできているものとして先に進めます。まだの方は各自環境構築を済ませてください。

#### LINE Messaging API SDK for Rubyのインストール

次に先程の図の下記の部分を行うための```gem```をインストールします。

![スクリーンショット 2022-07-29 17.46.08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/65bc8000-95d2-590b-cfe9-050867f5b876.jpeg)

LINE Messaging API SDKを利用することで簡単にLINE Botの開発をすることができます。

今回はRuby用に用意されている**LINE Messaging API SDK for Ruby**を利用します。

https://github.com/line/line-bot-sdk-ruby

gemファイルに下記の記述を行います。

```ruby:Gemfile
gem 'line-bot-api'
```

記述ができたら下記のコマンドでインストールを実行します。

```
bundle install
```

### ルーティングの設定

次にLINEプラットフォームらか送信されるリクエストをRails側で受信できるように設定します。

```ruby:config/routes.rb
Rails.application.routes.draw do
  post 'callback' => 'line_bot#callback'
end
```

### コントローラーの設定

次にルーターと紐付けられるための処理をコントローラーを作成します。

```
 rails g controller LineBot
```

下記のファイルが作られます。

```app/controllers/line_bot_controller.rb```

下記の値を入力します

```ruby:app/controllers/line_bot_controller.rb
class LineBotController < ApplicationController
  def callback
  end
end
```

これでRails側の準備も完了したので、LINEから送信されたメッセージを受け取る準備を進めて行きます。

### ngrokの利用

次にngrokを利用してローカルで作成したアプリを一時的に外部に公開できるように設定します。

```Homebrew```で```ngrok```をインストールします。

```
brew install ngrok
```

インストールしたら下記のコマンドでバージョンが出て来れば完了です。
```
ngrok --version
```

次にngrokのサイトに行ってアカウントを登録します。

https://ngrok.com/

登録が完了したらサイドメニューの```Your Authtoken```よりトークンを取得します。

![スクリーンショット 2022-07-29 18.39.23.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/f4587708-100d-58da-2489-193d2befaf1a.jpeg)

下記のコマンドを実行してPCとngrokアカウントを連携します。

```
ngrok authtoken 作成したトークン
```

これでngrokの準備が完了したので実行をして行きます。

下記のコマンドでローカル環境を立ち上げます。
```
 rails s
```

その上で下記のコマンドを実行し```ngrok```を実行します。

自分はポート番号が3000なので3000で設定しました。

```
ngrok http 3000
```

実行後に表示されているURLが外部からアクセスできるURLになります。
```
Forwarding  https://xxxx -> http://localhost:3000
```
最初はアクセスをしてもエラーが表示されます。

こちらのエラーはRailsで設定されているサイバー攻撃対策の影響で出てしまっているので設定を変更します。

### Rails側のセキュリティー設定

Railsで標準のセキュリティー設定がされているので、セキュリティー対策を無効にする設定を行います。

Railsのセキュリティーについての詳しい内容は公式ドキュメントを参考にしてください。

https://blog.saeloun.com/2019/10/31/rails-6-adds-guard-against-dns-rebinding-attacks

今回は結論コードだけを記載します。

```ruby:config/environments/development.rb
 Rails.application.configure do
    # 省略
    config.hosts.clear
  end
```

以上でLINEプラットフォームからのPOSTリクエストのRailsで受け取れるようになったので連携を進めて行きます

### LINEのチャネルとRailsの連携

次にRailsアプリとLINEチャネルの連携をしメッセージのやりとりをおこなえるように設定します。

#### LINEのチャネルでトークンを取得

![スクリーンショット 2022-07-31 8.24.15.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/f0f945e0-ce4c-0960-35cf-98bb9cadb126.jpeg)

チャネル作成時に発行されるチャネルシークレットとチャネルアクセストークンを取得しRailsアプリと連携をしていきます。

LINE Developersを開き先ほど作成プロバイダーページを確認します。

https://developers.line.biz/ja/

タブを**Basic settings**に切り替えて下の方にスクロールします。

![スクリーンショット 2022-07-31 8.27.40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/096e8d0a-45ab-2e26-b46d-87ceae1d2eae.jpeg)

下までスクロールすると**Channel secret**と**Assertion Signing Key**という項目があるので値を確認します。

![スクリーンショット 2022-07-31 8.28.30.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/02372982-9353-25ff-6189-2eadf964cf2c.jpeg)

次にタブを**Messaging API**に切り替え下までスクロールさせます。

するとチャネルのアクセストークンを発行する箇所があるのでトークンの発行を行います。

![スクリーンショット 2022-07-31 8.30.55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/3cd18493-cbf1-3422-1a06-15177da9bc50.jpeg)

これでチャネルシークレットとチャネルアクセストークンの準備が完了したのでRails側で値を設定していきます。

#### Railsの設定

Rails側の**環境変数**に先ほど取得したアクセストークンを設定します。

まずが環境変数を管理するためのgemを入れていきます。

```ruby:Gemfile
gem 'dotenv-rails'
```

```
bundle install
```

環境変数を定義するファイルを作成
```
touch .env
```

先ほど発行したシークレットとトークンを入れます。
```:.env
LINE_CHANNEL_SECRET='xxxxxxxx'
LINE_CHANNEL_TOKEN='xxxxxxxx'
```

#### LINE Messaging API SDKの準備

``LINE Messaging API SDK``ではLINE Botの処理を行うための```Line::Bot::Clien```というクラスがあらかじめ用意されているので、このクラスをインスタンス化し、メッセージの解析と返信機能を作成していきます。

記述法についてはこちらを参考に書いてきます。

https://github.com/line/line-bot-sdk-ruby

```ruby:app/controllers/line_bot_controller.rb
class LineBotController < ApplicationController

  def callback
  end

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

この記述によって```Line::Bot::Client```クラスがインスタンス化できました。

#### LINEチャネルにRailsアプリを登録する

環境変数を元にRails側におけるチャネルとの連携は完了したので、次にチャネル側でRailsアプリを連携させていきます。

タブを**Messaging API**に変えて**Webhook URL**に先ほどngrokで取得したURLを入れます。

Use WebhookもONに設定します。

![スクリーンショット 2022-07-31 22.50.25.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/4d19d0e5-43fd-a410-46c3-aeba3f3c011e.jpeg)


※ なおngrokから取得できるURLは有効期限があるので、ngrokを起動する度にURLの更新をする必要があります。

最後にLINE Botにメッセージを送った際に返信されるオートメッセージを無くす設定をします。

![スクリーンショット 2022-07-31 9.44.38.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/248a0188-7403-25bd-91f2-322b3e60edee.jpeg)

遷移先で下記のように設定をします。

![スクリーンショット 2022-07-31 9.46.01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/7b0638fd-5e57-6bc7-6262-fde58a9dff65.jpeg)

これで準備は完了したのでユーザーが送信したメッセージをそのまま返すオーム返し機能を実装していきます。

### LINEからRailsに送られてくるメッセージを確認する

Rails側のコントローラにコードを追加し、LINEから送信されたメッセージをRails側で確認できるようにします。

```ruby:app/controllers/line_bot_controller.rb
class LineBotController < ApplicationController
  def callback
    
    puts "======="
    puts body = request.body.read
    puts "======="
  end

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

この記述を書いた上でLINEでメッセージを送信してみます。

![スクリーンショット 2022-07-31 22.55.02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/dc7ee6e2-05e3-8b63-3b04-f7af5fc20b4c.jpeg)

するとコマンドライン上で下記のようにメッセージを取得できていることを確認できます。
![スクリーンショット 2022-07-31 22.57.20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/2c97d1e1-0e06-ceee-5310-f7146f5c9f96.jpeg)

次に実際にLINEから届いたメッセージをそのまま返信するような実装をしていきます。

callbackメソットをGitHubを参考に下記のように書き換えます。

https://github.com/line/line-bot-sdk-ruby

```ruby:app/controllers/line_bot_controller.rb
  def callback
    body = request.body.read
    events = client.parse_events_from(body)
  end
```

- ```parse_events_from```で引数にbodyを入れることでevents配列を取得できます

https://www.rubydoc.info/gems/line-bot/Line%2FBot%2FClient:parse_events_from

実際に```events```配列の中は下記のようなデータが入ってきています。(messageの部分のみ表示)

```
"{
  "events":
  [
    {
　　　 // 省略
      "message":
      {
        "type":"text",
        "id":"xxxxxxxxx",
        "text":"Hello world"
      }
    }
  ],
}"
```

```events```は配列なので```each```メソットを利用し```message["text"]```を取得しLINEから送信されてきたメッセージを取得します。

```ruby:app/controllers/line_bot_controller.rb
  def callback
    body = request.body.read
    events = client.parse_events_from(body)
    events.each do |event|
      case event
      when Line::Bot::Event::Message
        case event.type
        when Line::Bot::Event::MessageType::Text
          message = {
            type: "text",
            text: event.message["text"]
          }
          client.reply_message(event['replyToken'], message)
        end
      end
    end
  end
```

コードを詳しく解説していきます。
まず下記のコードでループされている``event``が``Line::Bot::Event::Message``クラスであるかのチェックをしています。
```ruby
    events = client.parse_events_from(body)
    events.each do |event|
      case event
      when Line::Bot::Event::Message
        case event.type
        when Line::Bot::Event::MessageType::Text
```
こちらの処理でLINEから受けととったイベントがメッセージイベントかをチェックしています。

なお、メッセージイベント以外については公式ドキュメントに掲載されているので確認してみてください。

https://developers.line.biz/ja/docs/messaging-api/receiving-messages/#webhook-event-types

次に実際にメッセージだった場合に受信したtextの値を``message``というハッシュに格納します。

また応答トークンを利用して返信機能を付与しています。

```ruby
        case event.type
        when Line::Bot::Event::MessageType::Text
          message = {
            type: "text",
            text: event.message["text"]
          }
          client.reply_message(event['replyToken'], message)
        end
```

応答トークンの処理については下記を参考にしてみてください。

https://developers.line.biz/ja/reference/messaging-api/#send-reply-message

実際でLINEでメッセージを送信するとデータが返ってきていることを確認できます。

![スクリーンショット 2022-07-31 23.37.37.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/c7b7f23e-03e1-0366-4cda-e5f7fb38f350.jpeg)

### 目標物の開発

ここまででLINE Bot開発の基礎を学んできました。

ここからは今回の目標物である「**通勤時にQiitaのトレンド記事が届くLINE Bot**」の開発を進めていきます。

機能としては下記のようになっています。

- LINE Botに対して「**出勤なう**」というメッセージを送るとトレンド記事が届く

なおQiitaのトレンド記事はQiita公式APIでは取得できないので、非公式で作られているQiitaトレンドAPIを利用します。

https://github.com/kaisugi/qiita-trend-api

#### 実装方針

目標物は下記の手順で実装していきます

1. RailsからLINEへ複数メッセージが送れるように設定
2. RailsでQiitaのトレンドAPIを叩いてレスポンスデータを取得
3. 「**出勤なう**」というメッセージが来たタイミングでLINEへレスポンスを返す

さっそく実装の方を進めていきます。

#### RailsからLINEへ複数メッセージが送れるように設定

まずはRailsからLINEへ複数メッセージを送る記述法を確認します。

先ほど実装していた``client.reply_message``の記述において第二引数で渡すメッセージを配列のオブジェクト形式にすることで複数のメッセージをLINEへ送信することができます。

```ruby:app/controllers/line_bot_controller.rb
    message = [{type: "text", text: "メッセージ1"}, {type: "text", text: 'メッセージ2'}]
    client.reply_message(event['replyToken'], message)
```

LINEが確認するとメッセージが2つ受信されていることを確認できます。

![スクリーンショット 2022-08-02 8.22.12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/0ae31ce3-07e0-3743-f6d9-247a3679d12e.jpeg)

つまりQiitaトレンドAPIを叩いてトレンド記事のURLを取得し、ハッシュとして格納することで複数のトレンド記事のURLを作成します。

#### RailsでQiitaのトレンドAPIを叩いてレスポンスデータを取得

次にQiitaトレンドAPIを叩いてURLを取得しLINEアプリへ送信するデータを作成します。

目標の形は下記のようになります。

```ruby:app/controllers/line_bot_controller.rb
    message = [{type: "text", text: "トレンドURL1"}, {type: "text", text: 'トレンドURL2'}]
    client.reply_message(event['replyToken'], message)
```

```Net::HTTP.get_response```を利用してQiitaトレンドAPIを叩いてデータを取得します。

https://docs.ruby-lang.org/ja/latest/method/Net=3a=3aHTTP/s/get_response.html

下記の記述を追加しLINEのメッセージが送信されたタイミングでQiitaトレンドAPIからデータが取得されているかを出力してみます。

```ruby:app/controllers/line_bot_controller.rb
    when Line::Bot::Event::MessageType::Text
        uri = URI('https://qiita-api.vercel.app/api/trend')
        res = Net::HTTP.get_response(uri)
        puts res.body if res.is_a?(Net::HTTPSuccess) # 出力の確認
          message = [
            {type: "text", text: "メッセージ1"}, {type: "text", text: 'メッセージ2'}
          ]
          client.reply_message(event['replyToken'],  message)
      end
```

ターミナルを確認するとQiitaのトレンドAPIのデータが表示されていることを確認できます。

![スクリーンショット 2022-08-02 8.38.33.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/ccfcf7ba-7058-b4fb-621b-a162b970f222.jpeg)

この中からlinkの値だけを取り出します。試しにレスポンスデータの1番目の値のトレンド記事URLを取得します。

```ruby
    uri = URI('https://qiita-api.vercel.app/api/trend')
    response = Net::HTTP.get_response(uri)
    response = JSON.parse(response.body)
    puts "==========="
    p response[0]["node"]["linkUrl"] //  # 出力
    puts "==========="
```
下記のようにデータが取得できていることを確認できます。
![スクリーンショット 2022-08-02 9.00.56.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/6edbdba2-1fb7-0a90-81ad-1da47673b574.jpeg)

実際にループしてLINEに返すメッセージを作成します。

```ruby
    uri = URI('https://qiita-api.vercel.app/api/trend')
    response = Net::HTTP.get_response(uri)
    response = JSON.parse(response.body)
    # LINEへ返すレスポンス
    message = []
    # トレンド上位5記事のみ抽出
    5.times {|i|
      hash = {}
      hash[:type] = "text"
      hash[:text] = response[i]["node"]["linkUrl"]
      message.push(hash)
    }
    client.reply_message(event['replyToken'],  message)
```

-  ``message = []``でLINEに返すデータの初期値を準備しています
-  ``5.times``トレンドの上位5記事を取得するため5回ループさせます
-  ``hash[:text] = response[i]["node"]["linkUrl"]``でトレンドi位のULRを取得
-  ``message.push(hash)``で取得したデータを配列に追加

実際に確認するとデータが返ってきています。

![IMG_7061.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/a13e6684-d5c3-e656-77e5-e04760ac2ed7.jpeg)


#### 「**出勤なう**」というメッセージが来たタイミングでLINEへレスポンスを返す

最後にLINE側から「出勤なう」という文言が送られてきた場合のみレスポンスを返すように条件分岐を付与します。

```ruby:app/controllers/line_bot_controller.rb
  def callback
    body = request.body.read
    events = client.parse_events_from(body)
    events.each do |event|
      case event
      when Line::Bot::Event::Message
        case event.type
        when Line::Bot::Event::MessageType::Text
          # ユーザーからのメッセージが「出勤なう」だった場合のみにメッセージを返す
          if event.message["text"] == "出勤なう"
            uri = URI('https://qiita-api.vercel.app/api/trend')
            response = Net::HTTP.get_response(uri)
            response = JSON.parse(response.body)
            # LINEへ返すレスポンス
            message = []
            # トレンド上位5記事のみ抽出
            5.times {|i|
              hash = {}
              hash[:type] = "text"
              hash[:text] = response[i]["node"]["linkUrl"]
              message.push(hash)
            }
            client.reply_message(event['replyToken'],  message)
          end
        end
      end
    end
  end
```

実際に挙動を確認してみましょう。

![IMG_7062.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2695521/07e73f0a-c1aa-2aec-e301-8044f9c81b92.jpeg)

データが返ってきました。

以上で目標物が完成しました。

## 最後に

いかがだったでしょうか。今回はチュートリアル形式でLINE Botの開発をしました。

今回は返信メッセージにスタイルを当てていないのでそのままURLが表示される形式なっていますが、``Flex Message``を利用することでこの辺もカスタマイズできそうなので挑戦したいと思います。

加えて時間設定で自動で出勤時間にメッセージが届く挙動にできるようにアップデート等も加えていけたらなと思っています。

この辺ができた上で一般には公開する予定です。(現状だと公開するのが恥ずかしい笑)

ぜひこの記事を参考にLINE Bot開発や個人開発に挑戦していただけたらなと思います。

他にもいろいろ記事を書いているので読んでいただけると嬉しいです。

https://qiita.com/KNR109/items/e50c981e0518141be28f

https://qiita.com/KNR109/items/ab88c8f9a014fdccfba3

https://qiita.com/KNR109/items/f3268b311e11d5b821c0