Commit da4dc611 authored by Vivek's avatar Vivek

wip

parent 17f60efd
......@@ -144,27 +144,29 @@
return;\n
})\n
\n
.declareMethod("interfaceGadgetTest", function (gadget, interface_gadget, interface_list) {\n
.declareMethod("interfaceGadgetTest", function (gadget_url, interface_url) {\n
var gadget = this;\n
//temperoray hardcoded :\n
gadget_url = "https://softinst60317.host.vifib.net/erp5/web_site_module/interface_demo/gadget_testgadget1.html";\n
interface_url = "https://softinst60317.host.vifib.net/erp5/web_site_module/interface_demo/demo_interface1.html";\n
return new RSVP.Queue()\n
.push(function () {\n
return gadget.getDeclaredGadget(INTERFACE_GADGET_SCOPE);\n
})\n
.push(function (interface_gadget) {\n
var status_list = [],\n
key;\n
for (key in interface_list) {\n
status_list.push(interface_gadget.verifyInterfaceImplementation(gadget, interface_list[key]));\n
}\n
status_list.push(interface_gadget.verifyInterfaceImplementation(gadget_url, interface_url));\n
return RSVP.all(status_list);\n
})\n
.push(function (result_list) {\n
var parameter = {interface_item: []},\n
key,\n
i = 0;\n
for (key in interface_list) {\n
parameter.interface_item.push({\n
interface_name: interface_list[key], \n
status: (result_list[i] ? "Verified Success":"Verified Failure")\n
interface_name: interface_url, \n
status: (result_list[0] ? "Verified Success":"Verified Failure")\n
});\n
i += 1;\n
}\n
gadget.props.header_element.innerHTML = gadget.props.header_template({\n
title: "Interface List"\n
});\n
......@@ -182,7 +184,7 @@
scope: INTERFACE_GADGET_SCOPE,\n
element: gadget.__element\n
});\n
})\n
/* })\n
.push(function () {\n
return RSVP.all([\n
gadget.getDeclaredGadget(INTERFACE_GADGET_SCOPE),\n
......@@ -193,6 +195,10 @@
var interface_gadget = interface_gadget_list[0],\n
interface_list = interface_gadget_list[1];\n
return gadget.interfaceGadgetTest(gadget, interface_gadget, interface_list);\n
*/\n
})\n
.push(function () {\n
return gadget.interfaceGadgetTest("dummyarg1", "dummyarg2");\n
});\n
});\n
\n
......@@ -331,7 +337,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>944.23155.255.46643</string> </value>
<value> <string>944.26193.28667.62890</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -349,7 +355,7 @@
</tuple>
<state>
<tuple>
<float>1436795666.02</float>
<float>1436977064.72</float>
<string>GMT</string>
</tuple>
</state>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Page" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_testgadget1.html</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_testgadget1_html</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value> <string>en</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Page</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content</string> </key>
<value> <string encoding="cdata"><![CDATA[
<!DOCTYPE html>\n
<html>\n
<head>\n
<meta charset="utf-8" />\n
<title>Test Gadget</title>\n
<meta name="viewport" content="width=device-width, initial-scale=1" />\n
\n
<link rel="http://www.renderjs.org/rel/interface" href="demo_interface1.html">\n
<link rel="http://www.renderjs.org/rel/interface" href="demo_interface2.html">\n
\n
<!-- renderjs -->\n
<script src="rsvp.js" type="text/javascript"></script>\n
<script src="renderjs.js" type="text/javascript"></script>\n
<script src="handlebars.js" type="text/javascript"></script>\n
<script src="jquery.js" type="text/javascript"></script>\n
\n
<!-- custom script -->\n
<script src="gadget_testgadget1.js" type="text/javascript"></script>\n
</head>\n
<body> </body>\n
</html>
]]></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>RenderJS Gadget Test Gadget 1</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope1</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1436977227.21</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>944.26154.65476.41352</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1436974757.22</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>empty</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1436974282.2</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_testgadget1.js</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>gadget_testgadget1_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value> <string>en</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Script</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content</string> </key>
<value> <string>/*global window, rJS, RSVP */\n
/*jslint nomen: true, indent: 2, maxerr: 3 */\n
(function (window, rJS, Handlebars, $, jQuery, RSVP) {\n
"use strict";\n
\n
rJS(window)\n
.ready(function (g) {\n
g.props = {};\n
})\n
\n
.declareMethod("method1", function (param1, param2) {\n
return;\n
})\n
.declareMethod("method2", function (param1) {\n
return;\n
})\n
.declareMethod("method3", function () {\n
return;\n
})\n
.declareMethod("testmethod1", function () {\n
return;\n
})\n
.declareMethod("testmethod2", function (param1) {\n
return;\n
})\n
.declareMethod("testmethod3", function (param1, param2) {\n
return;\n
})\n
.declareMethod("randommethod1", function (param1, param2, param3) {\n
return;\n
});\n
\n
}(window, rJS, Handlebars, $, jQuery, RSVP));</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>RenderJS Gadget Test Gadget 1 JS</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>001</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope1</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1436977235.46</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>944.26139.55503.54323</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1436973877.13</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <string>zope</string> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>empty</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="DateTime" module="DateTime.DateTime"/>
</klass>
<tuple>
<none/>
</tuple>
<state>
<tuple>
<float>1436973624.78</float>
<string>GMT</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
</ZopeData>
......@@ -111,7 +111,6 @@
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.\n
*/\n
/*! @source https://gist.github.com/1129031 */\n
\n
(function (DOMParser) {\n
"use strict";\n
var DOMParser_proto = DOMParser.prototype,\n
......@@ -152,6 +151,21 @@
/*jslint nomen: true, indent: 2, maxerr: 3 */\n
(function (window, rJS, Handlebars, $, RSVP, loopEventListener, DOMParser) {\n
"use strict";\n
\n
var VERIFY_GADGET_SCOPE = "verify_gadget";\n
\n
function getVerifyGadget(gadget_url, interface_gadget) {\n
return new RSVP.Queue()\n
.push(function () {\n
return interface_gadget.declareGadget(gadget_url, {\n
scope: VERIFY_GADGET_SCOPE,\n
element: interface_gadget.__element\n
});\n
})\n
.push(function () {\n
return interface_gadget.getDeclaredGadget(VERIFY_GADGET_SCOPE);\n
});\n
}\n
\n
function verifyInterfaceDefinition(interface_name) {\n
//to verify if interface definition follows the correct template.\n
......@@ -170,9 +184,9 @@
} \n
try {\n
for (var i=0; i<method_len; i+=1) {\n
if ((!next_element || next_element.localName !== "dt") ||\n
(!(next_element = next_element.nextElementSibling) || next_element.localName !== "dd") ||\n
(!(next_element = next_element.nextElementSibling) || next_element.localName !== "dl")) {\n
if ((!next_element || next_element.localName !== \'dt\') ||\n
(!(next_element = next_element.nextElementSibling) || next_element.localName !== \'dd\') ||\n
(!(next_element = next_element.nextElementSibling) || next_element.localName !== \'dl\')) {\n
throw new Error("Interface Definition Incorrect.");\n
}\n
if(next_element.getElementsByTagName(\'dt\').length !== next_element.getElementsByTagName(\'dd\').length) {\n
......@@ -181,8 +195,8 @@
var argument_len = next_element.getElementsByTagName(\'dt\').length,\n
next_child_element = next_element.firstElementChild;\n
for (var j=0; j<argument_len; j+=1) {\n
if ((!next_child_element || next_child_element.localName !== "dt") ||\n
(!(next_child_element = next_child_element.nextElementSibling) || next_child_element.localName !== "dd")) {\n
if ((!next_child_element || next_child_element.localName !== \'dt\') ||\n
(!(next_child_element = next_child_element.nextElementSibling) || next_child_element.localName !== \'dd\')) {\n
throw new Error("Interface Definition Incorrect.");\n
}\n
next_child_element = next_child_element.nextElementSibling;\n
......@@ -212,11 +226,11 @@
return defer.promise;\n
}\n
\n
function verifyAllMethods(interface_method_list, gadget_method_list) {\n
function verifyAllMethod(interface_method_list, gadget_method_list) {\n
var defer = RSVP.defer();\n
return RSVP.Queue()\n
.push(function() {\n
return verifyAllMethodsDeclared(interface_method_list, gadget_method_list);\n
return verifyAllMethodDeclared(interface_method_list, gadget_method_list);\n
})\n
.push(function() {\n
return verifyAllMethodsSignature(interface_method_list, gadget_method_list);\n
......@@ -230,7 +244,7 @@
});\n
}\n
\n
function verifyAllMethodsDeclared(interface_method_list, gadget_method_list) {\n
function verifyAllMethodDeclared(interface_method_list, gadget_method_list) {\n
//to verify if all the interface methods are declared by the gadget.\n
var defer = RSVP.defer(),\n
gadget_method_name_list = [],\n
......@@ -253,7 +267,7 @@
}\n
return defer.promise;\n
}\n
\n
\n
function verifyAllMethodsSignature(interface_method_list, gadget_method_list) {\n
//to verify if all the declared methods match the signature of the interface methods.\n
var defer = RSVP.defer(),\n
......@@ -358,26 +372,32 @@
});\n
})\n
\n
.declareMethod("verifyInterfaceImplementation", function (gadget, interface_name) {\n
.declareMethod("verifyInterfaceImplementation", function (gadget_url, interface_name) {\n
var interface_gadget = this;\n
return RSVP.Queue()\n
.push(function () {\n
return verifyInterfaceDefinition(interface_name);\n
})\n
.push(function () {\n
return getVerifyGadget(gadget_url, interface_gadget);\n
})\n
.push(function (gadget) {\n
return interface_gadget.getDeclaredGadgetInterfaces(gadget);\n
})\n
.push(function (declared_interface_list) {\n
return verifyInterfaceDeclaration(interface_name, declared_interface_list);\n
})\n
.push(function () {\n
return getVerifyGadget(gadget_url, interface_gadget);\n
})\n
.push(function (gadget) {\n
return RSVP.all([\n
interface_gadget.getDefinedInterfaceMethods(interface_name),\n
interface_gadget.getDeclaredGadgetMethods(gadget)\n
]);\n
})\n
.push(function(method_list) {\n
return verifyAllMethods(method_list[0], method_list[1]);\n
return verifyAllMethod(method_list[0], method_list[1]);\n
})\n
.push (function() {\n
console.log("Verified : Success");\n
......@@ -525,7 +545,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>944.23277.56085.50961</string> </value>
<value> <string>944.26103.31340.29354</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -543,7 +563,7 @@
</tuple>
<state>
<tuple>
<float>1436802159.16</float>
<float>1436973571.38</float>
<string>GMT</string>
</tuple>
</state>
......
web_page_module/gadget_interface**
web_page_module/demo_interface**
web_page_module/rjs_gadget_interface**
web_page_module/gadget_testgadget**
web_site_module/interface_demo
\ No newline at end of file
web_page_module/gadget_interface**
web_page_module/demo_interface**
web_page_module/rjs_gadget_interface**
web_page_module/gadget_testgadget**
web_site_module/interface_demo
\ No newline at end of file
web_page_module/demo_interface*
web_page_module/gadget_interface*
web_page_module/gadget_testgadget*
web_page_module/rjs_gadget_interface*
web_site_module/interface_demo
web_site_module/interface_demo/**
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment