New ZK Demo Introduction"

From Documentation
m
m
 
(15 intermediate revisions by 4 users not shown)
Line 5: Line 5:
 
}}
 
}}
 
__TOC__
 
__TOC__
[[Image:Zkdemo.PNG|thumb|The Main Page of New [http://www.zkoss.org/zkdemo/userguide/ ZK Demo]]]
+
[[Image:Zkdemo.PNG]]
 
=Introduction=
 
=Introduction=
 
This article is created for those who are interested in the architecture of the latest ZK Demo.  
 
This article is created for those who are interested in the architecture of the latest ZK Demo.  
Line 15: Line 15:
 
=The UI Part=
 
=The UI Part=
 
==BorderLayout==
 
==BorderLayout==
First, We create a [[Developer reference The XUL Components Components Borderlayout|borderlayout]] to construct the whole main page.
+
First, We create a [[ZK_Component_Reference/Layouts/Borderlayout|borderlayout]] to construct the whole main page.
 
It contains three parts.
 
It contains three parts.
*'''North''': The category selection bar which is made by a [[Macro_Component|macro components]] named <u>category</u> and a customized component, <u>categorybar</u>.
+
*'''North''': The category selection bar which is made by a [[ZK Developer's Reference/UI Composing/Macro Component|macro components]] named <u>category</u> and a customized component, <u>categorybar</u>.
*'''West''': The case list which we use [[Live_Data,_Paging,_setModel_and_Implement_your_own_renderer#What.27s_Model | listmodel ]] to generate and replace the data.
+
*'''West''': The case list which we use [[ZK_Developer's_Guide/ZK_in_Depth/Live_Data,_Paging,_setModel_and_Implement_your_own_renderer/What's_Model| listmodel ]] to generate and replace the data.
*'''Center''': The case content. If a demo case is selected in the west list, this part will show the demo case's content and it's sourced by including the corresponding zul file. Each of them shows data in a  [[Developer reference The XUL Components Components Tabbox|Tabbox]].
+
*'''Center''': The case content. If a demo case is selected in the west list, this part will show the demo case's content and it's sourced by including the corresponding zul file. Each of them shows data in a  [[ZK_Component_Reference/Containers/Tabbox|Tabbox]].
 
<source lang="xml">
 
<source lang="xml">
 
<borderlayout id="main" apply="org.zkoss.zkdemo.userguide.MainLayoutComposer">
 
<borderlayout id="main" apply="org.zkoss.zkdemo.userguide.MainLayoutComposer">
Line 39: Line 39:
 
#<category forEach="${'''main'''.categories}"  />
 
#<category forEach="${'''main'''.categories}"  />
 
#<listbox  model="${'''main'''.selectedModel}" ></listbox>
 
#<listbox  model="${'''main'''.selectedModel}" ></listbox>
Let's take a look at the composer<ref>Composer : A way to compose a component's behavior in ZK, users can add "[[ZUML_ZK_Attributes#The_use.2C_apply_Attribute|apply]]" to use it.</ref> of borderlayout, '''MainLayoutComposer'''.
+
Let's take a look at the composer<ref>Composer : A way to compose a component's behavior in ZK, users can add "[[ZK Developer's Reference/MVC/Controller|apply]]" to use it.</ref> of borderlayout, '''MainLayoutComposer'''.
 
We used the '''FusionInvoker'''<ref>FusionInvoker : Refer to the article [http://www.zkoss.org/smalltalks/fusionInvoker/ An Introduction of ZK Composer]</ref> and bind the composer object to original borderlayout, '''main'''.
 
We used the '''FusionInvoker'''<ref>FusionInvoker : Refer to the article [http://www.zkoss.org/smalltalks/fusionInvoker/ An Introduction of ZK Composer]</ref> and bind the composer object to original borderlayout, '''main'''.
<source lang="java5">
+
<source lang="java">
 
public class MainLayoutComposer extends GenericForwardComposer implements MainLayoutAPI, ComposerExt {
 
public class MainLayoutComposer extends GenericForwardComposer implements MainLayoutAPI, ComposerExt {
 
   /*...*/
 
   /*...*/
Line 55: Line 55:
  
 
==The Category Bar==
 
==The Category Bar==
[[Image:Zkdemo category.PNG|thumb|Category Bar]]
+
[[Image:Zkdemo category.PNG]]
 
This part contains two elements, category and category bar.
 
This part contains two elements, category and category bar.
 
===Categorybar===
 
===Categorybar===
This is a customized component, which extend the [[Developer reference The XUL Components Components Div | Div ]] component.
+
This is a customized component, which extend the [[ZK_Component_Reference/XHTML_Components| Div ]] component.
We created it and used [[ZUML_ZK_Attributes#The_forEach.2C_each_Attribute|EL forEach]]  to load the categories.
+
We created it and used [[ZUML Reference/ZUML/Attributes/forEach|forEach]]  to load the categories.
 
When the screen size is less than the width of the categories, users can use the scroll button and scroll to the hidden categories.
 
When the screen size is less than the width of the categories, users can use the scroll button and scroll to the hidden categories.
  
Line 79: Line 79:
 
</source>
 
</source>
 
The categorybar's code is in <u>/userguide/macros/categorybar.dsp</u>
 
The categorybar's code is in <u>/userguide/macros/categorybar.dsp</u>
<source lang="html4strict">
+
<source lang="html">
 
<%@ taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c" %>
 
<%@ taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c" %>
 
<%@ taglib uri="http://www.zkoss.org/dsp/zk/core" prefix="z" %>
 
<%@ taglib uri="http://www.zkoss.org/dsp/zk/core" prefix="z" %>
Line 95: Line 95:
 
</div>
 
</div>
 
</source>
 
</source>
For more information or guide about creating customized components in ZK, please refer to [http://www.zkoss.org/doc/compdevguide/ Component Develope Guide].  <br />
+
For more information or guide about creating customized components in ZK, please refer to [[ZK Component Development Essentials]].  <br />
 
We first define the categorybar, and use it in the <u> index.zul.</u>
 
We first define the categorybar, and use it in the <u> index.zul.</u>
 
<source lang="xml">
 
<source lang="xml">
Line 105: Line 105:
 
</source>
 
</source>
 
The main.categories reflect to the composer's '''getCategories()'''. It will load the categories form zkdemo.properties.  
 
The main.categories reflect to the composer's '''getCategories()'''. It will load the categories form zkdemo.properties.  
<source lang="java5">
+
<source lang="java">
 
public Category[] getCategories() {
 
public Category[] getCategories() {
 
   return (Category[]) getCategoryMap().values().toArray(new Category[] {});
 
   return (Category[]) getCategoryMap().values().toArray(new Category[] {});
Line 114: Line 114:
 
</source>
 
</source>
 
The '''DemoWebAppInit''' is the java class use to load the property file - zkdemo.properties
 
The '''DemoWebAppInit''' is the java class use to load the property file - zkdemo.properties
<source lang="java5" >
+
<source lang="java" >
 
public class DemoWebAppInit implements WebAppInit {
 
public class DemoWebAppInit implements WebAppInit {
 
   private static final Log log = Log.lookup(DemoWebAppInit.class);
 
   private static final Log log = Log.lookup(DemoWebAppInit.class);
Line 129: Line 129:
  
 
===Category===
 
===Category===
This is an [[Macro_Component|macro components]], which will show as an icon. (The data of categories was loaded from DemoWebAppInit.)
+
This is an [[ZK Developer's Reference/UI Composing/Macro Component|macro components]], which will show as an icon. (The data of categories was loaded from DemoWebAppInit.)
 
<source lang="xml" >
 
<source lang="xml" >
 
<div id="${arg.id}" style="" sclass="demo-category pointer" forward="main.onCategorySelect"
 
<div id="${arg.id}" style="" sclass="demo-category pointer" forward="main.onCategorySelect"
Line 138: Line 138:
 
</div>
 
</div>
 
</source>
 
</source>
It will forward<ref>forward : ZK's auto forward function from [http://www.zkoss.org/javadoc/3.5.2/zk/org/zkoss/zk/ui/util/GenericForwardComposer.html GenericForwardComposer], it' usage is [[ZUML_ZK_Attributes#The_forward_Attribute|here]].</ref> the select event to composer's '''onCategorySelect()'''.<br />
+
It will forward<ref>forward : ZK's auto forward function from [http://www.zkoss.org/javadoc/3.5.2/zk/org/zkoss/zk/ui/util/GenericForwardComposer.html GenericForwardComposer], it' usage is [[ZUML Reference/ZUML/Attributes/forward|here]].</ref> the select event to composer's '''onCategorySelect()'''.<br />
 
We create a '''Category''' class to save data.<br />
 
We create a '''Category''' class to save data.<br />
 
'''org.zkoss.zkdemo.userguide.Category'''
 
'''org.zkoss.zkdemo.userguide.Category'''
<source lang="java5" >
+
<source lang="java" >
 
public class Category {
 
public class Category {
 
   private String _id;
 
   private String _id;
Line 159: Line 159:
  
 
==The Demo Case List==
 
==The Demo Case List==
[[Image:Zkdemo caselist.PNG|thumb|Case List]]
+
[[Image:Zkdemo caselist.PNG]]
 
There's a toolbar with search function and a listbox with case list in this part.
 
There's a toolbar with search function and a listbox with case list in this part.
 
<source lang="xml">
 
<source lang="xml">
Line 177: Line 177:
 
**Listbox : '''itemList'''
 
**Listbox : '''itemList'''
 
The main.itemRenderer and main.selectedModel reflect to the composer's '''getItemRenderer()''' and '''getSelectedModel()'''.
 
The main.itemRenderer and main.selectedModel reflect to the composer's '''getItemRenderer()''' and '''getSelectedModel()'''.
<source lang="java5">
+
<source lang="java">
 
public ListModel getSelectedModel() {
 
public ListModel getSelectedModel() {
 
   Category cate = _selected == null ? getCategories()[0] :
 
   Category cate = _selected == null ? getCategories()[0] :
Line 192: Line 192:
 
==The Case Content==
 
==The Case Content==
 
For each case there's a window which applies composer, '''org.zkoss.zkdemo.userguide.DemoWindowComposer'''.
 
For each case there's a window which applies composer, '''org.zkoss.zkdemo.userguide.DemoWindowComposer'''.
[[Image:ZKdemo_case.png|thumb|Demo Case]]
+
[[Image:ZKdemo_case.png]]
 
<source lang="xml">
 
<source lang="xml">
 
<window id="demo" apply="org.zkoss.zkdemo.userguide.DemoWindowComposer">
 
<window id="demo" apply="org.zkoss.zkdemo.userguide.DemoWindowComposer">
Line 230: Line 230:
 
</source>
 
</source>
 
The composer used to handle the "reload" and "Try me" button, and create a div included the font/theme change button.
 
The composer used to handle the "reload" and "Try me" button, and create a div included the font/theme change button.
<source lang="java5">
+
<source lang="java">
 
public class DemoWindowComposer extends GenericForwardComposer {
 
public class DemoWindowComposer extends GenericForwardComposer {
 
Window view;
 
Window view;
Line 259: Line 259:
 
The composer of borderlayout is '''MainLayoutComposer'''. It extends the '''GenericForwardComposer'''<ref>GenericForwardComposer : See the introduction in this article : [http://www.zkoss.org/smalltalks/mvc3/ ZK MVC Made Easy] </ref>.
 
The composer of borderlayout is '''MainLayoutComposer'''. It extends the '''GenericForwardComposer'''<ref>GenericForwardComposer : See the introduction in this article : [http://www.zkoss.org/smalltalks/mvc3/ ZK MVC Made Easy] </ref>.
  
The "$" will auto forward the [[Component_Events#Other_Events|onBookmarkChange]] event to borderlayout, '''main''' ,  
+
The "$" will auto forward the [[ZK Component Reference/Events|onBookmarkChange]] event to borderlayout, '''main''' ,  
the [[Component_Events#List_and_Tree_Events|onSelect]] event to the '''itemList''', the [[Component_Events#Keystroke_Events|onCtrlKey]] event and [[Component_Events#Input_Events|onChanging]] event to '''searchBox'''.<br />
+
the [[ZK Component Reference/Events|onSelect]] event to the '''itemList''', the [[ZK Component Reference/Events|onCtrlKey]] event and [[ZK Component Reference/Events|onChanging]] event to '''searchBox'''.<br />
 
'''org.zkoss.zkdemo.userguide.MainLayoutComposer'''
 
'''org.zkoss.zkdemo.userguide.MainLayoutComposer'''
<source lang="java5">
+
<source lang="java">
 
public class MainLayoutComposer extends GenericForwardComposer implements MainLayoutAPI, ComposerExt {
 
public class MainLayoutComposer extends GenericForwardComposer implements MainLayoutAPI, ComposerExt {
 
         /** Event  */
 
         /** Event  */
Line 296: Line 296:
 
</source>
 
</source>
 
The '''org.zkoss.zkdemo.userguide.MainLayoutAPI''' interface is the main features of the demo.
 
The '''org.zkoss.zkdemo.userguide.MainLayoutAPI''' interface is the main features of the demo.
<source lang="java5">
+
<source lang="java">
 
public interface MainLayoutAPI {
 
public interface MainLayoutAPI {
 
public Category[] getCategories();
 
public Category[] getCategories();

Latest revision as of 03:34, 29 December 2010

DocumentationSmall Talks2008JanuaryNew ZK Demo Introduction
New ZK Demo Introduction

Author
Ryan Wu, Engineer, Potix Corporation
Date
Jan 20, 2008
Version
Since ZK 3.5.2

Zkdemo.PNG

Introduction

This article is created for those who are interested in the architecture of the latest ZK Demo.

The ZK Demo is one of the most important parts of ZK's website. In this article, I will introduce how the new demo was created and what type of ZK features was used.
You are recommended to download the source and read it with this article.

The UI Part

BorderLayout

First, We create a borderlayout to construct the whole main page. It contains three parts.

  • North: The category selection bar which is made by a macro components named category and a customized component, categorybar.
  • West: The case list which we use listmodel to generate and replace the data.
  • Center: The case content. If a demo case is selected in the west list, this part will show the demo case's content and it's sourced by including the corresponding zul file. Each of them shows data in a Tabbox.
<borderlayout id="main" apply="org.zkoss.zkdemo.userguide.MainLayoutComposer">
  <north border="none" size="100px" sclass="demo-header" collapsible="true">
    ...
  </north>
  <west title="ZK ${desktop.webApp.version} Live Demo" size="250px" flex="true" splittable="true"
    minsize="210" maxsize="500" collapsible="true">
    ...
  </west>
  <center autoscroll="true" flex="true">
    ...
  </center>
</borderlayout>
  • Namespace
    • BorderLayout : main

You might be confused why the borderlayout(main) could have some special functions, for example

  1. <category forEach="${main.categories}" />
  2. <listbox model="${main.selectedModel}" ></listbox>

Let's take a look at the composer[1] of borderlayout, MainLayoutComposer. We used the FusionInvoker[2] and bind the composer object to original borderlayout, main.

public class MainLayoutComposer extends GenericForwardComposer implements MainLayoutAPI, ComposerExt {
  /*...*/
  public void doBeforeComposeChildren(Component comp) throws Exception {
    bindComponent(comp);
    Object obj = FusionInvoker.newInstance(new Object[] { comp, this });
    comp.setVariable("main", obj, true);
    main = (Borderlayout) comp;
  }
  /*...*/
}

The Category Bar

Zkdemo category.PNG This part contains two elements, category and category bar.

Categorybar

This is a customized component, which extend the Div component. We created it and used forEach to load the categories. When the screen size is less than the width of the categories, users can use the scroll button and scroll to the hidden categories.

The client side function is written in the index.zul with a JavaScript Class zkCategoryBar.

zkCategoryBar = {
  init: function (cmp) { ... },
  onSize: function (cmp) { ... },
  _forceStyle: function (cmp, value) { ... },
  _isLegalType: function (n) { ... },
  _checkScrolling: function (cmp, body) { ... },
  _fixButton : function(cmp) { ... },
  onScrollTo: function (cmp) { ... },
  onClickArrow: function (evt) { ... },
  stop: function () { .. },
  scroll: function(cmp, move, btn, isRight, stopPropagate) { ... },
  goscroll: function(body, isRight, step) { ... }
};

The categorybar's code is in /userguide/macros/categorybar.dsp

<%@ taglib uri="http://www.zkoss.org/dsp/web/core" prefix="c" %>
<%@ taglib uri="http://www.zkoss.org/dsp/zk/core" prefix="z" %>
<c:set var="self" value="${requestScope.arg.self}"/>
<c:set var="uuid" value="${self.uuid}"/>
<div id="${uuid}" z.type="CategoryBar" ${self.outerAttrs}${self.innerAttrs}>
<div id="${uuid}!right"></div>
<div id="${uuid}!left"></div>
  <div id="${uuid}!body" class="${self.zclass}-body">
  <div id="${uuid}!cave">
    <c:forEach var="child" items="${self.children}">${z:redraw(child, null)}</c:forEach>
    <div class="z-clear"></div>
   </div>
  </div>
</div>

For more information or guide about creating customized components in ZK, please refer to ZK Component Development Essentials.
We first define the categorybar, and use it in the index.zul.

<?component name="categorybar" extends="div" moldURI="/userguide/macros/categorybar.dsp"?>
...
<categorybar zclass="demo-categorybar" id="header">
  <category forEach="${main.categories}" id="${each.id}" src="${each.icon}" label="${each.label}"/>
</categorybar>

The main.categories reflect to the composer's getCategories(). It will load the categories form zkdemo.properties.

public Category[] getCategories() {
  return (Category[]) getCategoryMap().values().toArray(new Category[] {});
}
private Map getCategoryMap() {
  return DemoWebAppInit.getCateMap();
}

The DemoWebAppInit is the java class use to load the property file - zkdemo.properties

public class DemoWebAppInit implements WebAppInit {
  private static final Log log = Log.lookup(DemoWebAppInit.class);
  final static String PATH = "/userguide/";
  final static String CONFIG = "zkdemo.properties";
  final static String CATEGORY_TYPE = "CATEGORY";
  final static String LINK_TYPE = "LINK";
  private static Map _cateMap = new LinkedHashMap () { ... };
  public void init(WebApp wapp) throws Exception { ... }
  static Map getCateMap() { ... }
  private void loadProperites(ServletContext context) { ... }
}

Category

This is an macro components, which will show as an icon. (The data of categories was loaded from DemoWebAppInit.)

<div id="${arg.id}" style="" sclass="demo-category pointer" forward="main.onCategorySelect"
  action="onmouseover:zk.addClass(this, 'demo-over'); onmouseout:zk.rmClass(this, 'demo-over'); onclick:if(zkau.insamepos(event)) onSelect(this)">
  <image sclass="demo-category-img" tooltiptext="${arg.label}" src="${arg.src}" action="onmousedown:return false;"/>
  <separator height="1px"/>
  <label sclass="demo-category-text" value="${arg.label}"/>
</div>

It will forward[3] the select event to composer's onCategorySelect().
We create a Category class to save data.
org.zkoss.zkdemo.userguide.Category

public class Category {
  private String _id;
  private String _icon;
  private String _label;
  private String _href;
  private List _items;
  public Category(String id, String icon, String label, String href) {...}
  public void addItem(DemoItem item) {...}
  public String getHref() {...}
  public List getItems() {...}
  public String getId() {...}
  public String getIcon() {...}
  public String getLabel() {...}
}

The Demo Case List

Zkdemo caselist.PNG There's a toolbar with search function and a listbox with case list in this part.

<panel>
  <toolbar>
  <label value="Search:"/><textbox id="searchBox" ctrlKeys="#down#up" focus="true" sclass="demo-search-inp"/>
  </toolbar>
  <panelchildren>
  <listbox id="itemList" oddRowSclass="non-odd" sclass="demo-items"
   itemRenderer="${main.itemRenderer}" model="${main.selectedModel}" fixedLayout="true" vflex="true">   
  </listbox>
  </panelchildren>
</panel>
  • Namespace
    • Textbox : searchbox
    • Listbox : itemList

The main.itemRenderer and main.selectedModel reflect to the composer's getItemRenderer() and getSelectedModel().

public ListModel getSelectedModel() {
  Category cate = _selected == null ? getCategories()[0] :
      getCategory(_selected.getId());
  return new ListModelList(cate.getItems());
}
...
public ListitemRenderer getItemRenderer() {
  return _defRend;
}
...

The Case Content

For each case there's a window which applies composer, org.zkoss.zkdemo.userguide.DemoWindowComposer. ZKdemo case.png

<window id="demo" apply="org.zkoss.zkdemo.userguide.DemoWindowComposer">
  <html><![CDATA[
    Description
  ]]></html>
  <separator/>
  <tabbox width="100%" tabscroll="false">
    <tabs>
      <tab id="demoView" label="Demo"/>
      <tab id="srcView" label="View Source"/>
    </tabs>
    <tabpanels>
      <tabpanel>
        <window id="view">
        </window>
      </tabpanel>
      
      <tabpanel>
        <panel>
          <panelchildren>
            <textbox id="codeView" class="code" rows="20" width="95%">
      <attribute name="value"><![CDATA[
            <!-- THE DEMO ZUL CODE -->
      ]]></attribute>
            </textbox>
          </panelchildren>
          <toolbar mold="panel">
            <button id="tryBtn" label="Try me!"/>
            <button id="reloadBtn" label="Reload" height="18px"/>
          </toolbar>
        </panel>
      </tabpanel>
    </tabpanels>
  </tabbox>
</window>

The composer used to handle the "reload" and "Try me" button, and create a div included the font/theme change button.

public class DemoWindowComposer extends GenericForwardComposer {
	Window view;
	Tab demoView;
	Textbox codeView;
	Button reloadBtn;
	Button tryBtn;
	public void doAfterCompose(Component comp) throws Exception {
		super.doAfterCompose(comp);
		((Window)comp).setContentSclass("demo-main-cnt");
		((Window)comp).setSclass("demo-main");
		final Div inc = new Div();
		Executions.createComponents("/userguide/bar.zul", inc, null);
		inc.setStyle("float:right");
		if (Library.getProperty("org.zkoss.zkdemo.theme.silvergray") != null) {
		...
		}
		comp.insertBefore(inc, comp.getFirstChild());
		if (view != null) execute();
	}
	public void execute() { ... }
	public void onClick$reloadBtn(Event event) { ... }
	public void onClick$tryBtn(Event event) { ... }
}

The Composer Part

The composer of borderlayout is MainLayoutComposer. It extends the GenericForwardComposer[4].

The "$" will auto forward the onBookmarkChange event to borderlayout, main , the onSelect event to the itemList, the onCtrlKey event and onChanging event to searchBox.
org.zkoss.zkdemo.userguide.MainLayoutComposer

public class MainLayoutComposer extends GenericForwardComposer implements MainLayoutAPI, ComposerExt {
        /** Event  */

	/* Init function of main */
	public void onMainCreate(Event event) {...}
	/*Category select*/
	public void onCategorySelect(ForwardEvent event) {...}
        /* Bookmark change of main */
	public void onBookmarkChange$main(BookmarkEvent event) {...}
        /* Select itemList */
	public void onSelect$itemList(SelectEvent event) {...}
        /* Catch arrow key "Up" and "Down" from users */
	public void onCtrlKey$searchBox(KeyEvent event) {...}
        /* Search demo during input */
	public void onChanging$searchBox(InputEvent event) {...}

        /** UI Control */

	public Category[] getCategories() {...}
	public ListitemRenderer getItemRenderer() {...}
	public void render(Listitem item, Object data) {...}
	public ListModel getSelectedModel() {...}

        /** Composer Implementation */

	public void doAfterCompose(Component comp) throws Exception {...}
	public ComponentInfo doBeforeCompose(Page page, Component parent,ComponentInfo compInfo) {...}
	public void doBeforeComposeChildren(Component comp) throws Exception {...}
	public boolean doCatch(Throwable ex) throws Exception {...}
	public void doFinally() throws Exception {...}
}

The org.zkoss.zkdemo.userguide.MainLayoutAPI interface is the main features of the demo.

public interface MainLayoutAPI {
	public Category[] getCategories();
	public ListModel getSelectedModel();
	public ListitemRenderer getItemRenderer();
}

Summary

This article shows the workings of the New ZK Demo and parts of ZK features we have used.
If you are interesting in other parts of ZKDemo, like "theme change", you can try: DemoWebAppInit.java and MainLayoutInit.java.

Finally, feel free to leave a comment to us.

Download

Reference

  1. Composer : A way to compose a component's behavior in ZK, users can add "apply" to use it.
  2. FusionInvoker : Refer to the article An Introduction of ZK Composer
  3. forward : ZK's auto forward function from GenericForwardComposer, it' usage is here.
  4. GenericForwardComposer : See the introduction in this article : ZK MVC Made Easy


Feel free to leave a comment to us.

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.