しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

APIが使えるビットコイン取引所一覧

自動取引をしたかったのでAPIが使える取引所を調べました。
情報は2018年1月時点のものです。

取引所一覧

参考URL

bitpress.jp

【php】Laravelをインストールして起動

phpのLaravelというフレームワークを触ってみました。
数年ぶりのphpです。

インストール

まずはcomposerというphpのパッケージ管理ツールをインストールします。

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

次にcomposerを使ってプロジェクトを作ります。
初回は5分ほどかかります。

composer create-project --prefer-dist laravel/laravel MyApp

これでカレントディレクトリにMyAppというプロジェクトが作られます。

f:id:llcc:20180205144228p:plain

起動

下コマンドでサーバーを立ち上げます。

php artisan serve

立ち上げ後、localhost:8000にアクセスすると下のようにデフォルトの画面が表示されます。

f:id:llcc:20180205144259p:plain

【読書メモ】♯HOOKED 消費者心理学者が解き明かす「つい、買ってしまった。」の裏にあるマーケティングの技術

♯HOOKEDという本で学んだ事のメモです。

♯HOOKED 消費者心理学者が解き明かす「つい、買ってしまった。」の裏にあるマーケティングの技術 (T's BUSINESS DESIGN)

♯HOOKED 消費者心理学者が解き明かす「つい、買ってしまった。」の裏にあるマーケティングの技術 (T's BUSINESS DESIGN)

  • 人は行動してから行動の理由付けをすることがある
  • この本では「気づかせる」→「考えさせる」→「行動させる」というフレームワークを提唱する
  • プリミティブなものは注意を引く
    • 性・食べ物・顔 が特に重要
    • 食べ物はカロリーが高いものの方がいい
    • 顔を使う場合、視線をキャッチコピーに向けると良い
  • 感情動かすものを使うと良い、かわいいもの・バイオレンス関連など
    • 喜び・不安・怒りなど興奮度合いの大きい感情が良い
    • 満足や悲しみなど興奮度合いの少ない感情では効果が薄い
  • 自分ごとにすると注意を引きやすい
    • 自分の名前など、自分に関連するものは目を引く
  • 驚きのあるコントラストは注意を引く
  • 違和感による驚きでも効果がある
  • メッセージに謎を入れることで好奇心を刺激する
    • 「○○の為の5つの方法」みたいな記事タイトルも好奇心を刺激している
  • 人は簡単な方に流れやすい
    • なので適切なタイミングでこちらからオススメを紹介すると良い
  • 反復する事で記憶に残る
  • 最初と最後は記憶に残りやすい
  • 希少性や権威やコミットを使うと行動に結びつきやすい
    • コミットの例として、最初からスタンプが押されたポイントカードなどがある
  • ストーリーを交えると覚えてもらいやすい
  • 目的に沿ったワードを使うと良い
    • ダイエット商品なら細い・スマートなど

Illustratorのライブトレースで画像をパス化する

ライブトレースという機能を使って画像をパスに変換してみました。
元画像は下のものです、ぱくたそ様のものを利用しました。

f:id:llcc:20180117141903j:plain

冬山山頂の煌めく雪と岩|ぱくたそフリー素材

まずはIllustratorに画像を配置します。

f:id:llcc:20180117142014p:plain

配置した画像を選択して、オブジェクトのライブトレースのトレースオプションを選びます。

f:id:llcc:20180117142036p:plain

下のような画面になるので自分の好みに合わせて調整します。

f:id:llcc:20180117142155p:plain

トレースボタンを押したあとは、画面上部の拡張ボタンを押す事でパス化できます。

f:id:llcc:20180117142234p:plain

少し見づらいですが下のようにパスができています。

f:id:llcc:20180117142337p:plain

【Swift】Speech Recognitionの制限について検証する

iOS10から登場した音声認識API(Speech Recognition)の挙動について調べてみました。

60秒を超えた時の挙動

テストプロジェクトを作り、ViewControllerを下のようにして検証しました。
このコードでは5秒時点と55秒時点と62秒時点でのタスクステータスを見ています。

import UIKit
import Speech

class ViewController: UIViewController {
    private var recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
    private var speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "ja-JP"))!
    private var recognitionTask: SFSpeechRecognitionTask?
    private var audioEngine = AVAudioEngine()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        SFSpeechRecognizer.requestAuthorization { _ in }
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        start()
    }
    
    func start() {
        recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
        speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "ja-JP"))!
        audioEngine = AVAudioEngine()
        
        let recordingFormat = audioEngine.inputNode.outputFormat(forBus: 0)
        audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
            self.recognitionRequest.append(buffer)
        }
        try! audioEngine.start()
        
        recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest) { result, error in
            print("resultHandler")
            print(result?.bestTranscription.formattedString ?? "")
            
            if let error = error {
                print("ERROR!")
                print(error.localizedDescription)
            }
        }
        print(recognitionTask!.state.rawValue)
        DispatchQueue.main.asyncAfter(deadline: .now() + 5.0, execute: {
            print(self.recognitionTask!.state.rawValue)
            print("5!")
        })
        DispatchQueue.main.asyncAfter(deadline: .now() + 55.0, execute: {
            print(self.recognitionTask!.state.rawValue)
            print("55!")
        })
        DispatchQueue.main.asyncAfter(deadline: .now() + 62.0, execute: {
            print(self.recognitionTask!.state.rawValue)
            print("62!")
        })
    }
}

検証結果は下の通りです。

  • 60秒経過するとresultHandlerが「kAFAssistantErrorDomain Code=203 "Retry"」エラーを引数にして呼ばれる
  • 5秒時点でのタスクのステータスはrunning
  • 55秒時点でのタスクのステータスはrunning
  • 62秒時点でのタスクのステータスはcompleted

それとこの挙動は「マイクに一度でも話しかけたかどうか」で変化がありました。
一度でもマイクに話しかけると下のような挙動になりました。

  • 60秒経過してもresultHandlerは呼ばれない
  • 55秒時点でのタスクのステータスはrunningではなくcompleted

自分でキャンセルした場合の挙動

制限ではないのですが、自分でタスクをキャンセルした時はresultHandlerが下エラーを引数に呼ばれます。

The operation couldn’t be completed. (kAFAssistantErrorDomain error 216.)

ユーザー辺りの制限

下のように延々と音声認識をして、どのくらいで制限が引っかかるか試しました。
連続で実施すると60秒制限に引っかかるので、5秒おきに開始と終了を繰り返しています。

import UIKit
import Speech

class ViewController: UIViewController {
    private var recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
    private var speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "ja-JP"))!
    private var recognitionTask: SFSpeechRecognitionTask?
    private var audioEngine = AVAudioEngine()
    var startCount = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        SFSpeechRecognizer.requestAuthorization { _ in }
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        start()
    }
    
    func start() {
        startCount += 1
        print(startCount)
        recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
        speechRecognizer = SFSpeechRecognizer(locale: Locale(identifier: "ja-JP"))!
        audioEngine = AVAudioEngine()
        
        let recordingFormat = audioEngine.inputNode.outputFormat(forBus: 0)
        audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer: AVAudioPCMBuffer, when: AVAudioTime) in
            self.recognitionRequest.append(buffer)
        }
        try! audioEngine.start()
        
        recognitionTask = speechRecognizer.recognitionTask(with: recognitionRequest) { result, error in
            print("resultHandler")
            print(result?.bestTranscription.formattedString ?? "")
            
            if let error = error {
                print("ERROR!")
                print(error.localizedDescription)
            }
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 5.0, execute: {
            self.recognitionTask?.cancel()
            self.recognitionTask?.finish()
            self.audioEngine.stop()
            print("RESTART")
            self.start()
        })
    }
}

結果としては2時間ほどは音声認識を使う事ができました。
時間がなかったのでそこまでしか検証しなかったのですが、結構長い時間使う事ができそうです。

【Ruby】benchmarkで処理速度を計測

Ruby標準ライブラリのbenchmarkを使って処理速度を測定してみました。

使い方は下の通りです。
配列へのpushの10000回ループと100回ループを測定しています。

require 'benchmark'

Benchmark.bm(10) do |x|
  x.report("10,000回") do
    arr = []
    (0...10000).each { |i| arr.push(i) }
  end
  x.report("100回") do
    arr = []
    (0...100).each { |i| arr.push(i) }
  end
end

結果は下の通りです。
realが実際にかかった時間、userがUser CPU timeでsystemがSysten CPU time、totalはTotal CPU timeです。

f:id:llcc:20180107173239p:plain

CPU timeはこちらの記事が参考になりました。

real time/user CPU time/system CPU timeの違いをメモ | Siguniang's Blog

Benchmark.bmの引数に渡している数字はラベルのサイズです。
引数を省略すると下のようにずれてしまうので入れています。

f:id:llcc:20180107173253p:plain

bmメソッドの代わりにbenchmarkメソッドを使うと出力のカスタマイズができます。

require 'benchmark'

Benchmark.benchmark("実際の時間\n", 10, "%10.6r\n") do |x|
  x.report("10,000回") do
    arr = []
    (0...10_000).each { |i| arr.push(i) }
  end
  x.report("100回") do
    arr = []
    (0...100).each { |i| arr.push(i) }
  end
end

f:id:llcc:20180107174445p:plain

手軽に実行時間を測定したい時はrealtimeメソッドも便利です。
このメソッドは実行時間を返してくれます。

require 'benchmark'

time = Benchmark.realtime do
  arr = []
  (0...10_000).each { |i| arr.push(i) }
end
p time

f:id:llcc:20180107174700p:plain

【Ruby】Parallelで並列処理

ParallelというGemで並列処理を試してみました。

github.com

インストール

インストールはBundlerを使いました。

source "https://rubygems.org"

gem "parallel"

使い方

使い方は下の通りです。
1,2,3を引数にしたブロックを並列に実行してくれます。

require 'parallel'

puts 'Start'
Parallel.each([1, 2, 3]) do |i|
  puts i
end
puts 'End'

結果は下の通りです。

f:id:llcc:20180107122058p:plain

並列なことを確かめるために、下のようにiが2の時に1秒待つようにしてみました。

require 'parallel'

puts 'Start'
Parallel.each([1, 2, 3]) do |i|
  sleep 1 if i == 2
  puts i
end
puts 'End'

結果は下の通りです。
1,3,2の順番に出力されました。

f:id:llcc:20180107122037p:plain

下のようにスレッド数を指定する事もできます。

require 'parallel'

Parallel.each([1, 2, 3], in_threads: 2) do |i|
  puts i
end

スレッド数を1にすると、並列ではなくなるので全てが順番に実行されます。

require 'parallel'

Parallel.each([1, 2, 3], in_threads: 1) do |i|
  sleep 1 if i == 2
  puts i
end

f:id:llcc:20180107122530p:plain

スレッドではなくプロセスを使う事もできます。

require 'parallel'

Parallel.each([1, 2, 3], in_processes: 2) do |i|
  puts i
end

プロセスはブロック内での変数の変更が共有されません。

require 'parallel'

array = []
Parallel.each([1, 2, 3], in_processes: 2) do |i|
  array.push(i)
end
p array # → []

array = []
Parallel.each([1, 2, 3], in_thread: 2) do |i|
  array.push(i)
end
p array # → []

変数の共有をしたい場合は下のようにmapを使います。

require 'parallel'

array = Parallel.map([1, 2, 3]) do |i|
  i
end
p array # → [1, 2, 3]

mapの返り値は引数の順番を保持してくれます。
下のようにi==2の時だけsleepしても結果は1, 2, 3になりました。

require 'parallel'

array = Parallel.map([1, 2, 3], in_thread: 2) do |i|
  sleep 1 if i == 2
  i
end
p array # → [1, 2, 3]

もし別々の処理を実施したい場合は下のような書き方もできます。

require 'parallel'

Parallel.each([
  -> { p 1 },
  -> { p 2 },
  -> { p 3 },
  ]) do |l|
  l.call
end