Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Dashboard
Sonar
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<div><table class="wysiwyg-macro" data-macro-name="unmigrated-inline-wiki-markup" data-macro-parameters="atlassian-macro-output-type=BLOCK" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e3VubWlncmF0ZWQtaW5saW5lLXdpa2ktbWFya3VwOmF0bGFzc2lhbi1tYWNyby1vdXRwdXQtdHlwZT1CTE9DS30&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>{iframe:src=http://update.sonarsource.org/plugins/delphi.html|width=700|height=250|frameborder=0} Your browser does not support iframes. {iframe}</pre></td></tr></table><div><span><br /></span></div><h1><span>Description / Features</span></h1><div><span>This plugin is donation of </span><a href="http://www.sabreairlinesolutions.com/home/">Sabre Airline Solutions</a></div><p>Delphi Sonar plugin enables analysis of projects written using Delphi or Pascal. It was tested with projects written in Delphi 6, 7, 2006 and XE.</p><p>It is using grammar in ANTLR v3 format. It is extended on grammar found at <a href="http://www.dragonkiller.nl/Delphi/delphi2009.txt">http://www.dragonkiller.nl/Delphi/delphi2009.txt</a></p><p>It is compatible with <span>the </span><a class="confluence-link" href="/display/SONAR/Issues+Report+Plugin" data-linked-resource-id="230398911" data-linked-resource-type="page" data-linked-resource-default-alias="Issues Report Plugin" data-base-url="http://docs.codehaus.org">Issues Report plugin</a><span> to run pre-commit local analysis.</span></p><h1>Installation</h1><ol><li>Install the Delphi plugin through the <a href="http://docs.codehaus.org/display/SONAR/Update+Center">Update Center</a> or download it into the SONAR_HOME/extensions/plugins directory</li><li>Restart the Sonar server</li></ol><h1>Usage</h1><h3>Run a Sonar Analysis with the Sonar Runner (Recommended Way)</h3><p>To launch a Sonar analysis of your Delphi project, use the <a href="http://docs.codehaus.org/display/SONAR/Analyzing+with+Sonar+Runner">Sonar Runner</a>.</p><p>A sample project is available on github that can be <a class="external-link" href="https://github.com/SonarSource/sonar-examples" rel="nofollow">browsed</a> or <a class="external-link" href="https://github.com/SonarSource/sonar-examples/zipball/master" rel="nofollow">downloaded</a>: /projects/languages/delphi/delphi-sonar-runner.</p><h3>Run a Sonar Analysis with the other Analyzers</h3><p><a href="http://docs.codehaus.org/display/SONAR/Analyzing+with+Maven">Maven</a> and <a href="http://docs.codehaus.org/display/SONAR/Analyzing+with+Ant+Task">Ant</a> can also be used to launch analysis on Delphi projects.</p></div><p>You can find a sample project in "src/Sample/SampleProject". It contains an Ant script, which you can use to do the analysis. You must have ANT installed.</p><p>Install the Delphi plugin on your Sonar instance, and type "ant sonar" from sample project directory in order to try the plugin.</p><h1>Metrics</h1><p>See <a class="confluence-link" href="/display/SONAR/Metric+definitions" data-linked-resource-id="230397406" data-linked-resource-type="page" data-linked-resource-default-alias="Metric definitions" data-base-url="http://docs.codehaus.org">Metrics documentation page</a>.</p><h1>IMPLEMENTED FEATURES</h1><ol><li>Counting lines of code, statements, number of files</li><li>Counting number of classes, number of packages, methods, accessors</li><li>Counting number of public API (methods, classes and fields)</li><li>Counting comments ratio, comment lines (including blank lines)</li><li>CPD (code duplication, how many lines, block and in how many files)</li><li>Code Complexity (per method, class, file; complexity distribution over methods, classes and files)</li><li>LCOM4 and RFC</li><li>Code colorization</li><li>Unit tests reports</li><li>Assembler syntax in grammar</li><li>Include statement</li><li>Parsing preprocessor statements</li><li>Rules</li><li>Code coverage reports</li><li>Source code highlight for unit tests</li><li>“Dead” code recognition</li><li>Unused files recognition</li></ol><h1>NOT IMPLEMENTED FEATURES (TODO)</h1><ol><li>Package tangle index</li></ol><h1>CODE ASSUMPTIONS</h1><ol><li>Grammar has problems with recognizing certain identifiers. When we add whitespace (“ “) at several places, everything works fine. It was difficult to solve this problem from the grammar level, so it is solved in <strong>DelphiSourceSanitizer</strong> class. It adds whitespaces where there are needed in parsed file, and grammar works fine. It is used for: <br /><ol><li>Colon, “:” -> “ :”</li><li>Array range, “x..y” -> “x .. y”</li></ol></li><li>Grammar is NOT case insensitive, but Delphi code is. Plugin deals with it by <strong>DelphiSourceSanitizer</strong> class, which feeds ANTLR parser lowercase characters (the “LA” method)</li><li>Number of classes includes: classes, records</li><li>Directory is count as a package. Number of packages equals number of directories.</li><li>Preprocessor definitions between <strong>{$if xxx}</strong> and <strong>{$ifend}</strong> are removed (<strong>DefineResolver</strong> class).</li><li>Sources imported to Sonar are parsed through <strong>IncludeResolver</strong> class. It means, that the source will be lowercased and unknown preprocessor definitions will be cut out.</li></ol><h1>GRAMMAR ASSUMPTIONS</h1><p>All assumptions in grammar file are commented with <strong>//ASSUMPTION </strong>comment.</p><ol><li>“ident” rule – was extended, now it uses some keywords that were used as variable names in source code, ex. “name”, “readonly”, “index”. If you use more keywords as variable names or function names, you should extend the rule further.</li><li>The grammar has problem with proper recognizing identifier that ends with “:” (“e:” does not work, does not recognize “e” as identifier), see <strong>code assumption 1</strong> for solution.</li><li>The grammar has problem with proper array range recognizing (“array[1..2]” does not work), see <strong>code assumption 1 </strong>for solution.</li><li>The grammar is not case-insensitive, and it should be. For parsing files using ANTLRWorks, convert them to lowercase. Plugin deals with it automatically, by<strong> AntlrNoCaseFileStream</strong> class.</li></ol><h1>MOST COMMON GRAMMAR PROBLEMS (FIXED):</h1><p>Below is the list of the most common grammar problems. You can also look at file <strong>GrammarTest.pas</strong> to get more detailed information.</p><ol><li>On e: exception do</li><li>Name = procedure (x: integer) of object;</li><li>Using keywords as variable names (ex. continue, message, name, db)</li><li>Array[1..2]</li><li>@address = someProcedure(x,y);</li><li>(expression).namespace.ident = x;</li><li>Default function argument values crashed AbstractAnalyser</li><li>Inherited;</li><li>if (tempstr[1] in ['0' .. '9', 'a' .. 'z'] = false) then</li><li>str: string[3];</li><li>function tfilewriter.writebytes(var ibytes; isize : dword) : boolean;</li><li>DetailedDescription : array of Byte;</li><li>ferrorlist : tlist<string>;</li><li>Delphi complier does not require “;” at the end of except statement:</li></ol><p>On e: exception do</p><p>Begin</p><p>End</p><h1>DEBUGGING GRAMMAR FROM ANTLRWORKS</h1><p>If you want to debug grammar from AntlrWorks, do the following:</p><ol><li>Convert file to be parsed to lowercase</li><li>Apply all transformations mentioned in <strong>code assumption 1</strong>.</li><li>Use more Java heap space while running AntlrWorks, ex. 1024M (java –Xmx1024m)</li></ol><h1>DUNIT TESTS</h1><p>You should put transformed DUnit xml files to directory specified in build.xml file, under sonar.surefire.reportsPath parameter. You can specify multiply directories separated by ‘,’. Then all specified directories will be parsed. The path can be either absolute or relative to the project main path.</p><p>The xml files should be renamed with “TEST-“ prefix, example: “dunit.xml” -> “TEST-dunit.xml”.</p><h1>CODE COVERAGE WITH AQTIME</h1><p>CodeCoverageSensor class is responsible for running CC analysis. It creates a parser that connects to specified data base holding AQTime generated CC report. Connection properties can be specified in a build.xml or pom.xml file (see below). If parser can’t connect to the data base, analysis is skipped.</p><p>You can specify exclude directories in build xml file, under sonar.delphi.codecoverage.excluded parameter. The files in specified directories will be not checked for code coverage.</p><h1>DELPHICSOURCESANITIZER CLASS</h1><p>This class prepares source code for parsing. It does the following:</p><p>- Parse preprocessor definitions (using DefineResolver class)</p><p>- Add include files (using IncludeResolver class)</p><p>- “Fix” the code as explained in <strong>code assumption 1 </strong>(using SourceFixcerResolver class).</p><p>- Feed ANTLR parser with lowercase characters (<strong>code assumption 2</strong>).</p><p>To properly do this things, the class firstly searches for areas that should not be parsed: comments and single quoted strings. Why? For example, you can have such piece of code:</p><pre>X := 5; //{$include file.inc}</pre><pre>S := ‘my {$include file.inc} string’;</pre><p>Without recognizing which areas to exclude, the parser would simply copy-paste the file “file.inc” into a comment or a string, and this would produce an error.</p><h1>ANT BUILD.XML / MAVEN POM.XML</h1><p>There are few additional project parameters that you can set in Ant’s build.xml.</p><table class="confluenceTable"><tbody><tr><td class="confluenceTd"><p><strong>KEY</strong></p></td><td class="confluenceTd"><p><strong>DESCRIPTION</strong></p></td><td class="confluenceTd"><p><strong>EXAMPLE</strong></p></td></tr><tr><td class="confluenceTd"><p><strong>sonar.delphi.sources.excluded</strong></p></td><td class="confluenceTd"><p>Excluded directories, they won’t be parsed and metrics won’t be calculated for them. Path’s can be relative to main project directory or absolute. Separate them with ‘,’.</p><p>Default value is “”.</p></td><td class="confluenceTd"><p><property key="sonar.delphi.sources.excluded " value="excluded\directory, another\excluded,c:\something" /></p><p> </p></td></tr><tr><td class="confluenceTd"><p><strong>sonar.delphi.codecoverage.excluded</strong></p></td><td class="confluenceTd"><p>Code coverage excluded directories list. Files in those directories will not be checked for code coverage. Default value is “”.</p></td><td class="confluenceTd"><p><property key="sonar.delphi.codecoverage.excluded" value="cc\test\excluded,c:\sth" /></p></td></tr><tr><td class="confluenceTd"><p><strong>sonar.delphi.sources.include</strong></p></td><td class="confluenceTd"><p>Path to include directories for files included with {$include} or {$i} directive.</p><p>Default value is “”.</p></td><td class="confluenceTd"><p><property key="sonar.delphi.sources.include" value="includes_dir,includes_dir2" /></p></td></tr><tr><td class="confluenceTd"><p><strong>sonar.delphi.sources.include.extend</strong></p></td><td class="confluenceTd"><p>Should we extend (copy-paste) include files? Possible values are “true” or “false”. </p><p>Default value is “true”.</p></td><td class="confluenceTd"><p><property key="sonar.delphi.sources.include.extend" value="true"></p></td></tr><tr><td class="confluenceTd"><p><strong>sonar.delphi.sources.projects</strong></p></td><td class="confluenceTd"><p>Project file. If provided, will be parsed for include lookup path, project source files and preprocessor definitions. Default value is “”.</p></td><td class="confluenceTd"><p><property key=" sonar.delphi.sources.project" value="projects\myProject.dproj"></p></td></tr><tr><td class="confluenceTd"><p><strong>sonar.delphi.sources.workgroup</strong></p></td><td class="confluenceTd"><p>Workgroup file. If provided, will be parsed, then all *.dproj files found in workgroup file will be parsed.</p></td><td class="confluenceTd"><p><property key=" sonar.delphi.sources.workgroup" value="projects\All.groupproj"></p></td></tr><tr><td class="confluenceTd"><p><strong>sonar.delphi.codecoverage.aqtime.jdbc.driver</strong></p></td><td class="confluenceTd"><p>Class name for JDBC driver. Default value is “net.sourceforge.jtds.jdbc.Driver”</p></td><td class="confluenceTd"><p><property key="sonar.delphi.codecoverage.aqtime.jdbc.driver" value="net.sourceforge.jtds.jdbc.Driver" /></p></td></tr><tr><td class="confluenceTd"><p><strong>sonar.delphi.codecoverage.aqtime.jdbc.url</strong></p></td><td class="confluenceTd"><p>Database connection url. Default value is “”.</p></td><td class="confluenceTd"><p><property key="sonar.delphi.codecoverage.aqtime.jdbc.url" value="<a>jdbc:jtds:sqlserver://localhost</a>" /></p></td></tr><tr><td class="confluenceTd"><p><strong>sonar.delphi.codecoverage.aqtime.jdbc.user</strong></p></td><td class="confluenceTd"><p>Database user name. Default value is “”.</p></td><td class="confluenceTd"><p><property key="sonar.delphi.codecoverage.aqtime.jdbc.user" value="admin" /></p></td></tr><tr><td class="confluenceTd"><p><strong>sonar.delphi.codecoverage.aqtime.jdbc.password</strong></p></td><td class="confluenceTd"><p>Database user password. Default value is “”.</p></td><td class="confluenceTd"><p><property key="sonar.delphi.codecoverage.aqtime.jdbc.password" value="pass" /></p></td></tr><tr><td colspan="1" class="confluenceTd"><strong>sonar.delphi.codecoverage.aqtime.jdbc.prefix</strong></td><td colspan="1" class="confluenceTd">Database prefix for connecting to AQTime database. Default value is "".</td><td colspan="1" class="confluenceTd"><property key="sonar.delphi.codecoverage.aqtime.jdbc.prefix" value="CC.dbo." /></td></tr></tbody></table><p> </p><h1>CUSTOM PMD RULES</h1><p>If you want to make a custom PMD rule, you can do it in two ways:</p><p>WRITE YOUR OWN CLASS</p><p>Create rule class, that extends from org.sonar.plugins.delphi.pmd.rules.DelphiRule class. You will need to overload visit(DelphiPMDNode node, Object data) method. You will have the current ast tree node and whole ast tree to your disposal. If you want to save a violation, invoke addViolation(Object data, DelphiPMDNode node) method.</p><p>If you want to initialize some class variables at start of each file, overload the init() method. Look at the org.sonar.plugins.delphi.pmd.rules package for sample classes.</p><p>After you write your class, modify the “rules.xml” and “default-delphi-profile.xml”, simply add your class to the list.</p><p>WRITE XPATH SENTENCE</p><p>You can write an XPath sentence which will parse the whole file. Open the “rules.xml” file, copy one of the XPath rules already available and change the “xpath” property to your XPath string. Don’t forget to add the rule to “default-delphi-profile.xml”. That’s it!</p><h1>IMPLEMENTED RULES</h1><p>For full summary (description, examples) of custom PMD rules, do the following: execute Sonar -> Configuration -> Default Delphi Profile and browse the rules under Delphi profile.</p><p>List of implemented rules, as follows:</p><table class="confluenceTable"><tbody><tr><td class="confluenceTd"><p align="center"><strong><em>RULE NAME</em></strong></p></td><td class="confluenceTd"><p align="center"><strong><em>RULE PRIORITY</em></strong></p></td></tr><tr><td class="confluenceTd"><p><em>1. </em><em>Then Try Rule (you should place ‘begin’ before ‘try’)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>2. </em><em>One Class Per File Rule (one class per file permitted)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>3. </em><em>Inherited Method With No Code Rule (method that only inherits behavior)</em></p></td><td class="confluenceTd"><p align="center"><em>2</em></p></td></tr><tr><td class="confluenceTd"><p><em>4. </em><em>Empty Except Block Rule (empty ‘except’ block, catching no exceptions)</em></p></td><td class="confluenceTd"><p align="center"><em>1</em></p></td></tr><tr><td class="confluenceTd"><p><em>5. </em><em>Empty Interface Rule (empty interface)</em></p></td><td class="confluenceTd"><p align="center"><em>2</em></p></td></tr><tr><td class="confluenceTd"><p><em>6. </em><em>Empty Then Statement Rule (empty ‘then’ statement)</em></p></td><td class="confluenceTd"><p align="center"><em>2</em></p></td></tr><tr><td class="confluenceTd"><p><em>7. </em><em>Empty Begin Statement Rule (empty ‘begin’ .. ‘end’ statement)</em></p></td><td class="confluenceTd"><p align="center"><em>2</em></p></td></tr><tr><td class="confluenceTd"><p><em>8. </em><em>Empty Else Statement Rule (empty ‘else’ statement)</em></p></td><td class="confluenceTd"><p align="center"><em>2</em></p></td></tr><tr><td class="confluenceTd"><p><em>9. </em><em>Too Long Method Rule (method too long, above certain line limit)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>10. </em><em>Too Many Arguments Rule (to many function/procedure arguments)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>11. </em><em>Too Many Variables Rule (to many variables in a function/procedure)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>12. </em><em>No Semi After Overload Rule (no semicolon ‘;’ after ‘overload’ keyword)</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>13. </em><em>No Function Return Type Rule (function with no return type specified)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>14. </em><em>Interface Name Rule (interface name should begin with ‘I’ letter)</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>15. </em><em>Class Name Rule (class name should begin with ‘T’ letter)</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>16. </em><em>Record Name Rule (record name should begin with ‘T’ letter)</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>17. </em><em>Catching General Exception Rule (catching Exception class in ‘except’ statement)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>18. </em><em>Raising General Exception Rule (raising Exception class in ‘raise’ statement)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>19. </em><em>Avoid Out Parameter Rule (using ‘out’ arguments)</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>20. </em><em>If True Rule (convert ‘if(x=true) then’ to ‘if (x) then’)</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>21. </em><em>If Not False Rule (convert ‘if not (x = false) then’ to ‘if (x) then’</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>22. </em><em>Public Field Rule (class fields should NOT be public)</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>23. </em><em>Avoid Unused Method Parameters Rule (avoid making function arguments that are not used in body)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>24. </em><em>No Interface Guid (no Guid at interface)</em></p></td><td class="confluenceTd"><p align="center"><em>5</em></p></td></tr><tr><td class="confluenceTd"><p><em>25. </em><em>If Assigned And Free (before calling ‘Free’ you don’t need to check for variable assignment ‘x <> nil’)</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>26. </em><em>Project File No Functions Rule (.dpr file should not contain procedures or functions)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>27. </em><em>Project File No Variables Rule (.dpr file should not contain variables)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>28. </em><em>Type Alias Rule (avoid using type aliases)</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>29. </em><em>Uppercase Reserved Keywords Rule (avoid using uppercase reserved keywords)</em></p></td><td class="confluenceTd"><p align="center"><em>5</em></p></td></tr><tr><td class="confluenceTd"><p><em>30. </em><em>Mixed Names Rule (avoid case mixing names of functions / variables)</em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>31. </em><em>Unused Unit Rule (searches for units that are not referenced in other units)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>32. </em><em>Unused Function Rule (searches for functions/procedures that are not used by other functions/procedures)</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr><tr><td class="confluenceTd"><p><em>33. </em><em>Constructor Without Inherited Statement Rule (constructor does not contain ‘inherited’ statement)</em></p></td><td class="confluenceTd"><p align="center"><em>2</em></p></td></tr><tr><td class="confluenceTd"><p><em>34. </em><em>Destructor Without Inherited Statement Rule (destructor does not contain ‘inherited’ statement)</em></p></td><td class="confluenceTd"><p align="center"><em>2</em></p></td></tr><tr><td class="confluenceTd"><p><em>35. </em><em>No ‘begin’ after ‘do Statement Rule </em></p></td><td class="confluenceTd"><p align="center"><em>4</em></p></td></tr><tr><td class="confluenceTd"><p><em>36. </em><em>‘With’ after ‘do’ statement Rule</em></p></td><td class="confluenceTd"><p align="center"><em>3</em></p></td></tr></tbody></table><p><em> </em></p><h1>FUTURE WORK</h1><ol><li>The <strong>org.sonar.squid.text.delphi</strong> package was copy-pasted from <strong>org.sonar.squid.text</strong> with modifications to work with Delphi source code. Hence some duplications are present. The whole package should be refactored, so duplications could be removed.</li><li>We made a "hack" of PMD engine to make it run with Delphi code. When we made it, PMD didn't allow to work with other than Java code. Refactoring steps should be taken to migrate it to newest available version (with multi-language support).</li></ol><p><em><br /></em></p><p><em><br /></em></p>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced