Subscribed unsubscribe Subscribe Subscribe

F# Monkey

about

(F#) throttleを実装してみた!

今コツコツやってるdeoplete-fsharpで、throttleのところでつまづいてるのですが、まぁそれはさておき、面白い記事を見つけたので、やってみました!

matarilloさんというかたがthrottleを自前で実装してたので僕もまねしてF#で実装してみました!

まずはその前にmatarilloさんが作ったC#のコードをF#で使ってみます!

C#のコードをF#でつかう

dll化して取り込めばオーケー

こんな感じ

$ msc -t:library abc.cs

F#のコードは

#r @"./abc.dll"
open WhoToFollowApp
open System
open System.Threading

// 下記のテストコードとおなじ

F#に書き換えてみる

さて,C#のコードを使って感じを掴めたのでF#に書き換えてみます!

こんな感じ

open System
open System.Threading
open System.Threading.Tasks

type Throttle<'T> (millisec:int, action:Action<'T>) =
    
    let mutable signalSequence : int64 = 0L

    member this.Signal (input: 'T) : Async<unit> =
        async { 
            let   id      = Interlocked.Increment( &signalSequence )
            do!   Async.Sleep(millisec)
            let   current = Interlocked.Read( &signalSequence )
            if    current = id
            then  action.Invoke(input)
            else  () 
        }

テストコード

// 500ms値が発行されなかったら最後に発行された値を後続に流す
let throttle = new Throttle<int>(500, fun i -> 
    stdout.WriteLine("{0:HH:mm:ss.fff} {1}", DateTime.Now, i ) )

// 100ms間隔で値を発行
[|1..10|] 
|> Array.iter( fun i ->
    stdout.WriteLine("{0:HH:mm:ss.fff} Signal({1})",DateTime.Now, i)
    throttle.Signal(i) |> Async.Start
    Thread.Sleep(100) )

Thread.Sleep(2000)

stdout.WriteLine("---------------")

// 100ms間隔で値を発行
[|1..5|] 
|> Array.iter( fun i ->
    stdout.WriteLine("{0:HH:mm:ss.fff} Signal({1})",DateTime.Now, i)
    throttle.Signal(i) |> Async.Start
    Thread.Sleep(100) )

Thread.Sleep(2000)

stdout.WriteLine("---------------")

結果

21:27:04.172 Signal(1)
21:27:04.277 Signal(2)
21:27:04.383 Signal(3)
21:27:04.488 Signal(4)
21:27:04.593 Signal(5)
21:27:04.698 Signal(6)
21:27:04.799 Signal(7)
21:27:04.903 Signal(8)
21:27:05.006 Signal(9)
21:27:05.107 Signal(10)
21:27:05.612 10
---------------
21:27:07.218 Signal(1)
21:27:07.323 Signal(2)
21:27:07.429 Signal(3)
21:27:07.534 Signal(4)
21:27:07.639 Signal(5)
21:27:08.140 5
---------------

*** time : 7.727785 s ***

参考

qiita.com

Remove all ads

福岡の美味しいお店〜 ポポット(POPOTE)

最近のcallmekoheiのお気に入りのお店です!

ちょっと飲み屋さんが密集してる場所からは離れてるのですが

すごくいい雰囲気でゆっくり飲めますっ!

福岡に出張などのときは是非!

f:id:callmekohei00:20170228183250p:plain

場所

警固交番の近く

すごく場所はわかりにくいですwww

Remove all ads

インテリセンスを150行で作ってみた!

Summary

F#Compiler Servicesというのを使って

インテリセンス(というか補完)をやってみました!

今回はF#側での補完の話です。Vim側の補完の話はこちらです。

callmekohei00.hatenablog.com

おおまかな動作

辞書(ConcurrentDictionary)に下記をあらかじめキャッシュしておきます。

01. file名
02. Systemのメソッド
03. Collection5のメソッド( Array, Seq, Set, Map, List )
04. Optionのメソッド

コードはこんな感じになります

// 最初にファイル名他を辞書にキャッシュします
if      Seq.isEmpty dic.Keys
then    asyncInit ()   |> Async.RunSynchronously


// もしファイルを変えた場合は
// ファイル名とSystemをキャッシュし直します
// この場合は非同期(Start)で動作します
elif    dic.Item( "filePath" ) <> postData.FilePath
then    asyncReInit () |> Async.Start 


// ドットでの補完かどうかで処理を分けます
if      postData.Line.Contains(".")
then    dotHint ()
else  
        postData.Line.Split(' ')
        |> Array.filter ( fun s -> s <> "" )
        |> fun ary ->
            if    Array.contains "[<" ary  && not ( Array.contains ">]" ary )
            then  attributeHint ( Array.last ary |> fun s -> s.Replace( "[<","" ) )
            else oneWordHint ( Array.last ary )

インテリセンスというか補完のコアになるコード

なぜこう書くのかとかわかりません。

マイクロソフトのホームページに書いてあったからですwww

let private asyncGetDeclarationListInfo ( checker:FSharpChecker) ( ps:PostData ) (arr:(string array * string)) : Async<FSharpDeclarationListInfo> = async {

    let! (projOptions : FSharpProjectOptions) =
        checker.GetProjectOptionsFromScript( ps.FilePath , ps.Source )

    // Perform parsing and type checking 
    let! (parseFileResults : FSharpParseFileResults) , (checkFileAnswer: FSharpCheckFileAnswer) =
        checker.ParseAndCheckFileInProject( ps.FilePath, 0, ps.Source, projOptions )

    let checkFileResults = 
        match checkFileAnswer with
        | FSharpCheckFileAnswer.Succeeded(res) -> res
        | res -> failwithf "Parsing did not finish... (%A)" res

    return! checkFileResults.GetDeclarationListInfo ( Some parseFileResults, int(ps.Row) , int(ps.Col) , ps.Line, (fst arr) |> Array.toList, (snd arr), fun _ -> false )
}

課題

上記のコードasyncGetDeclarationListInfo

いかにリアルタイムで呼び出さないかがポイントになるかと思います。

事前にキャッシュしてない補完項目は通常は気にならないスピードなのですが、

type providerが入ってるコードになると

途端に遅くなります。(2秒から5秒くらい?)

コード

コードは下記に置いてますっ!

こんな感じで作り直したらいいんじゃない?という提案ありましたら

どんな手段でも結構ですので言っていただけると嬉しいです!

github.com

参考のページ

fsharp.github.io

fsharp.github.io

callmekohei00.hatenablog.com

Remove all ads

非同期処理(async)をかじってみた!

Summary

Asyncとはお仕事を管理する方法

お仕事を管理する方法を2つのパターンで考えると理解しやすいかも

お仕事をasync { お仕事 }async { ... }でかこむ

お仕事を人に任せる時は!をつける(let!とかdo!とかreturn!とか)
( ! をつけると async<’T> が ’T となる)

上司部下パターン( Parents - child pattern )

上司の仕事の段取りをもとにお仕事を処理する

こんなかんじ

// 3sec.後にhello0というおしごと
let helloAfter3seconds () = async {
    do! Async.Sleep(3000)
    stdout.WriteLine("hello0")
}

// 上司の仕事の段取り(仕事の段取りは管理者の仕事なので async {} でかこむ)
async {
    
    // 部下に仕事をおねがいする ( ひとに任せるので let! )
    // お仕事の名前は workA とでもしておく
    let! workA = helloAfter3seconds () |> Async.StartChild

    // 上司は上司で自分の仕事をする
    stdout.WriteLine("hello1")

    // 部下にお仕事の進捗状況をたずねる (ひとに任せていたものなので do!)
    // この場合の do は どうだったの? の どう(do)
    do! workA
} 

// 上司の仕事の段取りを実際に行動にうつす
|> Async.RunSynchronously

結果

hello1
hello0

同僚パターン ( flat pattern )

お仕事を手分けして一斉に処理する

// 3sec.後にhello0というおしごと
let helloAfter3seconds () = async {
    do! Async.Sleep(3000)
    stdout.WriteLine("hello0")
}

// hello1というおしごと
let hello1() = async {
  stdout.WriteLine("hello1")
}

// するべきお仕事をリスト化
[ helloAfter3seconds () ; hello1 () ]

// お仕事を各人に割り当てる
|> Async.Parallel

// 一斉にお仕事を処理する
// 早く終わった人から仕事をきりぬける
// 最後の人が終わったらお仕事終了
|> Async.RunSynchronously

結果

hello1
hello0
Remove all ads

ConcurrentDictionaryの使い方

こんな感じ

open System.Collections.Generic
open System.Collections.Concurrent

let dic : ConcurrentDictionary<string,int> = new ConcurrentDictionary< string, int >()

// appleははじめてなので 100
dic.AddOrUpdate("apple",100, fun _ price -> price + 99 )
dic.Values |> printfn "%A" // seq [100]

// appleは2回目のなので 100 + 99
dic.AddOrUpdate("apple",100, fun _ price -> price + 99 )
dic.Values |> printfn "%A" // seq [199]

// appleはすでに登録されているので 199
dic.GetOrAdd("apple",999)
|> printfn "%A" // 199

// bananaははじめてなので 9999
dic.GetOrAdd("banana",9999)
|> printfn "%A" // 9999

// cherryははじめてなので 99999
dic.GetOrAdd( "cherry", fun _ -> 99999)
|> printfn "%A" // 99999


dic.Keys |> printfn "%A"
// seq ["banana"; "cherry"; "apple"]

dic.Values |> printfn "%A"
// seq [9999; 99999; 199]

dic.Item("cherry") |> printfn "%A" // 99999

dic.ContainsKey("apple") |> printfn "%A" // true

dic.Count |> printfn "%A" // 3

dic.ToArray() |> printfn "%A"
// [|[banana, 9999]; [cherry, 99999]; [apple, 199]|]

dic |> printfn "%A"
// seq [[banana, 9999]; [cherry, 99999]; [apple, 199]]

Remove all ads

F#からSQLiteをつかってみる

下記のページに書いてある分でやるとOSXでのFSharpでもSQLite使えました〜

fsprojects.github.io

Summary

FSharp on OSXSQLiteをつかう

下記の3点が必要

System.Data.SQLitenugetする

libSQLite.Interop.dylibコンパイルする

FSharpコード内でDLLImportする

すること

その1

System.Data.SQLitenugetする

その2

libSQLite.Interop.dylibコンパイルする

下記からソースコードをダウンロード

System.Data.SQLite: Downloads Page

List of Release Packages
-> Source Code
-> sqlite-netFx-full-source-1.0.104.0.zip

zipを解凍して

$ cd Setup

$ chmod +x compile-interop-assembly-release.sh

$ bash compile-interop-assembly-release.sh

これでlibSQLite.Interop.dylibができるので

$ chmod -x bin/2013/Release/bin/libSQLite.Interop.dylib

その3

FSharpコード内でDLLImportする

さっきのlibSQLite.Interop.dylibfsxと同じ場所にコピーしてくる

で、コード

#r @"./packages/System.Data.SQLite.Core/lib/net46/System.Data.SQLite.dll"
open System.Data.SQLite
open System.Runtime.InteropServices

module Database =
    
    [<DllImport(@"/Users/kohei/Documents/jikkenSqlite3/libSQLite.Interop.dylib" , CallingConvention = CallingConvention.Cdecl)>] 
    let sqlite_connection : System.Data.SQLite.SQLiteConnection  =
        ( new SQLiteConnection( @"Data Source=:memory:;Version=3;foreign keys=true" ))

    type ABC ( connection : System.Data.SQLite.SQLiteConnection ) =

        let cn = connection

        member theis.sqlite_open : unit =
            cn.Open()

        member this.sqlite_createTable sql  =
            ( new SQLiteCommand(sql, cn)).ExecuteNonQuery() |> ignore

        member this.sqlite_insert  sql =
            ( new SQLiteCommand(sql, cn)).ExecuteNonQuery() |> ignore

        member this.sqlite_select  sql f =
            let reader = ( new SQLiteCommand(sql, cn )).ExecuteReader()
            while ( reader.Read() ) do
               f reader 

module Jikken =
    open Database
            
    let s0 = @"CREATE TABLE IF NOT EXISTS foo ( name VARCHAR(20), price INT )"
    let s1 = @"INSERT INTO foo ( name, price ) VALUES ('apple', 3000 )"
    let s2 = @"SELECT name FROM foo"
    let f = fun (r:SQLiteDataReader) -> 
        [0]
        |> List.fold ( fun acc n -> acc + " " + r.GetString(n) |> fun s -> s.TrimStart() ) ""
        |> stdout.WriteLine

    let db = ABC( sqlite_connection )
    db.sqlite_open
    db.sqlite_createTable s0
    db.sqlite_insert s1
    db.sqlite_select s2 f

実行

fsi ではなく fsc で実行すること

結果

apple

*** time : 0.081165 s ***

追加

libSQLite.Interop.dylibコンパイルするのがめんどくさい人は

下記に置いてますのでgit cloneしてお使いくださいっ

github.com

Remove all ads

python ujsonをインストールする

またもやはまったのでメモ

はまった事柄

$ pip3 install ujson

でインストールできない。。。

対処

下記のサイトからダウンロード

pypi.python.org

ファイルを解凍して

$ sudo -H python3 setup.py install

確認

$ python3
Python 3.6.0 (default, Dec 24 2016, 08:01:42) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ujson
>>> 

おけおけ

Remove all ads

PythonでJsonをよむときにエラーが出た場合の対処

かなり手こずったのでメモメモ

エラー内容

Expecting value: line 1 column 1 (char 0)

対処

try~を入れてあげると解決しました〜

// ホームページからデーターをとってくる
jsons  = urlopen(url).read().decode('utf-8').split('\n')

result = []
for v in jsons :
    try:
        js = json.loads(v)
        result.append( js['info'] )
    except Exception:
        pass

追記 2017/02/13

下記でいけました〜

結局jsonデーターでない空の行が含まれてました

json_lines = [ json.loads(s) for s in responses if s != "" ]
Remove all ads

Suave server から json を出力する

こんな感じで

#r @"./packages/Newtonsoft.Json/lib/net45/Newtonsoft.Json.dll"
open Newtonsoft.Json

#r @"./packages/FsPickler/lib/net45/FsPickler.dll"
#r @"./packages/FsPickler.Json/lib/net45/FsPickler.Json.dll"
open MBrace.FsPickler
open MBrace.FsPickler.Json

#r @"./packages/Suave/lib/net40/Suave.dll"
open Suave
open Suave.Operators
open Suave.Successful
open Suave.Filters
open Suave.RequestErrors



// o はレコードとかリストとか
let jsonSerializer = FsPickler.CreateJsonSerializer(indent = false, omitHeader = true)
OK ( jsonSerializer.PickleToString(o) )
Remove all ads

インテリセンスを作ってみた

Summary

Vim(Neovim)F#のコード書くための実行環境を整えてみました!

01. コード実行結果の表示

02. インテリセンスによるコード補完

Motivation

vim-fsharpというすごく便利なプラグインがあるのですが

もっとシンプルなのが欲しかったのでつくってみました

ちょっとしたコードを即実行できる環境がほしかったのですよ

Like this

  コードを実行する

f:id:callmekohei00:20170205133525p:plain

コードを書くときはインテリセンスがききます

f:id:callmekohei00:20170211170918p:plain

Source

コードはこちらから〜

GitHub - callmekohei/deoplete-fsharp: Provides Intellisense completions for FSharp

感想

まだまだだと思いますけど

ゆっくりと作り込んでいきたいです

機能は増やさず安定した動作を

求めて行きたいです

Thanks

特に・・・

@ShougoMatsuさん, @_zchee_さん, @yukitosさん, @hafuuさん, @Haxeさん, @bleisさん, @kekyoさん, @omanukeさん, @pocketberserkerさん, @adacolaさん

本当にありがとうございます!

上記以外の方も本当にありがとうございます!

Remove all ads

deoplete.nvimのソースをつくってみた

やりたいこと

下記のような感じでオートコンプリートしたい

apと入力したらapple

baと入力したらbanana

chと入力したらcherry

f:id:callmekohei00:20170129233114p:plain

必要なもの

deoplete.nvim

# dein.toml の記入例
[[plugins]]
repo = 'Shougo/deoplete.nvim'
hook_add = 'let g:deoplete#enable_at_startup = 1'

ソースをつくる

ソースの置き場所

$XDG_CONFIG_HOME/nvim/rplugin/python3/deoplete/sources


まずフォルダをつくる

cd $XDG_CONFIG_HOME/nvim
mkdir -p rplugin/python3/deoplete/sources

ソース(パイソンファイル)を作成

cd rplugin/python3/deoplete/sources
vim callmekohei.py

callmekohei.pyの中身(さわるところは3ヶ所のみ!)

from .base import Base

class Source(Base):
    def __init__(self, vim):
        super().__init__(vim)
        self.name = 'callmekohei'           # なまえ
        self.mark = '[kohei]'               # mark のなまえ

    def gather_candidates(self, context):
        return ["apple","banana","cherry"]  # ポップアップのリスト






やりたいこと2

fruits.と入力したらapple, banana, cherry

f:id:callmekohei00:20170130111957p:plain

ソース

import re
from .base import Base

class Source(Base):
    def __init__(self, vim):
        super().__init__(vim)
        self.name = 'callmekohei'
        self.mark = '[kohei]'
        self.input_pattern = (r'^fruits\.')        # input_pattern で fruits. を指定する
        
    def get_complete_position(self, context):      # input_pattern を使うときは必須
        m = re.search(r'\w*$', context['input'])
        return m.start() if m else -1

    def gather_candidates(self, context):
        return ["apple","banana","cherry"]






やりたいこと3

appleを選択したらappleの説明を表示したい

f:id:callmekohei00:20170210005937p:plain

ソース

from .base import Base

class Source(Base):
    def __init__(self, vim):
        super().__init__(vim)
        self.name          = 'callmekohei'
        self.mark          = '[kohei]'

    def gather_candidates(self, context):
        return [
            {
                  'word' : "apple"
                , 'abbr' : "apple  : red, round and delicious!"
                , 'info' : "Apple is delicious"
                , 'kind' : "Food"
                , 'dup'  : 1
            }
        ]



参照

ヘルプ :help deoplete

CREATE SOURCE                    *deoplete-create-source*

To create source, you should read default sources implementation in
rplugin/python3/deoplete/source/*.py.

The files are automatically loaded and deoplete creates new Source class
object.
Source class must extend Base class in ".base".

Note: The sources must be created by Python3 language.

Note: If you call Vim functions in your source, it is not asynchronous.


qiita.com

Remove all ads

python 個人的チュートリアル

callmekoheiは今日からpythonをお勉強はじめました!

で、さっきまで学んだ内容のちょっとしたまとめをメモメモ

下準備

vimpythonを書くための下準備


python3で実行する(quickrunの設定)

let g:quickrun_config = {
\     , 'python': {
\           'command': 'python3'
\     },
}

オートコンプリートを効かせる(dein.toml)

[[plugins]]
repo = 'zchee/deoplete-jedi'

文法的ななにか

# Hello, World
print('Hello, World')


# dictionary  and tuple

d = dict(a = 1, b = 2, c = 3)

for key, value in d.items():
    print(key + ' - ' + str(value))


# function
def fizzbuzz(n):
    if n % 15 == 0:
        msg = 'fizzbuzz'
    elif n % 5 == 0:
        msg = 'buzz'
    elif n % 3 == 0:
        msg = 'fizz'
    else:
        msg = str(n)
    
    return msg

for v in range(1,100):
    print(fizzbuzz(v))


# class
class abc:
    x = 0
    def add100(self):
        return ( self.x + 100 )

cls = abc()
cls.x = 10
print(cls.add100())

# error handling
def test(n):
    try:
        print( 10 / n )
    except ZeroDivisionError as e:
        print(e)

test(0)
Remove all ads

チキンな自分向けのトレードルール

ちゃんとFX初めて1年たったのですが、ええ、大負けですよ。お・お・ま・け。で昨年の11月から、もーいーやと半分投げやりな感じでトレードの方法を変えたら月度単位でプラスに転じたので一応メモメモ。自分にはあってるかもです。

トレードルール

チャート見て上か下かきめる
→ オーダー

テキトーな時間に確認
→ 利益が出てたら利確

それだけ

テクニカル

ボリンジャーバンド(σ2のみ表示)

EMA10, SMA13, EMA21

含み損のときに耐える方法

ツイッターつらと書き込む

英語の勉強をする

プログラミングをかく

お酒をのむ

部屋の片付けをする

利確するとき

マシーンになる

損切りするとき

マシーンになる

つねにおもふこと

たのしいときも

つらいときも

わらっとこう

Remove all ads

お酒飲みながら英語を勉強してみる

callmekoheiは何回も英語の勉強に挑戦してるのですが、ことごとく失敗。というわけで、今年は勉強の仕方をかえてみます。お酒飲みながら英語を勉強してみますwww まぁ、うまくいくかわからないですけど。ただこの前、ちょっとフレーズ覚えてお店で使ったら「上達してる!」といわれたので多分フレーズ覚えたら何も考えずに使いまくるのがいいのかも?ですです。

教材

今すぐ言える! 英会話フレーズブック

今すぐ言える! 英会話フレーズブック

会話もメールも 英語は3語で伝わります

会話もメールも 英語は3語で伝わります

飲み屋さん

福岡市大名のラメーン一幸舎のとなりにある養巴コープという建物の2階のenuというお店

f:id:callmekohei00:20170119094616j:plain

店に入ったとき

// おつかれです
Hello! How are you?

// 今日は寒いですね〜
It's cold today!

// このまえの飲みどうでした?  
How did it go last day?

// やせたんじゃない?
Did you lose weight?

// 今日は1日家で読書してました
I read books all day at home.

着席するやいなや

// とりあえずビールにしよっと
// 生ビールいいですか?
I'll start with a beer!
Could I have some draft beer, please?

draft beer   生ビール
bottled beer 瓶ビール
craft beer   地ビール

注文するとき

// 今いいですか?
Excuse me. Let me know when you are ready.

// 注文しますね
Could I order?

// 今日はなにがおすすめです?
What's today's special?

// それってどんな感じです?
What’s that like?

// それってどんな感じです?
Could you give me some more detail?

// 自信のほどは?
How confident are you?

// おいしそう〜。それにします。
Sounds good. I’ll take it.

// うーん、やめときます
I'll pass.

// それと枝豆ください
I’d like a edamame, please.

// とりあえずこんなもんで
That's all.

// あせらなくていいよ
Take your time.

一杯目のビール飲んだ時の感想(ひとりごと)

// うまっ
It's tasty.

// なんとなく好き
I just like it.

// ビールに枝豆、うまっ
There's nothing like beer and edamame!

// なんといえばいいのかわからないけど
// まぁいえることは
// ビールはうまいということ
I don't know to put it, 
but I'm sure
this beer and you makes me happy.

おかわりするとき

// ドリンクのメニューはどこです?
Could I get a drink menu?


// おかわりですっ
Could I have another one, please?


// 次はウイスキーにしようかな
// ハーパーのソーダ割りで
I think I'll have whiskey next.
I'd like harper with soda.


// ジンベースの飲みやすいものをお願いします。
// フルーティーでアルコールが強くないものがいいいです。
I'd like something light with gin.
I want something fruity that's not too strong.

// ちょっとそのお酒を飲んでみようかと思います
I'll try to do some drink this one.

// このカクテルはうまそう
This cocktail has a nice look.

店員さんへのチップ

// よかったらいっぱいどうですか?
I'll get you an drink, if you wish.
You can have some drink.

// 乾杯!
cheers!

おあいそ

// すこし飲みすぎたみたい。酔っ払ったよ。
I think I drank a little too much. I'm drunk.

// おあいそいいですか?
Could I have the bill? Check please.

未整理

// 僕のいってることわかります?
Do you see what I mean?

// ずるい〜
That's not fair.

// 同じ意見〜
Same here.

// さっぱりわからないです
I have no idea.

// なんといえばいいのか・・・
How can I put it?

// まぁ、つまりこういうことです
Let me put it this way.

// つまりどういうことですか?
Could you keep it short?

// それおかしいでしょwww
It's funny.

// そうも考えれるけど
// 個人的にはそういう感じでは考えたくないです
I could think so,
but personally I don't want to go that route.

未整理2

// いまは仕事してません
I'm between jobs right now.

// かつては日本酒をのんでました
I used to do some drink sake.


Remove all ads

denite.vimの使い方

やりたいこと

denite.vimcolorsheme一覧を表示

一覧のなかからshineをえらぶ

手順

:Denite colorschemeと入力してリターン

f:id:callmekohei00:20170109163016p:plain


colorschemeの一覧が表示される

f:id:callmekohei00:20170109163024p:plain


ctlr oをおす(Normal modeにする)

f:id:callmekohei00:20170109171121p:plain


jをおして下まで移動してshineリターン

f:id:callmekohei00:20170109171136p:plain


shineになったー

f:id:callmekohei00:20170109171155p:plain

Remove all ads