Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
minerva
core
Commits
7ce63914
Commit
7ce63914
authored
Jun 24, 2021
by
Piotr Gawron
Browse files
methods moved to controller
parent
bf176b6a
Changes
3
Show whitespace changes
Inline
Side-by-side
rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationController.java
View file @
7ce63914
...
...
@@ -15,6 +15,7 @@ import org.springframework.security.core.Authentication;
import
org.springframework.security.core.authority.SimpleGrantedAuthority
;
import
org.springframework.web.bind.annotation.*
;
import
lcsb.mapviewer.annotation.services.ModelAnnotator
;
import
lcsb.mapviewer.annotation.services.dapi.DapiConnectionException
;
import
lcsb.mapviewer.annotation.services.dapi.dto.UserDto
;
import
lcsb.mapviewer.api.BaseController
;
...
...
@@ -22,8 +23,19 @@ import lcsb.mapviewer.common.Pair;
import
lcsb.mapviewer.converter.Converter
;
import
lcsb.mapviewer.converter.graphics.AbstractImageGenerator
;
import
lcsb.mapviewer.converter.graphics.ImageGenerators
;
import
lcsb.mapviewer.model.graphics.MapCanvasType
;
import
lcsb.mapviewer.model.map.MiriamType
;
import
lcsb.mapviewer.model.map.kinetics.SbmlUnitType
;
import
lcsb.mapviewer.model.map.model.SubmodelType
;
import
lcsb.mapviewer.model.map.reaction.Reaction
;
import
lcsb.mapviewer.model.map.species.Element
;
import
lcsb.mapviewer.model.map.species.field.ModificationState
;
import
lcsb.mapviewer.model.overlay.DataOverlayType
;
import
lcsb.mapviewer.model.security.PrivilegeType
;
import
lcsb.mapviewer.model.user.ConfigurationOption
;
import
lcsb.mapviewer.model.user.annotator.BioEntityField
;
import
lcsb.mapviewer.modelutils.map.ClassTreeNode
;
import
lcsb.mapviewer.modelutils.map.ElementUtils
;
import
lcsb.mapviewer.services.QueryException
;
import
lcsb.mapviewer.services.interfaces.IConfigurationService
;
...
...
@@ -36,18 +48,20 @@ public class ConfigurationController extends BaseController {
private
ConfigurationRestImpl
configurationRestImpl
;
private
IConfigurationService
configurationService
;
private
ServletContext
context
;
private
ModelAnnotator
modelAnnotator
;
private
List
<
Converter
>
modelConverters
;
@Autowired
public
ConfigurationController
(
ConfigurationRestImpl
configurationController
,
IConfigurationService
configurationService
,
ServletContext
context
,
List
<
Converter
>
modelConverters
)
{
List
<
Converter
>
modelConverters
,
ModelAnnotator
modelAnnotator
)
{
this
.
configurationRestImpl
=
configurationController
;
this
.
configurationService
=
configurationService
;
this
.
modelConverters
=
modelConverters
;
this
.
context
=
context
;
this
.
modelAnnotator
=
modelAnnotator
;
}
@GetMapping
(
value
=
"/"
)
...
...
@@ -56,20 +70,20 @@ public class ConfigurationController extends BaseController {
result
.
put
(
"options"
,
getOptions
(
authentication
));
result
.
put
(
"imageFormats"
,
getImageFormats
());
result
.
put
(
"modelFormats"
,
getModelFormats
());
result
.
put
(
"overlayTypes"
,
configurationRestImpl
.
getOverlayTypes
());
result
.
put
(
"elementTypes"
,
configurationRestImpl
.
getElementTypes
());
result
.
put
(
"reactionTypes"
,
configurationRestImpl
.
getReactionTypes
());
result
.
put
(
"miriamTypes"
,
configurationRestImpl
.
getMiriamTypes
());
result
.
put
(
"mapTypes"
,
configurationRestImpl
.
getMapTypes
());
result
.
put
(
"mapCanvasTypes"
,
configurationRestImpl
.
getMapCanvasTypes
());
result
.
put
(
"unitTypes"
,
configurationRestImpl
.
getUnitTypes
());
result
.
put
(
"modificationStateTypes"
,
configurationRestImpl
.
getModificationStateTypes
());
result
.
put
(
"privilegeTypes"
,
configurationRestImpl
.
getPrivilegeTypes
());
result
.
put
(
"overlayTypes"
,
getOverlayTypes
());
result
.
put
(
"elementTypes"
,
getElementTypes
());
result
.
put
(
"reactionTypes"
,
getReactionTypes
());
result
.
put
(
"miriamTypes"
,
getMiriamTypes
());
result
.
put
(
"mapTypes"
,
getMapTypes
());
result
.
put
(
"mapCanvasTypes"
,
getMapCanvasTypes
());
result
.
put
(
"unitTypes"
,
getUnitTypes
());
result
.
put
(
"modificationStateTypes"
,
getModificationStateTypes
());
result
.
put
(
"privilegeTypes"
,
getPrivilegeTypes
());
result
.
put
(
"version"
,
configurationService
.
getSystemSvnVersion
(
context
.
getRealPath
(
"/"
)
+
"META-INF/"
));
result
.
put
(
"buildDate"
,
configurationService
.
getSystemBuild
(
context
.
getRealPath
(
"/"
)
+
"META-INF/"
));
result
.
put
(
"gitHash"
,
configurationService
.
getSystemGitVersion
(
context
.
getRealPath
(
"/"
)
+
"META-INF/"
));
result
.
put
(
"annotators"
,
configurationRestImpl
.
getAnnotators
());
result
.
put
(
"bioEntityFields"
,
configurationRestImpl
.
getBioEntityFields
());
result
.
put
(
"bioEntityFields"
,
getBioEntityFields
());
return
result
;
}
...
...
@@ -148,4 +162,143 @@ public class ConfigurationController extends BaseController {
return
result
;
}
public
List
<
Map
<
String
,
Object
>>
getOverlayTypes
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
DataOverlayType
type
:
DataOverlayType
.
values
())
{
Map
<
String
,
Object
>
map
=
new
TreeMap
<>();
map
.
put
(
"name"
,
type
.
name
());
result
.
add
(
map
);
}
return
result
;
}
public
Set
<
Map
<
String
,
String
>>
getElementTypes
()
{
return
getClassStringTypesList
(
Element
.
class
);
}
private
Set
<
Map
<
String
,
String
>>
getClassStringTypesList
(
Class
<?>
elementClass
)
{
Set
<
Map
<
String
,
String
>>
result
=
new
LinkedHashSet
<>();
ElementUtils
elementUtils
=
new
ElementUtils
();
ClassTreeNode
top
=
elementUtils
.
getAnnotatedElementClassTree
();
Queue
<
ClassTreeNode
>
queue
=
new
LinkedList
<>();
queue
.
add
(
top
);
while
(!
queue
.
isEmpty
())
{
ClassTreeNode
clazz
=
queue
.
poll
();
queue
.
addAll
(
clazz
.
getChildren
());
if
(
elementClass
.
isAssignableFrom
(
clazz
.
getClazz
()))
{
Map
<
String
,
String
>
row
=
new
TreeMap
<>();
row
.
put
(
"className"
,
clazz
.
getClazz
().
getName
());
row
.
put
(
"name"
,
clazz
.
getCommonName
());
if
(
clazz
.
getParent
()
==
null
)
{
row
.
put
(
"parentClass"
,
null
);
}
else
{
row
.
put
(
"parentClass"
,
clazz
.
getParent
().
getClazz
().
getName
());
}
result
.
add
(
row
);
}
}
return
result
;
}
public
Set
<
Map
<
String
,
String
>>
getReactionTypes
()
{
return
getClassStringTypesList
(
Reaction
.
class
);
}
public
Map
<
String
,
Object
>
getMiriamTypes
()
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
for
(
MiriamType
type
:
MiriamType
.
values
())
{
result
.
put
(
type
.
name
(),
createMiriamTypeResponse
(
type
));
}
return
result
;
}
private
Map
<
String
,
Object
>
createMiriamTypeResponse
(
MiriamType
type
)
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
result
.
put
(
"commonName"
,
type
.
getCommonName
());
result
.
put
(
"homepage"
,
type
.
getDbHomepage
());
result
.
put
(
"registryIdentifier"
,
type
.
getRegistryIdentifier
());
result
.
put
(
"uris"
,
type
.
getUris
());
return
result
;
}
public
Object
getModificationStateTypes
()
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
for
(
ModificationState
type
:
ModificationState
.
values
())
{
result
.
put
(
type
.
name
(),
createModificationStateResponse
(
type
));
}
return
result
;
}
private
Map
<
String
,
Object
>
createModificationStateResponse
(
ModificationState
type
)
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
result
.
put
(
"commonName"
,
type
.
getFullName
());
result
.
put
(
"abbreviation"
,
type
.
getAbbreviation
());
return
result
;
}
public
List
<
Map
<
String
,
Object
>>
getMapTypes
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
SubmodelType
type
:
SubmodelType
.
values
())
{
Map
<
String
,
Object
>
row
=
new
TreeMap
<>();
row
.
put
(
"id"
,
type
.
name
());
row
.
put
(
"name"
,
type
.
getCommonName
());
result
.
add
(
row
);
}
return
result
;
}
public
List
<
Map
<
String
,
Object
>>
getMapCanvasTypes
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
MapCanvasType
type
:
MapCanvasType
.
values
())
{
Map
<
String
,
Object
>
row
=
new
TreeMap
<>();
row
.
put
(
"id"
,
type
.
name
());
row
.
put
(
"name"
,
type
.
getCommonName
());
result
.
add
(
row
);
}
return
result
;
}
public
List
<
Map
<
String
,
Object
>>
getUnitTypes
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
SbmlUnitType
type
:
SbmlUnitType
.
values
())
{
Map
<
String
,
Object
>
row
=
new
TreeMap
<>();
row
.
put
(
"id"
,
type
.
name
());
row
.
put
(
"name"
,
type
.
getCommonName
());
result
.
add
(
row
);
}
return
result
;
}
public
List
<
Map
<
String
,
Object
>>
getBioEntityFields
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
BioEntityField
field
:
BioEntityField
.
values
())
{
Map
<
String
,
Object
>
entry
=
new
TreeMap
<>();
entry
.
put
(
"name"
,
field
.
name
());
entry
.
put
(
"commonName"
,
field
.
getCommonName
());
result
.
add
(
entry
);
}
return
result
;
}
public
Map
<
String
,
Object
>
getPrivilegeTypes
()
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
for
(
PrivilegeType
type
:
PrivilegeType
.
values
())
{
result
.
put
(
type
.
name
(),
createPrivilegeTypeResponse
(
type
));
}
return
result
;
}
private
Map
<
String
,
Object
>
createPrivilegeTypeResponse
(
PrivilegeType
type
)
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
result
.
put
(
"commonName"
,
type
.
getDescription
());
if
(
type
.
getPrivilegeObjectType
()
!=
null
)
{
result
.
put
(
"objectType"
,
type
.
getPrivilegeObjectType
().
getSimpleName
());
}
else
{
result
.
put
(
"objectType"
,
null
);
}
result
.
put
(
"valueType"
,
"boolean"
);
return
result
;
}
}
\ No newline at end of file
rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationRestImpl.java
View file @
7ce63914
...
...
@@ -74,141 +74,6 @@ public class ConfigurationRestImpl extends BaseRestImpl {
this
.
configurationService
=
configurationService
;
}
public
List
<
Map
<
String
,
Object
>>
getOverlayTypes
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
DataOverlayType
type
:
DataOverlayType
.
values
())
{
Map
<
String
,
Object
>
map
=
new
TreeMap
<>();
map
.
put
(
"name"
,
type
.
name
());
result
.
add
(
map
);
}
return
result
;
}
public
Set
<
Map
<
String
,
String
>>
getElementTypes
()
{
return
getClassStringTypesList
(
Element
.
class
);
}
private
Set
<
Map
<
String
,
String
>>
getClassStringTypesList
(
Class
<?>
elementClass
)
{
Set
<
Map
<
String
,
String
>>
result
=
new
LinkedHashSet
<>();
ElementUtils
elementUtils
=
new
ElementUtils
();
ClassTreeNode
top
=
elementUtils
.
getAnnotatedElementClassTree
();
Queue
<
ClassTreeNode
>
queue
=
new
LinkedList
<>();
queue
.
add
(
top
);
while
(!
queue
.
isEmpty
())
{
ClassTreeNode
clazz
=
queue
.
poll
();
queue
.
addAll
(
clazz
.
getChildren
());
if
(
elementClass
.
isAssignableFrom
(
clazz
.
getClazz
()))
{
Map
<
String
,
String
>
row
=
new
TreeMap
<>();
row
.
put
(
"className"
,
clazz
.
getClazz
().
getName
());
row
.
put
(
"name"
,
clazz
.
getCommonName
());
if
(
clazz
.
getParent
()
==
null
)
{
row
.
put
(
"parentClass"
,
null
);
}
else
{
row
.
put
(
"parentClass"
,
clazz
.
getParent
().
getClazz
().
getName
());
}
result
.
add
(
row
);
}
}
return
result
;
}
public
Set
<
Map
<
String
,
String
>>
getReactionTypes
()
{
return
getClassStringTypesList
(
Reaction
.
class
);
}
public
Map
<
String
,
Object
>
getMiriamTypes
()
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
for
(
MiriamType
type
:
MiriamType
.
values
())
{
result
.
put
(
type
.
name
(),
createMiriamTypeResponse
(
type
));
}
return
result
;
}
private
Map
<
String
,
Object
>
createMiriamTypeResponse
(
MiriamType
type
)
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
result
.
put
(
"commonName"
,
type
.
getCommonName
());
result
.
put
(
"homepage"
,
type
.
getDbHomepage
());
result
.
put
(
"registryIdentifier"
,
type
.
getRegistryIdentifier
());
result
.
put
(
"uris"
,
type
.
getUris
());
return
result
;
}
public
Object
getModificationStateTypes
()
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
for
(
ModificationState
type
:
ModificationState
.
values
())
{
result
.
put
(
type
.
name
(),
createModificationStateResponse
(
type
));
}
return
result
;
}
private
Map
<
String
,
Object
>
createModificationStateResponse
(
ModificationState
type
)
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
result
.
put
(
"commonName"
,
type
.
getFullName
());
result
.
put
(
"abbreviation"
,
type
.
getAbbreviation
());
return
result
;
}
public
Map
<
String
,
Object
>
getPrivilegeTypes
()
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
for
(
PrivilegeType
type
:
PrivilegeType
.
values
())
{
result
.
put
(
type
.
name
(),
createPrivilegeTypeResponse
(
type
));
}
return
result
;
}
private
Map
<
String
,
Object
>
createPrivilegeTypeResponse
(
PrivilegeType
type
)
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
result
.
put
(
"commonName"
,
type
.
getDescription
());
if
(
type
.
getPrivilegeObjectType
()
!=
null
)
{
result
.
put
(
"objectType"
,
type
.
getPrivilegeObjectType
().
getSimpleName
());
}
else
{
result
.
put
(
"objectType"
,
null
);
}
result
.
put
(
"valueType"
,
"boolean"
);
return
result
;
}
public
List
<
Map
<
String
,
Object
>>
getAnnotators
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
ElementAnnotator
annotator
:
modelAnnotator
.
getAvailableAnnotators
())
{
result
.
add
(
prepareAnnotator
(
annotator
));
}
return
result
;
}
private
Map
<
String
,
Object
>
prepareAnnotator
(
ElementAnnotator
annotator
)
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
result
.
put
(
"className"
,
annotator
.
getClass
().
getName
());
result
.
put
(
"name"
,
annotator
.
getCommonName
());
result
.
put
(
"description"
,
annotator
.
getDescription
());
result
.
put
(
"url"
,
annotator
.
getUrl
());
result
.
put
(
"elementClassNames"
,
annotator
.
getValidClasses
());
result
.
put
(
"parameters"
,
prepareAnnotatorsParams
(
annotator
.
createAnnotatorData
().
getAnnotatorParams
()));
return
result
;
}
public
List
<
Map
<
String
,
Object
>>
getMapTypes
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
SubmodelType
type
:
SubmodelType
.
values
())
{
Map
<
String
,
Object
>
row
=
new
TreeMap
<>();
row
.
put
(
"id"
,
type
.
name
());
row
.
put
(
"name"
,
type
.
getCommonName
());
result
.
add
(
row
);
}
return
result
;
}
public
List
<
Map
<
String
,
Object
>>
getMapCanvasTypes
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
MapCanvasType
type
:
MapCanvasType
.
values
())
{
Map
<
String
,
Object
>
row
=
new
TreeMap
<>();
row
.
put
(
"id"
,
type
.
name
());
row
.
put
(
"name"
,
type
.
getCommonName
());
result
.
add
(
row
);
}
return
result
;
}
public
ConfigurationOption
updateOption
(
String
option
,
Map
<
String
,
Object
>
data
)
throws
QueryException
{
ConfigurationElementType
type
=
ConfigurationElementType
.
valueOf
(
option
);
...
...
@@ -221,28 +86,6 @@ public class ConfigurationRestImpl extends BaseRestImpl {
return
configurationService
.
getValue
(
type
);
}
public
List
<
Map
<
String
,
Object
>>
getUnitTypes
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
SbmlUnitType
type
:
SbmlUnitType
.
values
())
{
Map
<
String
,
Object
>
row
=
new
TreeMap
<>();
row
.
put
(
"id"
,
type
.
name
());
row
.
put
(
"name"
,
type
.
getCommonName
());
result
.
add
(
row
);
}
return
result
;
}
public
List
<
Map
<
String
,
Object
>>
getBioEntityFields
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
BioEntityField
field
:
BioEntityField
.
values
())
{
Map
<
String
,
Object
>
entry
=
new
TreeMap
<>();
entry
.
put
(
"name"
,
field
.
name
());
entry
.
put
(
"commonName"
,
field
.
getCommonName
());
result
.
add
(
entry
);
}
return
result
;
}
public
Map
<
String
,
Object
>
getDapiConfig
()
{
Map
<
String
,
Object
>
result
=
new
HashMap
<>();
result
.
put
(
"validConnection"
,
dapiConnector
.
isValidConnection
());
...
...
@@ -299,4 +142,22 @@ public class ConfigurationRestImpl extends BaseRestImpl {
configurationService
.
setConfigurationValue
(
ConfigurationElementType
.
DAPI_PASSWORD
,
user
.
getPassword
());
}
public
List
<
Map
<
String
,
Object
>>
getAnnotators
()
{
List
<
Map
<
String
,
Object
>>
result
=
new
ArrayList
<>();
for
(
ElementAnnotator
annotator
:
modelAnnotator
.
getAvailableAnnotators
())
{
result
.
add
(
prepareAnnotator
(
annotator
));
}
return
result
;
}
private
Map
<
String
,
Object
>
prepareAnnotator
(
ElementAnnotator
annotator
)
{
Map
<
String
,
Object
>
result
=
new
TreeMap
<>();
result
.
put
(
"className"
,
annotator
.
getClass
().
getName
());
result
.
put
(
"name"
,
annotator
.
getCommonName
());
result
.
put
(
"description"
,
annotator
.
getDescription
());
result
.
put
(
"url"
,
annotator
.
getUrl
());
result
.
put
(
"elementClassNames"
,
annotator
.
getValidClasses
());
result
.
put
(
"parameters"
,
prepareAnnotatorsParams
(
annotator
.
createAnnotatorData
().
getAnnotatorParams
()));
return
result
;
}
}
rest-api/src/test/java/lcsb/mapviewer/api/configuration/ConfigurationRestImplTest.java
View file @
7ce63914
package
lcsb.mapviewer.api.configuration
;
import
static
org
.
junit
.
Assert
.
*
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
java.util.*
;
import
java.util.HashMap
;
import
java.util.Map
;
import
org.apache.logging.log4j.LogManager
;
import
org.apache.logging.log4j.Logger
;
...
...
@@ -10,12 +11,8 @@ import org.junit.*;
import
org.springframework.beans.factory.annotation.Autowired
;
import
lcsb.mapviewer.api.RestTestFunctions
;
import
lcsb.mapviewer.model.map.MiriamType
;
import
lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction
;
import
lcsb.mapviewer.model.map.species.GenericProtein
;
import
lcsb.mapviewer.model.user.ConfigurationElementType
;
import
lcsb.mapviewer.model.user.ConfigurationOption
;
import
lcsb.mapviewer.model.user.annotator.BioEntityField
;
import
lcsb.mapviewer.services.QueryException
;
public
class
ConfigurationRestImplTest
extends
RestTestFunctions
{
...
...
@@ -53,38 +50,4 @@ public class ConfigurationRestImplTest extends RestTestFunctions {
assertNotNull
(
result
);
}
@Test
public
void
testGetElementTypes
()
throws
Exception
{
Set
<
Map
<
String
,
String
>>
list
=
configurationRestImpl
.
getElementTypes
();
GenericProtein
protein
=
new
GenericProtein
(
"id"
);
boolean
contains
=
false
;
for
(
Map
<
String
,
String
>
object
:
list
)
{
contains
|=
(
object
.
get
(
"name"
).
equals
(
protein
.
getStringType
()));
}
assertTrue
(
contains
);
}
@Test
public
void
testGetReactionTypes
()
throws
Exception
{
Set
<
Map
<
String
,
String
>>
list
=
configurationRestImpl
.
getReactionTypes
();
StateTransitionReaction
reaction
=
new
StateTransitionReaction
(
"re"
);
boolean
contains
=
false
;
for
(
Map
<
String
,
String
>
object
:
list
)
{
contains
|=
(
object
.
get
(
"name"
).
equals
(
reaction
.
getStringType
()));
}
assertTrue
(
contains
);
}
@Test
public
void
testGetMiriamTypes
()
throws
Exception
{
Map
<?,
?>
list
=
configurationRestImpl
.
getMiriamTypes
();
assertNotNull
(
list
.
get
(
MiriamType
.
PUBMED
.
name
()));
}
@Test
public
void
testGetBioEntityFields
()
throws
Exception
{
List
<?>
list
=
configurationRestImpl
.
getBioEntityFields
();
assertEquals
(
BioEntityField
.
values
().
length
,
list
.
size
());
}
}
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