Source Code Cross Referenced for ScenarioRunnerTask.java in  » UML » MetaBoss » com » metaboss » sdlctools » applications » anttasks » scenariorunner » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » UML » MetaBoss » com.metaboss.sdlctools.applications.anttasks.scenariorunner 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
002:        // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
003:        // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
004:        // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
005:        // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
006:        // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
007:        // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
008:        // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
009:        // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
010:        // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
011:        // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
012:        // POSSIBILITY OF SUCH DAMAGE.
013:        //
014:        // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
015:        package com.metaboss.sdlctools.applications.anttasks.scenariorunner;
016:
017:        import java.io.File;
018:
019:        import org.apache.tools.ant.BuildException;
020:        import org.apache.tools.ant.taskdefs.Java;
021:        import org.apache.tools.ant.types.Commandline;
022:        import org.apache.tools.ant.types.Environment;
023:        import org.apache.tools.ant.types.Path;
024:        import org.apache.tools.ant.types.Reference;
025:
026:        import com.metaboss.sdlctools.applications.anttasks.MetaBossTask;
027:
028:        /** Special Ant task used to run test scenarios.
029:         * The source UML Model must conform to UML Profile For MetaBoss Design Model. 
030:         * This task extends abstract {@link com.metaboss.sdlctools.applications.anttasks.MetaBossTask MetaBossTask}
031:         * and therefore suports all of its attributes. In addition it supports the following attributes:
032:         * <table border="1" cellpadding="2" cellspacing="0">
033:         *   <tr>
034:         *     <th>Attribute Name</th>
035:         *     <th>Attribute Description</th>
036:         *   </tr>
037:         *   <tr>
038:         *     <td valign="top">scenarioname</td>
039:         *     <td valign="top">The optional name of the scenario. If this attribute is not present the name will be set to the
040:         *     'UnnamedScenario'. This name will appear on the console log and will also form part of the log file name.</td>
041:         *   </tr>
042:         *   <tr>
043:         *     <td valign="top">runname</td>
044:         *     <td valign="top">The optional name of the scenario run. This name is appended as a suffix to the 
045:         *      scenario name to form full name of the scenario run (This name which appears on the console log and forms the
046:         *      part of the log file name). Suffix is used to specify additional important feature of the particuar
047:         *      scenario run. For example scenario 'SearchForClients' can have two runs: 'OnCORBA' and 'OnJ2EE'. If this attribute is not present it is simply omitted.</td>
048:         *   </tr>
049:         *   <tr>
050:         *     <td valign="top">scenariopath</td>
051:         *     <td valign="top">This mandatory attribute contains list of one or more directories
052:         *     (accepting : and ; as path separators. relative path names will be interpreted as relative to the project's basedir).
053:         *     This is where scenario files will be read from. The directories will be read from left to right, but the test case files
054:         *     in each directory will be picked up and executed in the ascending alphabetical order.</td>
055:         *   </tr>
056:         *   <tr>
057:         *     <td valign="top">includepath</td>
058:         *     <td valign="top">This optional attribute contains list of zero or more directories
059:         *     (accepting : and ; as path separators. relative path names will be interpreted as relative to the project's basedir).
060:         *     This is where include scenario files will be read from. The directories will be searched from the 
061:         *     left to right and the first file with matching name will be included.</td>
062:         *   </tr>
063:         *   <tr>
064:         *     <td valign="top">classpath</td>
065:         *     <td valign="top">Alternatively to the classpath subelement or classpathref attribute,
066:         *     the classpath can be specified using this attribute with the single string containing one or more
067:         *     directories or files (accepting : and ; as path separators. relative path names will be interpreted as relative to the project's basedir). 
068:         *     See the classpath subelement documentation below for more details.</td>
069:         *   </tr>
070:         *   <tr>
071:         *     <td valign="top">classpathref</td>
072:         *     <td valign="top">Alternatively to the classpath subelement or classpath attribute, the classpath can be specified 
073:         *     using this attribute using path reference id of the path defined elsewhere. See the classpath subelement documentation below for more details.</td>
074:         *   </tr>
075:         *   <tr>
076:         *     <td valign="top">clientclasspathdir</td>
077:         *     <td valign="top">THis optional attribute must point to the root directory of the client classpath tree. The invocation of every servicemodule
078:         *     can be done using dedicated classpath. For example when HatMaker.CRM.MarketingQueries servicemodule is invoked
079:         *     the classpath is build from the following components:
080:         *     <UL>
081:         *       <LI>All jarfiles located in the ${clientclasspathdir}/HatMaker.CRM.MarketingQueries directory, if it is present.</LI>
082:         *       <LI>All jarfiles located in the ${clientclasspathdir} directory, if it is present.</LI>
083:         *       <LI>All classes defined in the classpath subelements of this element.</LI>
084:         *     </UL>
085:         *     Note that this feature is very advanced and is used mainly in the big testing installations where many systems
086:         *     built on separate technologies are tested toghether.</td>
087:         *   </tr>
088:         *   <tr>
089:         *     <td valign="top">failonerror</td>
090:         *     <td valign="top">The optional boolean flag which tells scenario runner whether to fail or not
091:         *     if the test scenario run itself has failed. Default is true, which means the scenario runner will 
092:         *     fail if any of the tests will fail.</td>
093:         *   </tr>
094:         *   <tr>
095:         *     <td valign="top">logperformance</td>
096:         *     <td valign="top">The optional boolean flag which tells scenario runner whether to log the performance
097:         *     data or not. Default is true, which means the scenario runner will log performance data.</td>
098:         *   </tr>
099:         *   <tr>
100:         *     <td valign="top">specimenfile</td>
101:         *     <td valign="top">The optional path and name of the file where the original specimen log should be obtained from.
102:         *     If this is attrribute is given, the regression analysis will be performed at the end of the test. If this attribute is
103:         *     not given - the regression analysis will not be performed.</td>
104:         *   </tr>
105:         *   <tr>
106:         *     <td valign="top">rundir</td>
107:         *     <td valign="top">The optional path and name of the directory where to run the scenario runner from.
108:         *     If this is attrribute is not given, the project's base directory is used.</td>
109:         *   </tr>
110:         *   <tr>
111:         *     <td valign="top">logdir</td>
112:         *     <td valign="top">The optional path and name of the directory where the logs should be stored.
113:         *     If this is attrribute is not given, the directory where scenario runner is running from is used.
114:         *     This directory will be created if required.</td>
115:         *   </tr>
116:         * </table>
117:         * <p>This task also supports following subelements:
118:         * <table border="1" cellpadding="2" cellspacing="0">
119:         *   <tr>
120:         *     <th>SubElement Name</th>
121:         *     <th>SubElement Description</th>
122:         *   </tr>
123:         *   <tr>
124:         *     <td valign="top">classpath</td>
125:         *     <td valign="top">This optional Ant's Path-like element should occur once or not at all. It
126:         *     defines the classpath of the JVM which executes the ScenarioRunner. The classpath should include all the required
127:         *     jars apart from the following jars which are always included by default:
128:         *     <UL>
129:         *       <LI>MetaBossSystemTester.jar - the scenario runner</LI>
130:         *       <LI>MetaBossComponentNamingProvider.jar - the jndi component naming provider</LI>
131:         *       <LI>MetaBossCore.jar - the core framework classes</LI>
132:         *       <LI>MetaBossEnterprise.jar - the enterprise framework</LI>
133:         *       <LI>commons-logging-x.x.x.jar and log4j-x.x.x.jar - logging framework</LI>
134:         *     </UL></td>
135:         *   </tr>
136:         *   <tr>
137:         *     <td valign="top">sysproperty</td>
138:         *     <td valign="top">This optional Environment variable like element can occur any number of times.
139:         *     The specified value of the system properties will be passed to the underlying JVM which executes the ScenarioRunner.</td>
140:         *   </tr>
141:         * </table></p>
142:         */
143:        public class ScenarioRunnerTask extends MetaBossTask {
144:            private Java mJavaTask = null;
145:            private String mScenarioName = null;
146:            private String mRunName = null;
147:            private File mSpecimenFile = null;
148:            private File mClientClasspathDir = null;
149:            private File mRunDir = null;
150:            private File mLogDir = null;
151:            private Path mClasspath = null;
152:            private boolean mFailOnError = true;
153:            private boolean mLogPerformance = true;
154:            private Path mScenarioPath = null;
155:            private Path mIncludePath = null;
156:
157:            /** Default constructor */
158:            public ScenarioRunnerTask() {
159:            }
160:
161:            /** Adds a system property */
162:            public void addSysproperty(Environment.Variable pSystemProperty) {
163:                // Precreate task so we can delegate some atttribute straight to it
164:                createJavaTaskIfNecessary();
165:                mJavaTask.addSysproperty(pSystemProperty);
166:            }
167:
168:            /** Adds a system property */
169:            public Commandline.Argument createJvmarg() {
170:                // Precreate task so we can delegate some atttribute straight to it
171:                createJavaTaskIfNecessary();
172:                return mJavaTask.createJvmarg();
173:            }
174:
175:            /** The setter for the optional "classpath" subelement */
176:            public Path createClasspath() {
177:                if (mClasspath != null)
178:                    throw new BuildException(
179:                            "Only one of the 'classpath', 'classpathref' attributes or <classpath> subelement can be present.");
180:                mClasspath = new Path(getProject());
181:                return mClasspath;
182:            }
183:
184:            /** The setter for the optional "classpath" attribute */
185:            public void setClasspath(Path pClasspath) {
186:                if (mClasspath != null)
187:                    throw new BuildException(
188:                            "Only one of the 'classpath', 'classpathref' attributes or <classpath> subelement can be present.");
189:                mClasspath = pClasspath;
190:            }
191:
192:            /** The setter for the optional "classpath" attribute */
193:            public void setClasspathRef(String pClasspathRef) {
194:                if (mClasspath != null)
195:                    throw new BuildException(
196:                            "Only one of the 'classpath', 'classpathref' attributes or <classpath> subelement can be present.");
197:                mClasspath = new Path(getProject());
198:                mClasspath.setRefid(new Reference(pClasspathRef));
199:            }
200:
201:            /** The getter for the optional "classpath" attribute */
202:            public Path getClasspath() {
203:                return mClasspath;
204:            }
205:
206:            /** The setter for the optional "scenarioname" attribute */
207:            public void setScenarioName(String pScenarioName) {
208:                mScenarioName = pScenarioName;
209:            }
210:
211:            /** The getter for the optional "scenarioname" attribute */
212:            public String getScenarioName() {
213:                return mScenarioName;
214:            }
215:
216:            /** The setter for the optional "runname" attribute */
217:            public void setRunName(String pRunName) {
218:                mRunName = pRunName;
219:            }
220:
221:            /** The getter for the optional "runname" attribute */
222:            public String getRunName() {
223:                return mRunName;
224:            }
225:
226:            /** The setter for the optional "specimenfile" attribute */
227:            public void setSpecimenFile(File pSpecimenFile) {
228:                if (pSpecimenFile != null) {
229:                    if (!pSpecimenFile.isFile())
230:                        throw new BuildException(
231:                                "The value of the 'specimenfile' must point to the existing and readable file. The "
232:                                        + pSpecimenFile.getAbsolutePath()
233:                                        + " is not a file.");
234:                    if (!pSpecimenFile.canRead())
235:                        throw new BuildException(
236:                                "The value of the 'specimenfile' must point to the existing and readable file. The "
237:                                        + pSpecimenFile.getAbsolutePath()
238:                                        + " is not readable.");
239:                }
240:                mSpecimenFile = pSpecimenFile;
241:            }
242:
243:            /** The getter for the optional "specimenfile" attribute */
244:            public File getSpecimenFile() {
245:                return mSpecimenFile;
246:            }
247:
248:            /** The setter for the mandatory "scenariopath" attribute */
249:            public void setScenarioPath(Path pScenarioPath) {
250:                mScenarioPath = pScenarioPath;
251:            }
252:
253:            /** The getter for the mandatory "scenariopath" attribute */
254:            public Path getScenarioPath() {
255:                if (mScenarioPath == null || mScenarioPath.list().length == 0)
256:                    throw new BuildException(
257:                            "The 'scenariopath' attribute is mandatory and must contain the path consisting of one or more directories where scenario files are located.");
258:                return mScenarioPath;
259:            }
260:
261:            /** The setter for the mandatory "includepath" attribute */
262:            public void setIncludePath(Path pIncludePath) {
263:                mIncludePath = pIncludePath;
264:            }
265:
266:            /** The getter for the mandatory "includepath" attribute */
267:            public Path getIncludePath() {
268:                return mIncludePath;
269:            }
270:
271:            /** The setter for the optional "clientclasspathdir" attribute */
272:            public void setClientClasspathDir(File pClientClasspathDir) {
273:                if (pClientClasspathDir != null) {
274:                    if (!pClientClasspathDir.isDirectory())
275:                        throw new BuildException(
276:                                "The value of the 'clientclasspathdir' must point to the directory. The "
277:                                        + pClientClasspathDir.getAbsolutePath()
278:                                        + " is not a directory.");
279:                }
280:                mClientClasspathDir = pClientClasspathDir;
281:            }
282:
283:            /** The getter for the optional "clientclasspathdir" attribute */
284:            public File getClientClasspathDir() {
285:                return mClientClasspathDir;
286:            }
287:
288:            /** The setter for the optional "logdir" attribute */
289:            public void setLogDir(File pLogDir) {
290:                if (pLogDir != null) {
291:                    if (pLogDir.exists() == true
292:                            && pLogDir.isDirectory() == false)
293:                        throw new BuildException(
294:                                "The value of the 'logdir' must point to the directory. The "
295:                                        + pLogDir.getAbsolutePath()
296:                                        + " is not a directory.");
297:                }
298:                mLogDir = pLogDir;
299:            }
300:
301:            /** The getter for the optional "logdir" attribute */
302:            public File getLogDir() {
303:                return mLogDir;
304:            }
305:
306:            /** The setter for the optional "rundir" attribute */
307:            public void setRunDir(File pRunDir) {
308:                if (pRunDir != null) {
309:                    if (!pRunDir.isDirectory())
310:                        throw new BuildException(
311:                                "The value of the 'rundir' must point to the existing directory. The "
312:                                        + pRunDir.getAbsolutePath()
313:                                        + " is not a directory.");
314:                    if (!pRunDir.exists())
315:                        throw new BuildException(
316:                                "The value of the 'rundir' must point to the existing directory. The "
317:                                        + pRunDir.getAbsolutePath()
318:                                        + " does not exist.");
319:                }
320:                mRunDir = pRunDir;
321:            }
322:
323:            /** The getter for the optional "rundir" attribute */
324:            public File getRunDir() {
325:                return mRunDir;
326:            }
327:
328:            /** The setter for the optional "failonerror" attribute */
329:            public void setFailOnError(boolean pFailOnError) {
330:                mFailOnError = pFailOnError;
331:            }
332:
333:            /** The getter for the optional "failonerror" attribute */
334:            public boolean getFailOnError() {
335:                return mFailOnError;
336:            }
337:
338:            /** The setter for the optional "logperformance" attribute */
339:            public void setLogPerformance(boolean pLogPerformance) {
340:                mLogPerformance = pLogPerformance;
341:            }
342:
343:            /** The getter for the optional "logperformance" attribute */
344:            public boolean getLogPerformance() {
345:                return mLogPerformance;
346:            }
347:
348:            // The method actually executing the task.
349:            public void execute() throws BuildException {
350:                // Now create and execute the java task
351:                createJavaTaskIfNecessary();
352:                mJavaTask.setTaskName(getTaskName());
353:                mJavaTask
354:                        .setClassname("com.metaboss.sdlctools.applications.systemtester.ScenarioRunner");
355:                mJavaTask.setFailonerror(getFailOnError());
356:                mJavaTask.setFork(true);
357:                mJavaTask.setDir(getRunDir() != null ? getRunDir()
358:                        : getProject().getBaseDir());
359:                // Work on classpath
360:                if (getClasspath() != null) {
361:                    Path lClasspath = mJavaTask.createClasspath();
362:                    // Add the default classpath 
363:                    lClasspath
364:                            .addExisting(getPath("TestScenarioRunnerClasspath"));
365:                    // Add additional classpath specified in the task			
366:                    if (getClasspath() != null)
367:                        lClasspath.addExisting(getClasspath());
368:                }
369:                // Work on the sysproperties connecting the xalan transformation processor instead of the default one
370:                {
371:                    {
372:                        Environment.Variable lTransformerFactoryProperty = new Environment.Variable();
373:                        lTransformerFactoryProperty
374:                                .setKey("javax.xml.transform.TransformerFactory");
375:                        lTransformerFactoryProperty
376:                                .setValue("org.apache.xalan.xsltc.trax.TransformerFactoryImpl");
377:                        mJavaTask.addSysproperty(lTransformerFactoryProperty);
378:                    }
379:                    {
380:                        Environment.Variable lEndorsedDirProperty = new Environment.Variable();
381:                        lEndorsedDirProperty.setKey("java.endorsed.dirs");
382:                        lEndorsedDirProperty.setValue(getMetaBossHome()
383:                                .getAbsolutePath()
384:                                + "/thirdpartylib/xalan-j_2_6_0");
385:                        mJavaTask.addSysproperty(lEndorsedDirProperty);
386:                    }
387:                }
388:
389:                // Work on arguments
390:                // - scenario Name
391:                if (getScenarioName() != null) {
392:                    Commandline.Argument lTaskArgument = mJavaTask.createArg();
393:                    lTaskArgument
394:                            .setValue("-scenarioName=" + getScenarioName());
395:                }
396:                // - -scenario Run Name
397:                if (getRunName() != null) {
398:                    Commandline.Argument lTaskArgument = mJavaTask.createArg();
399:                    lTaskArgument.setValue("-scenarioRunName=" + getRunName());
400:                }
401:                // - scenario Path
402:                {
403:                    // Ensure that the semicolumns only are used
404:                    String[] lPathElements = getScenarioPath().list();
405:                    StringBuffer lBuffer = new StringBuffer();
406:                    for (int i = 0; i < lPathElements.length; i++) {
407:                        if (i > 0)
408:                            lBuffer.append(";");
409:                        lBuffer.append(lPathElements[i]);
410:                    }
411:                    Commandline.Argument lTaskArgument = mJavaTask.createArg();
412:                    lTaskArgument.setValue("-scenarioPath="
413:                            + lBuffer.toString());
414:                }
415:
416:                // - include Path
417:                if (getIncludePath() != null) {
418:                    // Ensure that the semicolumns only are used
419:                    String[] lPathElements = getIncludePath().list();
420:                    StringBuffer lBuffer = new StringBuffer();
421:                    for (int i = 0; i < lPathElements.length; i++) {
422:                        if (i > 0)
423:                            lBuffer.append(";");
424:                        lBuffer.append(lPathElements[i]);
425:                    }
426:                    Commandline.Argument lTaskArgument = mJavaTask.createArg();
427:                    lTaskArgument
428:                            .setValue("-includePath=" + lBuffer.toString());
429:                }
430:
431:                // - specimen File
432:                if (getSpecimenFile() != null) {
433:                    Commandline.Argument lTaskArgument = mJavaTask.createArg();
434:                    lTaskArgument.setValue("-specimenFile="
435:                            + getSpecimenFile().getAbsolutePath());
436:                }
437:                // -logging Path
438:                {
439:                    File lLogPath = getLogDir() != null ? getLogDir()
440:                            : getProject().getBaseDir();
441:                    Commandline.Argument lTaskArgument = mJavaTask.createArg();
442:                    lTaskArgument.setValue("-loggingPath="
443:                            + lLogPath.getAbsolutePath());
444:                }
445:
446:                // - client Path
447:                if (getClientClasspathDir() != null) {
448:                    Commandline.Argument lTaskArgument = mJavaTask.createArg();
449:                    lTaskArgument.setValue("-clientPath="
450:                            + getClientClasspathDir().getAbsolutePath());
451:                }
452:
453:                // - log Test Performance 
454:                {
455:                    Commandline.Argument lTaskArgument = mJavaTask.createArg();
456:                    lTaskArgument.setValue("-logTestPerformance="
457:                            + Boolean.toString(getLogPerformance()));
458:                }
459:
460:                mJavaTask.execute();
461:            }
462:
463:            // Helper. Ensures that the java task created when it is needed
464:            private void createJavaTaskIfNecessary() {
465:                if (mJavaTask == null)
466:                    mJavaTask = (Java) getProject().createTask("java");
467:            }
468:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.