也來寫機器人

今年五月,各平台陸續發表新的bot服務,為了學習golang也順便做點實驗,就順手寫了兩個平台上的機器人

Line: https://github.com/orsonwang/linebot_client

Line平台使用line官方的gloang 函式庫,直接可用

Facebook: https://github.com/orsonwang/fbbot_client

Facebook使用 https://github.com/frodsan/fbot 函式庫,但是在go 1.6會有點問題,所以我就自己Fork改了一下,雖然發了pull request回去,看來作者沒有要整併,也沒關係。 另外有 https://github.com/maciekmm/messenger-platform-go-sdk 可以直接使用,不過我懶得改過去了。

後面為了共用文字處理引擎,我借用 nats.io 來當one to many request response server,這樣就把這兩個程式變成純粹的收發平台,(幾乎)不做任何處理。

投影片10

收到訊息,就把發送者ID跟訊息往後拋,讓後面的文字處理引擎來回覆。

後面的文字處理本來想用jieba來斷字,但是就算斷完字,沒有語法引擎,還是要自己做patten matching,所以就乾脆的放棄斷字引擎,直接使用Reguar Expression來作業(也順便學一下RegEx的語法)。

投影片11

這也回到一個問題,現在的文字服務,不管是關鍵字對應還是機器學習,最終還是需要撰寫patten matching才能提供服務,加上中文的難斷字、亂文法特性。最終會變成一個很大的map/Result,尤其是單句就完成的指令式服務,AI的價值好像很難彰顯。但是要做有記憶力的服務,難度就大幅提昇了,需要多重主詞、情境、指令的記憶點跟如何問答來補足資訊,這樣的服務用RegEx來寫,就會累死人(難以窮舉),依靠機器學習來幫忙歸類才能讓負責寫答案的人專門寫答案。當然機器一定會有錯誤率,如果是在我所在的不能出錯行業,機器學習走監督式學習是必須的,讓機器學會把問題歸類到正確的答案區,整個對答就能很順利的完成。目前在這一塊技術,傳統的中文斷字NLP領域,領先的好像是在北大,早幾年是中研院領先,但被北大超越後,好像就沒有再贏過去的發展。走機器學習來處理的,就都是中國的廠商了,台灣的廠商好像沒聽說有人投入,投入沒價值嗎?泛亞洲區用的文字幾乎都是需要另外斷字的,發展好能處理中文的,泰國、印尼、馬來西亞等新興國家都在後面等著你,好生意,誰會投資呢?

目前這文字引擎,不會聊天,都是處理金融業務的查詢,也為了做真一點的demo,就讓他提供真的匯率(背後寫了一個定時去爬台銀匯率網頁的小爬蟲),另外也做了個圖片回覆的小功能,然後就沒了,沒時間玩了。

投影片12

現在在認真的測試聲紋辨識,希望能弄個方便的好東西出來。

WildFly as Debian 8 Service

All you have to do is create a service file at /etc/systemd/system since Debian is using systemd for service management.

Forget about copying file to /etc/init.d and /etc/defaults, they are useless for systemd.

Here is my content of /etc/systemd/system/wildfly.service

[Unit]
Description=WildFly application server
After=network.target

[Service]
Type=simple
Environment="CONFIG_FILE=standalone-full.xml"
User=wildfly
Group=wildfly
ExecStart=/opt/wildfly/bin/standalone.sh -c $CONFIG_FILE
# ExecStop=ps -ax | grep java | grep wildfly | awk {'print $1'} | xargs kill -9
[Install]
WantedBy=multi-user.target

Please note that I am using standalone-full.xml instead of standalone.xml and I was using a ExecStop script but it turns out the systemd can manage it.
I have leave it for personal note.

Aerogear

系統登入點

https://yoursite/ag-push/

後台管理登入點

https://yoursite/auth/admin/aerogear/console/index.html

Android 註冊

RegistrarManager.config("register", AeroGearGCMPushConfiguration.class)
    .setPushServerURI(URI.create(UNIFIED_PUSH_URL))
    .setSenderIds(GCM_SENDER_ID)
    .setVariantID(VARIANT_ID)
    .setAlias(ALIAS)
    .setSecret(SECRET)
    .asRegistrar();

iOS 註冊(Swift)

let device = AGDeviceRegistration(config: "pushconfig") 
// perform registration of this device
device.registerWithClientInfo({ (clientInfo: AGClientDeviceInformation!) in 
// set the deviceToken
clientInfo.deviceToken = deviceToken

// --optional config--
// set some 'useful' hardware information params
let currentDevice = UIDevice()

clientInfo.operatingSystem = currentDevice.systemName 
clientInfo.osVersion = currentDevice.systemVersion 
clientInfo.deviceType = currentDevice.model
clientInfo.Alias = currentDevice.alias

iOS 註冊(Objective-C)

AGDeviceRegistration *registration = 
[[AGDeviceRegistration alloc] initWithServerURL:
[NSURL URLWithString:@"http://YOUR_SERVER/ag-push/"]];

[registration registerWithClientInfo:^(id<AGClientDeviceInformation> clientInfo) {

[clientInfo setDeviceToken:deviceToken];
[clientInfo setVariantID:@"YOUR IOS VARIANT ID"];
[clientInfo setVariantSecret:@"YOUR IOS VARIANT SECRET"];

// --optional config--
UIDevice *currentDevice = [UIDevice currentDevice];
[clientInfo setOperatingSystem:[currentDevice systemName]];
[clientInfo setOsVersion:[currentDevice systemVersion]];
[clientInfo setDeviceType: [currentDevice model]];
[clientInfo setAlias:@"User Alias"];
} success:^() {
NSLog(@"UnifiedPush Server registration worked");
} failure:^(NSError *error) {
NSLog(@"UnifiedPush Server registration Error: %@", error);
}];

Cordova 註冊

var pushConfig = {
    pushServerURL: "<pushServerURL e.g http(s)//host:port/context >",
    alias: "<alias e.g. a username or an email address optional>",
    android: {
        senderID: "<senderID e.g Google Project ID>",
        variantID: "<variantID e.g. 1234456-234320>",
        variantSecret: "<variantSecret e.g. 1234456-234320>"
        alias: "User Alias"
    },
    ios: {
        variantID: "<variantID e.g. 1234456-234320>",
        variantSecret: "<variantSecret e.g. 1234456-234320>"
        alias: "User Alias"
    }
};

push.register(onNotification, successHandler, errorHandler, pushConfig);

WildFly 9 使用 Let’s Encrypt的憑證

先寫結論,明明WildFly 8的文件有寫可以直接用pem檔,但是所有能動的組合,都是使用Java Key Store,所以,以下是如何轉檔跟在WildFly 9的設定檔啟用的相關記錄。

  1. 把Let’s Encrypt的PEM檔轉換為PKCS12格式,在這他會要你輸入export key的密碼,輸入後請記住。
openssl pkcs12 -export -out cert.p12 -in /etc/letsencrypt/live/yoursite/cert.pem -inkey /etc/letsencrypt/live/yoursite/privkey.pem
  1. 匯入PEM,在這他會要你輸入keystore的密碼以及剛剛的export key,keystore的密碼輸入後也請記住,等等設定檔要用。
keytool -v -importkeystore -srckeystore cert.p12 -srcstoretype PKCS12 -destkeystore server.keystore -deststoretype JKS

注意:匯入後雖然 keytool -list 看的到一筆 alias: mykey ,實際上它名字是1,若你的keystore只有一筆資料,可以在WildFly的設定檔裡不指定alias,指定了alias=”mykey”反而會找不到,不然就用以下指令變更一下alias。

keytool -changealias -keystore server.keystore -alias 1 -destalias mykey

以上轉檔完畢,可以拿來用在任何需要SSL/CA的JAVA應用上。

 

在WildFly 9的設定檔裡在每個想用SSL的地方加上SSL參數,也就是這五行,為了整個網站都走HTTPS,我在ManagementRealm跟ApplicationRealm兩個security-realm都用了。
ManagementRealm

<security-realm name="ManagementRealm">
    <server-identities>
        <ssl>
            <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="keystore password" />
        </ssl>
    </server-identities>
...
</security-realm>

ApplicationRealm

<security-realm name="ApplicationRealm">
    <server-identities>
        <ssl>
            <keystore path="server.keystore" relative-to="jboss.server.config.dir" keystore-password="keystore password" />
        </ssl>
    </server-identities>
...
</security-realm>

再來把Management Interface也轉成HTTPS,在第三行把Socket-binding改成https

<management-interfaces>
    <http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
        <socket-binding https="management-https"/>
    </http-interface>
</management-interfaces>

然後把Application也啟用HTTPS,相關設定在undertow的subsystem,我增加了第五行的https-listener

<subsystem xmlns="urn:jboss:domain:undertow:2.0">
    <buffer-cache name="default"/>
    <server name="default-server">
        <http-listener name="default" socket-binding="http" redirect-socket="https"/>
        <https-listener name="default-https" socket-binding="https" security-realm="ApplicationRealm"/>
        <host name="default-host" alias="localhost">
            <location name="/" handler="welcome-content"/>
            <filter-ref name="server-header"/>
            <filter-ref name="x-powered-by-header"/>
        </host>
    </server>
...
</subsystem>

以上就把HTTPS啟用完畢。

 

WildFly 9服務預設只綁定127.0.0.1,若要啟用對外服務可以參考以下設定
注意:<any-ipv4-address/>跟<any-ipv6-address>在WildFly9已經不支援,剩下<any-address/>
同時WildFly9也支援以下格式,可以一次bind多個interface,當然”0.0.0.0″的效果跟<any-address/>一樣。

逐一指定所有要監聽的網卡

<interface name="public">
    <inet-address value="127.0.0.1"/>
    <inet-address value="192.168.1.1"/>
</interface>

直接監聽所有網卡
方法一

<interface name="public">
    <inet-address value="0.0.0.0"/>
</interface>

方法二

<interface name="public">
    <any-address/>
</interface>

支付發展二三事

大路線
從電學走到光學
因為行動設備的發展,以及美國政府受不了銀行只玩磁條。感應式行動支付在日本人玩了十幾年之後,開始大爆發,但也代表了盡頭的來臨。
現在Apple跟Google一邊跟卡組織合作,另一邊也在發展與帳戶擁有單位直接對聯的遊戲。
想想,擁有手機的人,也許擁有很多金融機構的很多支付帳戶,用起來方便嗎?
萬一,手機平台直接連動電信公司的代繳服務,這些金融帳戶,好像就不需要了吧?而Apple, Google跟這些電信巨頭的關係,比跟銀行好吧?這樣,銀行就被跳過了。

所以,從銀行的角度,要繼續佔有支付工具的發言權,下一步只好跳過行動設備,有什麼東西比行動設備更方便?人的身體。
指紋,落伍了。活體掌靜脈,太大了。活體指靜脈?答對了。
還有嗎?紅膜。
這些人身構件直接綁定一組銀行帳號。走到哪付到哪,什麼裝置都不用掏出來,夠方便吧?
這是未來,已經進行中。

TSM通訊 最初也是最終

現在寫,應該算是大勢底定,不會擋人財路。
先寫結論:TSM在台灣不會死,因為有金融卡跟金融帳戶。但信用卡就會走到HCE(很快,Android Pay),Apple Pay(還有得談)。
其實金融卡也可以走到HCE跟Apple Pay,不過這不是技術問題。

HCE對信用卡發卡銀行來說,沒有任何更動,只要把卡檔丟給唯一的代理公司(為什麼不能直接連Visa, Master呢?這又不是技術問題)。不需要TSM那一串GPS線上平台跟專門的檔案交換作業。

TSM會死最大的原因是,用戶體驗。台灣的TSM一直起不來(有技術跟政治問題),TSM公司的電子錢包又很難用(不知道為什麼一直打成電死),客戶還要去換sim卡,一整個麻煩。(不過也沒辦法,這是電信公司聯盟搞出來的規格,當然要保護電信公司的利益)。(不過這兩年前大家就都知道了,只是主管機關一直擋HCE,銀行也只能跟著政府的腳步)

至於HCE幾時會上線,等那家唯一的代理通過Visa,Master的驗證囉,驗證一通過Android Pay(Google Wallet)馬上就能開通。

那Apple Pay呢?等唯一的代理去談費率囉。

客戶關係管理 反面案例

現在開的車是本土第一大汽車廠的高級品牌。結果,反而讓我很快速的遇到低級的錯誤。
每次保養,所有服務的人員不斷的提醒客戶要給他最好、最優的評價,這一點在台灣,只要是現場有問卷會影響績效的,大家都這樣做,沒什麼。
神奇的是,某次保養完,突然想查詢某功能,就上網找,一找就出事。官方網站產品介紹的部份做的很『互動』,很『高級』,但是客戶服務的部份,就切換到初學者照書練習的等級,最重要的是,我找車主手冊。找到連結後,無法下載,直接送我web server預設的404頁面,我好心的全點一次,發現整個車主手冊頁面的所有檔案都不存在。
我好心的打電話給客服中心(客服中心吵雜的讓人很清楚知道他是附屬在某個不安靜的單位),客服人員說會通知IT,明天改好後回電。隔天下午,回電通知改好了,結果連上去一點,很抱歉,跟昨天一模一樣。
打電話回去回報,客服很專業的跟我說『我有點過,可以下載』,然後我問『你們有在外網試過嗎?』,當然沒有。然後,他要我抓畫面寄給他,照辦,結果客服不知道自己的email(代表電話跟email是兩個不同管理單位),電話上就寄給他們,結果跟我猜的一樣,email根本是不同單位,當天傍晚,系統回覆我制式回覆信。隔天,當然還是不能下載,但電話沒來,來了另一封制式通知信,告訴我已經轉交相關單位。我就做了一個小小的實驗,回信,大意是『你們效率太差,聯繫有問題,請不要再跟我聯絡』,結果一,沒有回覆的email了。結果二,三天內收到五通電話。結果三,兩週後收到專屬維修服務員的維修後care call,依然提醒我,萬一有問卷,記得給滿分。
結果三的出現,代表客服的消息,前線完全不知道。
結果二的出現,代表電子客服的消息,跟電話客服及維修後滿意度追蹤作業,也沒有同步。
結果一,算是可以預期。很容易做更好的是,在確認我的問題完整解決後,送一封信,跟我道歉說打擾,同時回報已經解決問題。

空中轉帳 去中間人(財金)

只要某家銀行願意做,這家銀行在每一家銀行都開一個戶頭。讓這家銀行的客戶在做跨行轉帳的時候不用透過財金跨行,而是在銀行的後台進行這樣的作業:
來源行,來源帳戶,目的行,目的帳戶,轉帳金額
扣來源帳戶(轉帳金額+手續費)
入GL準備金帳戶
發動由目的行端該行帳戶對目的帳戶作自行轉帳(把來源行及帳號寫入匯款附言)

轉帳完成,透過網際網路,閃過財金,銀行跟客戶都省下手續費。
財金一定會不爽,金管會呢?

不過跨行領現就難以使用這個一家銀行獨打的招式,需要大部分銀行一起用上面的招式玩。真要大家一起玩,就不用都開戶,可以直接利用同業資金調度系統作每日結算就好了。

快逃

ETC

flag_direction {N,E,W,S}
set flag_direction by the direction of 3 connected sensor door.
kick out all sensor record on reverse direction.

Intersection_Start, Intersection_End.
record intersection_Start by first sensor(direction doesn’t matter)
record intersection_Start by last sensor(direction doesn’t matter)
kick out all sensor record not between intersections and not in sequence.

kick out sensor data of same car within 20 minutes.