程式碼高𠅙

2018/08/07

Firefox 網頁黑化擴充套件

黑色主題 (或稱夜間模式、深色模式、暗黑模式等) 的網站不但可降低視覺壓力,減少裝置耗電,更能營造一股駭客風格,是近來使用介面設計的流行趨勢。較具代表性的,像是 Youtube 及 Twitter 就各自為自己的網站加入深色模式及夜間模式。

而對於那些沒有支援黑色主題的網站,則可使用本文介紹的瀏覽器擴充套件來達到網頁黑化效果。以下介紹一些筆者曾經使用或試用過的 Firefox 網頁黑化擴充套件。

Dark Reader






在 Windows 底下配色切換效果良好,幾乎大部分的網站不太需要調整就能正常顯示。

但在 Android 底下不知為何無法正常套用--Ok! 後來查出原因是因為筆者在 Android Firefox 中使用了 User Agent Switcher 套件,更改了瀏覽器的 user agent 字串,而與 Dark Reader 相沖突。不過其實好奇的是背景反黑為何要偵測 user agent 字串啊!

可以針對每個網站設定套用深色配色、淺色配色,或是不配色。

配色的演算法內建有三種,還有一種讓您可以對每個網站套用自己的 style,這個功能可用來取代 stylish/stylus 等自訂網頁樣式元件。

不過可惜的是它的網站客製化 style 只能套用到 domain 層級,似乎是沒法對每個網站的子目錄撰寫自訂樣式。

Dark Background and Light Text





在更換為 Dark Reader 之前,原本是用這個套件,配色切換的效果也是很好,甚至可能是同類套件中最好的。

它也能對每個網站選用以下方式客製化:

  • Disabled - 不使用
  • Stylesheet processor
  • Simple CSS
  • Invert
  • Default


因 Dark Reader 在 Android Firefox 上無法正常執行,目前 Android Firefox 上仍是使用這個外掛。

要論這個套件有什麼缺點 ,其一是在 Chrome 上沒有相對的元件。

而其二… 應該是這個元件的 UI 做的比較醜一些,這是比較可惜的地方。


Midnight Lizard – Add-ons for Android





這曾經是我的最愛。設定畫面漂亮,客製化功能最強的網站樣式修改元件。

可惜網頁載入速度慢,CPU loading 高,且程式碼 syntax 語法未正常高亮,google calendar 未正常顯示,所以還是捨棄!

Dark Mode (WebExtension)




這個套件提供很多配色方案讓人選擇,經測試,不同的方案只是呈現的字型或背景色調略有不同,轉換異常的地方,套用不同的配色方案後經常還是異常。

而且配色方案並不能針對各別網站進行配置,而是所有網站共用同一種。所以假定 A 網站適合用甲方案呈現,而 B 網站適合乙方案呈現,那當由 A 網站切換到 B 網站瀏覽時,還得自行切換相對應的樣式,使用相當不便。

這個套件提供白名單的機制,讓無法正常套用配色的網站避免反黑,針對個別網站的客製化能力,也僅止於此了!

結論

目前筆者在桌機上,是使用 Dark Reader,因其 UI 較美觀,轉換效果不錯。但網路上有用戶反應 Dark Reader 會影響網頁載入效能,筆者在使用時,偶爾的確也會遇到瀏覽器提示 Dark Reader 的 Javascript 影響網頁載入速度。但因尚可忍受,也就繼續使用了。Dark Reader 另有 Chrome 版本,是個跨瀏覽器的套件。

Android Firefox 可使用擴充套件,所以還是可以透過擴充套件使網頁黑化,這是 Chrome Android 版所沒有的功能。在 Android 上筆者是採用 Dark Background and Light Text 這個套件。相較 Dark Reader,它在 Android 中執行效能較高,黑化的效果與 Dark Reader 難分軒輊!

如果網友想在 Android Firefox 中想使用 Dark Reader 套件,那記得避免使用 User Agent Switch 相關套件,並將 Dark Reader 的預設主題生成模式改成 "過濾+",如此才能使 Dark Reader 正常運作,並得到較佳效能。

2014/09/03

原來使用 Postgresql 就可以直接查詢文字或 CSV 檔案

有些時候,我們會需要處理資料內容龐大的文字檔案,我們可能想要先略微檢視資料內容,了解資料分佈,或做些過濾查詢的動作,當然把資料先匯入 Database 再進行處理是一個可行的方案,但如果資料量龐大到數十 GB,那麼光是匯入資料的時間,以及資料匯入 DB 後產生的資料澎漲就足以令人怯步。

要想維持文字或 CSV 檔案的簡便性,又想擁有資料庫查詢的方便性,可以透過 Postgresql Foreign Table for File 的功能來達成。簡單來說,Postgresql 的 Foreign Data Wrappers 能讓您包裝其他資料來源,然後透過一個集中的資料庫來操作,而這也就是 Federated Database 的觀念。



當我們在 Federated Database 下達 SQL 指令時,中央控管的 SQL 會透過 ANSI SQL 2003 的標準 SQL/MED (Management of External Data),將 SQL 指令進行拆解,交付各個外部資料來源 (或資料庫) 來執行。最後再由中央控管的資料庫,將資料匯集起來傳給使用者。詳情可參考底下兩個連結:
Postgresql 的 Foreign Data Wrappers 實際上是 Postgresql 資料庫的 Extension,其中 file_fdw 在 Postgresql 9.1 之後的版本已內建,可讓我們把外部的文字或 CSV 檔案,變成是 Postgresql 的 FOREIGN TABLE。筆者進行測試的版本為 Postgresql 9.3 版。

為了示範,請到 http://data.gov.tw/node/8792 下載 "每日各站點進出站人數.csv" 檔案。完成下載後將檔名更改為 stationflow.csv。

接下來以 pgAdmin 執行以下 SQL:
CREATE EXTENSION file_fdw;
CREATE SERVER file_fdw_server FOREIGN DATA WRAPPER file_fdw;
CREATE FOREIGN TABLE stationflow (
yyyymmdd  char(8),
stationcode  integer,
stationname  varchar(5),
input   integer,
output   integer
) SERVER file_fdw_server
OPTIONS (format 'csv', header 'true', filename 'D:/testdata/stationflow.csv', delimiter ',', null '');
這裡 filename 參數用來指向我們剛剛下載、更名的 stationflow.csv,可能需要修正目錄的正確性。

注意,目前 pgAdmin 並不會把 FOREIGN TABLE 顯示在左方的樹狀節點中,因此若要查詢系統中有哪些 FOREIGN TABLE, 可以執行以下指令:

select * from information_schema.tables where table_type = 'FOREIGN TABLE'
如果在此時執行 SQL, 如:
select count(*) from stationflow;
那應該會收到 Postgresql 提示的 UTF8 編碼錯誤的訊息。這是因為檔案其實是以 Big5 編碼,我們可以使用以下指令修正 FOREIGN TABLE 的檔案編碼:
ALTER FOREIGN TABLE stationflow OPTIONS ( encoding 'Big5' ); 
完成之後,您便可以正常執行 SQL 操作:
select count(*) from stationflow;
select * from stationflow where stationname like '台東%'; 
如果你有內部資料表,甚至可以來個內外 Join, Union 或 Sub-Query 等等:
select * from stationflow where stationcode in (select id from stationlist ); 
測試完成後,可用以下指令刪除外部資料表:
drop FOREIGN table stationflow;
這篇文章僅展示了 Postgresql 查詢文字或 CSV 檔案的功能,事實上 Postgresql 可以外接的資料來源還很多,包括 SQL Database、NoSQL Database、Http、Twitter、Hadoop 等,有興趣的同學可以自行至 PostgreSQL Extension Network 下載編譯測試。

2014/06/18

Java: JSON Library

Below is a list of major JSON format processing libraries for java. Check it out.

  • JSON Processing
    • Summary
      • JSR 353: Java API for JSON Processing - Reference Implementation
    • Comment
      • the java version official implementation
  • JSON in Java (json.org)
    • Summary
      • json.org official implementation
    • Comment
      • The API requires you to load the entire document into a String. This is somewhat cumbersome to use and inefficient for large documents. But it's a DOM model so you can get a lot done with very little code. 
  • Jackson JSON Processor
    • Summary
      • High-performance JSON processor.
    • Comment
      • Jackson ones to be the fastest json processing library in the old age.
      • Has many features with modules approach.
      • Jackson has grown into a huge collection of data type processing library
  • Boon JSON
  • google-gson 
    • Summary
      • A Java library to convert JSON to Java objects and vice-versa
    • Feature
      • Provide simple toJson() and fromJson() methods to convert Java objects to JSON and vice-versa
      • Allow pre-existing unmodifiable objects to be converted to and from JSON
      • Extensive support of Java Generics
      • Allow custom representations for objects
      • Support arbitrarily complex objects (with deep inheritance hierarchies and extensive use of generic types)
  • json-simple
    • Summary
      • JSON.simple is a simple Java toolkit for JSON. You can use JSON.simple to encode or decode JSON text. 
    • Feature
      • Full compliance with JSON specification (RFC4627) and reliable (see compliance testing)
      • Provides multiple functionalities such as encode, decode/parse and escape JSON text while keeping the library lightweight
      • Flexible, simple and easy to use by reusing Map and List interfaces
      • Supports streaming output of JSON text
      • Stoppable SAX-like interface for streaming input of JSON text (learn more)
      • Heap based parser
      • High performance (see performance testing)
      • No dependency on external libraries
      • Both of the source code and the binary are JDK1.2 compatible
    • Comment
  • genson - A fast & extensible Java <> Json library
    • Summary
      • Genson is an open-source library doing conversion from Java to Json and Json to Java. Genson targets people who want an extensible but also configurable, fast, scalable and easy to use library. 
    • Feature
      • Easy to use, fast, highly configurable, lightweight and all that into a single small jar!
      • Full databinding and streaming support for efficient read/write
      • Support for polymorphic types (able to deserialize to an unknown type)
      • Does not require a default no arg constructor and really passes the values not just null, encouraging immutability. It can even be used with factory methods instead of constructors!
      • Full support for generic types
      • Easy to filter/include properties without requiring the use of annotations or mixins
      • You can apply filtering or transformation logic at runtime on any bean using the BeaView mechanism
      • Genson provides a complete implementation of JSR 353
      • Starting with Genson 0.95 JAXB annotations and types are supported!
      • Automatic support for JSON in JAX-RS implementations
      • Serialization and Deserialization of maps with complex keys
    •  Comment
      • Looks good!
 Want to use XPath with JSON? see below.
  • Commons JXPath
    • Summary
      • The org.apache.commons.jxpath package defines a simple interpreter of an expression language called XPath. JXPath applies XPath expressions to graphs of objects of all kinds: JavaBeans, Maps, Servlet contexts, DOM etc, including mixtures thereof.  
  • json-path 
    • Summary
      • Java JsonPath implementation

2014/03/27

Java Practice: Shutdown Hook

今日 Daily Java Practice 如下,請問其中 runTime.addShutdownHook 的作用。

public class Main implements Runnable {
    public void run() {
        System.out.println("Shutting down");
    }

    public static void main(String[] arg) {
        Runtime runTime = Runtime.getRuntime();
        Main hook = new Main();
        runTime.addShutdownHook(new Thread(hook));
    }
}

2014/03/24

Java Practice: Enum

今天來玩玩 enum, 以下透過一程式,說明 enum 如何把物件導向程式的三個特質封裝、繼承跟多型完美的結合在一起。
善用 enum,可以大幅減少程式碼。
以下請說明:
  • 程式輸出訊息。
  • 為何輸出此訊息。
  • S, M, L, XL ... 與 Size 的關係,是類別跟實體的關係,還是父類別跟子類別的關係?

public class SizeIterator {
    public static void main(String[] args) {
        Size[] sizes = Size.values();
        for (Size s : sizes) {
            s.showName();
            s.showType();
        }
    }
}

enum Size {
    S {
        @Override
        public void showName(){
            System.out.println("I am too small to show to others!");
        }
    }, M, L, XL, XXL, XXXL;
    public void showName() {
        System.out.println(this.name());
    }
    public void showType() {
        System.out.println(this.getClass().getName());
    }
}

2014/03/19

Java Practice: Object Serialization

今天的 Java Practice 如下, 請服用:
  1. Coper 類別的功用為何?
  2. Coper:: <T> copyInstance(T obj) 方法使用了 Java Generic 的技巧,請解釋這裡採用型別參數的好處?
  3. main 方法中印出的兩個 User 物件,內容是否相同? 若有差異,原因為何?
abstract class Copier {
    @SuppressWarnings("unchecked")
    public static <T> copyInstance(T obj) throws IOException,
            ClassNotFoundException {
        ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
        ObjectOutputStream outStream = new ObjectOutputStream(outBytes);
        outStream.writeObject(obj);
        outStream.close();
        ByteArrayInputStream inBytes = new ByteArrayInputStream(outBytes
                .toByteArray());
        ObjectInputStream inStream = new ObjectInputStream(inBytes);
        T copied = (T) inStream.readObject();
        inStream.close();
        return copied;
    }
}

class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private Date date = new Date();
    private String username;

    private transient String password;

    public User(String name, String pwd) {
        username = name;
        password = pwd;
    }

    public String toString() {
        String pwd = (password == null) ? "(n/a)" : password;
        return "logon info: \n   username: " + username 
            + "\n   date: " + date
            + "\n   password: " + pwd;
    }
}

public class CopierTest {
    /**
     * @param args
     * @throws Exception
     * @throws IOException
     */
    public static void main(String[] args) throws Exception {
        User jack = new User("Jack", "magic");
        System.out.println(jack);
        User copyOfJack = Copier.copyInstance(jack);
        System.out.println(copyOfJack);
    }
}  

2014/03/18

Java Practice: Random


練習一下使用 Java Random 類別。
以下題目,請試著寫出最後 min, max 印出來的最可能數值。
public class MathRandomTest {
 public static void main(String[] args) {
    Random rand = new Random();
   
   int n = 10;
    int min = Integer.MAX_VALUE;
    int max = Integer.MIN_VALUE;
   
    for(int i = 0; i < 100; i ++){
      int r = rand.nextInt(n + 1);
      min = Math.min(min, r);
      max = Math.max(max, r);
    }
    System.out.printf("Min = %d, Max = %d", min, max);
 }
}  

2014/03/17

Java Practice: Generics

從今天開始,預計把發給敝公司新人的 Java Practice 題目,release 在此給大家參考。Java 的初學者可以試著練習看看,老手也可溫故知新喔!

首先是 Java Generics 之應用,請在 ________ 填入正確宣告,使程式可以正常運作:
class TwoTypeParas <T,V> {
    T ob1;
    V ob2;

    TwoTypeParas(T o1, V o2) {
        ob1 = o1;
        ob2 = o2;
    }

    void showTypes() {
        System.out.println("Type of T is " + ob1.getClass().getName());
        System.out.println("Type of V is " + ob2.getClass().getName());
    }

    T getob1() {
        return ob1;
    }

    V getob2() {
        return ob2;
    }
}

public class TwoTypeParaTest {
    public static void main(String args[]) {
        TwoTypeParas______ tgObj = new TwoTypeParas______(88, "Generics");
        tgObj.showTypes();

        int v = tgObj.getob1();
        System.out.println("value: " + v);

        String str = tgObj.getob2();
        System.out.println("value: " + str);
    }
}

2013/12/16

ETL 概念、應用及工具簡介

企業裡面常有資料處理、轉換或整合的需求。好的資料管理工具雖然不一定能讓你上天堂,不好的工具卻肯定會讓你住病房。「ETL 資料轉換作業」是「資料管理」中最基礎的應用,本篇就來說說 ETL 的基本概念,它有何應用,以及市場上常見的工具。

ETL 是什麼

  • ETL 代表資料由資料來源端擷取 (Extract) 出來,經過轉換 (Transform),再載入 (Load)到目的端的資料傳輸過程。
  • Extract -- 從各種不同的資料來源中,將資料擷取出來。傳統上資料來源是來自於交易型資料庫。
  • Transform -- 對資料進行適當的轉換,如型態轉換、字串相連、彙總運算等等。這個步驟在 ETL 中不一定要執行。
  •  Load -- 將資料載入目的端;目的端通常是為了報表產製及商業智慧分析而最佳化的資料倉儲。


 

 ETL 的應用情境

  • 同步不同資料庫的資料。
  • 資料清理,移除錯誤資料。
  • 將資料載入資料倉儲以便後續分析, 如進行 OLAP 或 Data Mining 之應用。

 

使用 ETL 工具的優勢

使用 ETL 工具最大的優勢,在於可把傳統上需要透過手工方式開發的資料轉換程式碼,轉為由 ETL 工具去進行設定或設計,如此可大量減低資料轉換作業的建置時間及成本。

目前大部分開發人員還是使用自行開發的指令,來處理資料的整合作業。要透過這種方式來建立商業智慧系統,需要開發人員需具備一定的專業能力,還要費時費力的進行開發及除錯。

對於資料庫管理人員而言,若不使用外部工具,要連通不同種類的資料來源並不簡單。況且一旦外部資料來源改變,或者要加入新的資料來源,那這種勞心勞力自行開發的工作又要整個重來一次。使用 ETL 工具,將能簡化這種繁複瑣碎的工作。而良好的資料轉換流程之圖形介面設計工具,甚至可將這類操作變成樂趣。

 

ETL 工具簡介

以下來說說一些業界比較常用的 ETL 工具:

Informatica PowerCenter

  • Informatica 公司所提供的同名商業化套裝資料整合軟體。
  • 建立於 1993 年,主要業務即為資料整合。
  • 依據 Gartner Dataquest 的報告,它在資料整合領域具有最高的市占率。
  • 它提供了大量的套件供企業進行系統整合,並能連接到大量的新一代或既有的資料來源。
  • 提供良好的作業設計及監控介面,功能強大,但人員必須經過訓練才能上手。
  • 單價昂貴,顧問服務費用高。
  • 無縫整合著名的「下推優化」ELT 方法,使用資料庫的服務資源來進行資料轉換作業,效能優良,可以應用於大規模的系統。

    Pentaho Kettle (PDI)

    • Pentaho 是一家商業化的公司,約始於 2001 年,他們基於 Java 開發了一套開源 BI 套件,使用者社群人數眾多。 其中包含了一個 ETL 軟體,稱為 Kettle (或稱為 Pentaho Data Integration/PDI)。
    • 透過中介資料趨動 (metadata-driven) 的方式來設計資料轉換流程,而其使用介面功能完善且易於操作。不需像 Informatica 那樣大的前期投入。
    • 其作業設計及轉換使用了兩種腳本文件:Transformation 和 Job。Transformation 進行資料的轉換作業,以 Javascript 撰寫,Job 則用來控制整個作業流程。
    • 具有作業分派的功能 (需要一個像 cron 的分派器),可以透過分散式部署建立 Pentaho 群集,並能運行部署在 slave servers 上的遠程任務。
    • 擁有資料品質管理功能,可以撰寫自定義的 SQL 查詢,Javascript,和正則表達式。 
    • 從 4.3 版開始,改採 Apache 授權。參考 Pentaho changes ETL license for big data push -- Kettle 4.3, available under the Apache License Version 2.0, can ingest, output, manipulate and report on data from Apache Cassandra, Hadoop HDFS, Hadoop MapReduce, Apache Hive, Apache HBase, MongoDB and Hadapt’s Adaptive Analytical Platform.

    Talend

    • Talend 是一個開源碼的資料整合軟體, 大概啟始於 2006 年 10 月。
    • 採用程式碼產生器的方式來建立資料轉換作業,它將產生的 Java 或 Perl 程式碼佈署於伺服器執行。
    • 其 GUI 操作介面是建立在 Eclipse RCP 平台之上。
    • 使用者社群人數沒有 Pentaho 多,但在國外有許多商業公司進行支援。像著名的 Jaspersoft (Jasper Report 開發者) ETL 工具就是採用 Talend ETL。

    Trinity

    • Netpro 公司所出產的商業化資料管理整合軟體。
    • 包含 Data Management (即 ETL)、JCS (作業控制系統,用來排程及分派作業),以及 Metadata (管理資料源與資料轉換作業會用到的資料庫、資料表及欄位資訊) 三個部分。
    • 其最新版支援 BigData Management, 能連接到 Hadoop HDFS, Hbase 等 BigData 資料儲存體,亦能執行 Pig 與 HiveQL 操作。
    • 提供以 Web 為基礎的操作介面,資料流程設計工具及作業執行監控工具都能透過 Java Web Start 即時自網頁上即時啟動,整體配套措施相當完善。
    • 採分散式多 Agent 架構,可以簡易的 scale-out.
    • 還包含 Data Profile, Impact Analysis, Data Protection 等各種資料管理軟體,實用性相當高。

    2013/02/06

    在 2011 年版的 Mac Mini 上啟動 Linux Mint 的無線網路卡

    首先執行底下指令,確認自己的無線網路卡是 Broadcom 網路卡:

    inxi -N

    其輸出應類似如下,若不是,請另尋它法:

    Network:   Card-1: Broadcom BCM4331 802.11a/b/g/n driver: bcma-pci-bridge 
               Card-2: Broadcom NetXtreme BCM57765 Gigabit Ethernet PCIe driver: tg3
    

    1. 打開 Synaptic 套件管理員,在快速過濾的地方輸入 b43。
    2. 將 firmware-b43-installer 及 b43-fwcutter 標記為安裝,如下圖所示。
    3. 安裝完成後重新啟動系統,就能正常抓到 Wifi 無線網路了!

    2013/01/20

    Windows 8 遠端桌面連線多重登入 + Linux Client


    筆者目前在家中的使用的桌機是裝在二手 Mac-Mini 上的 Linux Mint, 雖然這台機器也有 i5 + 8G RAM, 但若想在裡面裝上五、六個 VM 跑 Hadoop, 終究也是力有未逮。

    不過家裡還有另一台硬體配備還算不差的 Windows 8 電腦 (i7-3770 CPU + 32G RAM),這台電腦本是看影片的專用機,但這樣的效能等級拿來看影片簡直是暴殄天物,便動腦筋想要充分運用這台 i7 的效能。

    希望效果

    希望達到的效果是,筆者還是使用 Linux Mint 作為主機,但透過 Windows 遠端桌面連線連到 Windows 8, 而且 Windows 8 的使用者要能 "無感" 於別人正在操作其電腦。要達到這樣的效果,必須達成兩件事:
    1. 必須讓 Windows 8 專業版可以支援遠端桌面連線多重登入。
    2. 讓 Linux Mint 可以透過 Windows 遠端桌面連線連到 Windows 8。

    讓 Windows 8 專業版可以支援遠端桌面連線多重登入

    要讓遠端電腦可以透過遠端桌面連線連到本機,得先在控制台->系統之中,開啟遠端桌面連線之設定,如 "如何開啟 Windows 8 遠端桌面連線?" 所述。 這裡有個重點,要把 "僅允許來自執行含有網路層級驗證之遠端桌面的電腦進行連線" 這個 checkbox 取消勾選,才能從 Linux 上連入 Windows 8.

    在 Google 上查詢 "Windows 遠端桌面連線多重登入", 大部分查到的資訊都是 Universal Termsrv.dll Patch 這個方式 (如 允許遠端桌面多重登入 解除遠端桌面連線多用戶同時連線的限制)。比較可惜的是,這個方式筆者試了一下,在 Windows 8 底下是不 work 的。

    在 Google 大神幫助下,找到了一個 Windows 8 Patcher 的方案,只要下載 Windows 8 Patcher.exe,並以管理員身份執行,重開機之後,便能達到以不同帳號遠端登入,而不會中斷現有使用者之操作之效果。

    在 Linux 底下透過遠端桌面連線連到 Windows 8


    這也是靠 Google 大神查來的,透過 rdesktop 這套軟體即能達到這個功能。安裝方式,如 "Linux下好用的遠端桌面連線程式:rdesktop" 所述,筆者節錄重點如下:

    安裝方式


    在命令列下執行:
    sudo apt-get install rdesktop

    執行方式

    rdesktop [IP]

    特別參數說明

    只要在命令列下達 rdesktop 不加任何參數,就會出現其參數說明:

    rdesktop: A Remote Desktop Protocol client.
    Version 1.7.1. Copyright (C) 1999-2011 Matthew Chapman et al.
    See http://www.rdesktop.org/ for more information.

    Usage: rdesktop [options] server[:port]
       -u: user name
       -d: domain
       -s: shell
       …
    筆者在命令列裡面是這樣下的:
    rdesktop -d WINDOWS主機名稱 -u 使用者名稱 -p - -r sound -f WINDOWS主機IP
    其中參數說明如下:
    • -u: 使用者名稱
    • -d: 使用者帳號的 domain,如果不加 -d 參數,則預設會以 MicrosoftAccount 做為登入 domain;MicrosoftAccount 其實就是 MSN 註冊帳號
    • -p: 密碼 (- to prompt)
    • -g: 視窗大小 (寬x高)
    • -f: 全螢幕模式,這個參數不能與 -g 同時使用
    • -r: 重定向遠端的特定功能,sound 代表要把遠端桌面的聲音重導回本機

    實際效果

    最後來看看實際的效果,筆者就在 Linux Mint 透過以上命令列連上 Windows 8. 在 Windows 8 中瀏覽 Youtube 網站,試試聲音重導的效果。

    哇哈哈,聲音真的跑到本機上來了。而令人感動的是,Windows 8 那台機器的主人還在看後宮甄嬛傳,影像跟聲音一切正常,完全感覺不到,筆者正在背景裡看 Youtube!



    對了,現在 Windows 8 遠端桌面連線是在全螢幕模式,該怎麼退出或切換到 Linux 上的其他視窗呢? 原來只要按下 Ctrl + Alt + Enter,就能離開全螢幕模式。

    呃… 是誰說要在裡面裝上五、六個 VM 跑 Hadoop,怎麼這會兒看起 Youtube 了… XD

    2012/12/28

    ETL 與 ESB 之異同與整合應用

    因為自己開發 ETL 相關產品,加上之前對 ESB 與 SOA 也有接觸,那就來聊聊這兩個東西有什麼關連吧!

    ETL 全名是 Extract, Transform, Load, 是指資料搬移過程中,從來源資料庫擷取 (Extract)、經過資料轉換 (Transform),再載入 (Load) 到目標資料庫的過程。通常會用商業智慧資料分析的資料準備階段,資料從前端的交易性資料庫,透過 ETL 軟體導到資料倉儲,再交給 OLAP、報表或資料探勘工具做進一步分析。

    而 ESB 全名是 Enterprise service bus,這是一種企業應用程式的中間層軟體,可以讓不同的應用程式系統,透過 ESB 所提供的開放式介面,彼此介接,達成訊息與應用整合的目標。ESB 是 SOA 服務導向架構在企業部署應用中,比較容易上手的解決方案。打個廣告,個人在 2006 年曾為 ITHome 撰寫的三篇 SOA 專欄文章:

    雖然已經有點過時,不過裡面所談到的 ESB 跟 SOA 的觀念,還是具有參考價值。我再找個時間來更新這部分的資料好了! 

    好了,談到這裡,那 ETL 與 ESB 有任何關係嗎? 也許有些人會覺得我是不是聯想力太豐富了,才會覺得這兩者有關。嘿! 它們還真的有點關係呢!

    前面所說,ESB 是一種企業應用程式的中間層軟體,用來整合應用,或交換訊息。而事實上,我們也可以把 ETL 看成是另一種中介軟體,但它所介接的兩端,不是應用系統,而是資料來源與目的端。這裡我用中介軟體,而沒講它是 Middleware, 是因 Middleware 有比較嚴謹的定義。可是實際上,如果從 Middleware 定義:"Middleware makes it easier for software developers to perform communication and input/output, so they can focus on the specific purpose of their application." 來講,ETL 軟體也的確具有這樣的功能。

    也就是說,基本上各種中間層軟體,都具有能讓介接兩端的系統,透過中間層軟體介面,達到彼此間獨立演進,又能統合在一起,彼此協作。ESB 是這樣的系統,ETL 其實也有這樣的特色。

    再來談談不同的部分。首先,ETL 通常具有主動性,透過排程,去資料來源抓取資料。但 ESB 通常是被動的,等待應用程式呼叫,才進行訊息的傳輸與 routing. 不過這一點並不絕對,現在的 ETL, 有些也採取 Event Trigger 的方式來設計。例如,當檔案內容發生改變時,觸發 ETL 作業過程。這種作業方式跟 MOM (Message-oriented middleware) 在收到訊息時進行資料傳輸的行為模式很類似。

    第二點,ETL 所傳輸的資料,通常包含多筆記錄,是屬於 table 或 collection based 的方式在傳輸資料。而 ESB 所傳輸的資料,通常是一個 remote procedure call 或是一個訊息等;是屬於 message 或 document based 的。這點也沒有絕對,因為 ETL 事實上也可以只傳一筆資料,而 ESB 事實上也可以一次傳輸多筆資料。不過就效能上來講,當然 ETL 在傳輸大是資料時,速度應該會較快。這跟架構有關,就先點到為止。

    第三點,是關於服務執行一次轉換或呼叫的時間,英文可稱為 session 吧。通常 ETL 因為一次會傳輸與轉換的量資料,所以執行一次轉換的時間會較久。而 ESB 單一訊息通常資料量不大,因此呼叫時間較短。

    最後則是呼叫或資料傳輸的方式,因為傳統上與 ETL 介接的都是資料庫系統,資料被取出之後,來源資料庫並不會等整個 ETL 過程結束等待回應,再去進行什麼操作。但 ESB 視其中介的性質,可能有不同的呼叫或等待回應方式,例如 SCA 裡面就定義了底下幾種方式:
    • Request response interaction
    • One-way interaction
    • Conversational interaction
    • Callback interaction 
    這些應用系統與 ESB 中間層軟件之間豐富的互動性,是傳統 ETL 軟件較缺乏的 (不過傳統上兩者用途本就不同)。


    前一陣去一某家公司拜訪,他們要導入某大廠的 ESB 系統,做跨事業部門的系統整合。除了各獨立的應用程式要能整合應用外,另一個需求就是以前不同事業單位,分散在各地的區域性資料庫,之後要能進行資料匯整,放到一個中央控管的整合資料庫。這時,若能在規劃中,加入 ETL 的應用,必然會使整個系統的開發更為順利。

    以上情境,當然 ESB 與 ETL 是可以分別採用不同的系統。不過筆者在想的是,住後以雲端為主的應用時代來臨,這兩者都必須要能朝雲端架構演進,甚至統整成為同一個系統,因為以後的應用情境很有很可是前端資料讀取的介面,採用 ESB 的訊息接收模式,而後端則採用 ETL 直接將訊息進行拆解,轉化,載入到 data warehouse 或 hadoop 分析平台之中。因此這兩種應用若能更密切的整合,系統開發跟維護心力就可大幅降低。

    而甚至資料傳輸樣式也超出傳統 ETL 或 ESB 的 message 或 collection based 的方式,而是如新一代的,streaming based 的資料串流,資料從不間斷的產生,永不止息(如 twitter)。如果有一套系統,只要透過組態或圖形化介面方式,就能設計出足以處理這種新的訊息型態的資料流程,那無異是即時訊息處理上的一把神兵利器。且讓我們拭目以待吧!



    2012/09/14

    你所想像不到的 Javascript

    /**
     * 這是一篇我在 N 年前所寫的 Javascript 教材,近來隨著 Node.js 及 Mobile web 
     * 的熱潮興起,Javascript 又再度走紅,因此再把它重新發佈,希望能對用到的人
     * 有所幫助。
     */
     
    這不是一篇教你如何在網頁中應用 JavaScript 的教材。這是一篇讓你明瞭看似簡單的 JavaScript,其實其核心語法功能強大。我將在這篇文章中說明 JavaScript 物件導向的特性,並說明如何透過這些特性,達到傳統程式語言 (C++/Java) 所難以完成的功能。
     
    Written by Edward Hsieh/謝鎮澤
     
    January 04, 2002 -- 1st Edition
    January 04, 2009 -- 2nd Edition
     
    Object and JavaScript
     
    一般談到 Object-Oriented,皆會提到物件導向語言必須具有的三個特性,即封裝、繼承及多型。這三種特性中,若缺少了繼承的特性、則稱為 Object-Based。
     
    Javascript 與其說是物件導向語言,倒不如說它是以物件為基礎的程式語言,但它極為動態的程式設計風格,卻能模擬出物件導向的特性。這種作法與大家所熟悉的,以類別 (class) 為基礎的靜態物件導向語言大不相同。
     
    在 Javascript 中有五種基礎的物件型態,包含 undefined, object, boolean, number, 以及 string。以下的範例可供驗證這五種基礎型態:
     
    alert (typeof(X));
    alert (typeof(null));
    alert (typeof(true));
    alert (typeof(123));
    alert (typeof('abc'));
     
    除了上述五種基礎類型,使用者還可自訂型態,而這些自訂的型態,都是「以物件為基礎」的。
     
    Create Objects in JavaScript
     
    在 Javascript 中建立物件的方法相當簡單。直接看個例子:
     
    var main = new Object;     // 建立新物件
    main.x = 123; // 設定物件成員變數(屬性)之一
    main["y"] = "XYZ"; // 設定物件成員變數(屬性)之二
    alert(main["x"]); // 取得物件屬性並輸出
    alert(main.y);    
     
    可以看到在 JavaScript 中,main.x 與 main["x"] 這兩種語法是通用的。其實在其他語言中,這兩種表示法的語意並不相同。我稍後再作說明。
     
    List All Members in an Object
     
    這是 JavaScript 的必殺技,使用 JavaScript 的人務必要學會這個技巧。底下函式可以傳回一個物件的所有成員的字串表達式,包括物件中的屬性及方法。在物件導向程式設計中,這種技術叫 reflection。
     
    function listMember(main) {
       var s = "";
       for( key in main ) // 使用 in 運算子列舉所有成員
       s += key + ": " + main[key] + "\n";
       return s;
    }
     
    範例碼中的 key 會對應到物件中的屬性名稱,如 "x" 或 "y",而 main[key] 則對應到屬性值。
     
    說這項技巧是必殺技的原因是,你可以透過這項技巧,將物件封裝的黑箱打開來,看看裡面藏有什麼東西。我常用這項技巧來看看 IE 與 Mozilla 的 DOM 物件模型有何不同。試試看下面呼叫範例,就可以知道這項技巧的強大了:
     
    var ary = [123, "abc"];
    alert (listMember(ary));
    alert (listMember(document.location));
     
    Construct Object with Initial Value
     
    要在建立物件的同時指定物件初始值,必須先透過 function 建立一個「原型物件」(或稱為 constructor),再透過 new 運算子建立新物件。例如以下程式碼會建立一個二維陣列的原型,再產生一個新的二維物件。
     
    function Array2DVar(x,y) {     // 定義二維陣列原型
       this.length = x;
       this.x = x;        // x 維度長度
       this.y = y;        // y 維度長度
       for(var i = 0; i < this.length; i++)  // 初始各元素值為 null
       this[i] = new Array(y);    // this 代表物件本身
    }
     
    var a2dv = new Array2DVar(10, 10);   // 建立新的 10*10 的二維陣列
    a2dv[1][3] = "ABC";       // 設定二維陣列元素值
    a2dv[2][6] = "XYZ";
    a2dv[9][9] = 1000;
     
    alert( a2dv[1][3]);  // 取得二維陣列元素值,並顯示出來
    alert( a2dv[2][6]);
    alert( a2dv[9][9]);
     
    Initial Array Object
     
    在 JavaScript 中陣列也是物件 (其實近代多數語言中陣列也都是物件,只有像 C 或 Assembly 這類古老的語言才不把陣列看成物件),因此也可以用 constructor 的語法來建構。當然 JavaScript 還提供了 [] 語法,以更方便建構陣列,範例如下:
     
    a = new Array("abc", "xyz", 1000); // constructor 語法,或
    a = ["abc", "xyz", 1000]; // 陣列標準語法
     
    陣列的元素可以是簡單的資料、其他物件,或是函數。舉個例子來在陣列裡面放函式:
     
    b = [ // 使用函式作為陣列元素
       function () { alert("這個好玩!") },
       function () { alert("再按一次離開!") },
       function () { alert("再來一次!") },
       function () { alert("最後一次!") }
    ];
     
    for (var i = 0; i < b.length ; i++)
       b[i]();
     
    最後一個 for 迴圈是個有趣的應用。由於 b 陣列中現在存放的所有元素都是函式,因此我們可以對 b 的每個元素進行呼叫。
     
    Object as Association Array
     
    關連陣列 (Assocation Array) 又稱作 Map 或 Dictionary,是一種物件容器,其中可以放置許多的 key-value pair,以存取子物件。在 JavaScript 中,物件本身就可以作為關連陣列。以關連陣列的方式初始化物件的範例如下:
     
    obj1 = {"a" : "Athens" , "b" : "Belgrade", "c" : "Cairo"};
    alert(obj1["a"]); // 顯示 Athens
     
    obj2 = {
       name: "Edward",
       showName: function() { alert(this.name); }  // 使用函式作為物件屬性
    }
     
    obj2.showName();  // 顯示 Edward
    obj2.age = 23; // 屬性可以動態加入
     
    其中 obj1 儲存了三個子元素,其鍵 (key) 為 "a", "b" 與 "c",而值 (value) 為 "Athens", "Belgrade" 與 "Cairo"。obj2 中 showName 鍵所對應的值為 function,因此 obj2.showName() 即為函式呼叫。
     
    Object as Return Value
     
    雖然 Javascript 的函式只能傳回一個變數,但你卻可以將傳回值設定為物件,達到傳回 1 個以上變數值的效果:
     
    function a () {
       return [32, 17];
    }
     
    b = a();
    alert( b ); // 或
    alert(a());
     
    function pixel () { return {"x": 32, "y":17}; }
     
    point = pixel (); alert (point.x + "n" + point.y); // 或 alert (pixel().x + "n" + pixel().y);
     
    Delegation Function Object
     
    函式也是物件,只是其中包含的是程式的邏輯。這項特性可拿來作為委任式的程式設計,亦即使用委任函式當作另一函式的參數:
     
    function doloop(begin, end, func) { // 這個函式是個 iterator
       for (var i = begin; i < end; i++) {
           func(i);
       }
    }
     
    function func1(i) { // 印出 ** n **
       document.writeln("** " + i + " **");
    }
     
    doloop(1, 10, func1); // 印出 1o 行 ** n **
     
    doloop(20, 29, function(i) { // 印出 10 行 ## n ##
       document.writeln("## " + i + " ## ");
    });
     
    Object = Properties + Behaviors
     
    古有明訓:程式 = 資料結構 + 演算法。而物件是建構程式的基本單位,自然的具有相同的性質。物件除了有屬性 (property),也可具有操作 (behavior),也就是函式。
     
    假如我們要使用一維陣列來模擬二維陣列,那麼就無法使用 ary[x][y] 這種表示法來設定或取得陣列成員。不過我可以定義一個 set 方法來設定成員變數,而以 get 方法來取得成員變數值。原型函式定義如下:
     
    function Array2D(x,y){      // 以一維陣列模擬二維陣列的原型物件
       this.length = x * y;      // 陣列總長
       this.x = x;         // x 維度長度
       this.y = y;         // y 維度長度
       for(var i = 0; i < this.length; i++)  // 初始各元素值為 null
           this[i] = null;
       this.get = function(x,y){      // 成員函式:取得陣列第 [x,y]個元素值
          return this[x*this.x + y];
       }
        
       this.set = function(x,y,value){  // 成員函式:設定陣列第 [x,y] 個元素值
       this[x*this.x + y] = value;
    }
    }
     
    我們接著來使用它:
     
    var a2d = new Array2D(10, 10);    // 建立新的「二維」陣列
     
    a2d.set(1, 3, "ABC");   // 設定「二維」陣列元素值
    a2d.set(2, 6, "XYZ");
    a2d.set(9, 9, 1000);
     
    alert( a2d.get(1,3) );  // 取得「二維」陣列元素值,並顯示出來
    alert( a2d.get(2,6) );
    alert( a2d.get(9,9) );   
     
    Member Function Outside of Constructor
     
    我們也可以將物件成員函式寫於原型物件之外。以下的 Array2D 物件與上一個範例中的 Array2D 物件有相同的作用,只不過這次是寫在原型物件之外。
     
    function Array2D(x,y){      // 以一維陣列模擬二維陣列的原型物件
       this.length = x * y;      // 陣列總長
       this.x = x;         // x 維度長度
       this.y = y;         // y 維度長度
       for(var i = 0; i < this.length; i++)  // 初始各元素值為 null
           this[i] = null;
       this.get = Array2DGet; // 用這種方式把成員函式掛進來
       this.set = Array2DSet;
    }
     
    function Array2DGet(x,y){      // 成員函式:取得陣列第 [x,y] 個元素值
    return this[x*this.x + y];
    }
     
    function Array2DSet(x,y,value){    // 成員函式:設定陣列第 [x,y] 個元素值
    this[x*this.x + y] = value;
    }
     
    Dynamic Object Function
     
    這裡說明如何為一個已定義物件,動態的加上其他操作的方法。
     
    如果一物件已定義完成,而您也使用它來建立了新的物件,這時候您想為原型物件增加新的操作 (而不修改原型物件的原始碼),讓所有該物件的複本都能使用該操作,該如何達成呢?方法是使用物件的 prototype 屬性。以下這個例子,為 Array 這類 Object 在執行期加入一個 max 方法,以取得陣列元素之最大值 (修改自微軟 jscript.chm之範例):
     
    function array_max(){      // 定義求取 Array 最大值之函式
       var i, max = this[0];
       for (i = 1; i < this.length; i++){
           if (max < this[i])
               max = this[i];
       }
       return max;
    }
    Array.prototype.max = array_max;   // 在 Array 原型中加入 max 函式
     
    上面的程式碼,首先建立一個 array_max 方法,以求取陣列之最大元素。接著將這個方法設定給 Array 原型物件。
     
    var x = new Array(1, 2, 3, 4, 5, 6);  // 透過 Array 建構子建立一陣列
                                     // 想求取 x 中某一元素之最大值
    var y = x.max( );       // 取得 x 之最大元素
     
    Dynamic Mix In
     
    假如物件 source 有 mathod1, method2 兩個函式;而另一物件 target 有 methodA 及 methodB 兩個函式。現在我想把 source 的所有特性 (feature) 匯入到 target 中,我們可以撰寫一個 mixin 函式如下,來達到這裡所說的功能:
     
    function mixin(target, source) {
       if( typeof source == "object")
           for( value in source )
               target[value] = source[value];
    }
     
    這個 mixin 函式可以動態的為 target 加上另一物件的所有操作。這種 Mix in 的功能可是 C++/Java 的 static type 語言所望塵莫及的。完整的應用範例如下:
     
    function listMember(main) {
       var s = "";
       for( key in main ) // 使用 in 運算子列舉所有成員
           s += key + ": " + main[key] + "\n";
       return s;
    }
     
    function main(){              // main 之建構子
       this.name = "main";
       this.methodA = function() {};
       this.methodB = function() {};
    }
    var dynamic = {
       method1: function() {},
       method2: function() {}
    }
    function mixin(target, source) {
       if( typeof source == "object")
           for( value in source )
               target[value] = source[value];
    }
    obj = new main();
    mixin(obj, dynamic);   // 匯入 dynamic 物件之所有功能
    alert(listMember(obj));
     
    Singleton Object
     
    用 associate array 的語法來建立 singleton, 用 function contructor 的語法來建立可多重複製的原型物件
     
    Inheritance Through Functions
     
    function superClass() {
     this.supertest = superTest; //attach method superTest
    }
     
    function subClass() {
     this.inheritFrom = superClass;
     this.inheritFrom();
     this.subtest = subTest; //attach method subTest
    }
     
    function superTest() {
     return "superTest";
    }
      
    function subTest() {
     return "subTest";
    }
     
     
    var newClass = new subClass();
     
    alert(newClass.subtest()); // yields "subTest"
    alert(newClass.supertest()); // yields "superTest"