Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
flatbuffers
Project
Project
Details
Activity
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
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
flatbuffers
Commits
2e7806ed
Commit
2e7806ed
authored
Aug 19, 2016
by
Harsh Vardhan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial support to add other languages to flatbuffers
parent
b36bd67b
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
155 additions
and
108 deletions
+155
-108
CMakeLists.txt
CMakeLists.txt
+1
-0
cpp_generator.cc
grpc/src/compiler/cpp_generator.cc
+27
-26
cpp_generator.h
grpc/src/compiler/cpp_generator.h
+9
-72
schema_interface.h
grpc/src/compiler/schema_interface.h
+108
-0
idl_gen_grpc.cpp
src/idl_gen_grpc.cpp
+10
-10
No files found.
CMakeLists.txt
View file @
2e7806ed
...
...
@@ -44,6 +44,7 @@ set(FlatBuffers_Compiler_SRCS
src/idl_gen_fbs.cpp
src/idl_gen_grpc.cpp
src/flatc.cpp
grpc/src/compiler/schema_interface.h
grpc/src/compiler/cpp_generator.h
grpc/src/compiler/cpp_generator.cc
)
...
...
grpc/src/compiler/cpp_generator.cc
View file @
2e7806ed
...
...
@@ -67,7 +67,8 @@ grpc::string FilenameIdentifier(const grpc::string &filename) {
template
<
class
T
,
size_t
N
>
T
*
array_end
(
T
(
&
array
)[
N
])
{
return
array
+
N
;
}
void
PrintIncludes
(
Printer
*
printer
,
const
std
::
vector
<
grpc
::
string
>&
headers
,
const
Parameters
&
params
)
{
void
PrintIncludes
(
grpc_generator
::
Printer
*
printer
,
const
std
::
vector
<
grpc
::
string
>&
headers
,
const
Parameters
&
params
)
{
std
::
map
<
grpc
::
string
,
grpc
::
string
>
vars
;
vars
[
"l"
]
=
params
.
use_system_headers
?
'<'
:
'"'
;
...
...
@@ -86,7 +87,7 @@ void PrintIncludes(Printer *printer, const std::vector<grpc::string>& headers, c
}
}
grpc
::
string
GetHeaderPrologue
(
File
*
file
,
const
Parameters
&
/*params*/
)
{
grpc
::
string
GetHeaderPrologue
(
grpc_generator
::
File
*
file
,
const
Parameters
&
/*params*/
)
{
grpc
::
string
output
;
{
// Scope the output stream so it closes and finalizes output to the string.
...
...
@@ -111,7 +112,7 @@ grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) {
return
output
;
}
grpc
::
string
GetHeaderIncludes
(
File
*
file
,
grpc
::
string
GetHeaderIncludes
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
)
{
grpc
::
string
output
;
{
...
...
@@ -154,7 +155,7 @@ grpc::string GetHeaderIncludes(File *file,
}
void
PrintHeaderClientMethodInterfaces
(
Printer
*
printer
,
const
Method
*
method
,
grpc_generator
::
Printer
*
printer
,
const
grpc_generator
::
Method
*
method
,
std
::
map
<
grpc
::
string
,
grpc
::
string
>
*
vars
,
bool
is_public
)
{
(
*
vars
)[
"Method"
]
=
method
->
name
();
(
*
vars
)[
"Request"
]
=
method
->
input_type_name
();
...
...
@@ -303,8 +304,8 @@ void PrintHeaderClientMethodInterfaces(
}
}
void
PrintHeaderClientMethod
(
Printer
*
printer
,
const
Method
*
method
,
void
PrintHeaderClientMethod
(
grpc_generator
::
Printer
*
printer
,
const
grpc_generator
::
Method
*
method
,
std
::
map
<
grpc
::
string
,
grpc
::
string
>
*
vars
,
bool
is_public
)
{
(
*
vars
)[
"Method"
]
=
method
->
name
();
...
...
@@ -445,13 +446,13 @@ void PrintHeaderClientMethod(Printer *printer,
}
}
void
PrintHeaderClientMethodData
(
Printer
*
printer
,
const
Method
*
method
,
void
PrintHeaderClientMethodData
(
grpc_generator
::
Printer
*
printer
,
const
grpc_generator
::
Method
*
method
,
std
::
map
<
grpc
::
string
,
grpc
::
string
>
*
vars
)
{
(
*
vars
)[
"Method"
]
=
method
->
name
();
printer
->
Print
(
*
vars
,
"const ::grpc::RpcMethod rpcmethod_$Method$_;
\n
"
);
}
void
PrintHeaderServerMethodSync
(
Printer
*
printer
,
const
Method
*
method
,
void
PrintHeaderServerMethodSync
(
grpc_generator
::
Printer
*
printer
,
const
grpc_generator
::
Method
*
method
,
std
::
map
<
grpc
::
string
,
grpc
::
string
>
*
vars
)
{
(
*
vars
)[
"Method"
]
=
method
->
name
();
(
*
vars
)[
"Request"
]
=
method
->
input_type_name
();
...
...
@@ -483,8 +484,8 @@ void PrintHeaderServerMethodSync(Printer *printer, const Method *method,
}
void
PrintHeaderServerMethodAsync
(
Printer
*
printer
,
const
Method
*
method
,
grpc_generator
::
Printer
*
printer
,
const
grpc_generator
::
Method
*
method
,
std
::
map
<
grpc
::
string
,
grpc
::
string
>
*
vars
)
{
(
*
vars
)[
"Method"
]
=
method
->
name
();
(
*
vars
)[
"Request"
]
=
method
->
input_type_name
();
...
...
@@ -599,8 +600,8 @@ void PrintHeaderServerMethodAsync(
}
void
PrintHeaderServerMethodGeneric
(
Printer
*
printer
,
const
Method
*
method
,
grpc_generator
::
Printer
*
printer
,
const
grpc_generator
::
Method
*
method
,
std
::
map
<
grpc
::
string
,
grpc
::
string
>
*
vars
)
{
(
*
vars
)[
"Method"
]
=
method
->
name
();
(
*
vars
)[
"Request"
]
=
method
->
input_type_name
();
...
...
@@ -669,8 +670,8 @@ void PrintHeaderServerMethodGeneric(
printer
->
Print
(
*
vars
,
"};
\n
"
);
}
void
PrintHeaderService
(
Printer
*
printer
,
const
Service
*
service
,
void
PrintHeaderService
(
grpc_generator
::
Printer
*
printer
,
const
grpc_generator
::
Service
*
service
,
std
::
map
<
grpc
::
string
,
grpc
::
string
>
*
vars
)
{
(
*
vars
)[
"Service"
]
=
service
->
name
();
...
...
@@ -764,7 +765,7 @@ void PrintHeaderService(Printer *printer,
printer
->
Print
(
"};
\n
"
);
}
grpc
::
string
GetHeaderServices
(
File
*
file
,
grpc
::
string
GetHeaderServices
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
)
{
grpc
::
string
output
;
{
...
...
@@ -795,7 +796,7 @@ grpc::string GetHeaderServices(File *file,
return
output
;
}
grpc
::
string
GetHeaderEpilogue
(
File
*
file
,
const
Parameters
&
/*params*/
)
{
grpc
::
string
GetHeaderEpilogue
(
grpc_generator
::
File
*
file
,
const
Parameters
&
/*params*/
)
{
grpc
::
string
output
;
{
// Scope the output stream so it closes and finalizes output to the string.
...
...
@@ -821,7 +822,7 @@ grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) {
return
output
;
}
grpc
::
string
GetSourcePrologue
(
File
*
file
,
const
Parameters
&
/*params*/
)
{
grpc
::
string
GetSourcePrologue
(
grpc_generator
::
File
*
file
,
const
Parameters
&
/*params*/
)
{
grpc
::
string
output
;
{
// Scope the output stream so it closes and finalizes output to the string.
...
...
@@ -845,7 +846,7 @@ grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) {
return
output
;
}
grpc
::
string
GetSourceIncludes
(
File
*
file
,
grpc
::
string
GetSourceIncludes
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
)
{
grpc
::
string
output
;
{
...
...
@@ -880,8 +881,8 @@ grpc::string GetSourceIncludes(File *file,
return
output
;
}
void
PrintSourceClientMethod
(
Printer
*
printer
,
const
Method
*
method
,
void
PrintSourceClientMethod
(
grpc_generator
::
Printer
*
printer
,
const
grpc_generator
::
Method
*
method
,
std
::
map
<
grpc
::
string
,
grpc
::
string
>
*
vars
)
{
(
*
vars
)[
"Method"
]
=
method
->
name
();
(
*
vars
)[
"Request"
]
=
method
->
input_type_name
();
...
...
@@ -981,8 +982,8 @@ void PrintSourceClientMethod(Printer *printer,
}
}
void
PrintSourceServerMethod
(
Printer
*
printer
,
const
Method
*
method
,
void
PrintSourceServerMethod
(
grpc_generator
::
Printer
*
printer
,
const
grpc_generator
::
Method
*
method
,
std
::
map
<
grpc
::
string
,
grpc
::
string
>
*
vars
)
{
(
*
vars
)[
"Method"
]
=
method
->
name
();
(
*
vars
)[
"Request"
]
=
method
->
input_type_name
();
...
...
@@ -1040,8 +1041,8 @@ void PrintSourceServerMethod(Printer *printer,
}
}
void
PrintSourceService
(
Printer
*
printer
,
const
Service
*
service
,
void
PrintSourceService
(
grpc_generator
::
Printer
*
printer
,
const
grpc_generator
::
Service
*
service
,
std
::
map
<
grpc
::
string
,
grpc
::
string
>
*
vars
)
{
(
*
vars
)[
"Service"
]
=
service
->
name
();
...
...
@@ -1153,7 +1154,7 @@ void PrintSourceService(Printer *printer,
}
}
grpc
::
string
GetSourceServices
(
File
*
file
,
grpc
::
string
GetSourceServices
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
)
{
grpc
::
string
output
;
{
...
...
@@ -1182,7 +1183,7 @@ grpc::string GetSourceServices(File *file,
return
output
;
}
grpc
::
string
GetSourceEpilogue
(
File
*
file
,
const
Parameters
&
/*params*/
)
{
grpc
::
string
GetSourceEpilogue
(
grpc_generator
::
File
*
file
,
const
Parameters
&
/*params*/
)
{
grpc
::
string
temp
;
if
(
!
file
->
package
().
empty
())
{
...
...
grpc/src/compiler/cpp_generator.h
View file @
2e7806ed
...
...
@@ -41,16 +41,7 @@
#include <memory>
#include <vector>
#ifndef GRPC_CUSTOM_STRING
#include <string>
#define GRPC_CUSTOM_STRING std::string
#endif
namespace
grpc
{
typedef
GRPC_CUSTOM_STRING
string
;
}
// namespace grpc
#include "src/compiler/schema_interface.h"
namespace
grpc_cpp_generator
{
...
...
@@ -64,83 +55,29 @@ struct Parameters {
grpc
::
string
grpc_search_path
;
};
// An abstract interface representing a method.
struct
Method
{
virtual
~
Method
()
{}
virtual
grpc
::
string
name
()
const
=
0
;
virtual
grpc
::
string
input_type_name
()
const
=
0
;
virtual
grpc
::
string
output_type_name
()
const
=
0
;
virtual
bool
NoStreaming
()
const
=
0
;
virtual
bool
ClientOnlyStreaming
()
const
=
0
;
virtual
bool
ServerOnlyStreaming
()
const
=
0
;
virtual
bool
BidiStreaming
()
const
=
0
;
};
// An abstract interface representing a service.
struct
Service
{
virtual
~
Service
()
{}
virtual
grpc
::
string
name
()
const
=
0
;
virtual
int
method_count
()
const
=
0
;
virtual
std
::
unique_ptr
<
const
Method
>
method
(
int
i
)
const
=
0
;
};
struct
Printer
{
virtual
~
Printer
()
{}
virtual
void
Print
(
const
std
::
map
<
grpc
::
string
,
grpc
::
string
>
&
vars
,
const
char
*
template_string
)
=
0
;
virtual
void
Print
(
const
char
*
string
)
=
0
;
virtual
void
Indent
()
=
0
;
virtual
void
Outdent
()
=
0
;
};
// An interface that allows the source generated to be output using various
// libraries/idls/serializers.
struct
File
{
virtual
~
File
()
{}
virtual
grpc
::
string
filename
()
const
=
0
;
virtual
grpc
::
string
filename_without_ext
()
const
=
0
;
virtual
grpc
::
string
message_header_ext
()
const
=
0
;
virtual
grpc
::
string
service_header_ext
()
const
=
0
;
virtual
grpc
::
string
package
()
const
=
0
;
virtual
std
::
vector
<
grpc
::
string
>
package_parts
()
const
=
0
;
virtual
grpc
::
string
additional_headers
()
const
=
0
;
virtual
int
service_count
()
const
=
0
;
virtual
std
::
unique_ptr
<
const
Service
>
service
(
int
i
)
const
=
0
;
virtual
std
::
unique_ptr
<
Printer
>
CreatePrinter
(
grpc
::
string
*
str
)
const
=
0
;
};
// Return the prologue of the generated header file.
grpc
::
string
GetHeaderPrologue
(
File
*
file
,
const
Parameters
&
params
);
grpc
::
string
GetHeaderPrologue
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
);
// Return the includes needed for generated header file.
grpc
::
string
GetHeaderIncludes
(
File
*
file
,
const
Parameters
&
params
);
grpc
::
string
GetHeaderIncludes
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
);
// Return the includes needed for generated source file.
grpc
::
string
GetSourceIncludes
(
File
*
file
,
const
Parameters
&
params
);
grpc
::
string
GetSourceIncludes
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
);
// Return the epilogue of the generated header file.
grpc
::
string
GetHeaderEpilogue
(
File
*
file
,
const
Parameters
&
params
);
grpc
::
string
GetHeaderEpilogue
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
);
// Return the prologue of the generated source file.
grpc
::
string
GetSourcePrologue
(
File
*
file
,
const
Parameters
&
params
);
grpc
::
string
GetSourcePrologue
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
);
// Return the services for generated header file.
grpc
::
string
GetHeaderServices
(
File
*
file
,
const
Parameters
&
params
);
grpc
::
string
GetHeaderServices
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
);
// Return the services for generated source file.
grpc
::
string
GetSourceServices
(
File
*
file
,
const
Parameters
&
params
);
grpc
::
string
GetSourceServices
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
);
// Return the epilogue of the generated source file.
grpc
::
string
GetSourceEpilogue
(
File
*
file
,
const
Parameters
&
params
);
grpc
::
string
GetSourceEpilogue
(
grpc_generator
::
File
*
file
,
const
Parameters
&
params
);
}
// namespace grpc_cpp_generator
...
...
grpc/src/compiler/schema_interface.h
0 → 100644
View file @
2e7806ed
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
#include <memory>
#include <vector>
#ifndef GRPC_CUSTOM_STRING
#include <string>
#define GRPC_CUSTOM_STRING std::string
#endif
namespace
grpc
{
typedef
GRPC_CUSTOM_STRING
string
;
}
// namespace grpc
namespace
grpc_generator
{
// An abstract interface representing a method.
struct
Method
{
virtual
~
Method
()
{}
virtual
grpc
::
string
name
()
const
=
0
;
virtual
grpc
::
string
input_type_name
()
const
=
0
;
virtual
grpc
::
string
output_type_name
()
const
=
0
;
virtual
bool
NoStreaming
()
const
=
0
;
virtual
bool
ClientOnlyStreaming
()
const
=
0
;
virtual
bool
ServerOnlyStreaming
()
const
=
0
;
virtual
bool
BidiStreaming
()
const
=
0
;
};
// An abstract interface representing a service.
struct
Service
{
virtual
~
Service
()
{}
virtual
grpc
::
string
name
()
const
=
0
;
virtual
int
method_count
()
const
=
0
;
virtual
std
::
unique_ptr
<
const
Method
>
method
(
int
i
)
const
=
0
;
};
struct
Printer
{
virtual
~
Printer
()
{}
virtual
void
Print
(
const
std
::
map
<
grpc
::
string
,
grpc
::
string
>
&
vars
,
const
char
*
template_string
)
=
0
;
virtual
void
Print
(
const
char
*
string
)
=
0
;
virtual
void
Indent
()
=
0
;
virtual
void
Outdent
()
=
0
;
};
// An interface that allows the source generated to be output using various
// libraries/idls/serializers.
struct
File
{
virtual
~
File
()
{}
virtual
grpc
::
string
filename
()
const
=
0
;
virtual
grpc
::
string
filename_without_ext
()
const
=
0
;
virtual
grpc
::
string
message_header_ext
()
const
=
0
;
virtual
grpc
::
string
service_header_ext
()
const
=
0
;
virtual
grpc
::
string
package
()
const
=
0
;
virtual
std
::
vector
<
grpc
::
string
>
package_parts
()
const
=
0
;
virtual
grpc
::
string
additional_headers
()
const
=
0
;
virtual
int
service_count
()
const
=
0
;
virtual
std
::
unique_ptr
<
const
Service
>
service
(
int
i
)
const
=
0
;
virtual
std
::
unique_ptr
<
Printer
>
CreatePrinter
(
grpc
::
string
*
str
)
const
=
0
;
};
}
// namespace grpc_generator
#endif // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
src/idl_gen_grpc.cpp
View file @
2e7806ed
...
...
@@ -24,7 +24,7 @@
namespace
flatbuffers
{
class
FlatBufMethod
:
public
grpc_
cpp_
generator
::
Method
{
class
FlatBufMethod
:
public
grpc_generator
::
Method
{
public
:
enum
Streaming
{
kNone
,
kClient
,
kServer
,
kBiDi
};
...
...
@@ -62,7 +62,7 @@ class FlatBufMethod : public grpc_cpp_generator::Method {
Streaming
streaming_
;
};
class
FlatBufService
:
public
grpc_
cpp_
generator
::
Service
{
class
FlatBufService
:
public
grpc_generator
::
Service
{
public
:
FlatBufService
(
const
ServiceDef
*
service
)
:
service_
(
service
)
{}
...
...
@@ -72,8 +72,8 @@ class FlatBufService : public grpc_cpp_generator::Service {
return
static_cast
<
int
>
(
service_
->
calls
.
vec
.
size
());
};
std
::
unique_ptr
<
const
grpc_
cpp_
generator
::
Method
>
method
(
int
i
)
const
{
return
std
::
unique_ptr
<
const
grpc_
cpp_
generator
::
Method
>
(
std
::
unique_ptr
<
const
grpc_generator
::
Method
>
method
(
int
i
)
const
{
return
std
::
unique_ptr
<
const
grpc_generator
::
Method
>
(
new
FlatBufMethod
(
service_
->
calls
.
vec
[
i
]));
};
...
...
@@ -81,7 +81,7 @@ class FlatBufService : public grpc_cpp_generator::Service {
const
ServiceDef
*
service_
;
};
class
FlatBufPrinter
:
public
grpc_
cpp_
generator
::
Printer
{
class
FlatBufPrinter
:
public
grpc_generator
::
Printer
{
public
:
FlatBufPrinter
(
std
::
string
*
str
)
:
str_
(
str
),
escape_char_
(
'$'
),
indent_
(
0
)
{}
...
...
@@ -133,7 +133,7 @@ class FlatBufPrinter : public grpc_cpp_generator::Printer {
int
indent_
;
};
class
FlatBufFile
:
public
grpc_
cpp_
generator
::
File
{
class
FlatBufFile
:
public
grpc_generator
::
File
{
public
:
FlatBufFile
(
const
Parser
&
parser
,
const
std
::
string
&
file_name
)
:
parser_
(
parser
),
file_name_
(
file_name
)
{}
...
...
@@ -163,13 +163,13 @@ class FlatBufFile : public grpc_cpp_generator::File {
return
static_cast
<
int
>
(
parser_
.
services_
.
vec
.
size
());
};
std
::
unique_ptr
<
const
grpc_
cpp_
generator
::
Service
>
service
(
int
i
)
const
{
return
std
::
unique_ptr
<
const
grpc_
cpp_
generator
::
Service
>
(
std
::
unique_ptr
<
const
grpc_generator
::
Service
>
service
(
int
i
)
const
{
return
std
::
unique_ptr
<
const
grpc_generator
::
Service
>
(
new
FlatBufService
(
parser_
.
services_
.
vec
[
i
]));
}
std
::
unique_ptr
<
grpc_
cpp_
generator
::
Printer
>
CreatePrinter
(
std
::
string
*
str
)
const
{
return
std
::
unique_ptr
<
grpc_
cpp_
generator
::
Printer
>
(
std
::
unique_ptr
<
grpc_generator
::
Printer
>
CreatePrinter
(
std
::
string
*
str
)
const
{
return
std
::
unique_ptr
<
grpc_generator
::
Printer
>
(
new
FlatBufPrinter
(
str
));
}
...
...
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