# 痞子軍團本部

## Blog 們

* [痞子軍團本部](http://blog.psmonkey.org)：正經地評論與雜談
* [人間窮話](https://poor-sketch.blogspot.com)：隨便寫寫的評論與雜談
* [Don'tCare Blog](http://blog.dontcareabout.us)：正經地寫一些軟體開發的文章
* [PT2Club Blog](http://pt2club.blogspot.com)：對於軟體業界的隨便亂寫

## Social Media

* [Threads @ps\_monkey](https://www.threads.net/@ps_monkey)
* [IG @ps\_monkey](https://www.instagram.com/ps_monkey/)：生活瑣碎帳
* [IG @piggy\_shoot\_monkey](https://www.instagram.com/piggy_shoot_monkey/)：隨拍攝影帳

## 其他

* [GWT Wiki](http://gwt.dontcareabout.us/)


# 軟體開發


# Java

| modifier     | class | interface | constructor | method | field |
| ------------ | :---: | :-------: | :---------: | :----: | :---: |
| private      |   V   |           |      V      |    V   |   V   |
| (default)    |  V(1) |     V     |      V      |    V   |   V   |
| protected    |  V(1) |           |      V      |    V   |   V   |
| public       |   V   |     V     |      V      |    V   |   V   |
|              |       |           |             |        |       |
| static       |       |           |             |    V   |   V   |
| abstract     |   V   |     V     |             |        |   V   |
| final        |   V   |           |             |    V   |   V   |
| native       |       |           |             |    V   |       |
| strictfp     |   V   |     V     |             |    V   |       |
| synchronized |       |           |             |    V   |       |
| transient    |       |           |             |        |   V   |
| volatile     |       |           |             |        |   V   |

(1)：只限於 inner class


# Hibernate

## 以程式初始化

版本：5+

```java
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
    .configure()    //非必須，有掛的話在 classpath 當中就得要有 hibernate.cfg.xml
    .applySetting(AvailableSettings.DRIVER, "org.h2.Driver")
    //apply... apply... apply...
    .build()
;

MetadataSources sources = new MetadataSources(registry)
    .addAnnotatedClass(Foo.class)    //等同 cfg.xml <mapping class="PACKAGE.Foo" />
    //目前看不出 Hibernate 有提供「載入指定 package 下所有 class」的方式... ＝＝"
;

SessionFactory sessionFactory  = sources.getMetadataBuilder().build()
    .getSessionFactoryBuilder().build();
```

## Entity 的哏

資料庫的欄位沒辦法直接 mapping 到 Java class，例如資料庫儲存的是「Y/N」實際上希望對應到 boolean。 目前發現兩招，第一招是掛 `@Basic`，例如

```
@Basic
private String enabled;

public Boolean getEnabled() {
    return "TRUE".equalsIgnoreCase(enabled);
}

public void setEnabled(Boolean enabled) {
    this.enabled = enabled ? "TRUE" : "FALSE";
}
```

第二招是掛 `@Converter`，還沒試過。 [reference](http://stackoverflow.com/questions/1154833/configure-hibernate-using-jpa-to-store-y-n-for-type-boolean-instead-of-0-1)

如果希望新增資料的時候，某個欄位直接使用 DB 預設值（而不是 entity field 當下的值）， 在 `@Column` 裡頭加上 `insertable = false`：

```
@Column(insertable = false)
private Date createDate;
```

## HQL 的哏

Session.createQuery() 裡頭的字串邏輯：

* 不是用 DB 的 table / column name，而是用 Java 的 class / field name
* parameter name 用 `:` 開頭，實際參數不需要 `:`

### Sub Query ##\#

在 `IN` / `NOT IN` 使用 sub query 的時候，如果這樣寫

```
FROM foo WHERE id NOT IN (FROM wtf)
```

`foo.id` 會比對的是 `wtf.id`。如果要作 NOT IN 的是 `wtf.fooId`，要這樣寫

```
FROM foo WHERE id NOT IN (SELECT fooId FROM wtf)
```


# JasperReport

## Subreport

Subreport 也是對應到一個 .jrxml， 可以作到只切換 / 動態指定整個 report 其中一部分的需求， 提高 report 的重用率、減少維護成本。

在 main report 當中加入 Subreport 之後， Subreport 的 `Subreport Expression` 指到一個 parameter，假設為 `$P{SubReport}`， `$P{SubReport}` 的 `Parameter Class` 是 `net.sf.jasperreports.engine.JasperReport`； Subreport 的 `Data Source Expression` 指到一個 parameter，假設為 `$P{ReportVO}`， `$P{ReportVO}` 的 `Parameter Class` 要是 data source，個人習慣是用 `JRBeanCollectionDataSource`。

在 Java 當中：

```
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put(
    "ReportVO",
    new JRBeanCollectionDataSource(getSubreportData())
);
parameters.put(
    "SubReport",
    JRLoader.loadObject(
        loader.getResourceAsStream(getJasperFile())
    )
);

//把 parameters 丟進 main report 的 JasperFillManager.fillReport()
```

這樣 Subreport 就會以 `getJasperFile()` 的 .jasper 檔案 搭配 `getSubreportData()` 的內容值產生報表。 只不過不是獨立存在、而是 main report 的一部分。

## iReport Editor

> ### 注意 #####\#
>
> * 這裡是 4.6.0 版的使用經驗
> * 官方在 2016 年就不再維護 iReport，要改用 Jaspersoft Studio

要切換到 Preview 才會產生 .jasper 檔

如果修改 XML（尤其是 `<parameter>` 或是 `<field>`），最好存檔之後關掉重新載入。 千萬不要直接切到 Designer，不然不但 Designer 沒有載入修改後的 XML， 還有可能把之前改的全部復原回去...... Orz


# Java Web Start

> 現在大家都會忘記 JWS 是代表 Java Web Start，檔名取 JNLP 又很點點點...

`.jnlp` 檔案會被 cache 起來（jar 檔應該也有），在 client side 的作法是執行 `javaws -uninstall` 或是用 `javaws -viewer` 叫出 GUI 介面操作。

看起來比較正規的作法是 `.jnlp` 檔案裡頭寫 `update` element，例如

但是實測結果好像沒啥鳥用... 不確定是少了什麼... ＝＝"

目前最實在的方法是讓 JNLP 中 `<jar>` 的 `version` 值持續遞增， 這樣除了 Chrome 會有重複下載的小問題外，Firefox 跟 IE 貌似都能正常運作。

## Maven

大概也只有 [Webstart Maven Plugin](http://www.mojohaus.org/webstart/webstart-maven-plugin/) 這個可以用，以下簡稱 `MWebStart`。 它的文件寫的不是很好，實務上建議直接跳 [JnlpDownloadServlet Example](http://www.mojohaus.org/webstart/webstart-maven-plugin/examples/advanced_jnlp_download_servlet.html) 這頁。

MWebStart 可以：

* 把 Maven Project 產出的 jar，包進 web 的 Maven Project 當中
* 以先 gen 好的 key 自動 sign jar
* gen `version.xml`

### 失敗 case ##\#

假設 `Foo` 這個專案是由幾個 Maven Project 組成的：

```
/Foo 
    /FooJWS
    /FooModel
    /FooWeb
```

原本的設計是在 `Foo/pom.xml` 當中掛進 `FooJWS`、`FooModel`、`FooWeb` 的 module， 如此就能確保 `FooWeb` 在 build 之前就先 build `FooJWS`。 但實際上卻會發現 JWS 出現無法順利載入的狀況， 最終發現原因是出在 MWebStart 產生的 `version.xml` 不正確。

假設 `FooWeb` 中設定使用 `FooJWS` 9.7.8 版，`version.xml` 預期是長這樣：

```
<?xml version="1.0"?>
<jnlp-versions>
    <resource>
        <pattern>
            <name>FooJWS.jar</name>
            <version-id>9.7.8</version-id>
        </pattern>
        <file>FooJWS-9.7.8.jar</file>
    </resource>
</jnlp-versions>
```

但是實際上產生的 `<file>` 值卻是 `FooJWS.jar`，沒有帶版號 （但是 `FooJWS-9.7.8.jar` 還是會 sign、會複製到 `webstart` 目錄）。 更有趣的是，是對 `Foo` 作 maven install 才會錯， 如果對 `FooWeb` 作 maven install 就會正常...... （就是這樣所以 debug 了老半天，還以為是 JNLP Download Servlet 出了啥問題 ＝＝"）

所以，在不知道 MWebStart 用了啥神奇邏輯的情況下， 就是移除 `Foo/pom.xml` 的 `FooJWS`，一切事情就沒事啦...... 至於 Jenkins 連動 build 的事情就是另一個故事了 \[遠目]

## 參考資料

1. <http://stackoverflow.com/questions/8828643/java-web-start-how-to-clear-cache-or-update-the-app-from-users-perspective>
2. <http://docs.oracle.com/javase/7/docs/technotes/guides/javaws/developersguide/syntax.html#update>


# JAXB

## 從 XSD 產生 VO

## XML ←→ VO

### Todo list

* @XmlSeeAlso 與 @XmlElementRef 的差別與使用時機。
* child element 有 attribute 的解法

### 通則

掛 `@XmlRootElement` 必須要有 empty constructor（不論哪種 modifier）

### Marshal（XML→Java）

還沒有測試過用 XSD 產生 entity 檔案，以下是手動寫 entity 的心得。

class 掛 `@XmlRootElement`，如果 class name 跟 XML root name 不一樣，加 `name = foo` 來指定。

field 掛 `@XmlElement`，如果 field name 跟 XML tag name 不一樣，加 `name = foo` 來指定。 如果該 field 有 setter，field 就不能掛 `@XmlElement`、setter 也不用掛。 如果 setter 名字跟 tag name 不一樣的解決招數相同。

如果 field 的 data type 需要參考到 `Foo` 這個 class， `Foo` 必須有掛 `@XmlRootElement`。

至於 `@XmlSeeAlso` 的寫法：

```
@XmlSeeAlso(Foo.class)
public class Wtf {
    private Foo foo;
    public Foo getFoo() {}
    public void setFoo(Foo foo) {}
}
```

跟 `@XmlElementRef` 的寫法：

```
public class Wtf {
    private Foo foo;
    public Foo getFoo() {}

    @XmlElementRef
    public void setFoo(Foo foo) {}
}
```

好像都不需要... 也不確定哪個比較好 / 使用時機。

field / setter 如果掛 `@XmlAttribute`，則視為 root element 的 attribute。 （所以看起來如果 child element 有 attribute，就只能用 `@XmlSeeAlso` 的方法另外開一個 class？）

#### 例外狀況 ##\#

目前測試的結果，只有 `@XmlRootElement` 的設定值跟 XML 對不上才會炸 exception， 如果 root 相同，其他 field 都對不上也不會怎樣，頂多值都是 null。

### Unmarshal（Java→XML）

marshal 得到的 XML 未必可以成功 unmarshal 回 entity。例如：

```
@XmlRootElement
class Foo {
    private String str;

    public String getStr() { return str; }

    @XmlElement(name="str+")
    public void setStr1(String str) {
        this.str = str;
    }
}
```

在 marshal 的時候可以正常吐出 XML

```
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo>
    <str+>String</str+>
</foo>
```

但是拿這個 output 去 unmarshal 就會炸 `SAXParseException`。 因為 XML 標準中，element 的名稱不允許 `+`。 這似乎也表示 JAXB 在做 marshal 的時候，基本上就是單純的組字串...... ＝＝"


# JVM

* 初始 heap 大小（Xms）：實體記憶體的 1/64。
* 最大 heap 大小（Xmx）：實體記憶體的 1/4。

資料來源： <http://docs.oracle.com/javase/6/docs/technotes/guides/vm/gc-ergonomics.html>

顯示目前設定值（Windows）

```
java -XX:+PrintFlagsFinal -version | findstr HeapSize
```


# Spring

提供一個 all-in-one 的開發環境（設定）， 基本上是下面幾個要點組成， 所以不一定要用 \[spring initializr] 產生：

* pom.xml

  ```markup
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>版本號碼</version>
        <relativePath/>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 開發階段用 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>    
        <dependency>
            <!-- 偵測檔案變動自動重起 Tomcat -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
  ```
* 傳統 Java application class

  ```java
    @SpringBootApplication
    public class SpringApp {
        public static void main(String[] args) {
            SpringApplication.run(SpringApp.class, args);
        }
    }
  ```

也不需要 `mvnw`，直接下 `mvn spring-boot:run` 就行。

\[spring initializr]: <http://start.spring.io>


# ZK

還有一些詰譙成份居多的散記在 [blameZK](https://plus.google.com/collection/wmvsb) 上。

## ZUL Coding Style

* 使用 `<?import wtf.foo>` 而不是在 `<zscript>` 中寫 `import wtf.foo;`。

## Eclipse

測試環境：

* Eclipse Luna
* Maven project

用 Server View 指定外部 Tomcat、然後 project 用 Run on Server 的方法。

### 用內建 XML Editor 修改 ZUL

1. 開 Preferences
2. 左邊選擇 General / Content Types
   1. 右邊中間選擇 Text / XML (Illformed)&#x20;
   2. 新增 \*.zul
3. 左邊選擇 General / File Associations
   1. 新增 \*.zul
   2. 下方 Associated editors 選擇 XML Editor 後按下「Default」按鈕

### 其他哏

* 用 external editor 修改 ZUL，

  &#x20; 需要要求 Tomcat 重新 publish 才能讀得到，不然就是 Navigator View 重新 refresh。

  &#x20; 簡單地說就是 Eclipse 不知道 ZUL 改了，所以不會叫 Tomcat 更新 ZUL。

  * 另外要注意 Navigator View 當下必須包含該 ZUL（如果有作 zoom in 就會有這個問題），

    &#x20; 不然重新 publish 還是一樣讀到舊的...&#x20;
  * 有遇到 publish 也無法更新 ZUL 的狀況，一定要到 Navigator View 作 refresh 才行。

    &#x20; 沒特殊需求還是乖乖用 Eclipse 內建 XML editor 就算了... \[死]
* 修改 MVVM 的 ViewModel，不用想了，一定要重新 restart Tomcat

## MVVM

### wire 相關

使用 `@Wire`、`@WireVariable` 必須在 `@Init` 的 method 以後才會有實際值。

**注意**：`Window` 是獨立的 IdSpace，也就是你無法直接 wire `Window` 裡頭的 component， 而必須從 `Window` 開始指進去，例如 `@Wire("#fooWindow #foo")`

### 觸發 NotifyChange 的其他方法

透過 MVVM 觸發了一個 `@Command` method `doFoo()`， 在 `doFoo()` 中呼叫另一個 `@Command` method `doWTF()`， 這裡必須注意在 `doFoo()` 中呼叫 `doWTF()` 是單純的 Java method call， 跟 MVVM 一點關係也沒有，所以 `doWTF()` 掛的那堆 `@NotifyChange` 完全不會被觸發。

解決方法是自己發 event 給 MVVM 的機制，例如：

```
String[] propertyList = {};
for (String property : propertyList) {
    BindUtils.postNotifyChange(null, null, this, property);
}
```

另一種解法是 `doFoo()` 必須長這樣

```
@Command
public void doFoo(@ContextParam(ContextType.BINDER) final Binder binder) {
    //......

    //doWTF()
    binder.postCommand("doWTF", null);
}
```

這樣是透過 MVVM 底層機制去觸發 `doWTF()`，相關的 `@NotifyChange` 自然也會觸發了。

### Form Binding

假設 `form` 長這樣：

```
form="@id('fx') @load(vm.currentData) @save(vm.currentData, before='save')"
```

如果有對 `currentData` 作 notify change，那有 load `fx` 或是 `fxStatus` 也會隨之 notify change。

假設有一個 field 的 binding 對象是用 `ListModelList`，像這樣：

在 VM 當中作 `fooList.setSelection(Arrays.asList(aFoo))` 只會讓畫面顯示正常， 並不會讓 `fx.foo` 的值變成 `aFoo`， 必須自己作 `form.setField("foo", aFoo)`。

#### 動態改變 middle object 的 class ##\#

如果 middle object 的 class 會在操作當中改變 （你問為什麼會有這種需求？這是一個很長的故事... \[淚目]）， 這時會炸出一個 exception，炸點在 ZUL 宣告 form binding 的附近， 內容主要是 property binding 錯誤。 目前找到唯一的解法，就是自己實作一個 `MyForm`，內容完全照抄 `org.zkoss.bind.impl.FormImpl`，然後加上：

```
public void clear() {
    _saveFieldNames.clear();
    _loadFieldNames.clear();
    _fields.clear();
    _initFields.clear();
    _dirtyFieldNames.clear();
}
```

這樣在切換時先呼叫 `clear()` 再 notify change binding 的 instance， 就不會炸了 \囧/

### 雜項

如果 bind `ParentVM` 的 component 裡頭有一個 child component 是 bind `ChildVM`， 而 `ParentVM` 跟 `ChildVM` 都有掛 `@Command` 的 method 假設叫做 `wtf()`。 那麼，在 child component 裡頭的 `@command('wtf')` 只會觸發 `ChildVM.wtf()`，不會連帶觸發 `ParentVM.wtf()`

`@load()` 可以用來呼叫 VM 的 method， 例如 `@load(vm.foo(each))` 就是呼叫 `foo()`，然後傳入 `each`。

這樣子作可以取得發出 event 的 component

```
@Command
public void wtf(@ContextParam(ContextType.COMPONENT) Component component) { }
```

這樣子作可以取得發出 event 的 event

```
@Command
public void wtf(@ContextParam(ContextType.TRIGGER_EVENT) Event event) { }
```

當然，可以指定 child class、也可以兩個同時一起用。

## Layout 之謎

在 `listbox` 的 `auxhead` 中，各個 component 要（視覺上合理地）撐滿， 學理上給 `width="100%"` 或是 `hflex="1"`，當然以 render 速度來說應該設 width 會比較快，不過：

* textbox：只能用 `hflex="1"`
* combobox：都可以

## Component

### Borderlayout

margins 的順序居然是「上、左、右、下」

`setCollapsible()` 的前提條件是 `getTitle` 必須有值。

### Cell

用了 Cell 會讓 DOM 結構與原本（不用 Cell）的 DOM 結構不一樣 [ref](http://books.zkoss.org/wiki/ZK%20Component%20Reference/Supplementary/Cell)。 這就會導致 Grid 原本賦予的 style 掛不上去。 解決方法大概有這幾種：

1. 每個 Row 裡頭 component 統一都用 Cell 包起來。
2. 寫一個 global 的 CSS 對應
3. 不管什麼 deprecated，繼續用 Row\.setSpans()

結果似乎最保險的是最後那個不管 deprecated... 真是幹他媽的好 ZK 阿...

### Combobox

`Combobox.setValue()` 是對應選到的 `Comboitem.getLabel()`， `Comboitem` 的 `value` 目前看起來無意義。

### Datebox

如果只是要借用 Datebox 顯示、而不讓使用者修改值，那除了 `setReadonly(true)` 之外還要加上 `setButtonVisible(false)`。

### Listbox

`row` 會蓋掉 `vflex` 的設定。不過如果有觸發 resize，那 `vflex` 的設定還是會再蓋回來。

`auxheader` 才能作 colspan，`listheader` 不行； 要出現 `auxheader` 必須要有 `listhead`（空的也無所謂）。 `auxheader` 設定寬度無效，會依照 `listheader` 的設定跑。

`auxhead` 如果塞 `textbox` 之類的元件，建議下 `hflex="1"` 會比 `width="100%"` 好看。

目前找到畫面載入時預設全選的最簡單方法：

&#x20;\`onAfterRender\` 的時候，資料已經 ready 了（先不考慮動態載入資料的問題 Zzzz）， 所以 \`selectAll()\` 可以運作。 在 EE 版，一個有設定 \`rod=true\` 的 Listbox 是不會出現 select all 的 checkbox。 如果不是在 EE 版，設定 \`rod=true\`（無論在 zk.xml 還是 ZUL）都會被忽略掉， 所以一定會出現 select all 的 checkbox。 ### nonselectableTags ### Listbox 中的某些 \*\*HTML tag\*\* 的 \`onClick\` 行為，天生就不會連帶觸發 Listbox 的 \`onSelect\` 行為， 例如 \`\`、\`\`、\`\`、\`[\`。 然後透過 \`nonselectableTags\` 這個 attribute，可以重新決定哪些 \*\*HTML tag\*\* 會 / 不會觸發 \`onSelect\`。 例如希望圖片跟按鈕都不要觸發 \`onSelect\`，就要這樣寫](/ruan-ti-kai-fa/java/zk)

`nonselectableTags` 也可以給 `*`，表示不管阿貓阿狗都不會觸發 `onSelect`。 然後建議搭配 `checkmark="true"`

最後，請注意，`nonselectableTags` 接受的值是**幹他媽的 HTML tag**， 不是 ZUL component 名稱，也就是說，你得知道哪些 component 實際上是由什麼 HTML 湊出來的。

### Macro

`macro` 似乎會預設兩個 style、其中一個是 `display:inline-block`。 如果對 macro 作 `setVisible(false)` 之後再 `setVisible(true)`， 這個 macro 的 style 就會被清光光...... WTF

### Textbox

ZUL 的 `onOK` 是按下 enter 時候會做的事情。

如果設定 `rows/cols`，那麼就會無視 `width/height/hflex/vflex` 的設定， Textbox 的大小會直接以 `rows/cols` 為準。 所以如果希望 Textbox 是 liquid（大小隨 parent 的大小而變動） 就是設定 `multiline="true"`，然後不要給 `rows/cols`。

Textbox 很容易被 parent 截掉、但是視覺上看不出來（例如在 Grid 當中）。 只能說當 Textbox 是多行狀態（等同於 HTML 的 textarea）， 在 Chrome / Firefox 當中，右下角都會出現可以調整大小的 button， 以此作為判斷依據，也可以避免發生「怎麼都沒有 scroll bar」的誤判狀況 Orz。

### Tree

如果要知道一個 multiple 的 Tree （不是 multiple 的沒有這個問題，用 getSelection() 就好） 剛剛點選 / 取消點選哪個 node， 無法直接從 API 取得，必須要：

1. ZUL 的 `treeitem` 這樣寫
2. `tree` 的 `onSelect` 在 VM 是：

   ```
    public void treeSelect(@ContextParam(ContextType.TRIGGER_EVENT) SelectEvent<Treeitem, Foo> se) {
        @SuppressWarnings("unchecked")
        TreeNode<Foo> node = (TreeNode<Foo>)se.getReference().getValue();
    }
   ```

ZK 7.0 似乎有新增相關的 API：`getPreviousSelectedObject()`，還未測。

### Window

要有設定 `title` 的情況下 `closable="true"` 才會有效果... ＝＝"


# JS


# pixi.js

> ## pixi.js \#

* 官網：<http://www.pixijs.com/>
* repo：<https://github.com/pixijs/pixi.js>
* API：<http://pixijs.github.io/docs/>
* ~~比文件好用的~~ Example：<http://pixijs.github.io/examples>

### PIXI

#### autoDetectRenderer() ##\#

`options` 還可以有這些 field：

* backgroundColor: 0xFFFFFF

#### loader.add() ##\#

第一個參數可以直接給 object，field 如下：

* url
* name / key：如果沒給的話就會用 url 的值
* onComplete / callback：load 完會觸發的 function

### DisplayObject

`foo.interactive = true` 之後，`foo` 就可以發出 event，處理方式。

```javascript
foo.click = wtfFunc;
foo.on("mouseup", wtfFunc)

function wtfFunc(event) {
    //event 是 pixi 重新包裝過的 `InteractionData`
}
```

其實起點都是 `InteractionManager.prototype.processMouseUp()`，行為好像也差不多， 只不過第二個 `EventEmitter` 的行為...... Zzz

## 瀏覽器差異

### 圖檔無法顯示

* 4.3.0
* Chrome / App WebViewer @ Android

如果要顯示的圖檔尺寸過大（不確定實際數字，4200 *4200 確定炸、4000* 4000 確定不會）， 在 Android 上的 Chrome / App WebViewer 就會無法載入圖檔。

Desktop 的 Chrome 基本上沒有這個問題。


# Browser

## 工具類

* <http://csstriggers.com/>
  * 哪些 CSS 會引發哪些 rendering 行為

## Reference

* <https://www.udacity.com/course/browser-rendering-optimization--ud860>
  * 一系列的教學影片
* <http://jankfree.org/>
  * 2014 之後好像沒再更新了，不過還是有很多資料可以挖


# 圖學

> ## 圖學 \#
>
> 應該是啦... 不是就算了 \[毆]

## transform matrix

參考資料：<https://www.siggraph.org/education/materials/HyperGraph/modeling/mod_tran/2dconc.htm>

* Scale：`Sx` 為 x 軸倍率，`Sy` 為 y 軸倍率

  ```
    | Sx    0   0 |
    |  0   Sy   0 |
    |  0    0   1 |
  ```
* Rotate：`a` 為旋轉弳度

  ```
    |  cos(a)   sin(a)   0 |
    | -sin(a)   cos(a)   0 |
    |       0        0   1 |
  ```
* Translate（移動）：`Tx` 為 x 軸移動量，`Ty` 為 y 軸移動量

  ```
    |  1    0   0 |
    |  0    1   0 |
    | Tx   Ty   1 |
  ```

### 組合技

如果需要一次（依序）做多個 transform，就（依序）對多個 transform matrix 做矩陣乘法。 注意：矩陣乘法沒有交換律。

* 原地選轉：

  ```
    |                       cos(a)                         sin(a)   0 |
    |                      -sin(a)                         cos(a)   0 |
    | Tx(1 - cos(a)) + Ty * sin(a)   Ty(1 - cos(a)) - Tx * sin(a)   1 |
  ```

  1. 移動到原點
  2. 旋轉
  3. 移動回原始位置


# PHP

## 陣列

* `get_object_vars($object)` 可以把一個 object 變成一個 key-value 格式的 array。
* `array_values($array)` 可以把 key-value 格式的 array 的 value 變成一個 array。

## JSON

* `json_decode($foo)` 會回傳 Object，改成用 `json_decode($foo, true)` 就會回傳 key-value 格式的 array。
* `json_decode()` 在 32bit 的機器上，處理夠大的 long 值會出現流失精準度的問題，解法是換成字串（WTF）

  ```
    function json_decode_suck($json) {
        return json_decode(
            preg_replace(
                '/("\w+"):(\d+)/', '\\1:"\\2"', 
                $json
            )
        );
    }
  ```

  不確定在 64bit 的機器上是不是絕對不會出現這問題。 參考資料：[StackOverflow](http://stackoverflow.com/questions/1777382/php-json-decode-on-a-32bit-server)

## PDO

* `PDOStatement::execute($array)` 的 array 長度，必須與 SQL 指令中用到的 parameter 數量相同，

  不然會炸 error。


# 軟體工程


# Eclipse

Eclipse 版本：2020-03

## 初始環境設定

1. import [PsMonkey.epf](https://github.com/PsMonkey/wiki/tree/746f7084567a374e4a622c56085cf29a26e06deb/SE/Eclipse/PsMonkey.epf)

下面全部都是在改 Preferences 設定

1. General：勾選 Show heap status
   * Appearance / Colors and Fonts
     * Basic / Text Font：改成 [Monaco](https://github.com/PsMonkey/wiki/tree/746f7084567a374e4a622c56085cf29a26e06deb/SE/Eclipse/MONACO.TTF)
   * Editors / Text Editors：

     &#x20; 勾選 Show whitespace characters（visibility 細節略），

     &#x20; 取消勾選 Show cursor position in the status line / Show selection size in the status line

     * Spelling：關掉
   * Startup and Shutdown
     * 勾選 Refresh workspace on startup
     * Plug-ins activated on startup
       * 取消 Mylyn\*
     * Web Browser：Use external web browser
   * Workspace
     * Text file encoding：Other / UTF-8
2. Java
   * Editor
     * Save Actions
       * 勾選 Perform the selected action on save
       * 勾選 Organize imports
       * 勾選 Additional actions，加上 Remove trailing white spaces on all lines
     * Syntax Coloring：Comments 的 Task Tags 改成紅色
   * Installed JREs：換成 JDK
3. Maven / Installations：改用外部 Maven

## Eclipse Marketplace

* GWT Eclipse Plugin 3.0.0


# Git

## 基本概念

移動、改名要用 `git mv`，不然會被 git 認為是「刪除一個檔案 + 新增一個檔案」。

Eclipse（至少在 Mars）用 Refactor / Rename 修改 Java class， 會用 `git mv` 做，可以安心直接使用。

## 設定

Windows 上設定 Notepad++ 為 commit editor （在 2.26.x 安裝時可以設定連結的 editor，不用再自己搞了），

```
git config --global core.editor "'C:\Program Files (x86)\Notepad++\notepad++.exe' -multiInst -nosession -noPlugin"
```

設定 username 跟 email

```
git config user.name Foo
git config user.email foo@wtf.org
```

gitk 使用 UTF-8 編碼（在 2.26.x 被炸到）

```
git config --global gui.encoding UTF-8
```

## branch 相關

開啟一個完全沒有 parent 的 branch（在這裡是 `gh-pages`）

```
git checkout --orphan gh-pages
```

刪除 branch

```
git branch -d wtfBranch
```

強制刪除 branch（沒有 merge 的話就需要）

```
git branch -D wtfBranch
```

刪除 remote 上的 branch

```
git push fooRemote :wtfBranch
git push fooRemote --delete wtfBranch
```

抓 remote 的某個 branch 變成 local 的 branch

```
git fetch fooRemote remoteBranch:localBranch
```

## pull / push

`pull` 時不想產生一個 merge commit（也有[寫入設定檔的招式](http://ihower.tw/blog/archives/3843)）

```
git pull -r
git pull --rebase
```

所有 branch 都 push 上 remote

```
git push --all origin
```

## 版本推進流程

1. pom 檔版號拿掉 `SNAPSHOT`、寫 `Release.md`，commit
2. 掛上版號 tag

   ```
    git tag wtf.foo.bar
   ```
3. pom 檔版號進版，加上 `SNAPSHOT`，commit
4. 推上 remote repo（所有 tag 都上）

   ```
    git push origin --tags
   ```

## SVN repo 匯入

1. 用 git svn 取出 repo

   ```
    git svn clone SVN_URL REPO_NAME
   ```
2. 用 git log 找出系統產生的 commiter email （假設為 `foo <foo@26f1cbcb-2ce9-9940-8e71-79534620cc70>`）
3. 用 git filter-branch 修正

   ```
    git filter-branch --commit-filter '
        if [ "$GIT_AUTHOR_EMAIL" = "foo@26f1cbcb-2ce9-9940-8e71-79534620cc70" ];
        then
            GIT_AUTHOR_NAME="FOO";
            GIT_AUTHOR_EMAIL="foo@DontCareAbout.us";
            git commit-tree "$@";
        else
            git commit-tree "$@";
        fi' HEAD
   ```
4. 因為不知道怎麼改上面那段程式碼，所以只好有幾個 author 就做幾次 \[死]
5. 確定改完後作 git push


# GitHub

假設帳號 `SOMEONE` 下的 `WTF`（<https://github.com/SOMEONE/WTF.git`）> 要改名為 `Foo`（<https://github.com/SOMEONE/Foo.git）。>

最重要的是 client 的 remote 設定值要改， 假設之前的 remote name 是 `origin`，git 指令會是

```
git remote set-url origin https://github.com/SOMEONE/Foo.git
```

如果原本有其他 repo 跟 `SOMEONE/WTF` 有關（無論誰 fork 誰）， 它們不改名字 or 更著改名字都不會影響，最多就是 PR 的時候看起來很怪... XD


# Scrum

* 978-986-434-110-8，2016.05
* 看完 Part.1

把重心放在閒置的工作，而不是人員。

sprint：短、固定的週期與目標

story 必須要有商業價值才放入待辦清單。 （看起來）技術債不算 story，是與 story 平行地位的待辦事項。


# 雜七雜八


# Markdown

## Coding Style

即使簡單如 markdown，還是需要 coding style。\[死]

1. 縮排用 tab
2. header
   1. h1, h2 用 Setext-stye（`====` 與 `----`），要跟 header 一樣長，但不得少於四個。
   2. 除了文件第一行之外，其餘 header 的上頭都要空兩行
      1. 例外：如果連續兩個 header，則 header 之間只要空一行
      2. 例外：作為 blockquote 的 title
   3. header 下頭要空一行
      1. 例外：作為 blockquote 的 title
3. code block
   1. 上頭空一行、下頭空兩行
4. blockquote 1. 上頭空一行、下頭空兩行 1. 行首全部都要加上 `>` 1. 用 blockquote 作諸如「備註」、「注意」的文字區塊， 則用第六級的 header（稱之為 title），例如：

   > #### title #####\#
   >
   > 內容內容內容......
5. list
   1. list 區段結束空兩行
6. horizontal 1. 上下都要空兩行 1. 使用 70 個底線
7. link 1. *建議*使用 reference 方式 1. reference link 段落上下都要空兩行
8. phrase emphasis 用 `*` 跟 `**` 而不用 `_` 跟 `__`

### 雜項 memo

* 引言當中要用 header，`>` 跟 `#` 之間只能用一個空格、不能用 tab。
* 如果要在 list 當中用 code block，除了前後要留空行之外，還要比當下的縮排還要再多一個

  ```
    （這行有兩個縮排，會是 code block）
  ```

  原因是第一階的縮排（如果不是 \* 開頭）還是會被當作是同一個 item 的項目。
* 如果接連兩段引言，基本上 parser 會把他們黏在一起變成一個 blockquote， 目前發現只有在之間插一個無意義的 reference link 才能分開：

  ```
    [MEANINGLESS]: http://
  ```

## GitHub (GFM)

GitHub 發展出來的[自有規格](https://github.github.com/gfm/)，基本上跟傳統版 markdown 相容， 但是多了：

* Table
* Task list
* 刪除線
* 自動轉 hyperlink
* 禁止原生 HTML 碼

### 裏技？

如果在文件的最開頭這樣寫：

```
header: context
標題: 內文
---
```

會製造出一個 table：

| header  | 標題 |
| ------- | -- |
| context | 內文 |


# Mermaid.js

分為兩個部份：「class 定義」、「class 間的關係」。

由於 generic type 的定義哏（後敘）， 先寫「class 定義」再寫「class 間的關係」比較保險。

## class 定義

有兩種方式，這裡只使用 `{}` 的定義法：

```
class C_NAME ~G_TYPE~ {
    <<S_TEXT>>
	F_TYPE F_NAME
	M_NAME(M_ARGS) R_TYPE
}
```

* `C_NAME`：class 名稱，case sensitive
* `G_TYPE`：generic type，前後用 `~` 夾起，
  * 只有 class 第一次出現時要加、也只有第一次出現時加才有用
  * 多個 type 用 `,` 分隔（單純的字串處理）
  * 不支援 nested type（generic type 裡頭還有 generic type）
  * **會** 忽略跟 `C_NAME` 之間的空格
* `S_TEXT`：class 的 stereotype（官方用「annotation」）， 前後用 `<<` / `>>` 夾起，單純的字串處理
  * 可以寫多個，但是只有第一個會顯示
  * 可以不用寫在 class 定義的第一行
* `F_NAME` / `M_NAME()`：field / method 的名稱
  * 每行第一個字串如果有 `()` 就是 method，沒有就是 field
* `F_TYPE` / `R_TYPE`：field 的 type / method 的 return type
  * 可以加上 generic type，一樣用 `~` 夾起， 但是 **不會** 忽略 跟 `*_TYPE` 之間的空格， **不會** 跟 diagram 的 class 定義有關聯， 單純的字串處理。
  * `R_TYPE` 可不寫
  * 官方文件寫「`R_TYPE` 跟 `)` 之間要有空格」，實測結果是不用... :roll\_eyes:
* `M_ARGS`：method 的參數。 跟 `F_TYPE` 一樣可以加上 generic type，單純的字串處理
* `F_TYPE`、`M_NAME` 前面可以加上符號表現 visibility，單純的字串處理

  | visibility | 符號 |
  | ---------- | -- |
  | public     | +  |
  | protected  | #  |
  | package    | \~ |
  | private    | -  |
* `F_NAME` / `M_NAME()`後面可以加 `$` 表示為 static
* `M_NAME()` 後面可以加 `*` 表示為 abstract method

## class 間的關係

完整語法：

```
CLASS_A "CM_TEXT" A_TYPE LINK A_TYPE "CM_TEXT" CLASS_B : L_TEXT
```

* `CLASS_A` / `CLASS_B`：class 名稱，case sensitive
  * 如果給沒定義過的 class 就會視同定義一個新的 class （下接 generic type 哏）
  * `CLASS_A` / `CLASS_B` 可以相同
  * 畫成圖形時，`CLASS_A` 會在 `CLASS_B` 的上方
* `A_TYPE`：端點類型（可以沒有）

  | 端點類型 | 符號        |
  | ---- | --------- |
  | 實心三角 | <\| 或 \|> |
  | 實心菱形 | \*        |
  | 空心菱形 | o         |
  | 箭頭   | < 或 >     |

  * 對，**沒有** 空心三角形
* `LINK`：線條樣式，限定只能兩個字元

  | 端點類型 | 符號 |
  | ---- | -- |
  | 實線   | -- |
  | 虛線   | .. |
* `CM_TEXT` / `L_TEXT`：寫在連接線上的文字（可以沒有），單純的字串處理。
  * `L_TEXT` 與 `CLASS_B` 中間需有 `:`，文字會顯示在連接線正中間，
  * `CM_TEXT` 前後用 `"` 夾起，文字會顯示在靠近對應 class 的地方

#### 注意事項

Mermain 只負責畫圖，不會判斷是否符合現實 / UML 規範。 要畫出 `Foo <|--|> WTF` 也是可以的 :dancer:


# GitBook

## SUMMARY.md

一定要有，不然 GitBook 無法 build。

基本上只轉換第一個 unordered list 成左邊的目錄結構，其他完全無視。

如果 list 的第一個 item 不是 link 到 `README.md`， GitBook 會自動生一個為 `Instruction` 的 item 指向 `README.md`。 所以反過來說，只要第一個 item link 到 `README.md`， 就可以指定要顯示的字串內容。

不是每個 item 都非得是 link（只不過目錄上的字樣會變成灰色）、 或著非得 link 到實際存在的 md（同前，不過有曾經亂 try 之後 GitBook build 失敗）。

## GLOSSARY.md

在 `GLOSSARY.md` 中撰寫詞彙與詞彙的定義， 若在書中出現該字詞，該字詞就會自動建立 hyper link 到 `GLOSSARY.md`， 滑鼠移上去還會以 `title` 的方式顯示定義。

不過在下列情況中，即使出現該字詞也不會有效果：

* 已經是 hyper link
* 在 `<code>` 或是 `<pre>` 當中

詞彙必須是 `h2`，詞彙的定義是該 h2 的第一個 `p` 也就是第一段文字。 撰寫定義時可以用其他 markdown 語法， 不過 `title` 只能顯示純文字。

詞彙可以包含空格。 如果同時要定義 `WTF` 與 `WTF Foo` 這兩個詞彙， 則 `WTF Foo` 要擺在 `WTF` 前面，否則會認定為只有 `WTF` 這個詞彙而已。

詞彙不分大小寫，`WTF` 跟 `wtf` 視為同一個字。 如果在 `GLOSSARY.md` 當中同時有 `WTF` 跟 `wtf` 這兩個詞彙， 則後面的定義會蓋過前面的定義。


# Jeff 大師語錄

> ## 恭錄 Jeff 大師語錄 \#

### 2014/11/23 ##\#

（跟 Jeff 大師去爬山）

嚮導：有兩條岔路，要走哪一條？\
我：路當然挑難走的走。\
Jeff 大師：那你為什麼用 GWT？給我回去刻 HTML 跟 JS \[指]\
我：大師我錯了...... Orz

### 2014/10/22 ##\#

* 16:33：積八成官
  * 大師看到「積沙成塔... 積少成多... 積非成是 \[咦咦]」所作的開示

### 2014/09/05 ##\#

* 10:51：學海無涯，回頭是幹
* 11:13：本來無進度，何處惹瑞麥（註：Redmine）


# 3C 產品秘技

* 自帶 AP，預設 static ip 為 192.168.0.20
* 預設 http 驗證帳號為 admin；

  &#x20; 預設密碼為空白，會與 mydlink Lite 設定的密碼同步
* 即時影像： <http://IP/video.cgi>&#x20;
* 即時擷圖： <http://IP/image.jpg>
* 控制方向（尚未驗證）： <http://IP/pantiltcontrol.cgi> ，POST 參數
  * PanSingleMoveDegree
  * TiltSingleMoveDegree
  * PanTiltSingleMove：九宮格，從左上（0）到右下（8）


# Portfolio


# 飛行紀錄

> 更早之前的紀錄就... 就這樣吧... Zzz

## 航班紀錄

### 2017

* 2017/03/05, CZ3098, A330, TPE, CAN
* 2017/03/05, CZ3896, B737-800, CAN, SWA
* 2017/03/10, CZ3891, B737-800, SWA, CAN
* 2017/03/10, CZ3097, A330-300, CAN, TPE

### 2016

* 2016/01/22, CX407, B777-367, TPE, HKG
* 2016/01/25, CX468, A333-343, HKG, TPE
* 2016/08/18, MU5008, A332, TPE, PVG
* 2016/08/18, MU577, B773, PVG, LAX
* 2016/08/18, VX114, A320, LAX, IAD
* 2016/08/30, BR29, B77W, JFK, TPE

### 2015

* 2015/03/21, CX451, B777-300, TPE, HKG
* 2015/03/21, TK071, B77W, HKG, IST
* 2015/03/28, KK14, A320, IST, AYT
* 2015/04/01, KK13, A320, AYT, IST
* 2015/04/02, TK024, A340-300, IST, TPE
* 2015/09/16, BR758, B77W, TPE, HGH
* 2015/09/27, BR757, B77W, HGH, TPE

## 機場

* AYT：土耳其 Antalya
* CAN：廣州白雲
* HGH：杭州蕭山
* HKG：香港
* IAD：華盛頓杜勒斯
* IST：伊斯坦堡 Ataturk
* JFK：紐約甘迺迪
* LAX：洛杉磯
* SWA：揭陽潮汕
* TPE：台北桃園
* PVG：上海浦東

## 航空公司

* BR：長榮
* CX：國泰
* CZ：中國南方
* KK：Atlasjet
* MU：中國東方
* TK：土耳其
* VX：維珍（美國）


# 桌遊紀錄

> ## 桌遊分區說明 \#

* [極品區](/portfolio/boardgame/level-1)：

  &#x20; 評價 90 分以上，沒有玩膩跡象。
* [優質區](/portfolio/boardgame/level-2)：

  &#x20; 評價 70～89 分，三不五時會想來一場。
* [正常區](/portfolio/boardgame/level-3)：

  &#x20; 評價 50～69 分，要不要玩都可以。
* [雞肋區](/portfolio/boardgame/level-4)：

  &#x20; 評價 30～49 分，食之無味、棄之可惜。
* [死亡區](/portfolio/boardgame/level-5)：

  &#x20; 連給分數都懶，純粹簽到用。


# 極品區

> ## 極品區 \#
>
> 評價 90 分以上，沒有玩膩跡象。

## 總排行榜

* 三國殺：90

## 三國殺

* 持有日期：大概 2013 年買了一組基本牌組，還沒拆封過。
* 評價：90

2012 年玩過一次面殺，後來都上官網打。

很喜歡這個遊戲，但是上手很困難，武將不熟根本玩不動。 這也很吃同伴的質與量，所以後來只能在官網打。 但是官網出來太多武將，搞得很複雜（又要錢），只能說各種辛酸...... T\_\_T


# 優質區

> ## 優質區 \#
>
> 評價 70～89 分，三不五時會想來一場。

## 總排行榜

* 妙語說書人：88
* 星域奇航：85
* 拼布藝術：82
* King Up!：80
* 形色棋：80
* 拉密：80
* 演化論：物種起源：80
* 洞察掀機：79
* Ticket to Ride：78
* 卡卡頌：77
* 神奈川學院：76
* CV：75
* 瘟疫危機：75
* 骰子街：73
* Marrakech：71

## 妙語說書人

* 持有日期：
  * 2008 基本版：2017.06～
* 測試日期：
  * 2017.06.18：四人場，無擴。

如果不考慮計分規則，那麼規則就超～簡單，幾乎不用教學。 因為規則超簡單，所以這個遊戲好不好玩就跟同伴的調性高度相關。 如果說書人的說書都沒啥哏，那就很難有趣。

## 星域奇航

* 測試日期：
  * 2017.07.13：兩人場，無擴。

很棒的兩人對戰遊戲，除了同類卡牌 combo 計算起來比較惱人之外， 規則相當簡單好上手，節奏步調十分明快。 要認真燒腦，光拿捏「要不要發動棄牌效果」就十分費神。 算是可輕鬆也可深入玩的遊戲。 有機會多試幾次測試耐玩度的話，有超越三國殺的可能。

不過卡牌的視覺設計實在... \[嘆氣]。 美觀這種見仁見智的就算了， 但是卡牌識別度以及功能的可讀性都很低，扣了不少分數 \[怒]

## 拼布藝術

* 測試日期：
  * 2017.06.25：兩人場。

規則簡單，但是遊戲的過程中卻可以十分燒腦，可以盤算的要素還蠻多； 但是要無腦玩也不太影響樂趣，而且耐玩度也很足夠。 真的是很神奇的一款遊戲。

這大概是兩人遊戲的極限吧？ \[遠目]

為什麼只給到 82 分的原因？ 我也說不出來，大概是缺乏嘴砲耍心機的遺憾吧 XDDD

## King Up!

* 測試日期：
  * 2017.07.13：五人（教學）場。

乍看很無聊，但是實際上很講心機的 party game。 晉升階段移動的角色未必是自己在意的（尤其是推上王座 XD）， 投票階段的有限否決權更是趣味精華。

不過角色的配色有點不良，連帶導致計分有點煩...... ＝＝"

## 形色棋

* 測試日期：
  * 2017.07.08：兩人場。

跟拉密有類似邏輯，玩起來比拉密單純，因此比較有計算的餘裕 （也許只是還沒找到拉密算牌的秘訣）， 遊戲過程我是認為比拉密來的好一些。

缺點是需要比較大的桌面、需要額外的實體計分機制（用籌碼是個好主意）、 一場時間平均會比拉密長（一定得用完牌堆）。

反過來說，因為變化不夠，所以也就比較沒有精進技術的空間。 拉密光是加上個「一分鐘之內出完牌」的限制就可難上許多。 所以整體評價跟拉密不相上下。

## 拉密

* 測試日期：
  * 2017.07.02：兩人場，只用基本百搭牌。
  * 2017.07.04：兩人場，用兩副撲克牌。
  * 此後常常開來玩，細節略。

就個人觀點，我不是那麼喜歡這個遊戲。 不過它簡潔的遊戲機制跟複雜的燒腦程度，的確值得這麼高分。

試過用兩副撲克牌玩，問題很多。 需要的桌面大小是個問題、 要拆開重組時，撲克牌不是很好移動、也會減慢思考速度。

還是乖乖掏錢買吧...... （馬麻馬麻，可以買麻將版嗎？ T\_\_T）

## 演化論：物種起源

* 測試日期：
  * 2017.02.28：三人場，無擴。

非常棒的一款遊戲，無論娛樂性、燒腦程度、玩家之間的互動都很棒； 更可貴的是，它非常具有教育意義， 遊戲間真的可以感受到物種演化的多樣性與大自然的無情。 （什麼？這輪食物才三個？ ◢▆▅▄▃-崩╰〒皿〒╯潰-▃▄▅▆◣ ） 不是一般電動遊戲中屬性點滿就可以稱霸天下的單調簡化。

問題是，上手實在太困難，我們在有店員帶玩的情況下都還常常搞不清楚狀況。 這是為什麼只有 80 分的原因。

## 洞察掀機

* 測試日期：
  * 2017.06.25：五人場。

簡單好上手的遊戲，判定一個人到底是「見微知著」還是「以管窺天」的利器 XD

非常適合破冰暖場，一堆人擠在一起看洞察機立馬縮小物理上的距離， 不是該回合擲骰玩家的無責任嘴砲很能炒熱氣氛。

缺點是短時間內不會想重複玩， 還有那個洞察機為什麼不用塑膠材質？ 看起來就很脆弱的硬紙板來組裝，完全削弱購買意願...... ＝＝"

## Ticket to Ride

* 測試日期：
  * 2017.07.18：歐洲版，四人場

規則稍微多了一點，但上手之後就會覺得還好。 目標卡以及對照地名是煩了一點， 我覺得入門可以拔掉目標卡、只剩下「誰連最長」的加分項目。

互動也稍弱了一點，尤其是每個人的目標卡分散各地的時候， 就不太會出現互卡路線的狀態， 就算要卡別人路線，那也要有車票可以卡...... \[遠目]

不過，實際玩起來還是相當有趣。 把車廂擺滿地圖非常有成就感 XD

## 卡卡頌

* 測試日期：
  * 2017.06.10：兩人場，無擴。

一開始被小人佔領的方式（例如一個圖版上有三條路，是只能佔其中一條嗎？）、 還有城堡怎麼樣才算圍完給搞得有點昏，甚至想放棄。 不過搞清楚跑完一輪就發現這款遊戲的後勁， 真的就是用一個很簡單的規則跟操作，製造出很多可能性與樂趣。

也許再多玩幾次，會調高評價 XD。

## 神奈川學院

* 測試日期：
  * 2017.07.18：四人場

遊戲的主題跟機制很特別，我很喜歡。 （太座大人討厭他的美術風格：「不要侮辱葛飾北齋」） （「是弟子在畫畫，又不是葛飾北齋本人」 XD）

但是規則有點難搞、細節太多（季節、主題、畫筆、技巧......） 還有成就系統要決定，有點繁瑣。 再加上互動性也不高，所以只有這個分數。

## CV

* 測試日期：
  * 2017.07.13：三人場。

遊戲機制相當不錯，不但需要策略，還附帶有蔣捷〈虞美人〉的意境 XD。 美術風格也相當優秀，十分賞心悅目。

不過遊戲機制本身缺乏玩家之間的互動，沒有合作、也很難產生競爭（或許要玩到很熟之後）。 如果在人生抉擇時，其他同伴不關心(X) 調侃(O) ，整體就會有點悶。

註：這款的中文名稱沒有很統一，遊戲盒子（應該）也只有大大的「CV」二字， 所以直接使用原文名稱。

## 瘟疫危機

* 測試日期：
  * 2017.06.25：兩人場，無擴。

以「試圖反應現實」的角度來看，這是一款設計週到的遊戲。 這可能造成一些反效果，因為初上手覺得規則多且瑣碎、複雜， 而勝利條件幾乎無法達成...... Orz

另一個問題是：這款遊戲真的需要多人玩嗎？ 當然，可以限制過程中不能交換意見，但如此一來難度又會提高很多， 因為同伴不但要熟悉規則而且還要默契十足， 不然始終各奔東西怎麼可能做出解藥...... Orz

即便講了一堆缺點，但是還是給到 75 分。 好想收一套自己單人分飾四角啊... XD

## 骰子街

* 測試日期：
  * 2017.06.10：兩人場，無擴。

很均衡的一款遊戲，規則簡單、吃運氣但是也需要規劃， 而且不太有閒置的時間，因為別人擲的骰子會影響到自己的收入、 玩家之間也有互動的機會（拜託你不要擲出 6... ＝＝"）。

缺點就是稍微單調了點，因為除了買卡片有選擇的空間外， 其他就是擲骰子、收錢、付錢...... 有些卡片會需要參考建築物的類別、這類別又不是很明顯，我覺得也是敗筆之一。

無論如何，還是海放璀璨寶石。

## Marrakech

* 測試日期：
  * 2017.07.02：兩人場，無擴。

跟拼布藝術的調性相似，規則一樣簡單好懂。 比拼布藝術多的是多人、互動、隨機與 combo 的刺激感； 比拼布藝術少的是算計的可能範圍，燒腦程度大幅降低。

註：這款的中文名稱沒有很統一，所以姑且使用原文名稱。


# 正常區

> ## 正常區 \#
>
> 評價 50～69 分，要不要玩都可以。

## 總排行榜

* 歌劇魅影：66
* 時間軸：65
* 犯人在跳舞：63
* 出包魔法師：61
* 跳跳猴大作戰：60
* 多米諾王國：55
* Mr. Jack：50

## 歌劇魅影

* 測試日期：
  * 2017.07.01

跟 Mr. Jack 應該是同一個系列作，基礎設計概念相同。 不過這一代大幅改善了 Mr. Jack 的各種缺點， 光 setting 變簡單、起手變化變多這兩點就大勝。 角色能力變簡單、獲勝條件變單純、可移動的範圍還變小許多， 但是燒腦程度跟 Mr. Jack 比應該還是不相上下，這實在是很大的改善。

會只有 66 分純粹是個人似乎不愛這種風格...... (艸

## 時間軸

* 測試日期：
  * 2017.06.25：兩人場。

規則超簡單，上手難度趨近於零。 在如此簡單的規則當中還是可以讓玩家發展策略，相當不容易。

缺點是短時間內無法反覆重玩，只適合當破冰暖身墊檔。 另外就是如果玩家們都沒歷史知識 / 常識， 很有可能一場要玩很久，從知性競賽變成單純的機率賭博 XDDD

## 犯人在跳舞

* 測試日期：
  * 2017.07.13：五人（教學）場。

以 party game 來說算是不錯，簡單好代入、步調快速、閒置時間短。 不過在五人（或是不足八人）場，每局重開的時候要確認牌組有點煩， 可能要在出牌的時候就先把必備牌特別留起來。

遊戲計分方式似乎沒有很均衡，犯人要獲勝有點難、但是分數卻沒有很高。 不過 party game 嘛..... \[遠目]

## 出包魔法師

* 測試日期：
  * 2017.07.13：三人場。

以三人場來說，要算牌幾乎不可能，因為還沒撐到後期可能就有人死了。 最後就會變成單純拼運氣，有點無趣。

也許四人以上會好一點，但是這遊戲又很需要場地配合... #$%&\*@!!!!

最多只想拿來當桌遊入門訓練... \[蓋牌]

## 跳跳猴大作戰

* 測試日期：
  * 2017.06.10：兩人場。

6 分是純大人玩的分數，如果考慮跟小孩一起玩可能會是滿分吧？ XD

## 多米諾王國

* 測試日期：
  * 2017.07.08：兩人場。

有點像是卡卡頌簡化後搭配拼布藝術的圖版混在一起的結果。

步調很快、一局遊戲也不長， 無論心機、互動、combo 翻盤都有兼顧， 單純以小品而言算是相當不錯， 但是綜合來看就顯得有些無力。

除非有時間 / 空間上的限制，不然我會選擇玩卡卡頌。

## Mr. Jack

* 持有日期：2017.02～
* 測試日期：
  * 2017.02（買來之後陸續跑過三四場）
  * 2017.07.01

沒有試玩過就矇眼買 XD

看起來好像還蠻簡單，結果跑一場也會殺掉不少時間 XD。

對於 setting 的部份有蠻多抱怨，像是華生一開始手電筒該照哪？ 另外，「每個角色物件是不是一定只能擺在指定地點？」這件事請也很苦惱， 如果是，那麼 setting 時間還蠻久的（我是不覺得熟練之後會快多少）、耐玩度也會降低很多。 如果不是，又覺得可能會不平衡、Jack 一下就可以衝出去。

耐玩度也真的是個大問題。


# 雞肋區

> ## 雞肋區 \#
>
> 評價 30～49 分，食之無味、棄之可惜。

## 總排行榜

* Nullern 49
* 璀璨寶石：45
* 火柴會說話：40
* 情書：35
* Las Vegas：32
* 卡魯巴：30

## Nullern

* 測試日期：
  * 2017.07.21：五人場。

簡化版、可多人玩的橋牌。 對於玩過（基礎）橋牌的人可能還有些困擾 （什麼？首家不是出王牌的話可出任意花色而且只比點數？）。 不過叫牌、計分方式的簡化倒是設計的不錯。

整體而言就是一種不上不下的感覺，所以給這個不上不下的分數。

## 璀璨寶石

* 測試日期：
  * 2017.02.28：三人場

很好上手，但是完全沒有玩家之間的互動成份， 大概只能避開別人的收集路線，要影響他人的行為幾乎不可能。 這樣桌遊的趣味就少了八成，我還寧願跟電腦玩....

## 火柴會說話

* 測試日期：
  * 2017.07.13：五人（教學）場。

可組合的透明卡牌，這個概念不錯，大概是唯一亮點。 我寧願玩傳統的比手畫腳。

## 情書

* 測試日期：
  * 2017.02.28：三人場

簡單好懂，但也就只有簡單好懂這個優點。 大概只有拿來當破冰暖場的價值。

## Las Vegas

* 測試日期：
  * 2017.07.18：四人場

運氣成份太重、策略成份太輕。 要作為 party game 也是各種無力， 人數吃不多、不開詛咒技能等別人骰的時間有點無聊......

大抵上比較適合喜歡傳統「喜巴辣」的人， 可是我不是...... Zzz

## 卡魯巴

* 測試日期：
  * 2017.07.13：三人場。

遊戲進行方式是賓果，然後目標達成方式是路經規劃。 除了觀察別人是不是有米寶可能比你先走到神殿， 才會決定是不是要棄牌搶頭籌（那也要有可能走到 Zzz）， 不然我想不到玩家彼此之間能有什麼互動， 甚至連開頭 setting 跟隊長的角色都很無意義...... \[捏鼻]。 ~~相比之下璀璨寶石的互動超高，其他遊戲簡直就是要連體嬰才能玩。~~

至於策略的部份，我想除非把所有圖板的類型數量記下來， 不然路徑規劃的部份... 要算的東西太多了，就算了吧... Zzz

什麼？吐嘈這麼多怎麼沒進死亡區？ 因為太座大人說還不錯...... Orz


# 死亡區

> ## 死亡區 \#
>
> 連給分數都懶，純粹簽到用。

## 農場大亨

* 測試日期：
  * 2017.07.21：五人場。

遊戲機制各種無法理解意義所在，失敗。

## 估估劃劃

* 測試日期：
  * 2017.07.13：五人（教學）場。

幾乎沒有加入任何新元素的比手畫腳， 沙漏時間也設定的太短。 唯一的價值大概是那疊題庫，那我寧願買火柴會說話。

## 蟑螂捕手

* 測試日期：
  * 2017.07.08：兩人場。

單純看設計概念跟實作方式，這是一個非常有趣且令人印象深刻的遊戲。 但是實際玩起來卻... 十分無趣， 除了蟑螂常常卡在角落不動之外， 一直擲骰子很煩、刀叉湯匙辨認起來有點麻煩、 影響到每回合時間卻又沒有機制去硬性規定每回合時間就更煩人。

結果就是一個好像很厲害但是實際很失敗的作品。

## 文獻室

* 測試日期：
  * 2017.06.10：兩人場。

贈與階段很無聊又很久，拍賣階段看起來能做的事情、會發生的變化好像也不多。 所以壓根沒跑完一輪就放棄了。 我是不太相信三或四個人玩會有不一樣的結論...... XD


# 島呼冊店

* 2017.05：《喜歡引用吉卜齡的賊》（臉譜版）
* 2017.04：《抽屜裡的生態箱》
* 忘記日期：
  * 《拉麵：一麵入魂的國民料理發展史》
  * 《饞：貪吃的歷史》
  * 《廚與藝：日本料理神人的思考與修鍊》


# 軍旅生涯

> ## 軍旅生涯紀錄 \#

說穿了，這只是努力不在軍中變笨的痕跡...... \[核爆]

* 2010.09.30 : 2100T 901R2B1C
* 2010.11.05 : 花防部調適兵
* 2010.11.12 : 花防部幹訓班代理參一（線掛在機步營）
* 2011.02.16 : 花防部幹訓班待命人員
* 2011.02.23 : 花防部幹訓班代理行政
* 2011.05.23 : 花防部幹訓班代理參三
* 2011.08.25 : 休退開始
* 2011.08.31 : 歸鄉手續辦理完畢

因為符合緩召條件，所以沒意外的話大概就到這邊了......

### 2011.07.01

整整就剩下兩個月的刑期役期，這段時間又幹了什麼好事呢？

卸任行政，然後轉行接參三，但是參一的人又都退光光了，只剩下我有欺負調適兵的經驗，所以就

```
平日參三、假日參一，沒事還要回答行政的問題...... Orz
```

再加上頭兩個禮拜參三的老闆都不在，真是太 high 啦～～～

雖然如此，還是唸了一點書：

讀完《牛頓加農砲》、《天使微積分》、《吃朋友》、《祖傳大煎鍋》、《新企業神話》； 《最後理論》讀了大概五十頁。好像還漏掉一兩本書，就算了。

另外，最大的成就（？）就是用 JavaScript 寫了單機兩人對下的大盤象棋跟黑白棋。 取名作「業務討論」系列...... \[大笑]

### 2011.05.20

應該是當行政太歡樂了，所以都懶得看書跟寫紀錄 \[誤]

看完《歷史學者》、《張系國大器小說：住書》、《找路》、《果蠅、基因、怪老頭》， 簡單重新讀過《聖境預言書》。

《四喜憂國》、《費曼的主張》、《不完全比賽》、《DNA 的語言》、《裸體午餐》則是各抽讀了其中的幾篇文章， 其中《四喜憂國》讓人頭昏、《裸體午餐》則是讓人發瘋，大概吸完毒才會知道他在寫什麼吧？ Orz

《美國眾神》讀到快結束，因為想一批新書，所以先還回去

漫畫則是看了《窮神》、《血色星期一》，這兩個在不同方面不錯的作品

大概就這樣... 吧？

### 2011.03.25

人笨又膽小，當行政也不知道去哪裡飄。 所以最保險的就是去圖書館啦 \囧/

這段期間《飲食男女》讀完，《歷史學者》讀到第二部、 《張系國大器小說：住書》讀一半、《天才神秘會社》讀到三分之二。 《撒謊的信徒》讀了一半放棄，因為對政治小說沒啥興趣， 那個時代的歷史也不熟，還不如看《城邦暴力團》來的有趣。

《小鳳仙》讀了二十幾頁，也放棄... 果然我還沒有那個程度去讀高陽的書嗎？ Orz

重新翻了一下《文化苦旅》跟《台北人》，然後在「舊書鋪子」買了一本林語堂著的《蘇東坡傳》（才 50 元好便宜！）

另外看了幾本不堪一提的漫畫.......

大概就這樣吧......

### 2011.02.26

好久沒有寫紀錄了。

一月中知道要歸建回機步營，心情有點起伏，加上年末真的很忙 （該死的提報資料、流感、爆炸多的調適兵... 如此這般那樣......）， 所以也沒看啥書。

年假放第一梯，所以從初一下午開始都在營區度過，著實看了不少書。 粗記至今看了：

看完《陳寅恪與傅斯年》、《推拿》、《中國武術史》。 重看《古都》，不過到後來實在撐不住，一方面是跳 tone 的敘述理解起來很麻煩、 一方面是這種懷舊的東西實在很傷神，所以沒看完。 粗略翻完《針灸護理學》以及《糧食戰爭》頭幾頁，還看完一本超爛的《餐桌禮儀˙日式、中式篇》

二月中確定調線成幹訓班的一員，改行接行政（預財士）， 所以重看高中國文課本（？）

大概是這樣吧？ XD

### 2011.01.07

在軍中跨年，以為會比較閒，結果好忙......

《陳寅恪與傅斯年》讀了一百多頁，背了兩首古詩《將進酒》、《歲暮歸南山》

好像就沒了 Zzzzzzzz

### 2010.12.24

第二次留守，開始想辦法改善作業流程 T\_T

不過年關近了，有一些有的沒的文件要生 Orz

《群》大概看了一百多頁， 買了一本 JavaScript 的原文書，於是開始搞中文翻譯，大概翻了七頁。

btw\... 站安官桌的規定也變嚴格了，以後大概會改拿口袋版唐詩選輯來練字順便背詩。

### 2010.12.10

第一次留守，前後呆了兩個禮拜，加上開始能夠掌握部隊生活作息的脈絡，因此還看了不少東西，計有：

《1949 大江大海》，看到〈管管你別哭〉就被學長拿去看了。 《老師的十二樣見面禮》，看完 3/4。

btw\... 這兩本都是中山室的藏書，頗驚訝 XD

《電腦也搞不定》唸完頭兩章，《詩與畫的界線》（拉奧孔）只讀了幾頁...... Orz

### 2010.11.26

開始接業務，外加這批調適兵實在有點多，因此根本沒看到啥書。 放假去了一趟當代館，算是有補充到腦漿 XDXD

### 2010.11.19

粗略掃完新潮文庫版的《金閣寺》，某種程度來說，這本比《西洋美學史》難懂多了...... Orz 等一兩個月後有興致再來重讀吧...... \[遠目]

購入《那漢子》、《電腦也搞不定》

### 2010.11.12

《西洋美學史》讀到柏拉圖結束，甚多不解。不過筆記本後來挪為他用， 原先做的筆記可能遺失，也罷，待有空從頭看起。


