Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
libSDL
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PocketInsanity
libSDL
Commits
2a486b27
Commit
2a486b27
authored
Jun 27, 2011
by
Markus Kauppila
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added identation to the output of XML logger.
parent
2e8932b1
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
215 additions
and
107 deletions
+215
-107
logger.c
test/test-automation/logger.c
+1
-20
logger.h
test/test-automation/logger.h
+1
-1
plain_logger.c
test/test-automation/plain_logger.c
+31
-15
plain_logger.h
test/test-automation/plain_logger.h
+1
-1
runner.c
test/test-automation/runner.c
+3
-1
xml.c
test/test-automation/xml.c
+16
-5
xml_logger.c
test/test-automation/xml_logger.c
+161
-63
xml_logger.h
test/test-automation/xml_logger.h
+1
-1
No files found.
test/test-automation/logger.c
View file @
2a486b27
...
...
@@ -57,25 +57,6 @@ SetupPlainLogger()
Log
=
PlainLog
;
}
/*!
* Prints the given message to stderr. Function adds nesting
* to the output.
*
* \return Possible error value (\todo)
*/
int
LogGenericOutput
(
const
char
*
message
,
...)
{
va_list
list
;
va_start
(
list
,
message
);
char
buffer
[
1024
];
SDL_vsnprintf
(
buffer
,
sizeof
(
buffer
),
message
,
list
);
fprintf
(
stderr
,
"%s
\n
"
,
buffer
);
fflush
(
stderr
);
}
#if 0
/*!
* Test app for logging functionality
...
...
@@ -91,7 +72,7 @@ main(int argc, char *argv[])
SetupPlainLogger();
}
RunStarted(
LogGeneric
Output, "some_<data_>here&here", 0);
RunStarted(Output, "some_<data_>here&here", 0);
SuiteStarted("Suite data here", 0);
TestStarted("test1", "suite", "desc", 0);
...
...
test/test-automation/logger.h
View file @
2a486b27
...
...
@@ -54,7 +54,7 @@ typedef void (*AssertSummaryFp)(int numAsserts, int numAssertsFailed, int numAss
typedef
void
(
*
LogFp
)(
const
char
*
logMessage
,
time_t
eventTime
);
int
LogGeneric
Output
(
const
char
*
message
,
...);
int
Output
(
const
char
*
message
,
...);
extern
RunStartedFp
RunStarted
;
extern
RunEndedFp
RunEnded
;
...
...
test/test-automation/plain_logger.c
View file @
2a486b27
...
...
@@ -4,53 +4,69 @@
#include <stdio.h>
#include <SDL/SDL.h>
#include "plain_logger.h"
LogOutputFp
logger
=
0
;
/*!
* Pritns out the output of the logger
* \return Possible error value (\todo)
*/
int
Output
(
const
char
*
message
,
...)
{
va_list
list
;
va_start
(
list
,
message
);
char
buffer
[
1024
];
SDL_vsnprintf
(
buffer
,
sizeof
(
buffer
),
message
,
list
);
fprintf
(
stderr
,
"%s
\n
"
,
buffer
);
fflush
(
stderr
);
}
void
PlainRunStarted
(
LogOutputFp
outputFn
,
const
char
*
runnerParameters
,
time_t
eventTime
)
PlainRunStarted
(
const
char
*
runnerParameters
,
time_t
eventTime
)
{
logger
=
outputFn
;
logger
(
"Test run started"
);
logger
(
"Given command line options: %s"
,
"add options"
);
Output
(
"Test run started"
);
Output
(
"Given command line options: %s"
,
"add options"
);
}
void
PlainRunEnded
(
int
testCount
,
int
suiteCount
,
int
testPassCount
,
int
testFailCount
,
time_t
endTime
,
time_t
totalRuntime
)
{
logger
(
"Ran %d tests in %0.5f seconds."
,
testCount
,
totalRuntime
);
Output
(
"Ran %d tests in %0.5f seconds."
,
testCount
,
totalRuntime
);
logger
(
"%d tests passed"
,
testPassCount
);
logger
(
"%d tests failed"
,
testFailCount
);
Output
(
"%d tests passed"
,
testPassCount
);
Output
(
"%d tests failed"
,
testFailCount
);
}
void
PlainSuiteStarted
(
const
char
*
suiteName
,
time_t
eventTime
)
{
logger
(
"Executing tests in %s"
,
suiteName
);
Output
(
"Executing tests in %s"
,
suiteName
);
}
void
PlainSuiteEnded
(
int
testsPassed
,
int
testsFailed
,
int
testsSkipped
,
double
endTime
,
time_t
totalRuntime
)
{
logger
(
"Suite executed. %d passed, %d failed and %d skipped"
,
testsPassed
,
testsFailed
,
testsSkipped
);
Output
(
"Suite executed. %d passed, %d failed and %d skipped"
,
testsPassed
,
testsFailed
,
testsSkipped
);
}
void
PlainTestStarted
(
const
char
*
testName
,
const
char
*
suiteName
,
const
char
*
testDescription
,
time_t
startTime
)
{
logger
(
"test %s (in %s) started"
,
testName
,
suiteName
);
Output
(
"test %s (in %s) started"
,
testName
,
suiteName
);
}
void
PlainTestEnded
(
const
char
*
testName
,
const
char
*
suiteName
,
int
testResult
,
time_t
endTime
,
time_t
totalRuntime
)
{
logger
(
"%s: ok"
,
testName
);
Output
(
"%s: ok"
,
testName
);
}
void
...
...
@@ -58,19 +74,19 @@ PlainAssert(const char *assertName, int assertResult, const char *assertMessage,
time_t
eventTime
)
{
const
char
*
result
=
(
assertResult
)
?
"passed"
:
"failed"
;
logger
(
"%s %d: %s"
,
assertName
,
assertResult
,
assertMessage
);
Output
(
"%s %d: %s"
,
assertName
,
assertResult
,
assertMessage
);
}
void
PlainAssertSummary
(
int
numAsserts
,
int
numAssertsFailed
,
int
numAssertsPass
)
{
logger
(
"Asserts:%d"
,
numAsserts
);
Output
(
"Asserts:%d"
,
numAsserts
);
}
void
PlainLog
(
const
char
*
logMessage
,
time_t
eventTime
)
{
logger
(
"%s %d"
,
logMessage
,
eventTime
);
Output
(
"%s %d"
,
logMessage
,
eventTime
);
}
#endif
test/test-automation/plain_logger.h
View file @
2a486b27
...
...
@@ -3,7 +3,7 @@
#include "logger.h"
void
PlainRunStarted
(
LogOutputFp
outputFn
,
const
char
*
runnerParameters
,
time_t
eventTime
);
void
PlainRunStarted
(
const
char
*
runnerParameters
,
time_t
eventTime
);
void
PlainRunEnded
(
int
testCount
,
int
suiteCount
,
int
testPassCount
,
int
testFailCount
,
time_t
endTime
,
time_t
totalRuntime
);
...
...
test/test-automation/runner.c
View file @
2a486b27
...
...
@@ -670,7 +670,7 @@ main(int argc, char *argv[])
return
0
;
}
RunStarted
(
LogGeneric
Output
,
NULL
,
0
);
RunStarted
(
Output
,
NULL
,
0
);
char
*
currentSuiteName
=
NULL
;
...
...
@@ -708,6 +708,8 @@ main(int argc, char *argv[])
}
}
SuiteEnded
(
0
,
0
,
0
,
0
.
0
f
,
0
);
UnloadTestCases
(
testCases
);
UnloadTestSuites
(
suites
);
...
...
test/test-automation/xml.c
View file @
2a486b27
...
...
@@ -153,8 +153,14 @@ const char *EscapeString(const char *string) {
while
(
token
)
{
char
*
nextToken
=
strtok
(
NULL
,
character
);
//! \todo use strncat and count the bytes left in the buffer
strcat
(
buffer
,
token
);
int
bytesLeft
=
bufferSize
-
SDL_strlen
(
buffer
);
if
(
bytesLeft
)
{
strncat
(
buffer
,
token
,
bytesLeft
);
}
else
{
// \! todo there's probably better way to report an error?
fprintf
(
stderr
,
"xml.c | EscapingString: Buffer is full"
);
}
if
(
nextToken
)
strcat
(
buffer
,
entity
);
...
...
@@ -211,7 +217,7 @@ static char buffer[bufferSize];
char
*
XMLOpenDocument
(
const
char
*
rootTag
)
{
const
char
*
doctype
=
"<?xml version=
\"
1.0
\"
encoding=
\"
utf-8
\"
?>
\n
"
;
const
char
*
doctype
=
"<?xml version=
\"
1.0
\"
encoding=
\"
ISO-8859-1
\"
?>
\n
"
;
memset
(
buffer
,
0
,
bufferSize
);
snprintf
(
buffer
,
bufferSize
,
"<%s>"
,
rootTag
);
...
...
@@ -303,8 +309,13 @@ XMLCloseElement(const char *tag)
SDL_free
(
lowOpenTag
);
SDL_free
(
lowTag
);
// \todo use strNcat
strcat
(
ret
,
buffer
);
int
bytesLeft
=
bufferSize
-
SDL_strlen
(
ret
);
if
(
bytesLeft
)
{
strncat
(
ret
,
buffer
,
bytesLeft
);
}
else
{
// \! todo there's probably better way to report an error?
fprintf
(
stderr
,
"xml.c | XMLCloseElement: Buffer is full"
);
}
RemoveOpenTag
(
openTag
->
tag
);
...
...
test/test-automation/xml_logger.c
View file @
2a486b27
...
...
@@ -28,27 +28,70 @@
#include "xml_logger.h"
LogOutputFp
logger
;
/*!
* Helper functions. Turns the given integer in to a string
*
* \param integer The converted integer
* \returns Given integer as string
*/
char
*
IntToString
(
const
int
integer
)
{
static
char
buffer
[
sizeof
(
int
)
*
8
+
1
];
// malloc might work better
memset
(
buffer
,
0
,
sizeof
(
buffer
));
SDL_snprintf
(
buffer
,
sizeof
(
buffer
),
"%d"
,
integer
);
return
buffer
;
}
static
int
indentLevel
;
//! Constants for XMLOuputters EOL parameter
#define YES 1
#define NO 0
/*! Controls printing the identation in relation to line breaks */
static
int
prevEOL
=
YES
;
/*
* Prints out the given xml element etc.
*
* \param identLevel the indent level of the message
* \param EOL will it print end of line character or not
* \param the XML element itself
*
*/
void
XMLOutputter
(
const
int
il
,
int
EOL
,
const
char
*
message
)
{
int
ident
=
0
;
for
(
;
ident
<
il
&&
prevEOL
;
++
ident
)
{
printf
(
" "
);
}
prevEOL
=
EOL
;
if
(
EOL
)
{
printf
(
"%s
\n
"
,
message
);
}
else
{
printf
(
"%s"
,
message
);
}
}
void
XMLRunStarted
(
LogOutputFp
outputFn
,
const
char
*
runnerParameters
,
time_t
eventTime
)
XMLRunStarted
(
const
char
*
runnerParameters
,
time_t
eventTime
)
{
logger
=
outputFn
;
char
*
output
=
XMLOpenDocument
(
"testlog"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
YES
,
output
);
SDL_free
(
output
);
output
=
XMLOpenElement
(
"parameters"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLAddContent
(
"Add: runner parameter"
);
logger
(
output
);
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"parameters"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
}
...
...
@@ -57,7 +100,7 @@ XMLRunEnded(int testCount, int suiteCount, int testPassCount, int testFailCount,
time_t
endTime
,
time_t
totalRuntime
)
{
char
*
output
=
XMLCloseDocument
(
"testlog"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
}
...
...
@@ -65,16 +108,19 @@ void
XMLSuiteStarted
(
const
char
*
suiteName
,
time_t
eventTime
)
{
char
*
output
=
XMLOpenElement
(
"suite"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
YES
,
output
);
SDL_free
(
output
);
output
=
XMLOpenElement
(
"eventTime"
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
output
=
XML
OpenElement
(
"eventtime"
);
logger
(
output
);
output
=
XML
AddContent
(
IntToString
(
eventTime
)
);
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
//XMLAddContent(evenTime);
output
=
XMLCloseElement
(
"eventtime"
);
logger
(
output
);
output
=
XMLCloseElement
(
"eventTime"
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
}
...
...
@@ -83,51 +129,56 @@ XMLSuiteEnded(int testsPassed, int testsFailed, int testsSkipped,
double
endTime
,
time_t
totalRuntime
)
{
char
*
output
=
XMLCloseElement
(
"suite"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
//! \todo endTime and totalRuntiem
}
void
XMLTestStarted
(
const
char
*
testName
,
const
char
*
suiteName
,
const
char
*
testDescription
,
time_t
startTime
)
{
char
*
output
=
XMLOpenElement
(
"test"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
YES
,
output
);
SDL_free
(
output
);
//Attribute attribute = {"test", "value"};
//XMLOpenElementWithAttribute("name", &attribute);
output
=
XMLOpenElement
(
"name"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLAddContent
(
testName
);
logger
(
output
);
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"name"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
output
=
XMLOpenElement
(
"description"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLAddContent
(
testDescription
);
logger
(
output
);
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"description"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
output
=
XMLOpenElement
(
"startTime"
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLOpenElement
(
"starttime"
);
logger
(
output
);
XMLAddContent
(
IntToString
(
startTime
)
);
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
//XMLAddContent(startTime);
output
=
XMLCloseElement
(
"starttime"
);
logger
(
output
);
output
=
XMLCloseElement
(
"startTime"
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
}
...
...
@@ -136,7 +187,7 @@ XMLTestEnded(const char *testName, const char *suiteName,
int
testResult
,
time_t
endTime
,
time_t
totalRuntime
)
{
char
*
output
=
XMLOpenElement
(
"result"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
if
(
testResult
)
{
...
...
@@ -145,20 +196,22 @@ XMLTestEnded(const char *testName, const char *suiteName,
}
else
{
output
=
XMLAddContent
(
"failed"
);
}
logger
(
output
);
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
}
else
{
output
=
XMLAddContent
(
"passed"
);
logger
(
output
);
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
}
output
=
XMLCloseElement
(
"result"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
//! \todo add endTime and TotalRuntime
output
=
XMLCloseElement
(
"test"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
}
...
...
@@ -167,23 +220,50 @@ XMLAssert(const char *assertName, int assertResult, const char *assertMessage,
time_t
eventTime
)
{
char
*
output
=
XMLOpenElement
(
"assert"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
YES
,
output
);
SDL_free
(
output
);
// log assert result
output
=
XMLOpenElement
(
"result"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLAddContent
((
assertResult
)
?
"pass"
:
"failure"
);
logger
(
output
);
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"result"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
// log assert message
output
=
XMLOpenElement
(
"message"
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLAddContent
(
assertMessage
);
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"message"
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
// log event time
output
=
XMLOpenElement
(
"eventTime"
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLAddContent
(
IntToString
(
eventTime
));
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"eventTime"
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"assert"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
}
...
...
@@ -191,50 +271,47 @@ void
XMLAssertSummary
(
int
numAsserts
,
int
numAssertsFailed
,
int
numAssertsPass
)
{
char
*
output
=
XMLOpenElement
(
"assertSummary"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
YES
,
output
);
SDL_free
(
output
);
output
=
XMLOpenElement
(
"assertCount"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
//XMLAddContent() \todo add string conversion
output
=
XMLAddContent
(
IntToString
(
numAsserts
));
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"assertCount"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
output
=
XMLOpenElement
(
"assertsPassed"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
const
int
bufferSize
=
sizeof
(
int
)
*
8
+
1
;
//char buffer[bufferSize];
char
*
buffer
=
SDL_malloc
(
bufferSize
);
memset
(
buffer
,
'a'
,
bufferSize
);
//SDL_vsnprintf(buffer, bufferSize, "%d", numAssertsPass);
snprintf
(
buffer
,
sizeof
(
buffer
),
"%d"
,
numAssertsPass
);
buffer
[
3
]
=
'a'
;
//printf("DEBUG |%s == %d of size %d", buffer, numAssertsPass, bufferSize);
XMLAddContent
(
buffer
);
output
=
XMLAddContent
(
IntToString
(
numAssertsPass
));
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"assertsPassed"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
output
=
XMLOpenElement
(
"assertsFailed"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
//XMLAddContent() \todo add string conversion
output
=
XMLAddContent
(
IntToString
(
numAsserts
));
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"assertsFailed"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"assertSummary"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
}
...
...
@@ -242,15 +319,36 @@ void
XMLLog
(
const
char
*
logMessage
,
time_t
eventTime
)
{
char
*
output
=
XMLOpenElement
(
"log"
);
logger
(
output
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
// log message
output
=
XMLOpenElement
(
"message"
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLAddContent
(
logMessage
);
logger
(
output
);
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"message"
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
// log eventTime
output
=
XMLOpenElement
(
"eventTime"
);
XMLOutputter
(
indentLevel
++
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLAddContent
(
IntToString
(
eventTime
));
XMLOutputter
(
indentLevel
,
NO
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"eventTime"
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
output
=
XMLCloseElement
(
"log"
);
logger
(
output
);
XMLOutputter
(
--
indentLevel
,
YES
,
output
);
SDL_free
(
output
);
}
test/test-automation/xml_logger.h
View file @
2a486b27
...
...
@@ -3,7 +3,7 @@
#include "logger.h"
void
XMLRunStarted
(
LogOutputFp
outputFn
,
const
char
*
runnerParameters
,
time_t
eventTime
);
void
XMLRunStarted
(
const
char
*
runnerParameters
,
time_t
eventTime
);
void
XMLRunEnded
(
int
testCount
,
int
suiteCount
,
int
testPassCount
,
int
testFailCount
,
time_t
endTime
,
time_t
totalRuntime
);
...
...
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