Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
haskell-gargantext
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
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Julien Moutinho
haskell-gargantext
Commits
b1117dc0
Commit
b1117dc0
authored
Oct 24, 2018
by
Alexandre Delanoë
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into dbflow
parents
410f4e06
84e6f29f
Changes
5
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
131 additions
and
92 deletions
+131
-92
API.hs
src/Gargantext/API.hs
+9
-3
Node.hs
src/Gargantext/API/Node.hs
+4
-2
Bashql.hs
src/Gargantext/Database/Bashql.hs
+3
-4
Node.hs
src/Gargantext/Database/Node.hs
+25
-13
Node.hs
src/Gargantext/Database/Types/Node.hs
+90
-70
No files found.
src/Gargantext/API.hs
View file @
b1117dc0
...
@@ -45,7 +45,6 @@ import GHC.Generics (D1, Meta (..), Rep)
...
@@ -45,7 +45,6 @@ import GHC.Generics (D1, Meta (..), Rep)
import
GHC.TypeLits
(
AppendSymbol
,
Symbol
)
import
GHC.TypeLits
(
AppendSymbol
,
Symbol
)
import
Control.Lens
import
Control.Lens
import
Data.Aeson
(
Value
)
import
Data.Aeson.Encode.Pretty
(
encodePretty
)
import
Data.Aeson.Encode.Pretty
(
encodePretty
)
import
qualified
Data.ByteString.Lazy.Char8
as
BL8
import
qualified
Data.ByteString.Lazy.Char8
as
BL8
import
Data.Swagger
import
Data.Swagger
...
@@ -71,7 +70,9 @@ import Gargantext.API.Node ( Roots , roots
...
@@ -71,7 +70,9 @@ import Gargantext.API.Node ( Roots , roots
,
NodesAPI
,
nodesAPI
,
NodesAPI
,
nodesAPI
,
GraphAPI
,
graphAPI
,
GraphAPI
,
graphAPI
,
TreeAPI
,
treeAPI
,
TreeAPI
,
treeAPI
,
HyperdataAny
,
HyperdataCorpus
,
HyperdataCorpus
,
HyperdataAnnuaire
)
)
import
Gargantext.Database.Types.Node
()
import
Gargantext.Database.Types.Node
()
import
Gargantext.API.Count
(
CountAPI
,
count
,
Query
)
import
Gargantext.API.Count
(
CountAPI
,
count
,
Query
)
...
@@ -208,12 +209,16 @@ type GargAPI' =
...
@@ -208,12 +209,16 @@ type GargAPI' =
-- Node endpoint
-- Node endpoint
:<|>
"node"
:>
Summary
"Node endpoint"
:<|>
"node"
:>
Summary
"Node endpoint"
:>
Capture
"id"
Int
:>
NodeAPI
Value
:>
Capture
"id"
Int
:>
NodeAPI
HyperdataAny
-- Corpus endpoint
-- Corpus endpoint
:<|>
"corpus"
:>
Summary
"Corpus endpoint"
:<|>
"corpus"
:>
Summary
"Corpus endpoint"
:>
Capture
"id"
Int
:>
NodeAPI
HyperdataCorpus
:>
Capture
"id"
Int
:>
NodeAPI
HyperdataCorpus
-- Annuaire endpoint
:<|>
"annuaire"
:>
Summary
"Annuaire endpoint"
:>
Capture
"id"
Int
:>
NodeAPI
HyperdataAnnuaire
-- Corpus endpoint
-- Corpus endpoint
:<|>
"nodes"
:>
Summary
"Nodes endpoint"
:<|>
"nodes"
:>
Summary
"Nodes endpoint"
:>
ReqBody
'[
J
SON
]
[
Int
]
:>
NodesAPI
:>
ReqBody
'[
J
SON
]
[
Int
]
:>
NodesAPI
...
@@ -256,8 +261,9 @@ server env = do
...
@@ -256,8 +261,9 @@ server env = do
-- orchestrator <- scrapyOrchestrator env
-- orchestrator <- scrapyOrchestrator env
pure
$
swaggerFront
pure
$
swaggerFront
:<|>
roots
conn
:<|>
roots
conn
:<|>
nodeAPI
conn
(
Proxy
::
Proxy
Value
)
:<|>
nodeAPI
conn
(
Proxy
::
Proxy
HyperdataAny
)
:<|>
nodeAPI
conn
(
Proxy
::
Proxy
HyperdataCorpus
)
:<|>
nodeAPI
conn
(
Proxy
::
Proxy
HyperdataCorpus
)
:<|>
nodeAPI
conn
(
Proxy
::
Proxy
HyperdataAnnuaire
)
:<|>
nodesAPI
conn
:<|>
nodesAPI
conn
:<|>
count
-- TODO: undefined
:<|>
count
-- TODO: undefined
:<|>
search
conn
:<|>
search
conn
...
...
src/Gargantext/API/Node.hs
View file @
b1117dc0
...
@@ -23,6 +23,8 @@ Node API
...
@@ -23,6 +23,8 @@ Node API
-------------------------------------------------------------------
-------------------------------------------------------------------
module
Gargantext.API.Node
module
Gargantext.API.Node
(
module
Gargantext
.
API
.
Node
(
module
Gargantext
.
API
.
Node
,
HyperdataAny
(
..
)
,
HyperdataAnnuaire
(
..
)
,
HyperdataCorpus
(
..
)
,
HyperdataCorpus
(
..
)
,
HyperdataResource
(
..
)
,
HyperdataResource
(
..
)
,
HyperdataUser
(
..
)
,
HyperdataUser
(
..
)
...
@@ -37,7 +39,7 @@ import Control.Monad ((>>))
...
@@ -37,7 +39,7 @@ import Control.Monad ((>>))
--import System.IO (putStrLn, readFile)
--import System.IO (putStrLn, readFile)
import
Data.Either
(
Either
(
Left
))
import
Data.Either
(
Either
(
Left
))
import
Data.Aeson
(
FromJSON
,
ToJSON
,
Value
()
)
import
Data.Aeson
(
FromJSON
,
ToJSON
)
--import Data.Text (Text(), pack)
--import Data.Text (Text(), pack)
import
Data.Text
(
Text
())
import
Data.Text
(
Text
())
import
Data.Swagger
import
Data.Swagger
...
@@ -83,7 +85,7 @@ nodesAPI conn ids = deleteNodes' conn ids
...
@@ -83,7 +85,7 @@ nodesAPI conn ids = deleteNodes' conn ids
------------------------------------------------------------------------
------------------------------------------------------------------------
-- | TODO: access by admin only
-- | TODO: access by admin only
-- To manager the Users roots
-- To manager the Users roots
type
Roots
=
Get
'[
J
SON
]
[
Node
Value
]
type
Roots
=
Get
'[
J
SON
]
[
Node
Any
]
:<|>
Post
'[
J
SON
]
Int
-- TODO
:<|>
Post
'[
J
SON
]
Int
-- TODO
:<|>
Put
'[
J
SON
]
Int
-- TODO
:<|>
Put
'[
J
SON
]
Int
-- TODO
:<|>
Delete
'[
J
SON
]
Int
-- TODO
:<|>
Delete
'[
J
SON
]
Int
-- TODO
...
...
src/Gargantext/Database/Bashql.hs
View file @
b1117dc0
...
@@ -77,7 +77,6 @@ module Gargantext.Database.Bashql ( get
...
@@ -77,7 +77,6 @@ module Gargantext.Database.Bashql ( get
import
Control.Monad.Reader
-- (Reader, ask)
import
Control.Monad.Reader
-- (Reader, ask)
import
Data.Text
(
Text
)
import
Data.Text
(
Text
)
import
Data.Aeson
import
Data.List
(
concat
,
last
)
import
Data.List
(
concat
,
last
)
import
Gargantext.Core.Types
import
Gargantext.Core.Types
...
@@ -101,7 +100,7 @@ mv :: NodeId -> ParentId -> Cmd [Int]
...
@@ -101,7 +100,7 @@ mv :: NodeId -> ParentId -> Cmd [Int]
mv
n
p
=
mkCmd
$
\
conn
->
U
.
update
(
U
.
Move
n
p
)
conn
mv
n
p
=
mkCmd
$
\
conn
->
U
.
update
(
U
.
Move
n
p
)
conn
-- | TODO get Children or Node
-- | TODO get Children or Node
get
::
PWD
->
Cmd
[
Node
Value
]
get
::
PWD
->
Cmd
[
Node
Any
]
get
[]
=
pure
[]
get
[]
=
pure
[]
get
pwd
=
Cmd
.
ReaderT
$
\
conn
->
runQuery
conn
$
selectNodesWithParentID
(
last
pwd
)
get
pwd
=
Cmd
.
ReaderT
$
\
conn
->
runQuery
conn
$
selectNodesWithParentID
(
last
pwd
)
...
@@ -110,10 +109,10 @@ home :: Cmd PWD
...
@@ -110,10 +109,10 @@ home :: Cmd PWD
home
=
map
_node_id
<$>
Cmd
(
ReaderT
(
getNodesWithParentId
0
Nothing
))
home
=
map
_node_id
<$>
Cmd
(
ReaderT
(
getNodesWithParentId
0
Nothing
))
-- | ls == get Children
-- | ls == get Children
ls
::
PWD
->
Cmd
[
Node
Value
]
ls
::
PWD
->
Cmd
[
Node
Any
]
ls
=
get
ls
=
get
tree
::
PWD
->
Cmd
[
Node
Value
]
tree
::
PWD
->
Cmd
[
Node
Any
]
tree
p
=
do
tree
p
=
do
ns
<-
get
p
ns
<-
get
p
children
<-
mapM
(
\
n
->
get
[
_node_id
n
])
ns
children
<-
mapM
(
\
n
->
get
[
_node_id
n
])
ns
...
...
src/Gargantext/Database/Node.hs
View file @
b1117dc0
...
@@ -40,7 +40,7 @@ import Prelude hiding (null, id, map, sum)
...
@@ -40,7 +40,7 @@ import Prelude hiding (null, id, map, sum)
import
Gargantext.Core
(
Lang
(
..
))
import
Gargantext.Core
(
Lang
(
..
))
import
Gargantext.Core.Types
import
Gargantext.Core.Types
import
Gargantext.Database.Types.Node
(
NodeType
,
defaultCorpus
)
import
Gargantext.Database.Types.Node
(
NodeType
,
defaultCorpus
,
Hyperdata
)
import
Gargantext.Database.Queries
import
Gargantext.Database.Queries
import
Gargantext.Database.Config
(
nodeTypeId
)
import
Gargantext.Database.Config
(
nodeTypeId
)
import
Gargantext.Prelude
hiding
(
sum
)
import
Gargantext.Prelude
hiding
(
sum
)
...
@@ -95,6 +95,9 @@ type DocId = Int
...
@@ -95,6 +95,9 @@ type DocId = Int
type
UserId
=
Int
type
UserId
=
Int
type
TypeId
=
Int
type
TypeId
=
Int
------------------------------------------------------------------------
------------------------------------------------------------------------
instance
FromField
HyperdataAny
where
fromField
=
fromField'
instance
FromField
HyperdataCorpus
where
instance
FromField
HyperdataCorpus
where
fromField
=
fromField'
fromField
=
fromField'
...
@@ -106,7 +109,13 @@ instance FromField HyperdataDocumentV3 where
...
@@ -106,7 +109,13 @@ instance FromField HyperdataDocumentV3 where
instance
FromField
HyperdataUser
where
instance
FromField
HyperdataUser
where
fromField
=
fromField'
fromField
=
fromField'
instance
FromField
HyperdataAnnuaire
where
fromField
=
fromField'
------------------------------------------------------------------------
------------------------------------------------------------------------
instance
QueryRunnerColumnDefault
PGJsonb
HyperdataAny
where
queryRunnerColumnDefault
=
fieldQueryRunnerColumn
instance
QueryRunnerColumnDefault
PGJsonb
HyperdataDocument
where
instance
QueryRunnerColumnDefault
PGJsonb
HyperdataDocument
where
queryRunnerColumnDefault
=
fieldQueryRunnerColumn
queryRunnerColumnDefault
=
fieldQueryRunnerColumn
...
@@ -118,6 +127,9 @@ instance QueryRunnerColumnDefault PGJsonb HyperdataCorpus where
...
@@ -118,6 +127,9 @@ instance QueryRunnerColumnDefault PGJsonb HyperdataCorpus where
instance
QueryRunnerColumnDefault
PGJsonb
HyperdataUser
where
instance
QueryRunnerColumnDefault
PGJsonb
HyperdataUser
where
queryRunnerColumnDefault
=
fieldQueryRunnerColumn
queryRunnerColumnDefault
=
fieldQueryRunnerColumn
instance
QueryRunnerColumnDefault
PGJsonb
HyperdataAnnuaire
where
queryRunnerColumnDefault
=
fieldQueryRunnerColumn
------------------------------------------------------------------------
------------------------------------------------------------------------
fromField'
::
(
Typeable
b
,
FromJSON
b
)
=>
Field
->
Maybe
DB
.
ByteString
->
Conversion
b
fromField'
::
(
Typeable
b
,
FromJSON
b
)
=>
Field
->
Maybe
DB
.
ByteString
->
Conversion
b
...
@@ -184,7 +196,7 @@ selectNode id = proc () -> do
...
@@ -184,7 +196,7 @@ selectNode id = proc () -> do
restrict
-<
_node_id
row
.==
id
restrict
-<
_node_id
row
.==
id
returnA
-<
row
returnA
-<
row
runGetNodes
::
Query
NodeRead
->
Cmd
[
Node
Value
]
runGetNodes
::
Query
NodeRead
->
Cmd
[
Node
Any
]
runGetNodes
q
=
mkCmd
$
\
conn
->
runQuery
conn
q
runGetNodes
q
=
mkCmd
$
\
conn
->
runQuery
conn
q
------------------------------------------------------------------------
------------------------------------------------------------------------
...
@@ -248,11 +260,11 @@ getNodesWith conn parentId _ nodeType maybeOffset maybeLimit =
...
@@ -248,11 +260,11 @@ getNodesWith conn parentId _ nodeType maybeOffset maybeLimit =
-- NP check type
-- NP check type
getNodesWithParentId
::
Int
getNodesWithParentId
::
Int
->
Maybe
Text
->
Connection
->
IO
[
Node
Value
]
->
Maybe
Text
->
Connection
->
IO
[
Node
Any
]
getNodesWithParentId
n
_
conn
=
runQuery
conn
$
selectNodesWithParentID
n
getNodesWithParentId
n
_
conn
=
runQuery
conn
$
selectNodesWithParentID
n
getNodesWithParentId'
::
Int
getNodesWithParentId'
::
Int
->
Maybe
Text
->
Connection
->
IO
[
Node
Value
]
->
Maybe
Text
->
Connection
->
IO
[
Node
Any
]
getNodesWithParentId'
n
_
conn
=
runQuery
conn
$
selectNodesWithParentID
n
getNodesWithParentId'
n
_
conn
=
runQuery
conn
$
selectNodesWithParentID
n
...
@@ -306,7 +318,7 @@ defaultUser :: HyperdataUser
...
@@ -306,7 +318,7 @@ defaultUser :: HyperdataUser
defaultUser
=
HyperdataUser
(
Just
$
(
pack
.
show
)
EN
)
defaultUser
=
HyperdataUser
(
Just
$
(
pack
.
show
)
EN
)
nodeUserW
::
Maybe
Name
->
Maybe
HyperdataUser
->
UserId
->
NodeWrite'
nodeUserW
::
Maybe
Name
->
Maybe
HyperdataUser
->
UserId
->
NodeWrite'
nodeUserW
maybeName
maybeHyperdata
=
node
NodeUser
name
(
Hyperdata
user
)
Nothing
nodeUserW
maybeName
maybeHyperdata
=
node
NodeUser
name
user
Nothing
where
where
name
=
maybe
"User"
identity
maybeName
name
=
maybe
"User"
identity
maybeName
user
=
maybe
defaultUser
identity
maybeHyperdata
user
=
maybe
defaultUser
identity
maybeHyperdata
...
@@ -315,14 +327,14 @@ defaultFolder :: HyperdataFolder
...
@@ -315,14 +327,14 @@ defaultFolder :: HyperdataFolder
defaultFolder
=
HyperdataFolder
(
Just
"Markdown Description"
)
defaultFolder
=
HyperdataFolder
(
Just
"Markdown Description"
)
nodeFolderW
::
Maybe
Name
->
Maybe
HyperdataFolder
->
ParentId
->
UserId
->
NodeWrite'
nodeFolderW
::
Maybe
Name
->
Maybe
HyperdataFolder
->
ParentId
->
UserId
->
NodeWrite'
nodeFolderW
maybeName
maybeFolder
pid
=
node
NodeFolder
name
(
Hyperdata
folder
)
(
Just
pid
)
nodeFolderW
maybeName
maybeFolder
pid
=
node
NodeFolder
name
folder
(
Just
pid
)
where
where
name
=
maybe
"Folder"
identity
maybeName
name
=
maybe
"Folder"
identity
maybeName
folder
=
maybe
defaultFolder
identity
maybeFolder
folder
=
maybe
defaultFolder
identity
maybeFolder
------------------------------------------------------------------------
------------------------------------------------------------------------
nodeCorpusW
::
Maybe
Name
->
Maybe
HyperdataCorpus
->
ParentId
->
UserId
->
NodeWrite'
nodeCorpusW
::
Maybe
Name
->
Maybe
HyperdataCorpus
->
ParentId
->
UserId
->
NodeWrite'
nodeCorpusW
maybeName
maybeCorpus
pId
=
node
NodeCorpus
name
(
Hyperdata
corpus
)
(
Just
pId
)
nodeCorpusW
maybeName
maybeCorpus
pId
=
node
NodeCorpus
name
corpus
(
Just
pId
)
where
where
name
=
maybe
"Corpus"
identity
maybeName
name
=
maybe
"Corpus"
identity
maybeName
corpus
=
maybe
defaultCorpus
identity
maybeCorpus
corpus
=
maybe
defaultCorpus
identity
maybeCorpus
...
@@ -331,7 +343,7 @@ defaultDocument :: HyperdataDocument
...
@@ -331,7 +343,7 @@ defaultDocument :: HyperdataDocument
defaultDocument
=
hyperdataDocument
defaultDocument
=
hyperdataDocument
nodeDocumentW
::
Maybe
Name
->
Maybe
HyperdataDocument
->
CorpusId
->
UserId
->
NodeWrite'
nodeDocumentW
::
Maybe
Name
->
Maybe
HyperdataDocument
->
CorpusId
->
UserId
->
NodeWrite'
nodeDocumentW
maybeName
maybeDocument
cId
=
node
NodeDocument
name
(
Hyperdata
doc
)
(
Just
cId
)
nodeDocumentW
maybeName
maybeDocument
cId
=
node
NodeDocument
name
doc
(
Just
cId
)
where
where
name
=
maybe
"Document"
identity
maybeName
name
=
maybe
"Document"
identity
maybeName
doc
=
maybe
defaultDocument
identity
maybeDocument
doc
=
maybe
defaultDocument
identity
maybeDocument
...
@@ -340,7 +352,7 @@ defaultAnnuaire :: HyperdataAnnuaire
...
@@ -340,7 +352,7 @@ defaultAnnuaire :: HyperdataAnnuaire
defaultAnnuaire
=
HyperdataAnnuaire
(
Just
"Title"
)
(
Just
"Description"
)
defaultAnnuaire
=
HyperdataAnnuaire
(
Just
"Title"
)
(
Just
"Description"
)
nodeAnnuaireW
::
Maybe
Name
->
Maybe
HyperdataAnnuaire
->
ParentId
->
UserId
->
NodeWrite'
nodeAnnuaireW
::
Maybe
Name
->
Maybe
HyperdataAnnuaire
->
ParentId
->
UserId
->
NodeWrite'
nodeAnnuaireW
maybeName
maybeAnnuaire
pId
=
node
NodeAnnuaire
name
(
Hyperdata
annuaire
)
(
Just
pId
)
nodeAnnuaireW
maybeName
maybeAnnuaire
pId
=
node
NodeAnnuaire
name
annuaire
(
Just
pId
)
where
where
name
=
maybe
"Annuaire"
identity
maybeName
name
=
maybe
"Annuaire"
identity
maybeName
annuaire
=
maybe
defaultAnnuaire
identity
maybeAnnuaire
annuaire
=
maybe
defaultAnnuaire
identity
maybeAnnuaire
...
@@ -349,17 +361,17 @@ defaultContact :: HyperdataContact
...
@@ -349,17 +361,17 @@ defaultContact :: HyperdataContact
defaultContact
=
HyperdataContact
(
Just
"Name"
)
(
Just
"email@here"
)
defaultContact
=
HyperdataContact
(
Just
"Name"
)
(
Just
"email@here"
)
nodeContactW
::
Maybe
Name
->
Maybe
HyperdataContact
->
AnnuaireId
->
UserId
->
NodeWrite'
nodeContactW
::
Maybe
Name
->
Maybe
HyperdataContact
->
AnnuaireId
->
UserId
->
NodeWrite'
nodeContactW
maybeName
maybeContact
aId
=
node
NodeContact
name
(
Hyperdata
contact
)
(
Just
aId
)
nodeContactW
maybeName
maybeContact
aId
=
node
NodeContact
name
contact
(
Just
aId
)
where
where
name
=
maybe
"Contact"
identity
maybeName
name
=
maybe
"Contact"
identity
maybeName
contact
=
maybe
defaultContact
identity
maybeContact
contact
=
maybe
defaultContact
identity
maybeContact
------------------------------------------------------------------------
------------------------------------------------------------------------
------------------------------------------------------------------------
------------------------------------------------------------------------
node
::
ToJSON
a
=>
NodeType
->
Name
->
Hyperdata
a
->
Maybe
ParentId
->
UserId
->
NodeWrite'
node
::
(
ToJSON
a
,
Hyperdata
a
)
=>
NodeType
->
Name
->
a
->
Maybe
ParentId
->
UserId
->
NodeWrite'
node
nodeType
name
hyperData
parentId
userId
=
Node
Nothing
typeId
userId
parentId
name
Nothing
byteData
node
nodeType
name
hyperData
parentId
userId
=
Node
Nothing
typeId
userId
parentId
name
Nothing
byteData
where
where
typeId
=
nodeTypeId
nodeType
typeId
=
nodeTypeId
nodeType
byteData
=
DB
.
pack
$
DBL
.
unpack
$
encode
$
unHyperdata
hyperData
byteData
=
DB
.
pack
.
DBL
.
unpack
$
encode
hyperData
-------------------------------
-------------------------------
node2row
::
(
Functor
maybe1
,
Functor
maybe2
,
Functor
maybe3
)
=>
node2row
::
(
Functor
maybe1
,
Functor
maybe2
,
Functor
maybe3
)
=>
...
@@ -479,7 +491,7 @@ mk c nt pId name = mk' c nt userId pId name
...
@@ -479,7 +491,7 @@ mk c nt pId name = mk' c nt userId pId name
mk'
::
Connection
->
NodeType
->
UserId
->
Maybe
ParentId
->
Text
->
IO
[
Int
]
mk'
::
Connection
->
NodeType
->
UserId
->
Maybe
ParentId
->
Text
->
IO
[
Int
]
mk'
c
nt
uId
pId
name
=
map
fromIntegral
<$>
insertNodesWithParentR
pId
[
node
nt
name
hd
pId
uId
]
c
mk'
c
nt
uId
pId
name
=
map
fromIntegral
<$>
insertNodesWithParentR
pId
[
node
nt
name
hd
pId
uId
]
c
where
where
hd
=
Hyperdata
(
HyperdataUser
(
Just
$
(
pack
.
show
)
EN
))
hd
=
Hyperdata
User
.
Just
.
pack
$
show
EN
type
Name
=
Text
type
Name
=
Text
...
...
src/Gargantext/Database/Types/Node.hs
View file @
b1117dc0
This diff is collapsed.
Click to expand it.
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