Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
doxverilog
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
doxverilog
Commits
e0e5c855
Commit
e0e5c855
authored
Feb 01, 2003
by
dimitri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Release-1.3-rc3
parent
5d7d90c3
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
145 additions
and
156 deletions
+145
-156
INSTALL
INSTALL
+2
-2
README
README
+2
-2
VERSION
VERSION
+1
-1
main.cpp
addon/doxmlparser/examples/metrics/main.cpp
+7
-5
language.doc
doc/language.doc
+3
-3
doxygen.spec
packages/rpm/doxygen.spec
+1
-1
code.l
src/code.l
+5
-1
docparser.cpp
src/docparser.cpp
+13
-6
doctokenizer.l
src/doctokenizer.l
+5
-1
doxygen.cpp
src/doxygen.cpp
+34
-0
doxytag.l
src/doxytag.l
+1
-2
filedef.cpp
src/filedef.cpp
+44
-0
filedef.h
src/filedef.h
+3
-0
index.cpp
src/index.cpp
+1
-1
memberdef.cpp
src/memberdef.cpp
+1
-1
memberlist.cpp
src/memberlist.cpp
+17
-125
scanner.l
src/scanner.l
+3
-3
xmlgen.cpp
src/xmlgen.cpp
+2
-2
No files found.
INSTALL
View file @
e0e5c855
DOXYGEN Version 1.3-rc
2-20030126
DOXYGEN Version 1.3-rc
3
Please read the installation section of the manual
(http://www.doxygen.org/install.html) for instructions.
--------
Dimitri van Heesch (
26 Jan
uary 2003)
Dimitri van Heesch (
01 Febr
uary 2003)
README
View file @
e0e5c855
DOXYGEN Version 1.3_rc
2_20030126
DOXYGEN Version 1.3_rc
3
Please read INSTALL for compilation instructions.
...
...
@@ -17,4 +17,4 @@ to subscribe to the lists or to visit the archives.
Enjoy,
Dimitri van Heesch (dimitri@stack.nl) (
26 Jan
uary 2003)
Dimitri van Heesch (dimitri@stack.nl) (
01 Febr
uary 2003)
VERSION
View file @
e0e5c855
1.3-rc
2-20030126
1.3-rc
3
addon/doxmlparser/examples/metrics/main.cpp
View file @
e0e5c855
...
...
@@ -3,7 +3,7 @@
* $Id$
*
*
* Copyright (C) 1997-200
2
by Dimitri van Heesch.
* Copyright (C) 1997-200
3
by Dimitri van Heesch.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation under the terms of the GNU General Public License is hereby
...
...
@@ -19,17 +19,19 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <doxmlintf.h>
bool
isDocumented
(
IDocRoot
*
brief
,
IDocRoot
*
detailed
)
{
bool
found
=
FALSE
;
bool
found
=
false
;
if
(
brief
)
{
IDocIterator
*
docIt
=
brief
->
contents
();
if
(
docIt
->
current
())
// method has brief description
{
found
=
TRUE
;
found
=
true
;
}
docIt
->
release
();
}
...
...
@@ -38,7 +40,7 @@ bool isDocumented(IDocRoot *brief,IDocRoot *detailed)
IDocIterator
*
docIt
=
detailed
->
contents
();
if
(
docIt
->
current
())
{
found
=
TRUE
;
found
=
true
;
}
docIt
->
release
();
}
...
...
@@ -202,7 +204,7 @@ int main(int argc,char **argv)
{
numParams
++
;
}
if
(
QString
(
mem
->
typeString
()
->
latin1
())
!=
"void"
)
if
(
strcmp
(
mem
->
typeString
()
->
latin1
(),
"void"
)
!=
0
)
{
numParams
++
;
// count non-void return types as well
}
...
...
doc/language.doc
View file @
e0e5c855
...
...
@@ -25,7 +25,7 @@ Doxygen has built-in support for multiple languages. This means
that the text fragments that doxygen generates can be produced in
languages other than English (the default) at configuration time.
Currently (version 1.3-rc
2-20030106
), 28 languages
Currently (version 1.3-rc
3
), 28 languages
are supported (sorted alphabetically):
Brazilian Portuguese, Catalan, Chinese, Chinese Traditional, Croatian,
Czech, Danish, Dutch, English, Finnish,
...
...
@@ -145,7 +145,7 @@ when the translator was updated.
<TD>Japanese</TD>
<TD>Ryunosuke Satoh<br>Kenji Nagamatsu</TD>
<TD>sun594@NOSPAM.hotmail.com<br>naga@NOSPAM.joyful.club.ne.jp</TD>
<TD>
1.2.18
</TD>
<TD>
up-to-date
</TD>
</TR>
<TR BGCOLOR="#ffffff">
<TD>Korean</TD>
...
...
@@ -262,7 +262,7 @@ when the translator was updated.
Italian & Alessandro Falappa & {\tt alessandro@falappa.net} & up-to-date \\
& Ahmed Aldo Faisal & {\tt aaf23@cam.ac.uk} & \\
\hline
Japanese & Ryunosuke Satoh & {\tt sun594@hotmail.com} &
1.2.18
\\
Japanese & Ryunosuke Satoh & {\tt sun594@hotmail.com} &
up-to-date
\\
& Kenji Nagamatsu & {\tt naga@joyful.club.ne.jp} & \\
\hline
Korean & Richard Kim & {\tt ryk@dspwiz.com} & 1.2.13 \\
...
...
packages/rpm/doxygen.spec
View file @
e0e5c855
Summary: A documentation system for C/C++.
Name: doxygen
Version: 1.3_rc
2_20030126
Version: 1.3_rc
3
Release: 1
Epoch: 1
Source0: ftp://ftp.stack.nl/pub/users/dimitri/%{name}-%{version}.src.tar.gz
...
...
src/code.l
View file @
e0e5c855
...
...
@@ -593,7 +593,11 @@ static MemberDef *setCallContextForVar(const QCString &name)
//printf("mn=%p md=%p md->getBodyDef()=%p g_sourceFileDef=%p\n",
// mn,md,
// md->getBodyDef(),g_sourceFileDef);
if (md->getBodyDef()==g_sourceFileDef)
// in case there are multiple members we could link to, we
// only link to members if defined in the same file or
// defined as external.
if (!md->isStatic() || md->getBodyDef()==g_sourceFileDef)
{
g_theCallContext.setClass(stripClassName(md->typeString()));
//printf("returning member %s in source file %s\n",md->name().data(),g_sourceFileDef->name().data());
...
...
src/docparser.cpp
View file @
e0e5c855
...
...
@@ -276,7 +276,7 @@ static void checkArgumentName(const QString &name,bool isParam)
}
}
/*! Checks if the parameters that have been specified using @param are
/*! Checks if the parameters that have been specified using
\
@param are
* indeed all paramters.
* Must be called after checkArgumentName() has been called for each
* argument.
...
...
@@ -2219,7 +2219,7 @@ int DocIndexEntry::parse()
break
;
}
}
if
(
tok
!=
TK_WHITESPACE
)
retval
=
tok
;
if
(
tok
!=
0
)
retval
=
tok
;
doctokenizerYYsetStatePara
();
endindexentry
:
DBG
((
"DocIndexEntry::parse() end retval=%x
\n
"
,
retval
));
...
...
@@ -4561,10 +4561,17 @@ void DocRoot::parse()
while
(
retval
==
RetVal_Section
)
{
SectionInfo
*
sec
=
Doxygen
::
sectionDict
[
g_token
->
sectionId
];
ASSERT
(
sec
!=
0
);
DocSection
*
s
=
new
DocSection
(
this
,
1
,
g_token
->
sectionId
);
m_children
.
append
(
s
);
retval
=
s
->
parse
();
if
(
sec
)
{
DocSection
*
s
=
new
DocSection
(
this
,
1
,
g_token
->
sectionId
);
m_children
.
append
(
s
);
retval
=
s
->
parse
();
}
else
{
warn_doc_error
(
g_fileName
,
doctokenizerYYlineno
,
"Warning: Invalid anchor id `%s'"
,
g_token
->
sectionId
.
data
());
retval
=
0
;
}
}
if
(
retval
==
RetVal_Internal
)
...
...
src/doctokenizer.l
View file @
e0e5c855
...
...
@@ -769,7 +769,8 @@ LABELID [a-z_A-Z][a-z_A-Z0-9\-]*
processSection();
BEGIN(St_Sections);
}
<St_SecLabel2>{LABELID}{BLANK}+ {
<St_SecLabel2>{LABELID}{BLANK}+ |
<St_SecLabel2>{LABELID} {
g_secLabel = yytext;
g_secLabel = g_secLabel.stripWhiteSpace();
BEGIN(St_SecTitle);
...
...
@@ -780,6 +781,9 @@ LABELID [a-z_A-Z][a-z_A-Z0-9\-]*
processSection();
BEGIN(St_Sections);
}
<St_SecTitle,St_SecLabel1,St_SecLabel2>. {
warn(g_fileName,yylineno,"Error: Unexpected character `%s' while looking for section label or title",yytext);
}
/* Generic rules that work for all states */
<*>\n {
...
...
src/doxygen.cpp
View file @
e0e5c855
...
...
@@ -1226,6 +1226,37 @@ static void findUsingDeclImports(Entry *root)
//----------------------------------------------------------------------
static
void
findIncludedUsingDirectives
()
{
// first mark all files as not visited
FileNameListIterator
fnli
(
Doxygen
::
inputNameList
);
FileName
*
fn
;
for
(
fnli
.
toFirst
();(
fn
=
fnli
.
current
());
++
fnli
)
{
FileNameIterator
fni
(
*
fn
);
FileDef
*
fd
;
for
(;(
fd
=
fni
.
current
());
++
fni
)
{
fd
->
visited
=
FALSE
;
}
fn
=
Doxygen
::
inputNameList
.
next
();
}
// then recursively add using directives found in #include files
// to files that have not been visited.
for
(
fnli
.
toFirst
();(
fn
=
fnli
.
current
());
++
fnli
)
{
FileNameIterator
fni
(
*
fn
);
FileDef
*
fd
;
for
(;(
fd
=
fni
.
current
());
++
fni
)
{
if
(
!
fd
->
visited
)
fd
->
addIncludedUsingDirectives
();
}
fn
=
Doxygen
::
inputNameList
.
next
();
}
}
//----------------------------------------------------------------------
static
MemberDef
*
addVariableToClass
(
Entry
*
root
,
ClassDef
*
cd
,
...
...
@@ -7796,6 +7827,9 @@ void parseInput()
msg
(
"Building file list...
\n
"
);
buildFileList
(
root
);
msg
(
"Searching for included using directives...
\n
"
);
findIncludedUsingDirectives
();
msg
(
"Building class list...
\n
"
);
buildClassList
(
root
);
buildClassDocList
(
root
);
...
...
src/doxytag.l
View file @
e0e5c855
...
...
@@ -20,7 +20,6 @@
* includes
*/
#include <stdio.h>
#include <iostream.h>
#include <assert.h>
#include <ctype.h>
...
...
@@ -165,7 +164,7 @@ static void addReference()
// docRefName.data(),(docBaseLink+"#"+docAnchor).data());
if (genIndex && !docRefName.isEmpty() && !docBaseLink.isEmpty())
{
if (
!
docAnchor.isEmpty())
if (docAnchor.isEmpty())
searchIndex.addReference(docRefName,docBaseLink);
else
searchIndex.addReference(docRefName,docBaseLink+"#"+docAnchor);
...
...
src/filedef.cpp
View file @
e0e5c855
...
...
@@ -615,6 +615,7 @@ MemberDef *FileDef::getSourceMember(int lineNr)
return
result
;
}
void
FileDef
::
addUsingDirective
(
NamespaceDef
*
nd
)
{
if
(
usingDirList
==
0
)
...
...
@@ -648,6 +649,49 @@ void FileDef::addIncludeDependency(FileDef *fd,const char *incName,bool local)
}
}
void
FileDef
::
addIncludedUsingDirectives
()
{
if
(
!
visited
)
{
visited
=
TRUE
;
NamespaceList
nl
;
if
(
includeList
)
// file contains #includes
{
QListIterator
<
IncludeInfo
>
iii
(
*
includeList
);
IncludeInfo
*
ii
;
for
(;(
ii
=
iii
.
current
());
++
iii
)
// foreach #include...
{
if
(
ii
->
fileDef
)
// ...that is a known file
{
// recurse into this file
ii
->
fileDef
->
addIncludedUsingDirectives
();
}
}
// iterate through list from last to first
for
(
iii
.
toLast
();(
ii
=
iii
.
current
());
--
iii
)
{
if
(
ii
->
fileDef
)
{
NamespaceList
*
unl
=
ii
->
fileDef
->
usingDirList
;
if
(
unl
)
{
NamespaceListIterator
nli
(
*
unl
);
NamespaceDef
*
nd
;
for
(
nli
.
toLast
();(
nd
=
nli
.
current
());
--
nli
)
{
// append each using directive found in a #include file
if
(
usingDirList
==
0
)
usingDirList
=
new
NamespaceList
;
usingDirList
->
prepend
(
nd
);
}
}
}
}
}
// add elements of nl to usingDirList
}
}
void
FileDef
::
addIncludedByDependency
(
FileDef
*
fd
,
const
char
*
incName
,
bool
local
)
{
//printf("FileDef::addIncludedByDependency(%p,%s,%d)\n",fd,incName,local);
...
...
src/filedef.h
View file @
e0e5c855
...
...
@@ -146,6 +146,7 @@ class FileDef : public Definition
void
addMembersToMemberGroup
();
void
distributeMemberGroupDocumentation
();
void
findSectionsInDocumentation
();
void
addIncludedUsingDirectives
();
void
addListReferences
();
...
...
@@ -175,6 +176,8 @@ class FileDef : public Definition
NamespaceSDict
*
namespaceSDict
;
ClassSDict
*
classSDict
;
bool
visited
;
private
:
...
...
src/index.cpp
View file @
e0e5c855
...
...
@@ -1388,7 +1388,7 @@ void writeAlphabeticalClassList(OutputList &ol)
"<tr>"
"<td><div class=
\"
ah
\"
> "
);
ol
.
writeString
(
s
);
ol
.
writeString
(
" "
ol
.
writeString
(
"
</div>
"
"</td>"
"</tr>"
"</table>
\n
"
);
...
...
src/memberdef.cpp
View file @
e0e5c855
...
...
@@ -654,7 +654,7 @@ void MemberDef::writeDeclaration(OutputList &ol,
//printf("%s MemberDef::writeDeclaration() inGroup=%d\n",name().data(),inGroup);
// hide members whose brief section should not be visible
if
(
!
isBriefSectionVisible
())
return
;
//
if (!isBriefSectionVisible()) return;
// write tag file information of this member
if
(
!
Config_getString
(
"GENERATE_TAGFILE"
).
isEmpty
())
...
...
src/memberlist.cpp
View file @
e0e5c855
...
...
@@ -193,130 +193,16 @@ void MemberList::writePlainDeclarations(OutputList &ol,
case
MemberDef
:
:
Property
:
// fall through
case
MemberDef
:
:
Event
:
{
if
(
first
)
ol
.
startMemberList
(),
first
=
FALSE
;
md
->
writeDeclaration
(
ol
,
cd
,
nd
,
fd
,
gd
,
m_inGroup
);
if
(
md
->
isBriefSectionVisible
())
{
if
(
first
)
ol
.
startMemberList
(),
first
=
FALSE
;
md
->
writeDeclaration
(
ol
,
cd
,
nd
,
fd
,
gd
,
m_inGroup
);
}
break
;
}
case
MemberDef
:
:
Enumeration
:
{
if
(
first
)
ol
.
startMemberList
(),
first
=
FALSE
;
#if 0
OutputList typeDecl(&ol);
QCString name(md->name());
int i=name.findRev("::");
if (i!=-1) name=name.right(name.length()-i-2); // strip scope (TODO: is this needed?)
if (name[0]!='@') // not an anonymous enum
{
if (md->isLinkableInProject() || md->hasDocumentedEnumValues())
{
if (!Config_getString("GENERATE_TAGFILE").isEmpty())
{
Doxygen::tagFile << " <member kind=\"enumeration\">" << endl;
Doxygen::tagFile << " <name>" << convertToXML(md->name()) << "</name>" << endl;
Doxygen::tagFile << " <anchor>" << convertToXML(md->anchor()) << "</anchor>" << endl;
Doxygen::tagFile << " <arglist>" << convertToXML(md->argsString()) << "</arglist>" << endl;
Doxygen::tagFile << " </member>" << endl;
}
md->writeLink(typeDecl,cd,nd,fd,gd);
}
else
{
typeDecl.startBold();
typeDecl.docify(name);
typeDecl.endBold();
}
typeDecl.writeChar(' ');
}
int enumMemCount=0;
QList<MemberDef> *fmdl=md->enumFieldList();
uint numVisibleEnumValues=0;
if (fmdl)
{
MemberDef *fmd=fmdl->first();
while (fmd)
{
if (fmd->isBriefSectionVisible()) numVisibleEnumValues++;
fmd=fmdl->next();
}
}
if (numVisibleEnumValues==0 && !md->isBriefSectionVisible()) break;
if (numVisibleEnumValues>0)
{
uint enumValuesPerLine = (uint)Config_getInt("ENUM_VALUES_PER_LINE");
typeDecl.docify("{ ");
if (fmdl)
{
MemberDef *fmd=fmdl->first();
bool fmdVisible = fmd->isBriefSectionVisible();
while (fmd)
{
if (fmdVisible)
{
/* in html we start a new line after a number of items */
if (numVisibleEnumValues>enumValuesPerLine
&& (enumMemCount%enumValuesPerLine)==0
)
{
typeDecl.pushGeneratorState();
typeDecl.disableAllBut(OutputGenerator::Html);
typeDecl.lineBreak();
typeDecl.writeString(" ");
typeDecl.popGeneratorState();
}
if (fmd->hasDocumentation()) // enum value has docs
{
if (!Config_getString("GENERATE_TAGFILE").isEmpty())
{
Doxygen::tagFile << " <member kind=\"enumvalue\">" << endl;
Doxygen::tagFile << " <name>" << convertToXML(fmd->name()) << "</name>" << endl;
Doxygen::tagFile << " <anchor>" << convertToXML(fmd->anchor()) << "</anchor>" << endl;
Doxygen::tagFile << " <arglist>" << convertToXML(fmd->argsString()) << "</arglist>" << endl;
Doxygen::tagFile << " </member>" << endl;
}
fmd->writeLink(typeDecl,cd,nd,fd,gd);
}
else // no docs for this enum value
{
typeDecl.startBold();
typeDecl.docify(fmd->name());
typeDecl.endBold();
}
if (fmd->hasOneLineInitializer()) // enum value has initializer
{
typeDecl.writeString(" = ");
typeDecl.parseText(fmd->initializer());
}
}
bool prevVisible = fmdVisible;
fmd=fmdl->next();
if (fmd && (fmdVisible=fmd->isBriefSectionVisible()))
{
typeDecl.writeString(", ");
}
if (prevVisible)
{
typeDecl.disable(OutputGenerator::Man);
typeDecl.writeString("\n"); // to prevent too long lines in LaTeX
typeDecl.enable(OutputGenerator::Man);
enumMemCount++;
}
}
if (numVisibleEnumValues>enumValuesPerLine)
{
typeDecl.pushGeneratorState();
typeDecl.disableAllBut(OutputGenerator::Html);
typeDecl.lineBreak();
typeDecl.popGeneratorState();
}
}
typeDecl.docify(" }");
md->setEnumDecl(typeDecl);
}
#endif
int
enumVars
=
0
;
MemberListIterator
vmli
(
*
this
);
MemberDef
*
vmd
;
...
...
@@ -381,8 +267,11 @@ void MemberList::writePlainDeclarations(OutputList &ol,
}
case
MemberDef
:
:
Friend
:
{
if
(
first
)
ol
.
startMemberList
(),
first
=
FALSE
;
md
->
writeDeclaration
(
ol
,
cd
,
nd
,
fd
,
gd
,
m_inGroup
);
if
(
md
->
isBriefSectionVisible
())
{
if
(
first
)
ol
.
startMemberList
(),
first
=
FALSE
;
md
->
writeDeclaration
(
ol
,
cd
,
nd
,
fd
,
gd
,
m_inGroup
);
}
break
;
}
case
MemberDef
:
:
EnumValue
:
...
...
@@ -400,10 +289,13 @@ void MemberList::writePlainDeclarations(OutputList &ol,
if
(
md
->
fromAnonymousScope
()
&&
!
md
->
anonymousDeclShown
())
{
//printf("anonymous compound members\n");
if
(
first
)
ol
.
startMemberList
(),
first
=
FALSE
;
md
->
setFromAnonymousScope
(
FALSE
);
md
->
writeDeclaration
(
ol
,
cd
,
nd
,
fd
,
gd
,
m_inGroup
);
md
->
setFromAnonymousScope
(
TRUE
);
if
(
md
->
isBriefSectionVisible
())
{
if
(
first
)
ol
.
startMemberList
(),
first
=
FALSE
;
md
->
setFromAnonymousScope
(
FALSE
);
md
->
writeDeclaration
(
ol
,
cd
,
nd
,
fd
,
gd
,
m_inGroup
);
md
->
setFromAnonymousScope
(
TRUE
);
}
}
}
}
...
...
src/scanner.l
View file @
e0e5c855
...
...
@@ -355,7 +355,7 @@ static void addSpecialItem(const char *listName)
//sectionLabel=anchorLabel;
//addSection();
//current->name = tmpName;
//printf("%s: text
%s
doc %s\n",listName,item->text.data(),cmdString.data());
//printf("%s: text
`%s'
doc %s\n",listName,item->text.data(),cmdString.data());
}
current->brief = slString.copy(); // restore orginial brief desc.
}
...
...
@@ -4127,7 +4127,6 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
}
<DocBaseClass>\n { yyLineNr++; BEGIN( ClassDoc ); }
<ClassDocBrief>{BS}({BL}|"\\n\\n") {
current->brief=current->brief.stripWhiteSpace();
//if (!current->doc.isEmpty()) current->doc+=" <p>";
if (lastBriefContext==TodoParam ||
lastBriefContext==TestParam ||
...
...
@@ -4139,6 +4138,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
}
else
{
current->brief=current->brief.stripWhiteSpace();
if (yytext[yyleng-1]=='\n') yyLineNr++;
}
BEGIN( lastBriefContext );
...
...
@@ -4186,7 +4186,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'"))
}
else
{
current->brief += "
";
current->brief += "
\n
";
if (!current->doc.isEmpty())
{
current->doc += "<p>";
...
...
src/xmlgen.cpp
View file @
e0e5c855
...
...
@@ -528,8 +528,8 @@ static void generateXMLForMember(MemberDef *md,QTextStream &ti,QTextStream &t,De
t
<<
" <type>"
;
linkifyText
(
TextGeneratorXMLImpl
(
t
),
scopeName
,
md
->
name
(),
typeStr
);
t
<<
"</type>"
<<
endl
;
t
<<
" <definition>"
<<
md
->
definition
(
)
<<
"</definition>"
<<
endl
;
t
<<
" <argsstring>"
<<
md
->
argsString
(
)
<<
"</argsstring>"
<<
endl
;
t
<<
" <definition>"
<<
convertToXML
(
md
->
definition
()
)
<<
"</definition>"
<<
endl
;
t
<<
" <argsstring>"
<<
convertToXML
(
md
->
argsString
()
)
<<
"</argsstring>"
<<
endl
;
}
t
<<
" <name>"
<<
convertToXML
(
md
->
name
())
<<
"</name>"
<<
endl
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment