[JS] AngularJS Tutorial 4

Step_04_篇

第四篇的教學,算是加強之前的觀念。重點 Model 與 View 的綁定關係。最後順便實做一下 ASP.NET PartialView 與 Angular 。

主頁面只做產生畫面及載入相關 css 的動作,InitDialog 則為註冊共用 controller 給 Partial,而過瀘器的部份如果有練習過前幾章節,應該是可以快速上手。

@section scripts{
 @Styles.Render("~/Content/themes/base/css")

 <script src="~/Scripts/angular.js"></script>
 <script src="~/Scripts/MyLibs/Tutorial_04/A001.js"></script>
 @Scripts.Render("~/bundles/jqueryui")

 <script type="text/javascript">
  $(function () {
   //建立 jquery UI
   InitDialog("My.Helpers.A001");
   //註冊 Angular
   angular.bootstrap(this);
  })
 </script>
 
}

<div ng-controller="My.Helpers.A001">
 <input ng-model="query">
 <select ng-model="sel">
  <option value="Date">ByDate</option>
  <option value="Todo">ByTodo</option>
 </select>

 <ul ng-repeat="item in History | filter:query | orderBy:sel">
  <li>{{item.Date}}/{{item.Todo}}</li>
 </ul>
</div>

@{
 Html.RenderPartial("~/Views/Home/common/DialogView.cshtml");
}

在 Partial 部份,則使用 jQuery 來為元素增加屬性。

<script src="~/Scripts/MyLibs/Dialog.js"></script>
<script type="text/javascript">
 function InitDialog(controller) {

  $("#DialogView").attr("ng-controller", controller);

  var m = new My.Helpers.Dialog( "#DialogView" );
  m.SetTitle("Show");
  m.Open();
 }
</script>

<div id="DialogView">
 <p>{{ForPart}}</p>
 <ul ng-repeat="item in History">
  <li>{{item.Date}}/{{item.Todo}}</li>
 </ul>
</div>

Controller 類,僅產生物件。

 function toLog(obj: any) {
 console.log(obj);
}

module My.Helpers {
 export interface I001 {
  History: M001[];
  //Partial Tip
  ForPart: string;
  //Init Dialog
  InitDialog: () => void;
 }
 export class M001 {
  Date: string;
  Todo: string;
  constructor(pDate:string, pTodo:string) {
   this.Date = pDate;
   this.Todo = pTodo;
  }
 }

 export class A001 {
  constructor($scope: I001) {
   console.log($scope);

   $scope.History = [];
   $scope.History.push(new M001("01", "A"));
   $scope.History.push(new M001("02", "B"));
   $scope.History.push(new M001("03", "C"));
   $scope.History.push(new M001("04", "D"));
   $scope.History.push(new M001("05", "E"));
   $scope.History.push(new M001("00", "Z"));
   
   $scope.ForPart = "Angular to Partial";
  }
 }
}

Partial View 控制 UI 類

function toLog(obj: any) {
 console.log(obj);
}

declare var $;

module My.Helpers {
 export class Dialog {
  Name: string;

  SetTitle(pTitle: string): void {
   $(this.Name).dialog({"title":pTitle});
  }

  Open(): void {
   $(this.Name).dialog("open");
  }

  constructor(pName: string) {
   this.Name = pName;

   $(this.Name).dialog({ autoOpen: false });
  }
 }
}

[JS] AngularJS Tutorial 3

Step_03_篇

昨天花了點時間研究了 Jasmine, 拿來做單元測試還滿方便的…再加上 TypeScript 本身也有支援,用起來感覺超好。而 Angular 本身則有提供這功能,使用上 也更加方便。

//引用
<script src="~/Scripts/angular-scenario.js" ng-autotest></script>

//開始測試
<script type="text/javascript">
 'use strict';

 describe('Unit Test', function () {

  it("Intro", function () {
   var t = "test";
   expect(t).toBe("right");
  });

 });
</script>

filter,也可以自定義 JS 版本的 過瀘器

<div ng-controller="My.Helper.A002">
 <input ng-model='query'/>

 <ul>
  <li ng-repeat="ch in EnChars  | filter:query">[{{$index + 1}}] {{ch}}
  </li>
 </ul>

 <p ng-show="checked">ShowMe</p>

</div>

module My.Helper {
 export interface IA002{
  EnChars: string[];
 }

 // Class
 export class A002 {
  // Constructor
  constructor($scope: IA002) {
   console.log($scope)

   $scope.EnChars = [];
   for (var i: number = 97 ; i < 123 ; i++) {
    $scope.EnChars.push( String.fromCharCode(i) + String.fromCharCode(Math.random() * 100) + String.fromCharCode(Math.random() * 100) );
   }
   //console.log($scope.EnChars);
  }

 }

}

最後,使用 ASP.NET 再實作 Jasmine 時,如果是再同一頁,會發生找不到指定物件的現像。目前只能把 Runner 跟測試頁分開。

//留意!
beforeEach(function () {
 browser().navigateTo('/');
});

describe('Learn', function () {
    
 it('測試_0', function () {
  input('query').enter('a');
  expect(repeater('li').count()).toBe(1);
 });

});

[JS] AngularJS Tutorial 1 & 2 Note

Step_01_篇 Step_02_篇

當使用 AngularJS 與 傳統頁面的差異。反而, Jasmine Wiki 是我覺得比較好玩的,可以直接做單元測試。 雖然不是必需的,但是學習一下對自已 JS 專案的測試會有加成效果。從 lib 看知道有那些功能, jasmine.Matchers.prototype,這些功能都可能在官網那邊找到對應範例。下面則是從 Browser 的代碼做筆記。

describe('描述',function(){
 it('單元測試名稱或內容或目地,會顯示在標頭',function(){
  //預期(來源值)應該為(來源值)
  expect(來源值).toBe(來源值);
 });
});

[JS] AngularJS Tutorial 0-Bootstrapping Note

Step_00_篇

Bootstrap,先偷看一下說明文件…除了原本的 ng-app,AngularJS 讓使用者可以手動決定初始的時 間點。直接切至函式,可以看到 bootstrap(element, modules) 的結構。至於,$provide$injector,還無法很完全的理解,先小記…。

<script src="~/Scripts/angular.js"></script>
<script type="text/javascript">
 $(function () {
  angular.bootstrap(this);
 });
</script>

//網頁語法
<div>
 Hi !! {{UserName}}!
 <input type="text" ng-model="UserName" />
</div>

[JS] AngularJS Note [關於 Watcher 及 scope ]

用 TypeScript 做了一下簡單的測試,與 Knockout 的想法,有異曲同工之妙,bind-with 改由 controller 來做取代。不過光綁定這個動作… 實在加成分數太多。

<div ng-app>
 <div ng-controller="My.Helpers.C0001">
  <p>{{TestValue0 || "請輸入"}}</p>
  <input type="text" ng-model="TestValue0" />
  <input type="button" value="Remove" ng-click="Remove()"/>
  <input type="button" value="Add" ng-click="Add()"/>
 </div>

 <div ng-controller="My.Helpers.C0002">
  <p>{{TestValue1 || "請輸入"}}</p>
 </div>

 <div ng-controller="My.Helpers.C0003">
  <p>{{TestValue2 || "請輸入"}}</p>
 </div>

</div>
function toLog( obj : any) {
 console.log(obj);
}

module My.Helpers {
 export interface I0001 {
  TestValue0: string;
  Add: () => void;
  Remove: () => void;
 }
 export interface I0002 {
  TestValue1: string;
 }
 export interface I0003 {
  TestValue2: string;
 }
 export class C0001 {
  constructor($scope: I0001) {
   // 測試 $$watch 陣列當中值的變動
   $scope.TestValue0 = "C0001";
   $scope.Add = function () {
    this.TestValue0 = "C0001X";
   }
   $scope.Remove = function () {
    delete (this.TestValue0);
   }
   toLog($scope);
  }
 }

 export class C0002 {
  constructor($scope: I0002) {
   $scope.TestValue1 = "C0002";
   toLog($scope);
  }
 }

 export class C0003 {
  constructor($scope: I0003) {
   $scope.TestValue2 = "C0003";
   //每個 Ctrl 有個自的 $$watchers...
   //而 scope 也會自動分配,可以從 物件有 add 函式,
   //而物件2,3都沒有該項函式中知道
   toLog($scope);
  }
 }
}

[C#][Dictionary] 基本運用

小記一下,再 C++ std::map::find常用這指命來取得對應的資訊,只要結果不等於 map::end,就表示有找到對應的值,但在 C# 當中,如果直接使用 key 來驗證是否為 null,則會造成 nullable exception,學習長知識一下。

using System;
using TestConsol.MyLibs;

namespace TestConsol
{
 class Program
 {
  static void Trace(T param)
  {
   Console.WriteLine(param);
  }

  static void Main(string[] args)
  {
   Trace("test");

   TestDic temp = new TestDic();
   temp.AddData("a","is a");
   temp.AddData("a", "is b");
   
   Console.WriteLine("Value ==> {0}", temp.HasDataByKey("a") );

   Console.WriteLine("Value ==> {0}", temp.GetDataByKey("a") );

   Console.ReadKey(true);
  }
 }
}

取資料當然也可以使用 return dicData.FirstOrDefault( x => x.Key == _key ).Value; 但這樣會變成使用 IEnumAble iterator,如果是使用 List 應該就很建議使用。原因應該很多達人都有分享,不再累述。

using System.Collections.Generic;

namespace TestConsol.MyLibs
{
 /// <summary>
 /// @link http://www.dotnetperls.com/dictionary
 /// @link http://msdn.microsoft.com/zh-tw/library/xfhwa508(v=VS.95).aspx
 /// </summary>
 class TestDic
 {
  /// <summary>
  /// 資料儲存區
  /// </summary>
  private Dictionary<string, string> dicData = null;
  public TestDic() {
   dicData = new Dictionary<string, string>();
  }

  /// <summary>
  /// 加入資訊
  /// </summary>
  /// <param name="value"></param>
  public void AddData( string _key, string _value  ){
   if (!HasDataByKey(_key))
   {
    dicData.Add(_key, _value);
   }
   else {
    dicData[_key] = _value;
   }
  }

  /// <summary>
  /// 經由 Key 取得資料
  /// </summary>
  /// <param name="_key">ID 值</param>
  /// <returns></returns>
  public string GetDataByKey(string _key)
  {
   //return dicData.FirstOrDefault( x => x.Key == _key ).Value;
   if (HasDataByKey(_key))
   {
    return dicData[_key];
   }
   return null;
  }

  /// <summary>
  /// 是否已經有這筆資料
  /// </summary>
  /// <param name="_key"></param>
  /// <returns>true 則表示有這筆資料</returns>
  public bool HasDataByKey(string _key) {
   return dicData.ContainsKey(_key);
  }

 }
}


[JS][Knockoutjs]Todo 練習

最近在練習 Angular 突然覺得,應該也要補一下 knockoutjs 的練習。本來還有 Tempalte 的運用,但是覺得實用性好像不高,就沒有加進來了。

  • 日期:
    內容:

順便補一個,TypeScript 的寫法,再引數當中,也是可以這樣使用的。

Note(T: { value; todo; }) {
 //console.log(T.value);
}

[JS][LINQ]LINQ to JavaScript Note

原文引用

這東西算是無意間發現的,竟然有中文版,那就來玩一下,順便小記一下。
安裝指命 Install-Package jslinq

引用""
  1. 投影:Select, SelectMany
  2. 條件檢查:Where
  3. 排序:OrderBy, OrderByDescending, Reverse
  4. 轉換成陣列:ToArray
  5. 設定:Distinct, Intersect
  6. 數量詞作業:Any, All
  7. 串連資料:Concat
  8. 彙總:Count
  9. 項目作業:First, Last, FirstOrDefault, LastOrDefault, ElementAt, ElementAtOrDefault, DefaultIfEmpty

上面這段算是功能小記,而安裝完後可以在 JSLINQ-vsdoc.js 這隻檔案當中看到功能細項。而在多數函式的引數,都可以看到 clause 這個字眼。下方為引用...

引用""

這個參數是用來傳回特定條件是否成立(例如 Where)或是處理後續程序(如 Select)所需要的函式指標,就如同在使用 jQuery 的 Callback 函數一樣。

資料結構可以是一般陣列或是 JSON 物件

$(function () {
 var singleArray = new Array(0, 2, 3, 6, 65, 30, 430, 654, 23, 103, 49, 97);

 function sortArray() {
  JSLINQ(singleArray)
  .Where(function (item) { return (item >= 50 && item <= 100); })
  .OrderByDescending(function (item) { return item; })
  .Select(function (item) {
   $("#container").html($("#container").html() + "
" + item); }); } sortArray();

文章最後還有其它推的 JS+LINQ,像linqjs裡面函式功能多到不行,不過看了一下時間,仍停留在去年,而且還在 Beta。最後,又看到了一套 breezejs,看了這套… 我覺得前面都不重要了... 可搭配的選擇,也都是目前滿流行的 JS 類,目前是免費狀態,當然付費後,可以得到的服務是比較多的。

[JS][Knockout] 測試 observableArray

本來只是單純想寫一段代碼,記錄在使用 knockout 時遇到的問題,結果打一打就寫成一個小功能了。ko.observableArray 這功能搭配本身的 for-each ,可以很 快速的達到動態物件產生,如第二段代碼的 15 行,但也造成了一個盲點,如果物件數量過多整體效能就會變得很差,所以,這時應該先暫存在純 Array 上,等最後 產生完畢之後再指定給 observableArray 對像,這樣效能會好一些,此外,順便測試了一下,ko.toJSON(),果然引數值是可以使用自定義的...,應該是為了方便直接 輸出吧...

var ko;
var $;

// Module
module My.Helper {
 export class Data {
  myDate: string;
  myTodo: string;

  constructor(txtDate: string, txtTodo: string) {
   this.myDate = txtDate;
   this.myTodo = txtTodo;
  }
 }
 // Class
 export class Test {
  public txtDate: (input?:string)=>string ;
  public txtTodo: (input?: string) => string;

  public data: Data[];
  constructor() {
   this.data = ko.observableArray([]);
   
   this.txtDate = ko.observable("2013-05-24");
   this.txtTodo = ko.observable("");
  }

  AddTodo(): void {
   this.data.push(new Data(this.txtDate(), this.txtTodo()));
   //using ko
   //console.log( ko.toJSON(this.data) );
   //console.log( ko.toJSON({ a: 123, b: "test" }) );
   //console.log(ko.toJSON(this["data"]()[0] ));
  }
 }

}

不得不說,TypeScript 真的很方便… 可能因為編輯器的支援度也夠高吧… 用起來順手的很


<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.0/knockout-min.js"></script>
<script type="text/javascript" src="~/Scripts/myLibs/Test0002.js"></script>
<script type="text/javascript">
 var model;

 $(function () {
  model = new My.Helper.Test();
  ko.applyBindings(model);
 })

</script>
 
<ol data-bind="foreach: data">
 <li>
  <b data-bind="text: myDate" style="color:red"></b>
  <b data-bind="text: myTodo"></b>
 </li>
</ol>

<input type="date" data-bind="value: txtDate"/>
<input type="text" data-bind="value: txtTodo" />
<br/>
<button data-bind="click:AddTodo">Add Todo</button>

[ASP.NET] Creating Web APIs Note

筆記

文章區塊會以大段落為主,而每個段落之間的分枝,就直接寫在一起,只保留關鍵字。

原文引用

1. Getting Started

關於試作 WebAPI 的部份,這邊算是入門教學,照著做就對了。所以,並不會有什麼不一樣的地方 Http Request Life Cycle 反倒是意外發現這張圖,解說從 Client 端發出送請求到訊息回應的流程圖。

2. Creating Web APIs

名詞解說 CRUD stands for "Create, Read, Update, and Delete"。這四個動作是基於與資料庫做溝通時,通常會使用到的動作,也是多數網頁請求會使用到的行為。 基本上選擇空白具可讀取的選項,都會自動幫使用者建立出這四個函式。路徑與函式之間的概念, 可能會需要去了解 MVC Routes 才會懂這邊想表達的意思。當收到Client端的請求時, 預設是以請求的形態來做 map 的動作。

$(function () {
 $.ajax({
  type: "Get",
  url: ""
 });
});

對收到的對像來說,會先至 Routes 找尋對應規則 ,再預設當中,如 type Get 則會優先尋找開頭為 Get 且不需攜帶引數的函式。

Request.CreateResponse<T>(HttpStatusCode.Created, new T());

Http StatusCode 允許使用者定義回應狀態。

Entity Framework 設計
  1. Database-first
  2. Model-first
  3. Code-first

Entity Framework 會使用 ID 屬性來當 primary key 並自動 map 到資料庫的欄位,所以 DB 會自動產生這個值。POCOs (plain-old CLR objects) [ScaffoldColumn(false)] 告訴 MVC 產生表單編輯時,請略過這個屬性,或者說不用編輯。 [Required] 對當前 Model 對言,必需是有效值且不能為空白字串。修改預設回應 xml 為 json 格式, Response 物件就會被序列化成 json 格式。建好這部份的關聯,可以在 伺服器管理員 -> 資料連接當中發現 DbContext(EF) 物件。

var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;

config.Formatters.Remove(config.Formatters.XmlFormatter);

自定義測試這邊,DropCreateDatabaseIfModelChanges 一直無法觸發到 Seed 這函式,看了一些討論文章,大家的做法不差異不會很大,也有人在討論觸發的時機點,感覺是個有問題的功能。 暫時先不理會這段,之後再來深入。後面就只剩下畫面呈現的部份,就不在紀錄。

WebAPI Doc 對應 XML 註解樣式 經由 Package Manager Console Install-Package Microsoft.AspNet.WebApi.HelpPage,對於相同名稱的函式,ApiExplorer 也會自動做區分,讓每個函式都是唯一的, 不顯示的函式,[ApiExplorerSettings(IgnoreApi=true)] 直接加上標籤就會略過了。

3. Web API Clients

Console 及 WPF Application 模式,則是使用 HttpClient 就可以處理完畢。HTTP Message Handlers 等五章節再來研究。

4. Web API Routing and Actions

關於 HTTP Methods,使用者可以指定當前的 Mathod 所提示的支援,HttpGet, HttpPut, HttpPost, or HttpDelete, 同時,也可以使用 [AcceptVerbs("GET", "HEAD")],同樣的,也可使用 [ActionName("youwant")] 來讓 Template 對應至這個位置。對應的 tag 則為 [NonAction]

5. Working with HTTP

在測試狀態,可以使用System.Diagnostics.Debug.WriteLine("輸出至(輸出視窗)"); 將需要測試的內容輸出到視窗,不見得一定要下中斷點,經由圖解可以知道 Message Handlers 的流程,所以再收到 Request 到 Response 的過程,如果想要額外處理訊息, 就會需要委派到別的訊息處理。比較需要留意的是當自行定義 task 回應之後,流程是無法到達 ctrl ,而純修改 Response ,只需要重新設定關係鏈結仍可以到 ctrl。 如範例的 ApiKey,就可讓某些頁面必需有 ApiKey才能使用,這類型的工作就可以委派出去。

DelegatingHandler[] handlers = new DelegatingHandler[] {
 new MessageHandler3()
};

//需自行定義結束點,讓流程可以進行到 ctrl 。
var routeHandlers = HttpClientFactory.CreatePipeline(
 new HttpControllerDispatcher(config), handlers);

config.Routes.MapHttpRoute(
 name: "Route2",
 routeTemplate: "api2/{controller}/{id}",
 defaults: new { id = RouteParameter.Optional },
 constraints: null,
 handler: routeHandlers
);
6. Formats and Model Binding

MIME type 的結構解說,通常會有主(次)描述用來描述訊息內容的規格,如 text/html。所以,使用者可以自行定義所要描述訊息內容,再做序列化的處理。 最後,對應不同平台做註冊的動作。Asp.Net 直接註冊再 WebApiConfig 裡面。

不使用第三方 Json

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.UseDataContractJsonSerializer = true;

以類別來說,預設會將所包含的屬性欄位,全序列化為 Json 格式,但可能有些屬性是不需要輸出,這時就可以使用 Newtonsoft.Json.JsonIgnore; [JsonIgnore]來做修飾。另一種則是使用 [DataContract],則有使用到 [DataMember],才會認定做序列化處理。XML 產生序列化的開關,仍是使用 [DataContract] 及 [DataMember], 而當 A 有 B 物件,B 有 A 物件 的環狀結構。則需額外設定。

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.All;

最後的這隻類別,還滿不錯用的…連泛型都直接寫好了。收起來...

Content Negotiation
  • Accept: Which media types are acceptable for the response, such as “application/json,” “application/xml,” or a custom media type such as "application/vnd.example+xml"
  • Accept-Charset: Which character sets are acceptable, such as UTF-8 or ISO 8859-1.
  • Accept-Encoding: Which content encodings are acceptable, such as gzip.
  • Accept-Language: The preferred natural language, such as “en-us”.

Model 屬性驗證,簡單的來說,這類別裡面的屬性 都可以拿來做驗證,例 PhoneAttribute 則為 [Phone] ,最後對應 ModelState.IsValid,而當驗證失敗時,針對錯誤的欄位做失敗 處理。

7. OData

Install-Package Microsoft.AspNet.WebApi.OData
System.Web.Http.OData
EntitySetController<TEntity, TKey>
在 API 函式上增加 [Queryable] ,就有基本功能可支援。暫時還想不出硬要擴充出來的功能。


本來想繼續做些 Data Develop 部份的筆記,但看了一下,多到讓人完全動力不足阿...先小記吧!!

Data Developer Center

[JS][Tools][0] TypeScript Note

相關網站

TypeScript (codeplex)專案 | TypeScript 官方網站 | Web Essentials | DefinitelyTyped

目前為止,我覺得 TypeScript 的上手度還滿高的,基本寫作模式在官方網站的影片也有解說,比較可惜的是 private 及 public ,只在 ts(TypeScript) 當中有效,最後輸出的時侯,仍然是無視這些。

DefinitelyTyped 可以到這邊找尋對應的 JS 工具, 最近很火紅的 angularjs 也有。

$(function () {
 // press f12, chrome debug mode
 var p = new My.Helper.Tools();
 p.Run();
 p.Run4();
});

namespace 觀念跟其它程式語言相同,只要不重覆就可以放在一起。

// Module
module My.Helper {
 // Class
 export class Tools{
  // Constructor( 選擇性 )
  constructor() { }
  //預設為 public
  Run(): void {
   //靜態用法
   Test.Run_0();

   var t = new Test();
   t.Run_1();
   t.Run_2();

   //不允許
   //t.Run3();
  }

  private Run4(): void {
   console.log("private Run_4");
  }
 }

 export class Test {
  constructor() { }
  static Run_0(): void {
   //for chrome
   console.log("static Run_0");
  }

  Run_1(): void {
   console.log("public Run_1");
  }

  public Run_2(): void {
   console.log("public Run_2");
  }

  private Run3(): void {
   console.log("private Run_3");
  }
 }

}

正常來說,有寫過其它程式語言,無痛上手應該是沒問題的 !!

外部 ts 檔的引用

/// <reference path="Test0000.ts" />
// Module
module My.Helper {
 // Class 繼承自 TestParent
 export class TestChild extends TestParent{
   // Constructor
  constructor() { super(); }
 }
}

被引用的對像

// Module
module My.Helper {
 // Class
 export class TestParent {
  constructor() { 
   //call me 
  }
 }
}

目前為止再專案上的使用,個人覺得還滿方便的,用法上可能上手度很高,所以覺得沒啥必要介面語法,除了比較特殊的地方。此外,ts 強型別對 debug 的幫助,也不小補,最後,可以暫時跳脫一堆 html 代碼 = =!! 。


網站記錄...

自從上次整理完一次 blog,就跑去工作到現在…不知不覺中,又過了二年。

前一年的工作依舊著眼在 flash 的開發,也參與了部份的框架的撰寫與構思,感覺還滿充實的。真的停下來回顧時,才發現一轉眼一年過了… 產品也正式上線了。其實,心理層面的學習,佔了很大的一部份吧。

第二年,開始開發手機的遊戲,排除時間上的壓力,學習新東西… 真的滿能帶給人滿足感,而在不同程式碼之間的游走,一不小心就又亂錯,常常 C++ 寫一寫,切回 Java Debug… 搞定之後,有時還會有人來詢問 AS3 的問題,那陣子自已都覺得好笑,有時除錯到都有點錯亂。不過,就程式上來說,是滿足的...

今年會開始把焦點,放在 Asp.Net 及 Go, 與 Dart 上。還是覺得應該小記,不然要記的東西,實在太多了。關於之前的檔案,想了一下,還是決定不救了,Google App Engine,看起來只能針對文字資訊來做備份,所以暫時就先這樣子,之後在抽時間整理 blogger 的代碼吧。