Total Pageviews

2017/01/07

[Redmine] Fail to Create Project via Rest API

Problem
I am using Redmine Rest API to create project, but I get this error message:
1
2
3
4
5
6
org.springframework.web.client.HttpClientErrorException: 422 Unprocessable Entity
 at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
 at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:667) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
 at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:620) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
 at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:580) ~[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
 at com.cht.commons.web.client.RestRequest.post(RestRequest.java:175) ~[cht-commons-web-client-0.3.0-SNAPSHOT.jar:0.3.0-SNAPSHOT]




How-To
This error results from the project identifier's limitation. 
I provide an illegal project identifier, so I fail to create project.



Owing to the Redmine Rest API cannot provide meaningful information for user, so I need to utilize regular expression to provide meaningful information when the project identifier is not legal.
1
2
3
4
5
6
    private void checkProjectIdentifier(String identifier) {
        Pattern pattern = Pattern.compile("^[a-z0-9_=]*$");
        if (!pattern.matcher(identifier).matches()) {
            throw new RuntimeException("僅允許使用小寫英文字母 (a-z), 阿拉伯數字, 虛線與底線");
        }
    }

    
    
Reference
[1] https://www.redmine.org/projects/redmine/wiki/Rest_Projects    


2017/01/06

[Angular2] Services

Requirement
It's very common that multiple components may need access to the same code and we don't want to copy and paste the same code over and over. 
Therefore, we need create a single reusable data service and inject it in the components that need it.

How-To
(1) Create a service class looks like:
1
2
3
4
5
6
7
8
9
import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class ProjectService {

  constructor(private http: Http) { }
}

(2) Import, register and initialize the service class in component class
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { Component, Pipe, PipeTransform } from '@angular/core';
import { CORE_DIRECTIVES } from '@angular/common';
import { TAB_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
import { Router } from '@angular/router';
// import ProjectService
import { ProjectService } from './project.service';
import { MODAL_DIRECTIVES, ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
import { PAGINATION_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
import { StatusPipe } from './project.pipe';

@Component({
  selector: 'project-list',
  templateUrl: 'project.list.html',
  directives: [MODAL_DIRECTIVES, PAGINATION_DIRECTIVES],
  providers: [ProjectService], // register ProjectService to providers
  pipes: [StatusPipe]
})

export class ProjectComponent {
  
  // initialize ProjectService in constructor
  constructor(private projectService: ProjectService) {

  }
}

(3) If I add a search method in ProjectService:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import { Injectable } from '@angular/core';
import { Http, Response, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class ProjectService {

  constructor(private http: Http) { }
  
  search(searchProject: Project, page: number) {
    let name: string = searchProject.name;
    let status: number = searchProject.status;
    return this.http.get('/api/projects/search?name=' + name + '&status=' + status + '&page=' + page)
                    .map(res => <Page<Project>>res.json());
  }
}

(4) The component class code snippet looks like:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { Component, Pipe, PipeTransform } from '@angular/core';
import { CORE_DIRECTIVES } from '@angular/common';
import { TAB_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
import { Router } from '@angular/router';
// import ProjectService
import { ProjectService } from './project.service';
import { MODAL_DIRECTIVES, ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal';
import { PAGINATION_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
import { StatusPipe } from './project.pipe';
import { Project, Page } from '../model/model';

@Component({
  selector: 'project-list',
  templateUrl: 'project.list.html',
  directives: [MODAL_DIRECTIVES, PAGINATION_DIRECTIVES],
  providers: [ProjectService], // register ProjectService to providers
  pipes: [StatusPipe]
})

export class ProjectComponent {
  
  projects: Page<Project>;
  
  // initialize ProjectService in constructor
  constructor(private projectService: ProjectService) {  }
  
  search() {
    this.projectService.search(this.searchProject, this.currentPage).subscribe(
          res => {
            this.projects = res;
          }
    );
  }

}



2017/01/05

[Angular2] Custom Pipe

Problem
I retrieve a collection of data with json data type, the json structure looks like:


These data will be displayed in data grid:


The second column displays status code, but I would like to display its description instead of code (i.e. 1:使用中、5:已關閉、9:已封存) :


How to do it?

How-To
Utilize custom pipe can solve this problem:

Step1. Create a custom pipe
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'statusPipe' })
export class StatusPipe implements PipeTransform {
  transform(status: number) {
    let statusName = '';
    if (status == 1) {
      statusName = '使用中';
    } else if (status == 5) {
      statusName = '已關閉';
    } else if (status == 9) {
      statusName = '已封存';
    }
    return statusName;
  }
}


Step2. Import custom pipe to your component. Here is the code snippet:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//...
import { StatusPipe } from './project.pipe';

@Component({
  selector: 'project-list',
  templateUrl: 'project.list.html',
  directives: [MODAL_DIRECTIVES, PAGINATION_DIRECTIVES],
  providers: [ProjectService],
  pipes: [StatusPipe]
})

export class ProjectComponent {

  searchProject: Project = new Project();
  projects: Page<Project>;

  constructor(private projectService: ProjectService, private appNotificationSerivce: AppNotificationService) {
  }
  //...
}  


Step3. Apply pipe to your html page. Here is the code snippet:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
  <div class="well" *ngIf="projects && projects.content.length > 0">
    <div class="table-responsive">
      <table class="table">
        <thead>
          <tr>
            <th width="70%">專案名稱</th>
            <th width="20% ">狀態</th>
            <th width="10% "></th>
          </tr>
        </thead>

        <tbody>
          <tr *ngFor="let project of projects.content; let rowIdx=i ndex ">
            <td> {{ project.name }}</td>
            <td> {{ project.status | statusPipe }}</td>
            <td> </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>



2017/01/04

[VS Code] How to configure proxy setting?

Problem
If I would like to change the proxy setting in Visual Studio Code, how to do?

How-To
Step1. Open setting.json


Then you can see the default setting values in setting.json


Step2. Set your proxy values to overwrite the default values



Reference
[1] https://code.visualstudio.com/docs/customization/userandworkspace

2017/01/03

[Angular2] Fail to install npm package

Problem
When I try to install npm package...
Command:
npm install -g angular-cli@webpack

I get this error message:
npm ERR! network If you are behind a proxy, please make sure that the
npm ERR! network 'proxy' config is set properly.  See: 'npm help config'
npm ERR! Please include the following file with any support request:

npm ERR!     C:\Users\chtti\npm-debug.log


How-to
The problem results from you don't configure proxy properly. Therefore, you need to set your corporate web proxy before you install npm package.
The command is as bellows:
npm config set proxy [your proxy]

Reference
[1] https://jjasonclark.com/how-to-setup-node-behind-web-proxy

2017/01/02

[Eclipse] "Annotation processor 'lombok.core.AnnotationProcessor' not found"

Problem
I fail to startup my Spring boot application, and get this error : "Annotation processor 'lombok.core.AnnotationProcessor' not found".

My tools is :
(1) Eclipse with Mars version
(2) Spring Boot 1.4
(3) JDK 1.8
(4) Lombok 1.16.10


How-To
The root cause is still unknown. But after I reinstall Project Lombok jar file, the problem has been fixed.

Steps:
(1) Close Eclipse
(2) Download jar file from https://projectlombok.org/
(3) Install Lombok
(4) Launch Eclipse


2017/01/01

[閱讀筆記] Wikinomics

  1. Wikinomics的四個原則:openness (開放), peering (對等), sharing (分享) 與 acting globally (全球運作)
  2. 現代的企業,與其像音樂、影視業者不斷地建造高聳的藩籬來保護公司的智慧財產與打擊盜版。聰明的企業應該把公司的智慧財產 (intellectual property) 視為共同基金 (mutual fund),將公司的智慧資產 (intellectual property assess, IP assets) 當作一個均衡的投資組合 (balanced portfolios) 來做管理,有些 IP assets予以保護,有些 IP assets 則分享給大眾,掌握客戶導向創新的機會,說不定可以協助公司創造出新的 business model 或進入不同的 industries。
  3. 要保持全球競爭力的公司,必須持續關注全球事業的發展、廣納全球的人才庫。透過全球的同盟、人力資本市集 (human capital marketplaces) 與同儕生產社群 (peer production communities) 來幫企業引入新的想法、市場、點子與技術。
  4. 在新的時代,人們逐漸不相信媒體與廣告,人們反而比較信任同儕的意見與社群網路
  5. Coase’s Law 的重點在於 transaction costs,交易成本過高,會影響交易的進行。隨著網路的興起,交易成本大幅降低,促進全球化交易的進行
  6. Peer production 能夠運行,至少要符合三個條件:
    1. 成員間的溝通成本低
    2. 任務可以切成一小塊一小塊,讓每個人在每一小塊做出貢獻,最後將每一小塊組成最終的產品或服務
    3. 整合每一小塊的成本也要低,包含社群間的領導機制、品質控管機制等
  7. Collaborative outsourcing 比較適合的是:公司產品中非核心的部分,或公司 business model 非核心的部分。以 IBM 來說,其 Web Servers 與 OS 落後其他競爭者一大截,擁抱 open source 並不會讓自己失去什麼,反而因為 peer production 而產生正向的效果
  8. Open source 的三個原則:沒有人擁有它每個人都可以使用它任何人都可以改進它。這也是open source 無止盡的創新的來源,但也帶給 IT 主管無盡的挫折,因為有太多的選擇,你必須挑選出品質優良、適用的 open sources,並將其組裝起來並運行正確
  9. 企業與大學建立夥伴關係,是加速創新與成長的好方法,但是要注意:
    1. 利用企業與大學的夥伴關係來整理出未來的產品線:企業必須要有新的刺激才會導入突破性的元素,開創新的產品
    2. 確保雙方是雙贏的關係:如此關係才會長久
    3. 研究社群間的合作要夠深且夠廣:不同社群可產生不同想法且產生綜效,不只是研究社群提供 inputs 給企業,企業也可提供解決方案給社群,加速研究腳步
    4. 技術的知識保持開放,最終的應用保持專屬(proprietary)
    5. 讓具代表性的客戶及早且時常參與,提供回饋:每當做出一個雛形就讓 early users 使用並提供回饋,不斷修正
  10. 對於企業來說,如何開放一個與外界合作的平台,是加速創新成功與擴大創新範圍的鎖鑰。每個企業的經營者都要問自己:
    1. 要如何建立一個與外界合作的平台?
    2. 選擇哪些事業要開放,如何、何時與在哪裡開放?
    3. 如何吸引外界的人才到此開放平台,一起合作與創新?
  11. 以Boeing為例,從一個飛機製造商變成整合成千上萬的合作夥伴的腳色,你必須要:
    1. 了解市場的需求且確保需求是可行的
    2. 必須將你所了解的轉換成需求
    3. 必須將所有的合作夥伴整合起來並朝向共同的目標前進 (這是最困難的部分)
    4. 建立一個合作的平台,可以讓所有合作夥伴在平台上即時溝通、分享資訊、進行元件/零件模擬測試相容性,避免到製造階段才發現不合用
  12. 將設計與開發產品的工作,從原本都是自己做,變成與供應商一起協同合作,這對雙方來說都是有利的。對於供應商來說,透過協同研發,可以增加公司的智慧財產,並且可以在終端產品上得到可觀的利潤。對於自身來說,變成整合者的角色,可以加速上市速度、公司敏捷度與具焦於高附價加值的活動
  13. 從 Boeing, BMW的身上我們可以學到:
    1. 聚焦於關鍵的價值驅動力:如汽車業應該從過去的製造汽車,變成設計 interface,讓合作夥伴們能順利的合作與與軟硬體測試
    2. 透過管理合作夥伴與協同合作來增加彼此的價值
    3. 透過協同合作的平台,加速設計流程
    4. 採用模組化的架構
    5. 建立一個透明的、人人平等的生態系統
    6. 大家一起分享決定權、利潤、成本與風險
    7. 敏銳地關注未來趨勢
  14. 傳統的工作場所像是個聽著軍樂、一個口令一個動作在行軍的軍隊;在未來,工作場所比較像是個爵士樂團,每個音樂家以有創意的方式,即興演奏旋律與節奏在座演奏。員工會自己建立與外界溝通的管道,形成跨功能的團隊並與外界做即時的溝通
  15. 未來的公司,不會是還停留在是否要參與、或是否要與 peer-production comminities 合作,他是要決定何時要加入這些社群,以及如何與這些社群合作,發揮綜效
  16. 對於公司經營者來說,有關 Openness,你要注意
    1. 你的競爭者在創新什麼東西?你要聚焦於如何做出不一樣的東西,與競爭對手差異化?
    2. 你的員工是否知道正確的 knowledge-creating networks,並從中獲取資訊?
    3. 有哪些產品、流程或資產你可以開放出來給大家知道,藉此降低 R&D 成本、提升成長? 以及如何增加所經營的 ecosystem 的參與人數?
    4. 你要決定你要加入哪個 ideagoras (http://www.ideagoras.biz/) 去獲得關鍵的創新材料,或是將你的創新授權給別人使用
  17. 有哪些 Intellectual Property & Proprietary 要開放,以下有幾個簡單的準則
    1. 若你提供的Proprietary產品或服務的市占率一直下降,不妨將其 open 出來,或許可以注入新的創意與人才,為日漸下滑的產品或服務注入新生命
    2. 若有些問題或瓶頸,內部一直無法突破,不妨將問題 open 出來,並提供相關的資訊與協助,擴展解決問題的人才庫
    3. 你是否有一個開放的平台,讓你的 ecosystems 裡面的夥伴們,能夠有效率的合作與創新
    4. 在與外部合作的專案,資訊要公開、透明,如此一來,參與者才會專注於手邊的工作,而非專注在爭奪專利所有權
  18. Enterprise 2.0 的企業是,打破企業高牆、善用外部知識、資源、能力與人才。讓自己成為創新中心,像個磁鐵把人才聚集起來。內部員工聚焦於價值整合與管理,將全世界當作是它們的研發部門

2016/12/31

2016/12 高雄

高雄彩虹教堂
DSC00946

高雄風車公園
DSC00950

DSC00953


駁二藝術特區
DSC00978


紅毛港文化園區
DSC00980
DSC00983


武德殿
DSC00998
DSC01014


鳳儀書院
DSC01028
DSC01055





2016/12/13

[iPhone] 無法連上VPN ,錯誤 619 : 無法建立與遠端電腦的連線,因此已關閉用於此連線的連接埠

Problem
因為工作關係,需要透過 VPN 連上另外一個工作地點的伺服器作業,其採用 PPTP 此通信協定


我利用 iPhone (手機作業系統為 iOS 10) 做為我連外的網路,但在一直遇到 VPN 連線錯誤,錯誤訊息如下:「錯誤 619 : 無法建立與遠端電腦的連線,因此已關閉用於此連線的連接埠」


How-To
經過幾天的搜尋資料與更改設定,仍舊無法解決此怪異的問題,一直看到 apple 的官網的一段描述
如果您設定了 PPTP VPN 伺服器,iOS 10 和 macOS Sierra 使用者將無法連線到該伺服器。iOS 10 和 macOS Sierra 會在使用者升級裝置時,移除任何 VPN 描述檔的 PPTP 連線。(If you’ve set up a PPTP VPN server, iOS 10 and macOS Sierra users won't be able to connect to it. iOS 10 and macOS Sierra will remove PPTP connections from any VPN profile when a user upgrades their device.)
此時改用其他人的手機 (如 android 手機或 iOS 10 以前的手機),卻可以成功連上 VPN ,代表是 iOS 將 PPTP 的 VPN 連線拒絕了,此時只能改用非 iOS 10 的手機來連線,或是更改 VPN Server 的協定,改用更安全的 L2TP/IPSec、IKEv2/IPSec 或 Cisco IPSec 等 protocols


Reference
[1] https://support.apple.com/zh-tw/HT206844
[2] https://mrmad.com.tw/upgrade-ios10-macos-sierra-pptp
[3] https://discussions.apple.com/thread/7673183?start=0&tstart=0

2016/12/11

[Windows 7] 如何將遠端的電腦重開機

Problem
當我透過遠端桌面連線來連到遠端的電腦時,若因某些緣故要重開遠端的電腦,但是其只有三個選項:登出、中斷連線與鎖定,無法從遠端重開




How-to
可以透過指令的方式達到重開機的目的,如 10 秒鐘後自動重開機,指令如下:
shutdown -r -t 10

若要關機,可以透過指令的方式達到關機的目的,如 10 秒鐘後關機,指令如下:
shutdown -s -t 10


Reference 
[1] https://technet.microsoft.com/en-us/library/bb491003.aspx

2016/12/10

[Windows 7] 無法遠端連線

Problem
當我要從我的電腦透過遠端桌面連線到另外一台電腦時,發生無法連線的錯誤



How-to
解決步驟如下 (以下設定是在遠端的電腦)
步驟 1. 於搜尋視窗輸入 gpedit.msc

步驟 2. 開啟本機群組原則編輯器後,透過左方目錄樹,到電腦設定→系統管理範本→Windows元件→遠端桌面服務→遠端桌面工作階段主機→連線 資料夾

步驟 3.  啟用 "允許使用者使用遠端桌面服務從與端連線"、設定 "限制連線數目" 為 999999 表示無限制連線數目




2016/12/09

[iPhone] 電腦與 iPhone 中的 google map 的 my map 資訊不一致

Problem
當我們在自助旅行時,會利用google map來做行程規劃 (如 http://goo.gl/iTD6d8 ),但是在 iPhone 使用上遇到一個問題,當我在電腦版的 google map 做了變動以後,在 iPhone 上的 google map app,卻沒有更新

How-to
1. 打開 google map app
2. 點選 Settings


3. 點選 About, terms and privacy


4. 點選 Clear Application Data


5. 點選 OK後, app 就會自動抓到最新的 map 資訊



Reference
[1] https://goo.gl/A306g0

2016/12/08

[Chrome Extension] Background Pages

A common need for extensions is to have a single long-running script to manage some task or state. Background pages to the rescue.

Assume I have a simple requirement, I hope it will print current timestamp each 3 seconds in background.

Steps are as bellows:

1. Define background scripts in manifest.json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "manifest_version": 2,
  "name": "Build Chrome Extension With AngularJS",
  "description": "利用 AngularJS 建置 Chrome Extension ",
  "version": "1.0",
  "permissions": [ "activeTab", "storage"],
  "browser_action": {
    "default_icon": "img/icon.png",
    "default_popup": "todo.html",
    "default_title": "Build Chrome Extension With AngularJS"
  },
   "commands": {
    "_execute_browser_action": {
      "suggested_key": {
        "default": "Alt+Shift+D"
      }
    }
  },
  "background": {
    "scripts": ["js/background.js"]
  },
  "options_page": "options.html"
}


2. Create background.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var myVar = setInterval(myTimer, 3000);

function myTimer() {
    var now = new Date();
    var year = now.getFullYear();
    var month = now.getMonth() + 1;
    var date = now.getDate();
    var hour = now.getHours();
    var minutes = now.getMinutes();
    var seconds = now.getSeconds();
    var time = year + '/' + month + '/' + date + ' ' + hour + ':' + minutes + ':' + seconds;
    console.log(time);
}


3. Reload extensions and open background page to test