<commit_before><commit_msg>Add kitchensink example<commit_after>require 'sinatra'   # gem 'sinatra'
require 'line/bot'  # gem 'line-bot-api'

THUMBNAIL_URL = 'https://via.placeholder.com/1024x1024'
HORIZONTAL_THUMBNAIL_URL = 'https://via.placeholder.com/1024x768'

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

def reply_text(event, texts)
  texts = [texts] if texts.is_a?(String)
  client.reply_message(
    event['replyToken'],
    texts.map { |text| {type: 'text', text: text} }
  )
end

def reply_content(event, messages)
  res = client.reply_message(
    event['replyToken'],
    messages
  )
  puts res.read_body if res.code != 200
end

post '/callback' do
  body = request.body.read

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

  events = client.parse_events_from(body)

  events.each do |event|
    case event
    when Line::Bot::Event::Message
      handle_message(event)

    when Line::Bot::Event::Follow
      reply_text(event, "[FOLLOW]\nThank you for following")

    when Line::Bot::Event::Unfollow
      puts "[UNFOLLOW]\n#{body}"

    when Line::Bot::Event::Join
      reply_text(event, "[JOIN]\n#{event['source']['type']}")

    when Line::Bot::Event::Leave
      puts "[LEAVE]\n#{body}"

    when Line::Bot::Event::Postback
      message = "[POSTBACK]\n#{event['postback']['data']} (#{JSON.generate(event['postback']['params'])})"
      reply_text(event, message)

    when Line::Bot::Event::Beacon
      reply_text(event, "[BEACON]\n#{JSON.generate(event['beacon'])}")

    else
      reply_text(event, "Unknown event type: #{event}")
    end
  end

  "OK"
end

def handle_message(event)
  case event.type
  when Line::Bot::Event::MessageType::Sticker
    handle_sticker(event)
  when Line::Bot::Event::MessageType::Location
    handle_location(event)
  when Line::Bot::Event::MessageType::Text
    case event.message['text']
    when 'profile'
      if event['source']['type'] == 'user'
        profile = client.get_profile(event['source']['userId'])
        profile = JSON.parse(profile.read_body)
        reply_text(event, [
          "Display name\n#{profile['displayName']}",
          "Status message\n#{profile['statusMessage']}"
        ])
      else
        reply_text(event, "Bot can't use profile API without user ID")
      end

    when 'buttons'
      reply_content(event, {
        type: 'template',
        altText: 'Buttons alt text',
        template: {
          type: 'buttons',
          thumbnailImageUrl: THUMBNAIL_URL,
          title: 'My button sample',
          text: 'Hello, my button',
          actions: [
            { label: 'Go to line.me', type: 'uri', uri: 'https://line.me' },
            { label: 'Send postback', type: 'postback', data: 'hello world' },
            { label: 'Send postback2', type: 'postback', data: 'hello world', text: 'hello world' },
            { label: 'Send message', type: 'message', text: 'This is message' }
          ]
        }
      })

    when 'confirm'
      reply_content(event, {
        type: 'template',
        altText: 'Confirm alt text',
        template: {
          type: 'confirm',
          text: 'Do it?',
          actions: [
            { label: 'Yes', type: 'message', text: 'Yes!' },
            { label: 'No', type: 'message', text: 'No!' },
          ],
        }
      })

    when 'carousel'
      reply_content(event, {
        type: 'template',
        altText: 'Carousel alt text',
        template: {
          type: 'carousel',
          columns: [
            {
              title: 'hoge',
              text: 'fuga',
              actions: [
                { label: 'Go to line.me', type: 'uri', uri: 'https://line.me' },
                { label: 'Send postback', type: 'postback', data: 'hello world' },
                { label: 'Send message', type: 'message', text: 'This is message' }
              ]
            },
            {
              title: 'Datetime Picker',
              text: 'Please select a date, time or datetime',
              actions: [
                {
                  type: 'datetimepicker',
                  label: "Datetime",
                  data: 'action=sel',
                  mode: 'datetime',
                  initial: '2017-06-18T06:15',
                  max: '2100-12-31T23:59',
                  min: '1900-01-01T00:00'
                },
                {
                  type: 'datetimepicker',
                  label: "Date",
                  data: 'action=sel&only=date',
                  mode: 'date',
                  initial: '2017-06-18',
                  max: '2100-12-31',
                  min: '1900-01-01'
                },
                {
                  type: 'datetimepicker',
                  label: "Time",
                  data: 'action=sel&only=time',
                  mode: 'time',
                  initial: '12:15',
                  max: '23:00',
                  min: '10:00'
                }
              ]
            }
          ]
        }
      })

    when 'image carousel'
      reply_content(event, {
        type: 'template',
        altText: 'Image carousel alt text',
        template: {
          type: 'image_carousel',
          columns: [
            {
              imageUrl: THUMBNAIL_URL,
              action: { label: 'line.me', type: 'uri', uri: 'https://line.me' }
            },
            {
              imageUrl: THUMBNAIL_URL,
              action: { label: 'postback', type: 'postback', data: 'hello world' }
            },
            {
              imageUrl: THUMBNAIL_URL,
              action: { label: 'message', type: 'message', text: 'This is message' }
            },
            {
              imageUrl: THUMBNAIL_URL,
              action: {
                type: 'datetimepicker',
                label: "Datetime",
                data: 'action=sel',
                mode: 'datetime',
                initial: '2017-06-18T06:15',
                max: '2100-12-31T23:59',
                min: '1900-01-01T00:00'
              }
            }
          ]
        }
      })

    when 'imagemap'
      reply_content(event, {
        type: 'imagemap',
        baseUrl: THUMBNAIL_URL,
        altText: 'Imagemap alt text',
        baseSize: { width: 1024, height: 1024 },
        actions: [
          { area: { x: 0, y: 0, width: 512, height: 512 }, type: 'uri', linkUri: 'https://store.line.me/family/manga/en' },
          { area: { x: 512, y: 0, width: 512, height: 512 }, type: 'uri', linkUri: 'https://store.line.me/family/music/en' },
          { area: { x: 0, y: 512, width: 512, height: 512 }, type: 'uri', linkUri: 'https://store.line.me/family/play/en' },
          { area: { x: 512, y: 512, width: 512, height: 512 }, type: 'message', text: 'Fortune!' },
        ]
      })

    when 'flex'
      reply_content(event, {
        type: "flex",
        altText: "this is a flex message",
        contents: {
          type: "bubble",
          header: {
            type: "box",
            layout: "vertical",
            contents: [
              {
                type: "text",
                text: "Header text"
              }
            ]
          },
          hero: {
            type: "image",
            url: HORIZONTAL_THUMBNAIL_URL,
            size: "full",
            aspectRatio: "4:3"
          },
          body: {
            type: "box",
            layout: "vertical",
            contents: [
              {
                type: "text",
                text: "Body text",
              }
            ]
          },
          footer: {
            type: "box",
            layout: "vertical",
            contents: [
              {
                type: "text",
                text: "Footer text",
                align: "center",
                color: "#888888"
              }
            ]
          }
        }
      })

    when 'flex carousel'
      reply_content(event, {
        type: "flex",
        altText: "this is a flex carousel",
        contents: {
          type: "carousel",
          contents: [
            {
              type: "bubble",
              body: {
                type: "box",
                layout: "horizontal",
                contents: [
                  {
                    type: "text",
                    text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
                    wrap: true
                  }
                ]
              },
              footer: {
                type: "box",
                layout: "horizontal",
                contents: [
                  {
                    type: "button",
                    style: "primary",
                    action: {
                      type: "uri",
                      label: "Go",
                      uri: "https://example.com"
                    }
                  }
                ]
              }
            },
            {
              type: "bubble",
              body: {
                type: "box",
                layout: "horizontal",
                contents: [
                  {
                    type: "text",
                    text: "Hello, World!",
                    wrap: true
                  }
                ]
              },
              footer: {
                type: "box",
                layout: "horizontal",
                contents: [
                  {
                    type: "button",
                    style: "primary",
                    action: {
                      type: "uri",
                      label: "Go",
                      uri: "https://example.com"
                    }
                  }
                ]
              }
            }
          ]
        }
      })

    when 'bye'
      case event['source']['type']
      when 'user'
        reply_text(event, "[BYE]\nBot can't leave from 1:1 chat")
      when 'group'
        reply_text(event, "[BYE]\nLeaving group")
        client.leave_group(event['source']['groupId'])
      when 'room'
        reply_text(event, "[BYE]\nLeaving room")
        client.leave_room(event['source']['roomId'])
      end

    else
      reply_text(event, "[ECHO]\n#{event.message['text']}")

    end
  else
    puts "Unknown message type: #{event.type}"
    reply_text(event, "[UNKNOWN]\n#{event.type}")
  end
end

def handle_sticker(event)
  # Message API available stickers
  # https://developers.line.me/media/messaging-api/sticker_list.pdf
  msgapi_available = event.message['packageId'].to_i <= 4
  messages = [{
    type: 'text',
    text: "[STICKER]\npackageId: #{event.message['packageId']}\nstickerId: #{event.message['stickerId']}"
  }]
  if msgapi_available
    messages.push(
      type: 'sticker',
      packageId: event.message['packageId'],
      stickerId: event.message['stickerId']
    )
  end
  reply_content(event, messages)
end

def handle_location(event)
  message = event.message
  reply_content(event, {
    type: 'location',
    title: message['title'] || message['address'],
    address: message['address'],
    latitude: message['latitude'],
    longitude: message['longitude']
  })
end
{'fraction_non_alphanumeric': 0.13609519612163948, 'fraction_numerical': 0.016659321286910535, 'mean_word_length': 1.4295503211991434, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 3, 'https://': 11, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2855418', 'n_tokens_mistral': 3465, 'n_tokens_neox': 3231, 'n_words': 720}