Home » Source Code » Using Markdown for Effective Logging

Using Markdown for Effective Logging

maninwest
2015-01-28 22:59:27
The author
View(s):
Download(s): 0
Point (s): 1 
Category Category:
.NET.NET Transact-SQLTransact-SQL

Description

MarkdownLog 
生成 Markdown格式的测试结果
我开发了一个免费的购物清单软件( 适用于 iOS)。我想我需要这样一个购物清单应用:可以在我键入条目提供建议并且根据商店的自动安排我的清单。

写测试套件
在进行更改前,我构建了一个测试套件。我可以在开发时运行它来检查是否损坏了什么或者降低了性能。
单元测试
单元测试会测试特定行为并返回 PASS/FAIL 结果
例如

Assert.AreEqual(3, Math.Sqrt(9));
Assert.AreEqual(Double.NaN, Math.Sqrt(-1));

单元测试很适合测试具有特定行为的单个方法和类。
皮下集成测试
皮下测试用来显示这个 APP 在用户界面下的性能和行为 -就像在皮下一样。
这些测试需要在真实数据和真实设备上进行来模拟用户体验。每个测试都有一些步骤,对应用户和设备之间的交互
例如
  1. 用户键入 br
  2. 希望面包 bread会出现推荐的物品中
  3. 用户从推荐列表中选择 bread
  4. 用户输入购物模式 Shopping Mode
  5. 希望 bread 可以归类到烘焙 Bakery 区
为了让测试的编写更加简单,我构建了一个框架,这样可以使用流利的编码风格精简地编写代码。 这个是使用和 app 相同的工具写的 - C#, .NET 和 Xamarin,这就意味着可以直接在 iPhone 上运行
完成的测试的例子:
tests.Run(app => app
    .Type("2 small onions").PressEnterKey()
    .Type("5 kilos of potatoes").PressEnterKey()
    .Type("br")
    .ExpectThat(x => x.SuggestionsInclude("bread"))
    .SelectSuggestion("bread")
    .StartShopping()
    .ExpectThat(x => x.CategoryContains("Bakery", new[] {"bread"}))
    .ExpectThat(x => x.CategoryContains("Fresh Fruit, Veg & Flowers",
        new[]
        {
            "2 small onions",
            "5 kilos of potatoes"
        })),
    synopsis: "Can select suggestion and categorise");

测试运行时,会记录每个用户动作和相关的观察、结果和时间信息。
测试框架中,我构建了个库  MarkdownLog,这个库可以简化从应用程序中的数据结构生成 Markdown 格式的文本的过程。使用一行代码,一组.NET对象可以输出为表格或列表。由于输出是 Markdown 格式,稍后还可以转化成 HTML 进行公布。
这是测试中提取的 Markdown 格式的记录
Summary of Test Suite Run
=========================

Suite completed on 17 July 2014 at 09:52:04 (UTC)

3 tests (223 actions) passed in **422** ms

     Result | Expected Behaviour                          | Actions | Time Taken
     ------:| ------------------------------------------- | -------:| ----------:
     PASS   | Can select suggestion and categorise        |      36 |        199
     PASS   | Common products are included in suggestions |      75 |        153 
     PASS   | Common brands are included in suggestions   |     112 |         80   

Environment
===========

     Key               | Value                               
     ----------------- | ------------------------------------ 
     HardwareModel     | iPhone 
     SystemName        | iPhone OS                           
     SystemVersion     | 7.1                                 
     AppVersion        | 1.01                                
     DeviceIdForVendor | ---

Test 1: Can select suggestion and categorise
============================================

Completed in **199** ms

*Note: Some output has been removed from here for brevity* 

Action: Type 'b'
----------------

Suggestions are shown:

     -------------
    | bread       |
    | beans       |
    | breakfast > |
     -------------

Action: Type 'r'
----------------

Suggestions are shown:

     -------------
    | bread       |
    | breakfast > |
    | British   > |
     -------------

Check: Suggestions list should include 'bread'
----------------------------------------------

PASS: 'bread' was present in the list of suggestions

Action: Choose 'bread' from suggestions list
--------------------------------------------

The shopping list now contains:

      -----------------------
     |  2 small onions       |
     |  5 kilos of potatoes  |
     |  bread                |
    >|                       |
      -----------------------

Action: Enter 'Shopping' mode
-----------------------------

Shopping mode has been entered.

Items have been categorised:

     --------------------------
    |Fresh Fruit, Veg & Flowers|
    |--------------------------|
    | [ ] 2 small onions       |
    | [ ] 5 kilos of potatoes  |
    |--------------------------|
    |Bakery                    |
    |--------------------------|
    | [ ] bread                |
     --------------------------

Check: Section 'Bakery' should contain 'bread'
----------------------------------------------

PASS: 'bread' was found in 'Bakery' section 

Check: Section 'Fresh Fruit, Veg & Flowers' should contain: '2 small onions', '5 kilos of potatoes'
---------------------------------------------------------------------------------------------------

PASS: '2 small onions' was found in 'Fresh Fruit, Veg & Flowers' section 
PASS: '5 kilos of potatoes' was found in 'Fresh Fruit, Veg & Flowers' section

Test 1 Timings (ms)
===================
      Typing '2'         |###  3
      Typing ' '         |###  3
      Typing 's'         |###  3
      Typing 'm'         |######  6
      Typing 'a'         |################################  32
      Typing 'l'         |#####  5
      Typing 'l'         |#  1
      Typing ' '         |##  2
      Typing 'o'         |##  2
      Typing 'n'         |###  3
      Typing 'i'         |#########  9
      Typing 'o'         |##  2
      Typing 'n'         |#  1
      Typing 's'         |###############  15
      Typing '5'         |  0
      Typing ' '         |#  1
      Typing 'k'         |###  3
      Typing 'i'         |#  1
      Typing 'l'         |########  8
      Typing 'o'         |##  2
      Typing 's'         |  0
      Typing ' '         |#  1
      Typing 'o'         |###  3
      Typing 'f'         |####  4
      Typing ' '         |#  1
      Typing 'p'         |####  4
      Typing 'o'         |###  3
      Typing 't'         |#####  5
      Typing 'a'         |###  3
      Typing 't'         |#  1
      Typing 'o'         |#  1
      Typing 'e'         |#########################################  41
      Typing 's'         |##  2
      Typing 'b'         |#  1
      Typing 'r'         |#  1
      Categorising items |###################  19
                         ------------------------------------------

Overall Slowest Timings
=======================

Note: timings are classified based on human perception metrics from [Jacob Nielson's article](http://www.nngroup.com/articles/powers-of-10-time-scales-in-ux/):

   * Anything that takes less than 0.1 seconds feels IMMEDIATE - as if the user 
     is directly causing something to happen.
   * Between 0.1 and 1 second is quick enough to give the user MAINTAINED-FOCUS 
     and feel in control.
   * Longer than 1 second but less than 10 seconds is acceptable for 
     MAINTAINED-ATTENTION, but the user may begin to feel impatient.
   * Generally, BROKEN-FLOW, will occur after 10 seconds and the user will
     context switch and do something else.

     Test                                        | Action             | Perception | Time (ms)
     ------------------------------------------- | ------------------ | ---------- | ---------
     Can select suggestion and categorise        | Typing 'e'         | IMMEDIATE  |        41
     Can select suggestion and categorise        | Typing 'a'         | IMMEDIATE  |        32
     Common products are included in suggestions | Typing 'g'         | IMMEDIATE  |        28
     Can select suggestion and categorise        | Categorising items | IMMEDIATE  |        19
     Common products are included in suggestions | Typing 'c'         | IMMEDIATE  |        19
     Common products are included in suggestions | Typing 'c'         | IMMEDIATE  |        19
     Can select suggestion and categorise        | Typing 's'         | IMMEDIATE  |        15
     Common products are included in suggestions | Typing 'w'         | IMMEDIATE  |        13
     Common products are included in suggestions | Typing 'b'         | IMMEDIATE  |        12
     Common products are included in suggestions | Typing 'b'         | IMMEDIATE  |        10



可以看出,Markdown 格式的日志原始记录非常易读,所以输出可以写到控制台中并立即查看。
MarkdownLog
MarkdownLog 是轻量级的,容易使用的 .NET 可移植(PCL) 类库,除了.NET 框架外,不依赖其他。
开始
  1. 从build 服务器中下载 MarkdownLog.dll 
  2. 从项目中添加到 MarkdownLog.dll 的引用
  3. 在文件顶部添加 using  MarkdownLog; .
  4. 从数据中生成Markdown 输出
MarkdownLog可以生成 Markdown 说明中的所有元素
从集合中创建一个列表
var myStrings = new[] { "John", "Paul", "Ringo", "George" };
Console.Write(myStrings.ToMarkdownBulletedList());

生成
   * John
   * Paul
   * Ringo
   * George




该集合可以是任何类型,不一定是 strings。会调用每个对象的 ToString 来生成清单项目文本,你也可指定一个函数,如:
var processes = Process.GetProcesses();
Console.Write(processes.ToMarkdownBulletedList(i => i.ProcessName));

如果你喜欢数字列表,可使用 ToMarkdownNumberedList 扩展方法::
var files = new DirectoryInfo(@"C:\MarkdownLog").EnumerateFiles();
Console.Write(files.ToMarkdownNumberedList(i => i.Name + " is " + i.Length + " bytes"));


生成:
 1. appveyor.yml is 302 bytes
   2. LICENSE is 1088 bytes
   3. MarkdownLog.sln is 1480 bytes
   4. README.md is 6173 bytes

创建表格

使用 ToMarkdownTable 扩展方法,一个数据集合可以输出为  GitHub Flavoured Markdown 表格
var data = new[]
{
    new{Name = "Meryl Streep", Nominations = 18, Awards=3},
    new{Name = "Katharine Hepburn", Nominations = 12, Awards=4},
    new{Name = "Jack Nicholson", Nominations = 12, Awards=3}
};

Console.Write(data.ToMarkdownTable());

这会生成:
 

 Name              | Nominations | Awards
 ----------------- | -----------:| ------:
 Meryl Streep      |          18 |      3
 Katharine Hepburn |          12 |      4
 Jack Nicholson    |          12 |      3
 

列会根据数据类型自动对齐。文本左对齐,数字右对齐。 
要添加的列和数据选择的方法可以使用重载方法指定。只需为每个需要的列传递一个函数:
 var tableWithHeaders = data
            .ToMarkdownTable(i => i.Name, i => i.Nominations + i.Awards)
            .WithHeaders("Name", "Total");
Console.Write(tableWithHeaders);

这会生成:
 


 Name              | Total
 ----------------- | -----:
 Meryl Streep      |    21
 Katharine Hepburn |    16
 Jack Nicholson    |    15

创建条形图
可以使用一组标签和数字创建条形图。
var worldCup = new Dictionary
{
    {"Brazil", 5},
    {"Italy", 4},
    {"Germany", 4},
    {"Argentina", 2},
    {"Uruguay", 2},
    {"France", 1},
    {"Spain", 1},
    {"England", 1}
};


Console.Write(worldCup.ToMarkdownBarChart());

这会作为 Markdown 代码块渲染:
Brazil    |#####  5
Italy     |####  4
Germany   |####  4
Argentina |##  2
Uruguay   |##  2
France    |#  1
Spain     |#  1
England   |#  1
          ------


条形图支持负的和浮点数字, 以及缩放值:
Cos(0.0)                     |####################  1
Cos(0.3)                     |###################  0.95
Cos(0.6)                     |################  0.81
Cos(0.9)                     |############  0.59
Cos(1.3)                     |######  0.31
Cos(1.6)                     |  0
Cos(1.9)               ######|  -0.31
Cos(2.2)         ############|  -0.59
Cos(2.5)     ################|  -0.81
Cos(2.8)  ###################|  -0.95
Cos(3.1) ####################|  -1
Cos(3.5)  ###################|  -0.95
Cos(3.8)     ################|  -0.81
Cos(4.1)         ############|  -0.59
Cos(4.4)               ######|  -0.31
Cos(4.7)                     |  0
Cos(5.0)                     |######  0.31
Cos(5.3)                     |############  0.59
Cos(5.7)                     |################  0.81
Cos(6.0)                     |###################  0.95
         -----------------------------------------




创建头文件
Console.Write("The Origin of the Species".ToMarkdownHeader());

这会生成:

The Origin of the Species
=========================


创建次级头文件

Console.Write("By Means of Natural Selection".ToMarkdownSubHeader());

这会生成

By Means of Natural Selection
-----------------------------

创建字词绕回段落

var text = "Lolita, light of my life, fire of my loins." +
"My sin, my soul. Lo-lee-ta: the tip of the tongue taking a trip of" +
"three steps down the palate to tap, at three, on the teeth. Lo. Lee. Ta.";


Console.Write(text.ToMarkdownParagraph());

这会生成:

Lolita, light of my life, fire of my loins. My sin, my soul. Lo-lee-ta: the tip 
of the tongue taking a trip of three steps down the palate to tap, at three, on 
the teeth. Lo. Lee. Ta.

默认情况下在第 80 列,这可以配置。


创建块引用

const string text = "There are only two hard things in computer science:\n" +
                    "cache invalidation,\n" + 
                    "naming things,\n" +
                    "and off-by-one errors.";


Console.Write(text.ToMarkdownBlockquote());

生成:

> There are only two hard things in computer science:
> cache invalidation,
> naming things,
> and off-by-one errors.



块引用也可以包含其他  Markdown 元素,例如:
var blockQuote = new Blockquote();


blockQuote.Append(new HorizontalRule());
blockQuote.Append(new Header("COMPUTING MACHINERY AND INTELLIGENCE"));
blockQuote.Append(new SubHeader("By A. M. Turing."));


blockQuote.Append(new Paragraph("..."));


blockQuote.Append(new Paragraph("The idea behind digital computers" +
"may be explained by saying that these machines are intended to carry" +
"out any operations which could be done by a human computer. The human" +
"computer is supposed to be following fixed rules; he has no authority" +
"to deviate from them in any detail. We may suppose that these rules" +
"are supplied in a book, which is altered whenever he is put on to a" +
"new job. He has also an unlimited supply of paper on which he does his" +
"calculations. He may also do his multiplications and additions on a" +
"\"desk machine,\" but this is not important."));"
blockQuote.Append(new Paragraph("If we use the above explanation as" +
"a definition we shall be in danger of circularity of argument. We avoid" +
"this by giving an outline. of the means by which the desired effect is" +
"achieved. A digital computer can usually be regarded as consisting of three parts:"));


blockQuote.Append(new NumberedList("Store", "Executive unit", "Control"));


Console.Write(blockQuote);

生成:
> --------------------------------------------------------------------------------
> 
> COMPUTING MACHINERY AND INTELLIGENCE
> ====================================
> 
> By A. M. Turing.
> ----------------
> 
> ...
> 
> The idea behind digital computers may be explained by saying that these 
> machines are intended to carry out any operations which could be done by a 
> human computer. The human computer is supposed to be following fixed rules; he 
> has no authority to deviate from them in any detail. We may suppose that these 
> rules are supplied in a book, which is altered whenever he is put on to a new 
> job. He has also an unlimited supply of paper on which he does his 
> calculations. He may also do his multiplications and additions on a "desk 
> machine," but this is not important.
> 
> If we use the above explanation as a definition we shall be in danger of 
> circularity of argument. We avoid this by giving an outline. of the means by 
> which the desired effect is achieved. A digital computer can usually be 
> regarded as consisting of three parts:
> 
>    1. Store
>    2. Executive unit
>    3. Control
> 




通过写入容器推迟输出

目前为止,我们都是直接向 Console 窗口直接写入元素。如果要在程序运行时,这种方法在输出窗口生成特定数据结构的快照比较有用。但是要生成完整的可以存储在磁盘中的日志,每个元素都需要写入 MarkdownContainer.

var log = new MarkdownContainer();
var countries = new[]{"Zimbabwe", "Italy", "Bolivia", "Finland", "Australia"};
log.Append("Countries (unsorted)".ToMarkdownHeader());
log.Append(countries.ToMarkdownNumberedList());
var sorted = countries.OrderBy(i => i);
log.Append("Countries (sorted)".ToMarkdownHeader());
log.Append(sorted.ToMarkdownNumberedList());
Console.Write(log);

生成:

Countries (unsorted)
====================


   1. Zimbabwe
   2. Italy
   3. Bolivia
   4. Finland
   5. Australia


Countries (sorted)
==================


   1. Australia
   2. Bolivia
   3. Finland
   4. Italy
   5. Zimbabwe

Sponsored links

File list

Tips: You can preview the content of files by clicking file names^_^
Name Size Date
01.97 kB
.gitignore607.00 B2014-07-21|05:14
01.97 kB
01.97 kB
._.gitignore212.00 B2014-07-21|05:14
appveyor.yml302.00 B2014-07-21|05:14
._appveyor.yml212.00 B2014-07-21|05:14
LICENSE1.06 kB2014-07-21|05:14
._LICENSE212.00 B2014-07-21|05:14
01.97 kB
BarChart.cs3.67 kB2014-07-21|05:14
01.97 kB
._BarChart.cs212.00 B2014-07-21|05:14
BarChartDataPoint.cs319.00 B2014-07-21|05:14
._BarChartDataPoint.cs212.00 B2014-07-21|05:14
BlockQuote.cs1.17 kB2014-07-21|05:14
._BlockQuote.cs212.00 B2014-07-21|05:14
BulletedList.cs433.00 B2014-07-21|05:14
._BulletedList.cs212.00 B2014-07-21|05:14
CodeBlock.cs848.00 B2014-07-21|05:14
._CodeBlock.cs212.00 B2014-07-21|05:14
EmptyTableCell.cs276.00 B2014-07-21|05:14
._EmptyTableCell.cs212.00 B2014-07-21|05:14
Header.cs262.00 B2014-07-21|05:14
._Header.cs212.00 B2014-07-21|05:14
HeaderBase.cs1.00 kB2014-07-21|05:14
._HeaderBase.cs212.00 B2014-07-21|05:14
HorizontalRule.cs242.00 B2014-07-21|05:14
._HorizontalRule.cs212.00 B2014-07-21|05:14
IIosTableViewCell.cs177.00 B2014-07-21|05:14
._IIosTableViewCell.cs212.00 B2014-07-21|05:14
IIosTableViewHeaderCell.cs107.00 B2014-07-21|05:14
._IIosTableViewHeaderCell.cs212.00 B2014-07-21|05:14
IMarkdownElement.cs111.00 B2014-07-21|05:14
._IMarkdownElement.cs212.00 B2014-07-21|05:14
IosTableViewCell.cs2.58 kB2014-07-21|05:14
._IosTableViewCell.cs212.00 B2014-07-21|05:14
IosTableViewCheckmarkCell.cs731.00 B2014-07-21|05:14
._IosTableViewCheckmarkCell.cs212.00 B2014-07-21|05:14
IosTableViewHeaderCell.cs483.00 B2014-07-21|05:14
._IosTableViewHeaderCell.cs212.00 B2014-07-21|05:14
ITableCell.cs187.00 B2014-07-21|05:14
._ITableCell.cs212.00 B2014-07-21|05:14
ListBase.cs1.63 kB2014-07-21|05:14
._ListBase.cs212.00 B2014-07-21|05:14
ListItem.cs417.00 B2014-07-21|05:14
._ListItem.cs212.00 B2014-07-21|05:14
MarkDownBuilderExtensions.cs7.27 kB2014-07-21|05:14
._MarkDownBuilderExtensions.cs212.00 B2014-07-21|05:14
MarkdownContainer.cs641.00 B2014-07-21|05:14
._MarkdownContainer.cs212.00 B2014-07-21|05:14
MarkdownElement.cs250.00 B2014-07-21|05:14
._MarkdownElement.cs212.00 B2014-07-21|05:14
MarkdownLog.csproj4.05 kB2014-07-21|05:14
._MarkdownLog.csproj212.00 B2014-07-21|05:14
MarkdownToHtmlConverter.cs64.83 kB2014-07-21|05:14
._MarkdownToHtmlConverter.cs212.00 B2014-07-21|05:14
MarkdownToHtmlExtensions.cs485.00 B2014-07-21|05:14
._MarkdownToHtmlExtensions.cs212.00 B2014-07-21|05:14
NumberedList.cs462.00 B2014-07-21|05:14
._NumberedList.cs212.00 B2014-07-21|05:14
NumberExtensions.cs557.00 B2014-07-21|05:14
._NumberExtensions.cs212.00 B2014-07-21|05:14
Paragraph.cs1.39 kB2014-07-21|05:14
._Paragraph.cs212.00 B2014-07-21|05:14
01.97 kB
AssemblyInfo.cs1.14 kB2014-07-21|05:14
01.97 kB
._AssemblyInfo.cs212.00 B2014-07-21|05:14
._Properties212.00 B2014-07-21|05:14
RawMarkdown.cs348.00 B2014-07-21|05:14
._RawMarkdown.cs212.00 B2014-07-21|05:14
ReflectionExtensions.cs1.88 kB2014-07-21|05:14
._ReflectionExtensions.cs212.00 B2014-07-21|05:14
StringExtensions.cs3.93 kB2014-07-21|05:14
._StringExtensions.cs212.00 B2014-07-21|05:14
SubHeader.cs269.00 B2014-07-21|05:14
._SubHeader.cs212.00 B2014-07-21|05:14
Table.cs5.82 kB2014-07-21|05:14
._Table.cs212.00 B2014-07-21|05:14
TableCell.cs816.00 B2014-07-21|05:14
._TableCell.cs212.00 B2014-07-21|05:14
TableCellRenderSpecification.cs604.00 B2014-07-21|05:14
._TableCellRenderSpecification.cs212.00 B2014-07-21|05:14
TableColumn.cs506.00 B2014-07-21|05:14
._TableColumn.cs212.00 B2014-07-21|05:14
TableColumnAlignment.cs148.00 B2014-07-21|05:14
._TableColumnAlignment.cs212.00 B2014-07-21|05:14
TableRow.cs384.00 B2014-07-21|05:14
._TableRow.cs212.00 B2014-07-21|05:14
TableView.cs2.52 kB2014-07-21|05:14
._TableView.cs212.00 B2014-07-21|05:14
TableViewCellAccessory.cs205.00 B2014-07-21|05:14
._TableViewCellAccessory.cs212.00 B2014-07-21|05:14
TableViewSection.cs475.00 B2014-07-21|05:14
._TableViewSection.cs212.00 B2014-07-21|05:14
._MarkdownLog212.00 B2014-07-21|05:14
MarkdownLog.sln1.45 kB2014-07-21|05:14
._MarkdownLog.sln212.00 B2014-07-21|05:14
README.md6.03 kB2014-07-21|05:14
._README.md212.00 B2014-07-21|05:14
01.97 kB
BarChartTests.cs7.41 kB2014-07-21|05:14
01.97 kB
._BarChartTests.cs212.00 B2014-07-21|05:14
BlockquoteTests.cs3.46 kB2014-07-21|05:14
._BlockquoteTests.cs212.00 B2014-07-21|05:14
CodeBlockTests.cs1.89 kB2014-07-21|05:14
._CodeBlockTests.cs212.00 B2014-07-21|05:14
DocumentationExamples.cs5.58 kB2014-07-21|05:14
._DocumentationExamples.cs212.00 B2014-07-21|05:14
HeaderTests.cs1.08 kB2014-07-21|05:14
._HeaderTests.cs212.00 B2014-07-21|05:14
HorizontalRuleTests.cs518.00 B2014-07-21|05:14
._HorizontalRuleTests.cs212.00 B2014-07-21|05:14
IosTableViewTests.cs4.98 kB2014-07-21|05:14
._IosTableViewTests.cs212.00 B2014-07-21|05:14
ListTests.cs4.62 kB2014-07-21|05:14
._ListTests.cs212.00 B2014-07-21|05:14
NumberExtensionsTests.cs1.04 kB2014-07-21|05:14
._NumberExtensionsTests.cs212.00 B2014-07-21|05:14
ParagraphTests.cs4.17 kB2014-07-21|05:14
._ParagraphTests.cs212.00 B2014-07-21|05:14
01.97 kB
AssemblyInfo.cs1.42 kB2014-07-21|05:14
01.97 kB
._AssemblyInfo.cs212.00 B2014-07-21|05:14
._Properties212.00 B2014-07-21|05:14
StringExtensionsTests.cs4.05 kB2014-07-21|05:14
._StringExtensionsTests.cs212.00 B2014-07-21|05:14
TableTests.cs11.43 kB2014-07-21|05:14
._TableTests.cs212.00 B2014-07-21|05:14
TestExtensions.cs2.30 kB2014-07-21|05:14
._TestExtensions.cs212.00 B2014-07-21|05:14
UnitTests.csproj5.24 kB2014-07-21|05:14
._UnitTests.csproj212.00 B2014-07-21|05:14
._UnitTests212.00 B2014-07-21|05:14
._MarkdownLog212.00 B2014-07-21|05:14
...
Sponsored links

Comments

(Add your comment, get 0.1 Point)
Minimum:15 words, Maximum:160 words
  • 1
  • Page 1
  • Total 1

Using Markdown for Effective Logging (84.05 kB)

Need 1 Point(s)
Your Point (s)

Your Point isn't enough.

Get 22 Point immediately by PayPal

Point will be added to your account automatically after the transaction.

More(Debit card / Credit card / PayPal Credit / Online Banking)

Submit your source codes. Get more Points

LOGIN

Don't have an account? Register now
Need any help?
Mail to: support@codeforge.com

切换到中文版?

CodeForge Chinese Version
CodeForge English Version

Where are you going?

^_^"Oops ...

Sorry!This guy is mysterious, its blog hasn't been opened, try another, please!
OK

Warm tip!

CodeForge to FavoriteFavorite by Ctrl+D
500 Internal Server Error

Internal Server Error

Fatal error: syntax error, unexpected '&'