2016年3月15日 星期二

AWS 筆記 - 使用 CodeCommit

AWS_CodeCommit_05

雖然很習慣自己架 git server ,但基於摸熟 AWS 服務,就小試一下。整個流程很簡單,建立一個 git repo 就輸入完名稱即可建立,接著提供 SSH / HTTPS 的存取方式。而特別的地方應該是 Triggers ,可以搭配以下四種 event 觸發動作,如簡訊寫信或HTTP endpoint (AWS SNS) 或是呼叫 AWS Lambda function 做事:

AWS_CodeCommit_06

其中以 AWS SNS 為例,還必須先去 AWS SNS 建立的對應服務才行,也能 Test trigger 一下,看起來是把資料都埋在 Message 裡頭:

{
  "Type" : "Notification",
  "MessageId" : "580672ce-b036-5484-b1ca-3daf00303ba3",
  "TopicArn" : "arn:aws:sns:us-east-1:HelloWorld",
  "Subject" : "TEST: AWS CodeCommit us-east-1 push: study-codecommit",
  "Message" : "{\"Records\":[{\"awsRegion\":\"us-east-1\",\"codecommit\":{\"references\":[{\"commit\":\"0000000000000000000000000000000000000000\",\"ref\":\"refs/heads/TestReference\"}]},\"customData\":\"codecommit\",\"eventId\":\"36e338ce-a719-4188-93bb-aa6c28298a71\",\"eventName\":\"TriggerEventTest\",...}]}",
  ...
}

AWS 筆記 - 使用 Simple Notification Service (SNS)

AWS_SNS_01_home

共有 4種動作可挑選,以 Create Topic 為例,先輸入完 Topic 名稱後,可以在挑選 Subscription:

AWS_SNS_02_Subscription

以 HTTP/HTTPS 為例,就是會去 query 一個網址,而 SMS 則會寄簡訊。而 HTTP/HTTPS 也不是隨便設置完就好,還必須認證該 HTTP endpoint 是由你所擁有的,過程為:

Create Subscription -> HTTP/HTTPS -> 輸入 HTTP Endpoint -> Request confirmations -> 這時 AWS 就會發 HTTP POST 資料過去,請記得印出來,把 SubscribeURL 取出來用 -> Confirm Subscription 輸入剛剛的 SubscribeURL 即可完成驗證

這時在 HTTP endpoint 會收到 HTTP POST 資料,以 PHP 為例:

<?php

file_put_contents('/tmp/sns_check', file_get_contents('php://input'));


{
  "Type" : "SubscriptionConfirmation",
  "MessageId" : "9f5f6846-5227-4ef9-b94d-c172ef6c9c23",
  "Token" : "xxxxxx",
  "TopicArn" : "arn:aws:sns:us-east-1:HelloWorld",
  "Message" : "You have chosen to subscribe to the topic arn:aws:sns:us-east-1:HelloWorld.\nTo confirm the subscription, visit the SubscribeURL included in this message.",
  "SubscribeURL" : "https://sns.us-east-1.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:us-east-1:HelloWorld&Token=xxxxx
",
  ...
}


若一直沒有去做驗證,會一直卡在 PendingConfirmation 狀態,而沒確認的將於三天後自動刪除。

最後,也可以在AWS SNS介面上發動通知事件(Publish a message),以 raw format 為例,填寫的資料會出現在 Message 中:

AWS_SNS_05_Publish_message

若輸入的 raw = yoyo 字眼,那 HTTP endpoint 收到的 HTTP Post 資料為:

{
  "Type" : "Notification",
  "MessageId" : "f737bee7-7567-5f29-b230-f186ddaa84cc",
  "TopicArn" : "arn:aws:sns:us-east-1:HelloWorld",
  "Subject" : "haha",
  "Message" : "yoyo",
   ...
  }
}

2016年3月12日 星期六

Android 開發筆記 - 使用 Android Studio 和 ViewPagerIndicator

上網亂找一下,大家好像還滿推四年前就沒再更新的 ViewPagerIndicator ,且很猛的共有超過 7k 的人關注,接近 4k 的人 fork 了此專案:https://github.com/JakeWharton/ViewPagerIndicator

總之,為了之後的維護管理,還是老樣子繼續練 Android Studio!添加額外第三方時,因為此 project 已經很久沒更新了,所以要採用下述安裝法:

build.gradle (Project):

allprojects {
repositories {
maven { url "http://dl.bintray.com/populov/maven" }
mavenCentral()
}
}


build.gradle (app):

dependencies {
// https://github.com/JakeWharton/ViewPagerIndicator/releases , 2012/09/13: 2.4.1
compile 'com.viewpagerindicator:library:2.4.1@aar'
// 預設的 Android Studio 環境應該不會使用下述,若仍有問題再開啟吧
//compile 'com.android.support:support-v4:23.2.0'
}


接著在 content_main.xml (若其他 layout) 添加 com.viewpagerindicator.* 系列程式碼,並且要配置 android.support.v4.view.ViewPager 才行:

    <com.viewpagerindicator.TabPageIndicator
        android:id="@+id/indicator"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent"
        />
    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        />


最後在 Activity 初始化:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewPager mViewPager = (ViewPager)findViewById(R.id.pager);
        mViewPager.setAdapter(new PagerAdapter() {
            @Override
            public int getCount() {
                return 0;
            }

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return false;
            }
        });

        TabPageIndicator mTabPageIndicator = (TabPageIndicator)findViewById(R.id.indicator);
        mTabPageIndicator.setViewPager(mViewPager);
}


以上是先滿足編譯跟執行需求,至於 TabPageIndicator 真的要怎樣用就不在此贅述了。

2016年3月9日 星期三

Bash 筆記 - 變數的字串取代方法(餵給 sed 關鍵字的前置處理)

這個需求是這樣的,想要用 sed 來取代檔案中的資料,但用 sed 查詢資料時,又需要處理 pattern 字串,例如想把檔案內所有 "http://127.0.0.1:8000" 的關鍵都取代成 "/"

這時用 sed 的指令就變成 sed 's/http:\/\/127\.0\.0\.1:8000/\//' filename,變得有點不方便,所以就想到有沒有在餵給 sed 指令前,把字串處理一下來避開 sed regular expression 的用法,找了一下,頗方便:

#!/bin/bash

keyword=$1

keyword =${keyword//\//\\\/};
keyword =${keyword//-/\\-};
keyword =${keyword//\./\\.};

cmd="sed 's/$keyword/\//' filename"

echo $cmd
eval $cmd


其中 Bash 裡的字串,要做取代的方式:

#只處理一次取代
keyword=${keyword/OldPattern/NewPattern}

#處理全部處代
keyword=${keyword//OldPattern/NewPattern}


收工!

2016年3月6日 星期日

Android 開發筆記 - 在 Android NDK/JNI 環境中,操作 HashMap 和 Vector 方法與資料型態定義

過去在 C++ 把玩 std::vector<std::unordered_map<int, std::string>> ,而搬到 Java 環境中時,就會出現檔案形態的轉變,於是乎就先挑個 Vector<HashMap<String,String>> 來試試,順手筆記一下。

其中 JNI 在呼叫 Java 物件時,Java 八大型態及 Java Class 型態在 JNI 中採用的關鍵字:

Java boolean type => "Z"
Java byte type => "B"
Java char type => "C"
Java short type => "S"
Java int type => "I"
Java long type => "J"
Java float type => "F"
Java double type => "D"
Java object type => "Ljava/lang/Object;"
Java Array of int type => "[I"
Java Array of double type => "[D"
Java Array of java/lang/Object type => "[Ljava/lang/Object;"


舉例來說,以 Vector 的 public boolean add(E e) 函數為例:

jclass vectorClass = env->FindClass("java.util.Vector");
jmethodID vector_add = env->GetMethodID(vectorClass, "add", "(Ljava/lang/Object;)Z");


其中 "(Ljava/lang/Object;)Z" 代表此函式回傳為 boolean 型態,而需要傳遞一個 java/lang/Object 當作參數。

最後是比較冗長的操作:

Java code:

static {
System.loadLibrary("test")
}
public native boolean test(Vector<HashMap<String, String>> obj);

void usage() {

Vector<HashMap<String, String>> output = new Vector<HashMap<String, String>>();
boolean ret = test(output);
Log.i(tag, "Ret: "+ret+", output size: "+output.size());
}


build.gradle (Module:app):

android.ndk {
moduleName = "test"
ldLibs.addAll(["log"])
CFlags.add("-std=c++11")
stl = "c++_shared"
}


C/C++ code:

#include <jni.h>
#include <android/log.h>

#define LOG_TAG "JNI"
#define LOGV(...)__android_log_print( ANDROID_LOG_VERBOSE,LOG_TAG, __VA_ARGS__ )
#define LOGD(...)__android_log_print( ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__ )
#define LOGI(...)__android_log_print( ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__ )
#define LOGW(...)__android_log_print( ANDROID_LOG_WARN,LOG_TAG, __VA_ARGS__ )
#define LOGE(...)__android_log_print( ANDROID_LOG_ERROR,LOG_TAG, __VA_ARGS__ )

extern "C" {


jboolean Java_YourPackageName_test(JNIEnv *env, jobject thiz, jobject vectorObject) {

jclass vectorClass = env->GetObjectClass(vectorObject);
jmethodID vector_size = env->GetMethodID(vectorClass, "size", "()I");
jmethodID vector_add = env->GetMethodID(vectorClass, "add", "(Ljava/lang/Object;)Z");
jmethodID vector_elementAt = env->GetMethodID(vectorClass, "elementAt", "(I)Ljava/lang/Object;");

jclass hashMapClass = env->FindClass("java/util/HashMap");
jmethodID hashMap_init = env->GetMethodID(hashMapClass, "<init>", "(I)V");
jmethodID hashMap_put = env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
jmethodID hashMap_get = env->GetMethodID(hashMapClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
jmethodID hashMap_size = env->GetMethodID(hashMapClass, "size", "()I");

std::unordered_map<int, std::string> attrs;
attrs[0] = "Hello";
attrs[1] = "World";

if (vectorObject && vectorClass && hashMapClass) {
// init HashMap object
jobject dataHashMap = env->NewObject(hashMapClass, hashMap_init, 1);
for (auto it = attrs.begin(); it != attrs.end(); ++it) {
jstring key = env->NewStringUTF(std::to_string(it->first).c_str());
jstring value = env->NewStringUTF(it->second.c_str());
env->CallObjectMethod(dataHashMap, hashMap_put, key, value);
env->DeleteLocalRef(key);
env->DeleteLocalRef(value);
}
LOGI("hashmap size: %d", env->CallIntMethod(dataHashMap, hashMap_size));

LOGI("vector size: %d", env->CallIntMethod(vectorObject, vector_size));

// vector add
env->CallBooleanMethod(vectorObject, vector_add, dataHashMap);
env->DeleteLocalRef(dataHashMap);

// access vector
for (int i=0, cnt = env->CallIntMethod(vectorObject, vector_size) ; i<cnt; ++i) {
LOGI("get vector_elementAt: %d", i);
if (vector_elementAt) {
jobject dataInVector = env->CallObjectMethod(vectorObject, vector_elementAt, i);
jclass dataInVectorClass = env->GetObjectClass(dataInVector);
jmethodID dataInVector_get = env->GetMethodID(dataInVectorClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
if (dataInVector && dataInVector_get) {
jstring key = env->NewStringUTF(std::to_string(0).c_str());
jstring value = (jstring)env->CallObjectMethod(dataInVector, dataInVector_get, key);
LOGI("get vector_elementAt: %d, value: [%s]", i, value);
env->DeleteLocalRef(key);
}
}
}

}


return false;
}

}