Total Pageviews

2016/01/31

2016/01 Travel

進擊的巨人展



2016/01/27

[AngularJS] How to set selected row and set highlight in ng-gird pragmatically?

Requirement
After I create a new record, the program should refresh the data grid and set selected item and highlighted the selected item.


After I update an existing record, the program should refresh the data grid and set selected item and highlighted the selected item.


Here has the code snippet regarding ng-grid:
 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
        $scope.itemGridCols  = [ 
            {
               field : 'accountYr',
               displayName : '年度',
               cellClass: 'text-left',
               width: '150px'
            }, 
            {
               field : 'orgType',
               displayName : 'orgType',
               cellClass: 'text-left',
               visible : false
            },
            {
                field : 'orgTypeName',
                displayName : '機關類別',
                cellClass: 'text-left',
                width: '250px'
             },
             {
                field : 'masterAge',
                displayName : 'masterAge',
                cellClass: 'text-left',
                visible : false
             },
             {
                field : 'masterAgeName',
                displayName : '主管機關名稱',
                cellClass: 'text-left',
                width: '250px'
             },
             {
                field : 'ageName',
                displayName : '機關名稱',
                cellClass: 'text-left',
                width: '250px'
              },
             {
                field : 'age',
                displayName : '機關代號',
                cellClass: 'text-left',
                width: '250px'
             }
          ];
        
        $scope.itemGrid = {
                keepLastSelected: false,
                selectedItems: $scope.selectedItem,
                multiSelect : false,
                data : 'itemData',
                columnDefs : 'itemGridCols',
                enableColumnResize: true,
                afterSelectionChange : function(rowItem){ 
                    if (rowItem.selected) {
                        $scope.model.accountYr = rowItem.entity.accountYr;
                        $scope.model.orgType   = rowItem.entity.orgType;
                        $scope.model.masterAge = rowItem.entity.masterAge;
                        $scope.model.ageNm     = rowItem.entity.ageName;
                        $scope.model.age       = rowItem.entity.age;
                    }else{
                        $scope.model = {};
                        
                        $scope.model.accountYr = getCurrentYear()-1;
                    }
                }
        };

create and update button code snippet is as following:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
        $scope.createBtn = function(){
            // 驗證表單
               if (!$scope.validate(this.dbm039eForm)) {
                   return;
               }
               
               dbmService.execute("rest/create", $scope.model)
                   .then(function(response) { 
                       $scope.itemData = response;
                       cAlerter.info('新增成功');
                   }
               );
          };
          
          $scope.saveBtn = function(){
              dbmService.execute("rest/save", $scope.model)
                  .then(function(response) { 
                      $scope.itemData = response;                    
                      cAlerter.info('修改成功');
                  }
              );
          };

How To
Utilize $scope.itemGrid.selectRow(index, true); to fulfill this requirement, and remember to move this code in $timeout:
 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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
         $scope.setSelectedRow = function(itemData, selectedItem){
              var index = 0;
              var keepGoing = true;

              angular.forEach(itemData, function(value, key) {
                  if(keepGoing){
                      if(value.accountYr == selectedItem.accountYr && 
                         value.orgType == selectedItem.orgType  && 
                         value.age == selectedItem.age){
                           index = key;
                           keepGoing = false;
                      }
                  }
              });
              
              // remember to set select row in $timeout, or it will NOT work
              $timeout(function () {
                  $scope.itemGrid.selectRow(index, true);
              },1 );
              
          };
    
        $scope.createBtn = function(){
            // 驗證表單
               if (!$scope.validate(this.dbm039eForm)) {
                   return;
               }
               
               dbmService.execute("rest/create", $scope.model)
                   .then(function(response) { 
                       $scope.itemData = response;
                       
                       //set model to selectedItem
                       $scope.selectedItem[0] = $scope.model;
                       //set selected row
                       $scope.setSelectedRow($scope.itemData, $scope.selectedItem[0]);
                       
                       cAlerter.info('新增成功');
                   }
               );
          };
          
          $scope.saveBtn = function(){
              if($scope.selectedItem.length == 0){
                  cAlerter.fatal('請選擇要修改的資料');
                  return;
              }
              
              dbmService.execute("rest/save", $scope.model)
                  .then(function(response) { 
                      $scope.itemData = response;
                      
                      // set selected row
                      $scope.setSelectedRow($scope.itemData, $scope.selectedItem[0]);
                      
                      cAlerter.info('修改成功');
                  }
              );
          };
          
         


Reference
[1] https://github.com/angular-ui/ui-grid/issues/2267

2016/01/08

[Oracle] Nulls with Comparison Conditions

Problem
Assume the data in the table is as following:
1
2
3
4
select fyr, age, type1
from ave107fa
where paydat between '1041201' and '1041231'
order by type1 ;



We can find out the value of type1 has D and null.

If I would like to find the data which Type1 is not eqal to D:
1
2
3
4
5
select fyr, age, type1
from ave107fa
where paydat between '1041201' and '1041231'
       and type1 <> 'D'
order by type1 ;

But Oracle return nothing
:


How To
In Oracle,  null represents a lack of data, a null cannot be equal or unequal to any value or to another null. Therefore, it will return nothing.

Hence, we can modify SQL statement as bellows:
1
2
3
4
5
select fyr, age, type1
from ave107fa
where paydat between '1041201' and '1041231'
      and nvl(type1, ' ') <> 'D'
order by type1 ;


The data which Type1 is null can be retrieved now:


Reference
[1] https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements005.htm

2016/01/07

[Spring Framework] Spring Data JPA @Query

If I have an SQL query statement which is simple, and not dynamic, we can utilize @Query to fulfill out requirement.

Example 1. Apply @Query without parameter:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public interface Dbm002fbRepository extends EntityRepository<Dbm002fb, String> {

    /**
     * 找出 kind_code = 'DEBTT' 的下拉單.
     * 
     * @return the list
     */
    @Query(value = "select * from dbm002fb where kind_code='DEBTT' and is_use='Y' order by code_no", nativeQuery = true)
    List<Dbm002fb> findDEBTT();

    /**
     * 找出 kind_code = 'DEBTI' 的下拉單.
     * 
     * @return the list
     */
    @Query(value = "select * from dbm002fb where kind_code='DEBTI' and is_use='Y' order by code_no", nativeQuery = true)
    List<Dbm002fb> findDEBTI();
}


Example 2. Apply @Query and bind named parameters:
1
2
3
4
5
6
7
public interface Fms426faRepository extends EntityRepository<Fms426fa, Fms426faId>,
        Fms426faRepositoryCustom {

    @Query(value = "select * from fms426fa where accyr=:twYear and data_type='T' order by rpt_no", nativeQuery = true)
    List<Fms426fa> findTAlcAmt(@Param("twYear") String twYear);

}


Reference
[1] http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query
[2] http://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-from-method-names/

2016/01/06

[Git] The requested URL returned error: 403

Problem
When I try to clone project from GitLab, it shows the following error message




How-To
Try to use SSH instead of HTTP, this annoying problem will be resolved.




But the root cause does not know yet.




2016/01/05

[Fortify] Fix Unreleased Resource: Streams

Problem
The following code snippet had been complain unreleased resource problem by Fortify : 
 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
 @RequestMapping(value = "/importFile", method = RequestMethod.POST)
    public @ResponseBody
    void importFile(@RequestParam("file") MultipartFile multipartFile, Dbm002eFormBean formBean,
            Alerter alerter) throws IOException {

        ImportTypeEnum importType = ImportTypeEnum.IT0; // 匯入維度 (固定帶年度)
        String importId = formBean.getImpType(); // 匯入代號
        UpdTypeEnum updType = null; // 更新類別
        if ("0".equals(formBean.getUpdType())) {
            updType = UpdTypeEnum.UT0;
        } else if ("1".equals(formBean.getUpdType())) {
            updType = UpdTypeEnum.UT1;
        }
        Integer subtractYears = 5; // 減去X年
        String userId = UserHolder.getUser().getId(); // log in user id
        InputStream inputStream = null;
        try {
            inputStream = multipartFile.getInputStream();
            // file input stream
            String fileName = multipartFile.getOriginalFilename(); // file name
            
            if(!StringUtils.endsWith(fileName, ".xls") || !StringUtils.endsWith(fileName, ".XLS")) {
                throw new RuntimeException("只接受副檔名為 xls 的檔案, fileName = " + fileName);
            }

            importFileProcessService.saveImportFile(importType, importId, updType, subtractYears,
                    userId, inputStream, fileName);

            alerter.info("檔案上傳成功 (檔名:" + fileName + ")");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


How-To
It results from inputStream does not been close properly. Here has the updated code snippet:
 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
36
37
@RequestMapping(value = "/importFile", method = RequestMethod.POST)
    public @ResponseBody
    void importFile(@RequestParam("file") MultipartFile multipartFile, Dbm002eFormBean formBean,
            Alerter alerter) throws IOException {

        ImportTypeEnum importType = ImportTypeEnum.IT0; // 匯入維度 (固定帶年度)
        String importId = formBean.getImpType(); // 匯入代號
        UpdTypeEnum updType = null; // 更新類別
        if ("0".equals(formBean.getUpdType())) {
            updType = UpdTypeEnum.UT0;
        } else if ("1".equals(formBean.getUpdType())) {
            updType = UpdTypeEnum.UT1;
        }
        Integer subtractYears = 5; // 減去X年
        String userId = UserHolder.getUser().getId(); // log in user id
        InputStream inputStream = null;
        try {
            inputStream = multipartFile.getInputStream();
            // file input stream
            String fileName = multipartFile.getOriginalFilename(); // file name
            
            if(!StringUtils.endsWith(fileName, ".xls") || !StringUtils.endsWith(fileName, ".XLS")) {
                throw new RuntimeException("只接受副檔名為 xls 的檔案, fileName = " + fileName);
            }

            importFileProcessService.saveImportFile(importType, importId, updType, subtractYears,
                    userId, inputStream, fileName);

            alerter.info("檔案上傳成功 (檔名:" + fileName + ")");
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }





2016/01/03

[Oracle] How to compiles all procedures, functions, packages, and triggers in the specified schema.

Problem
If you do alter table in Oracle database, your stored procedures or views' state may become invalid as bellows:


You need to rebuild all invalid stored procedures one by one
1
ALTER PROCEDURE PROC_FMS406R_TAB5_RPT1_STEP1 COMPILE;

If I have multiple invalid stored procedures, it will be very annoying. 
Does Oracle provide any convenient way to rebuild all invalid stored procedures?

How-To
You can use exec dbms_utility.compile_schema(SCHEMA NAME) to fulfill this requirement. Assume my schema name is AP_PSR, then the command is as follows:
1
exec dbms_utility.compile_schema('AP_PSR');

See...all invalid stored procedures had become invalid




Reference
[1] http://dbataj.blogspot.tw/2007/08/how-to-compile-invalid-objects.html

2016/01/02

[閱讀筆記] 易讀程式之美 (Part 1)


  1. 程式碼應該易於理解
  2. 撰寫程式時,應該將讀者理解所需的時間降到最短
  3. 雖然減少程式碼數量是個很好的目標,但縮短理解時間更加重要
  4. 實務上,讓程式碼易於了解,往往也會產生良好的架構且易於測試
  5. 無論是重新命名變數、函數或類別,基本原則大同小異。名稱可視為簡短的註解,即使空間有限,透過選擇好的名稱就能包含許多資訊
  6. retval 這類名稱不包含任何有意的資訊,只能代表return value,應該使用能夠說明便數值意義的名稱
  7. tmp 這樣的名稱,只適用於變數生命週期很短,且作為暫存用途的變數
  8. 變數名稱不宜太長,名稱愈長就愈不容易記住,也會佔用更多畫面空間,甚至造成額外的自動換行
  9. 反覆思考名稱,自問別人會怎麼解釋這個名稱
  10. 對於邊界的極值而言,最清楚的方式是在名稱前面加上max_或min_
  11. 選擇 boolean 變數或回傳 boolean 值的函數名稱時,必須確保能清楚表示true / false的意義
  12. 一般來說,加上is / has / can / should 可以讓boolean value更加明確
  13. 避免在名稱中使用否定描述,如disableSSL,改用useSSL會比較容易閱讀且簡短
  14. 最好的名稱是最不容易被誤用的名稱,閱讀程式碼的人能夠清楚了解撰寫程式的人的意圖。不幸的是,許多英文單字在程式碼都會有兩種以上的解釋,如filter、length以及limit
  15. 在決定名稱前,要從反向思考,想像可能造成的誤解,最好的名稱能夠盡量避免誤會
  16. 對於定義數值的上下限,max與min是很有幫助的prefix;對於必區間,first與last也是十分合適的prefix;對於半開放區間,begin與end是符合使用慣例的好選擇
  17. 注意使用者對特定單字的預期,如使用者會認為get與size是lightweight accessor
  18. 良好的程式碼也應該賞心悅目,其應該包含以下三原則:排版一致,讓讀者習慣固定的模式;調整類似程式碼有相似的外觀;組織相關程式碼成為段落
  19. 賞心悅目的程式碼會比較容易處理,寫程式大多數時間都花在閱讀程式上,能預快瀏覽程式碼,就愈容易使用程式碼
  20. 一致化的風格比「正確」的風格重要
  21. 程式註解的目的是協助使用者了解程式碼作者的思想
  22. 不要註解那些能很快從程式碼知道的事實
  23. 好程式 > 壞程式 + 好註解
  24. 程式設計師常用的標記有,TODO:作者還沒處理的部份;FIXME:已知的問題:HACK:承認程式解決方法不夠優雅;XXX:危險!重要問題
  25. 程式註解要有高資訊空間比
  26. 使用包含大量資訊的詞彙讓註解更加簡潔
  27. 在使用if-else判斷式時,先處理肯定條件;先處理簡單的情況,必較能在畫面中同時呈現if與else區塊,在閱讀上很有幫助;先處理比較有趣或明顯的情況
  28. 縮短其他人理解程式所需的時間,比減少程式碼行數來得重要
  29. 只有在最簡單的情況下使用三元運算子,複雜的情況還是盡量使用if / else
  30. 避免使用do / while loop

2016/01/01

[閱讀筆記] The Intelligent Investor (Part 5)


  1. 公司用多餘的資金買回庫藏股,使在外流通的股數變少,進而提升公司每股盈餘,乍聽之下似乎不錯。實際上,是高階主管把配到的股票賣出,公司為了降低在外流通多的股數,才花錢將其買回並註銷
  2. 輪盤共有37個數字,賭對了可獲得35元,但猜對機率只有1/37,如為了每次都猜對每個數字都下注1元,這樣會反倒虧2元。這是莊家優勢,確保賭客賠錢。智慧型投資者也要用相同方式,提高贏錢機會,降低風險,多元化投資是個最簡單與便宜的方式
  3. 沒有好股票或壞股票,只有便宜的股票與昂貴的股票。即便是好公司,當他股價過高時,也是得賣掉;然而不好的公司,當它的股價夠低,也值得買進
  4. 投機與投資的差別在於,投機在買進的時候,"希望"股價會一直上漲;投資則是根據企業的價值來買進
  5. 投資四原則:一、知道你在做什麼;二、別讓其他人幫你操作;三、除非經過可靠計算得知此項投資可以產生合理利潤,不然不要進場;四、對你的知識與經驗要有信心
  6. 去達成可接受、令人滿意的投資成果,比一般人所以理解的還要簡單;但是,要達成優異的投資成果,卻比一般人想像的還要困難
  7. 想靠投資變有錢,方法就是『不要賠錢』
  8. 賠錢是投資中無法避免的一個部分,你無法完全預防。但是,身為一位智慧型投資者,你應該負起責任,確保不會失去你大部分或全部的資金,讓你元氣大傷,難以恢復
  9. 經過鉅額損失,恢復期要很久。假定有一筆投資每年有5%的獲利,如一開始第一年市場遭逢變故損失50%,即便接下來第二年開始,每年有10%的獲利,你也要花16年的時間才能恢復
  10. 投資時,別在一開始就投入太多資金,你應該要降低你的資產被瞬間摧毀的機會
  11. 財務危機不在於你擁有哪幾種投資項目,而是在你自己。時時提醒你自己,你就是自己的危機。你是否高估你對投資的理解?是否誇飾你度過價格崩跌的能力
  12. 好的投資決策的產生前,會先問自己兩個問題:我對投資的了解,是不是有我認為的這麼了解?如果我的分析到最後被市場證明是錯誤的,我該怎麼辦?
  13. 在投資前,你一定要先評估過,你分析正確的機率,以及若結果是錯的時候,你該如何重新站起來
  14. 在不確定的情況下所做的決定,其結果一定是被機率所支配,我們永遠不知道未來會長怎麼樣。所以,當結果不是你想像的那個樣子的時候,你一定要有能力去面對與處理這樣的結果。
  15. 成功的投資在於風險管理,而不是逃避風險
  16. 投資與不確定性,這兩個名詞其實是同義字。在真實世界,沒有人有能力去算出何時是最佳買點
  17. 投資是一場冒險旅程,未來永遠是一個未知的世界。抓準你的安全邊際、管理風險,可以讓你一生的投資航程更加安全與有自信
  18. No tree grows to heaven
  19. A bull can make money, a bear may make money, but a hog never makes money 
  20. 當一家公司賺的錢越多,就越有機會遇到新的競爭(因為有競爭者覬覦大餅)。新的競爭會導致商品售價降低、利潤減少的狀況。當時瘋狂的網路股買家,始終相信早期成功者將可永遠維持其競爭優勢,事實剛好相反