takuocean’s diary

備忘録がメインなので、説明が足りないことも多い。もう少し詳しくという人はコメントをお願いします。

scriptやscreenコマンドでログに挿入されたラインフィールドやバックスペースを削除する方法

scriptやscreenコマンドを利用した場合、制御コード(ラインフィールドやバックスペースなど)も一緒にログとして残る。
この際、ラインフィールドやバックスペースは以下のように削除することができる。

col -bv < 変換前ファイル > 変換後ファイル

複数Excelファイルの一括置換ツール作成

以下のサイトを参考にVBAを使って一括置換ツールを作成します。

http://t-wata.com/?p=284

  • やりたいこと
    - 置換リストの作成
    - 複数ファイルの一括置換

* 置換リストの作成 以下の画像のようにリストを作成

f:id:takuocean:20170130231342p:plain

構成は
- 1列目:置換したいファイル名
- 3列目:置換したい文字
- 5列目:置換後の文字

* 複数ファイルの一括置換 作成したVBAのツールは以下のとおり。

Sub replaceStrFromFiles()

    Dim book As Workbook
    Dim sheet As worksheet
    
    Dim filename_fullpath As String     ' ファイル名(フルパス)
    Dim filename As String ' ファイル名
    Dim tmp As Variant
    
    Dim row_list As Long
    Dim row As Long
    
    Dim find_str As String
    Dim replace_str As String

    find_str = Cells(1, 3)
    replace_str = Cells(1, 5)
    
    ' リストの先頭から最後まで繰り返す
    For row_list = 2 To Cells(Rows.Count, 1).End(xlUp).row
        ' ファイル名を取得
        filename_fullpath = Cells(row_list, 1).Value
        
        ' フルパスからファイル名を抽出
        tmp = Split(filename_fullpath, "\")
        filename = tmp(UBound(tmp))
        
        ' ファイルをオープンする
        Workbooks.Open (filename_fullpath)
        
        ' オープンしたブックをアクティブにする
        Set book = Workbooks(filename)
        
        ' 保存時の警告を非表示にする
        book.CheckCompatibility = False
        
        'すべてのシートに対して操作を行う。
        For Each sheet In book.Worksheets
            For row = 1 To Cells(Rows.Count, 1).End(xlUp).row
                Cells(row, 1) = Replace(Cells(row, 1), find_str, replace_str)
            Next
        Next
        
        '保存して閉じる
        Workbooks(filename).Close SaveChanges:=True
        
    Next
End Sub

モジュールを作成したら、先ほど作ったリストのボタンに登録する。
sample1.xlsx が以下のようなとき

f:id:takuocean:20170130232313p:plain

置換ツールを実行すると

f:id:takuocean:20170130232315p:plain

となります。

これを応用すれば列だけでなく行の変換も可能

IFTTTとLine message apiとの連携

以前、Line botの作り方を示しました。Line botはLine message apiを利用して実現しています。

takuocean.hatenablog.com

さて、この場合はLineから送られてきたメッセージに何か返答をすることができますが、Line@の管理者からは能動的に何か送ることはできません。
実際はLine@から何か送りたい場合があると思います。例えば、IFTTTというサービスと連携させてLine@に何か投稿したいとか。
ちなみにIFTTTはネットワークのサービスを連携させるサービスです。例えば、Twitterに投稿した内容をFacebookにも投稿するとか、Flickrで投稿した画像をTwitterFacebookInstagramにそれぞれ同じものを投稿する。または投稿の際にLineやGmailで通知を送るなどです。具体的には以下のサイトを参考にしてください。

http://hoomey.net/ifttt_study_1/

今回はそのやり方を紹介します。

今回やること

Flickrで投稿した画像をLine@でも投稿する

ただし、IFTTTを利用する場合Flickrの投稿をIFTTTを通して直接Line@に投稿することはできません。 Flickr -> IFTTT -> Maker -> 用意したサーバー -> Line@
の順に情報を送ります。

そのためにIFTTTでの設定以外にサーバーを準備し、その中で動くサ―バープログラムが必要になります。 サーバーはLine botの作り方を参考にしてください。また、サーバーからLine@にリクエストを投げるのもほとんどLine botのプログラムを流用することでできます。

1. IFTTTの設定をする

まずはIFTTTの右上にある自分のアカウント名をクリックし、さらに「New Applet」を選択してください。 f:id:takuocean:20161205221023j:plain

次に、「This」を選択します。 f:id:takuocean:20161205221026j:plain

選択後出てくる検索画面で「Flickr」と入力し、表示されたFlickrアイコンを選択します。 f:id:takuocean:20161205221027j:plain

ここではFlickrに画像が何か投稿したら何かアクションをしたいので、「Any new public photo」を選択して下さい。 f:id:takuocean:20161205221037j:plain

次に、「That」を決めていきます。 f:id:takuocean:20161205221039j:plain

検索画面で「Maker」と入力し、表示されたMakerのアイコンを選択します。 f:id:takuocean:20161205221041j:plain

次の画面では選択肢はひとつしかありません。 f:id:takuocean:20161205221043j:plain

最後にMakerでどのようなリクエストをサーバーに送るか設定します。
自分のサーバーのURL。Line botで作ったサーバーと同じものを使うなら https://自分の作成したアプリ名.herokuapp.com.:443/callback


Post


application/json

{{OriginalSourceUrl}}

f:id:takuocean:20161205222315j:plain

設定ができたら、「Create action」を選択し、最後に「Finish」を選択してIFTTTの設定は終了になります。

サーバープログラムの作成

require 'line/bot'

module Line
  module Bot
    class HTTPClient
      def http(uri)
        proxy = URI(ENV["FIXIE_URL"])
        http = Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port, proxy.user, proxy.password)
        if uri.scheme == "https"
          http.use_ssl = true
        end

        http
      end
    end
  end
end


class WebhookController < ApplicationController

  protect_from_forgery with: :null_session # CSRF対策無効化

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

  def callback
    body = request.env["rack.input"].gets

    message = {
      type: 'image',
      originalContentUrl: body,
      previewImageUrl: body
    }
    client.push_message("ここはUser Id", message)
    render status: 200, json: { message: 'OK' }
  end
end

User IdはLine@に紐づいたIDです。 ちゃんとした調べ方が分からなかったので以前作ったLine botプログラムを動作させた際に、受信したリクエストのBodyをまずputs関数で表示させました。 そして、表示させたものからUser Idのタグを探し、ID番号を抽出しました。その値を使っています。

結果としてFlickrで画像を投稿したら f:id:takuocean:20161205230153p:plain

以下のようにLineにも投稿されます。
f:id:takuocean:20161205230151p:plain

odコマンド

odコマンドはバイナリファイルを16進数などでダンプするコマンドです。また、エスケープシーケンスを見つけるのにも活躍します。

od -c ファイル名

これでファイルをエスケープシーケンスも含め文字列で表示してくれる。

Line botの導入の仕方

ここではrailsで実装したサーバーをHerokuで実行してLine botを作っています。
Gitのアカウントは持っている前提で進めます。持っていない人は以下のサイトが参考になると思います。

GitHubアカウント作成とリポジトリの作成手順 - Qiita

1. Developer用のLineアカウントをゲットする

2. Channel SecretとChannel Access Tokenをゲットする

以下サイトを参考にしてアカウント作成からChannel SecretとChannel Aceess Tokenをゲットしてみてくだい。

わずか5分。新LINE Messaging APIでbotを作ってみた手順全公開 - BITA デジマラボ

3. サーバープログラムの作成

今回はLineで呟いたものを返答してくれるbotを作成します。
まずはrailsの初期ファイル群を作成します。

rails new botApp

次にサーバープログラムを作成していきます。
公式サイトでも紹介されている以下のAPIを利用。

github.com

botApp/app/controllers/webhook_controller.rb

require 'line/bot'

class WebhookController < ApplicationController
  protect_from_forgery with: :null_session # CSRF対策無効化

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

  def callback
    body = request.body.read

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

    events = client.parse_events_from(body)
    events.each { |event|
      case event
      when Line::Bot::Event::Message
        case event.type
        when Line::Bot::Event::MessageType::Text
          message = {
            type: 'text',
            text: event.message['text']
          }
          response = client.reply_message(event['replyToken'], message)
        when Line::Bot::Event::MessageType::Image, Line::Bot::Event::MessageType::Video
          response = client.get_message_content(event.message['id'])
          tf = Tempfile.open("content")
          tf.write(response.body)
        end
      end
    }

    render status: 200, json: { message: 'OK' }
  end
end

次にGemfileを以下のように修正。

Gemfile
修正前

# Use sqlite3 as the database for Active Record
get 'sqlite3'

修正後

gem 'sqlite3', group: :development
# 本番ではpostgressを使用する
gem 'pg', group: :production
gem 'rails_12factor', group: :productio

また、

gem 'line-bot-api'

も追加。

*注意点
実はこれだけではForbidden 403というエラーが出たのであとで修正をします。

4. 作成したプログラムをgitにコミット

git init
git add .
git commit -m "initial commit"

5. Herokuへのデプロイ

まずはHerokuのアプリを登録するところを確保します。

heroku apps:create botAPPheroku

ここでbotAPPherokuは適当な名前で!他のひとが使っている名前は使えません。

次にこのスペースに先ほど作ったサーバープログラムを登録します。また、その際にLINE_CHANNEL_SECRETとLINE_CHANNEL_TOKENの変数も登録して下さい。

git push heroku master
heroku config:set LINE_CHANNEL_SECRET="Lineのdeveloperアカウントで取得したchannel_secret"
heroku config:set LINE_CHANNEL_TOKEN="Lineのdeveloperアカウントで取得したchannel_token"

git push heroku masterの時点でサーバーアプリは起動します。

6. Fixieアドオンを使う

このFixieアドオンを使うことでプロキシ経由の通信ができます。(Line botHTTPSによる通信でないとできないためこのようなことをします。)

heroku addons:create fixie:tricycle 

これによりherokuのアプリページにfixieアドオンが追加されています。 fixieアドオンのページに飛んでもらい右上のaccountをクリックするとプロキシURLとIPアドレスが作成されています。
これをメモしてください。

heroku config:set FIXIE_URL="example.com"

exmple.comにはプロキシURLを設定してください。

8. LineアカウントでコールバックURLとホワイトリストの設定

アカウントペーにcallback URLという欄があるので以下のように入力してください。隠れているところにはherokuに作ったアプリページ名を。

f:id:takuocean:20161108214429p:plain

ホワイトリストは左のメニューバーに
「Server IP Whitelist」
があるので選択。
表示されるページにIPアドレスを入力できるスペースがあるので先ほどfixieで取得したIPアドレスを入力。

7. サーバーアプリのログを見る

heroku logs -t

ここで紐づけられたLineアカウントにコメントしてみましょー
おそらく何も返ってこないでしょう。

はい、足りないものがありました。

8. プログラムの修正

プロキシを通す際には設定がhttpクラスに設定が必要でした。

botApp/app/controllers/webhook_controller.rbに以下の行を追加。

module Line
  module Bot
    class HTTPClient
      def http(uri)
        proxy = URI(ENV["FIXIE_URL"])
        http = Net::HTTP.new(uri.host, uri.port, proxy.host, proxy.port, proxy.user, proxy.password)
        if uri.scheme == "https"
          http.use_ssl = true
        end

        http
      end
    end
  end
end

...

修正後、gitに追加、コミット、herokuへpushすると、、、

f:id:takuocean:20161108221601p:plain

こんな感じでつぶやきが返ってきました。

次はこれをIFTTTとの連携に活かしてみます。

この記事は以下も参考にしました。

github.com