Skip to content
Snippets Groups Projects
Commit 13cd1256 authored by Jan Tattermusch's avatar Jan Tattermusch
Browse files

Used StyleCop to get rid of tabs in the source code

parent 49fd7fe1
No related branches found
No related tags found
No related merge requests found
*.userprefs
StyleCop.Cache
test-results
packages
Grpc.v12.suo
......
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
......@@ -30,7 +29,6 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
......@@ -38,13 +36,12 @@ using Grpc.Core;
namespace Grpc.Core.Internal
{
internal delegate void CompletionCallbackDelegate(GRPCOpError error, IntPtr batchContextPtr);
internal delegate void CompletionCallbackDelegate(GRPCOpError error,IntPtr batchContextPtr);
/// <summary>
/// grpc_call from <grpc/grpc.h>
/// </summary>
internal class CallSafeHandle : SafeHandleZeroIsInvalid
{
internal class CallSafeHandle : SafeHandleZeroIsInvalid
{
const UInt32 GRPC_WRITE_BUFFER_HINT = 1;
[DllImport("grpc_csharp_ext.dll")]
......@@ -58,22 +55,22 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_unary(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
byte[] send_buffer, UIntPtr send_buffer_len);
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
byte[] send_buffer, UIntPtr send_buffer_len);
[DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_call_blocking_unary(CallSafeHandle call, CompletionQueueSafeHandle dedicatedCq,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
byte[] send_buffer, UIntPtr send_buffer_len);
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
byte[] send_buffer, UIntPtr send_buffer_len);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_client_streaming(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_server_streaming(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
byte[] send_buffer, UIntPtr send_buffer_len);
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
byte[] send_buffer, UIntPtr send_buffer_len);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_duplex_streaming(CallSafeHandle call,
......@@ -81,28 +78,27 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_send_message(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
byte[] send_buffer, UIntPtr send_buffer_len);
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback,
byte[] send_buffer, UIntPtr send_buffer_len);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_send_close_from_client(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_send_status_from_server(CallSafeHandle call, [MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback, StatusCode statusCode, string statusMessage);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_recv_message(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
[DllImport("grpc_csharp_ext.dll")]
static extern GRPCCallError grpcsharp_call_start_serverside(CallSafeHandle call,
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
[MarshalAs(UnmanagedType.FunctionPtr)] CompletionCallbackDelegate callback);
[DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_call_destroy(IntPtr call);
private CallSafeHandle()
{
}
......@@ -114,12 +110,12 @@ namespace Grpc.Core.Internal
public void StartUnary(byte[] payload, CompletionCallbackDelegate callback)
{
AssertCallOk(grpcsharp_call_start_unary(this, callback, payload, new UIntPtr((ulong) payload.Length)));
AssertCallOk(grpcsharp_call_start_unary(this, callback, payload, new UIntPtr((ulong)payload.Length)));
}
public void BlockingUnary(CompletionQueueSafeHandle dedicatedCq, byte[] payload, CompletionCallbackDelegate callback)
{
grpcsharp_call_blocking_unary(this, dedicatedCq, callback, payload, new UIntPtr((ulong) payload.Length));
grpcsharp_call_blocking_unary(this, dedicatedCq, callback, payload, new UIntPtr((ulong)payload.Length));
}
public void StartClientStreaming(CompletionCallbackDelegate callback)
......@@ -129,7 +125,7 @@ namespace Grpc.Core.Internal
public void StartServerStreaming(byte[] payload, CompletionCallbackDelegate callback)
{
AssertCallOk(grpcsharp_call_start_server_streaming(this, callback, payload, new UIntPtr((ulong) payload.Length)));
AssertCallOk(grpcsharp_call_start_server_streaming(this, callback, payload, new UIntPtr((ulong)payload.Length)));
}
public void StartDuplexStreaming(CompletionCallbackDelegate callback)
......@@ -139,7 +135,7 @@ namespace Grpc.Core.Internal
public void StartSendMessage(byte[] payload, CompletionCallbackDelegate callback)
{
AssertCallOk(grpcsharp_call_send_message(this, callback, payload, new UIntPtr((ulong) payload.Length)));
AssertCallOk(grpcsharp_call_send_message(this, callback, payload, new UIntPtr((ulong)payload.Length)));
}
public void StartSendCloseFromClient(CompletionCallbackDelegate callback)
......@@ -172,19 +168,20 @@ namespace Grpc.Core.Internal
AssertCallOk(grpcsharp_call_cancel_with_status(this, status.StatusCode, status.Detail));
}
protected override bool ReleaseHandle()
{
protected override bool ReleaseHandle()
{
grpcsharp_call_destroy(handle);
return true;
}
return true;
}
private static void AssertCallOk(GRPCCallError callError)
{
Trace.Assert(callError == GRPCCallError.GRPC_CALL_OK, "Status not GRPC_CALL_OK");
}
private static UInt32 GetFlags(bool buffered) {
private static UInt32 GetFlags(bool buffered)
{
return buffered ? 0 : GRPC_WRITE_BUFFER_HINT;
}
}
}
}
\ No newline at end of file
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
......@@ -28,43 +27,40 @@
// 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.
#endregion
using System;
using Grpc.Core.Internal;
namespace Grpc.Core.Internal
{
internal class ClientStreamingInputObserver<TWrite, TRead> : IObserver<TWrite>
{
{
readonly AsyncCall<TWrite, TRead> call;
public ClientStreamingInputObserver(AsyncCall<TWrite, TRead> call)
{
{
this.call = call;
}
}
public void OnCompleted()
{
public void OnCompleted()
{
var taskSource = new AsyncCompletionTaskSource();
call.StartSendCloseFromClient(taskSource.CompletionDelegate);
// TODO: how bad is the Wait here?
taskSource.Task.Wait();
}
}
public void OnError(Exception error)
{
throw new InvalidOperationException("This should never be called.");
}
public void OnError(Exception error)
{
throw new InvalidOperationException("This should never be called.");
}
public void OnNext(TWrite value)
{
public void OnNext(TWrite value)
{
var taskSource = new AsyncCompletionTaskSource();
call.StartSendMessage(value, taskSource.CompletionDelegate);
// TODO: how bad is the Wait here?
taskSource.Task.Wait();
}
}
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
......@@ -28,9 +27,7 @@
// 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.
#endregion
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
......@@ -40,8 +37,8 @@ namespace Grpc.Core.Internal
/// <summary>
/// grpc_completion_queue from <grpc/grpc.h>
/// </summary>
internal class CompletionQueueSafeHandle : SafeHandleZeroIsInvalid
{
internal class CompletionQueueSafeHandle : SafeHandleZeroIsInvalid
{
[DllImport("grpc_csharp_ext.dll")]
static extern CompletionQueueSafeHandle grpcsharp_completion_queue_create();
......@@ -73,11 +70,11 @@ namespace Grpc.Core.Internal
grpcsharp_completion_queue_shutdown(this);
}
protected override bool ReleaseHandle()
protected override bool ReleaseHandle()
{
grpcsharp_completion_queue_destroy(handle);
return true;
}
}
return true;
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
......@@ -28,9 +27,7 @@
// 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.
#endregion
using System;
using Grpc.Core.Internal;
......@@ -41,35 +38,35 @@ namespace Grpc.Core.Internal
/// and then halfcloses the call. Used for server-side call handling.
/// </summary>
internal class ServerStreamingOutputObserver<TRequest, TResponse> : IObserver<TResponse>
{
{
readonly AsyncCallServer<TRequest, TResponse> call;
public ServerStreamingOutputObserver(AsyncCallServer<TRequest, TResponse> call)
{
{
this.call = call;
}
}
public void OnCompleted()
{
public void OnCompleted()
{
var taskSource = new AsyncCompletionTaskSource();
call.StartSendStatusFromServer(new Status(StatusCode.OK, ""), taskSource.CompletionDelegate);
// TODO: how bad is the Wait here?
taskSource.Task.Wait();
}
}
public void OnError(Exception error)
{
public void OnError(Exception error)
{
// TODO: implement this...
throw new InvalidOperationException("This should never be called.");
}
throw new InvalidOperationException("This should never be called.");
}
public void OnNext(TResponse value)
{
public void OnNext(TResponse value)
{
var taskSource = new AsyncCompletionTaskSource();
call.StartSendMessage(value, taskSource.CompletionDelegate);
// TODO: how bad is the Wait here?
taskSource.Task.Wait();
}
}
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
......@@ -28,21 +27,19 @@
// 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.
#endregion
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace Grpc.Core.Internal
{
/// <summary>
/// gpr_timespec from grpc/support/time.h
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct Timespec
{
/// <summary>
/// gpr_timespec from grpc/support/time.h
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct Timespec
{
const int nanosPerSecond = 1000 * 1000 * 1000;
const int nanosPerTick = 100;
......@@ -54,23 +51,22 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
static extern int gprsharp_sizeof_timespec();
// TODO: revisit this.
// NOTE: on linux 64bit sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8
// NOTE: on linux 64bit sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8
// so IntPtr seems to have the right size to work on both.
public System.IntPtr tv_sec;
public System.IntPtr tv_nsec;
public System.IntPtr tv_sec;
public System.IntPtr tv_nsec;
/// <summary>
/// Timespec a long time in the future.
/// </summary>
public static Timespec InfFuture
{
get
{
/// <summary>
/// Timespec a long time in the future.
/// </summary>
public static Timespec InfFuture
{
get
{
return gprsharp_inf_future();
}
}
}
}
public static Timespec Now
{
......@@ -92,7 +88,8 @@ namespace Grpc.Core.Internal
/// Creates a GPR deadline from current instant and given timeout.
/// </summary>
/// <returns>The from timeout.</returns>
public static Timespec DeadlineFromTimeout(TimeSpan timeout) {
public static Timespec DeadlineFromTimeout(TimeSpan timeout)
{
if (timeout == Timeout.InfiniteTimeSpan)
{
return Timespec.InfFuture;
......@@ -100,7 +97,8 @@ namespace Grpc.Core.Internal
return Timespec.Now.Add(timeout);
}
public Timespec Add(TimeSpan timeSpan) {
public Timespec Add(TimeSpan timeSpan)
{
long nanos = tv_nsec.ToInt64() + (timeSpan.Ticks % TimeSpan.TicksPerSecond) * nanosPerTick;
long overflow_sec = (nanos > nanosPerSecond) ? 1 : 0;
......@@ -109,6 +107,6 @@ namespace Grpc.Core.Internal
result.tv_sec = new IntPtr(tv_sec.ToInt64() + (timeSpan.Ticks / TimeSpan.TicksPerSecond) + overflow_sec);
return result;
}
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
......@@ -28,7 +27,6 @@
// 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.
#endregion
using System;
......@@ -36,40 +34,40 @@ using System.Runtime.InteropServices;
namespace Grpc.Core
{
/// <summary>
/// Represents RPC result.
/// </summary>
public struct Status
{
readonly StatusCode statusCode;
readonly string detail;
/// <summary>
/// Represents RPC result.
/// </summary>
public struct Status
{
readonly StatusCode statusCode;
readonly string detail;
public Status(StatusCode statusCode, string detail)
{
this.statusCode = statusCode;
this.detail = detail;
}
public Status(StatusCode statusCode, string detail)
{
this.statusCode = statusCode;
this.detail = detail;
}
/// <summary>
/// Gets the gRPC status code. OK indicates success, all other values indicate an error.
/// </summary>
public StatusCode StatusCode
{
get
{
return statusCode;
}
}
public StatusCode StatusCode
{
get
{
return statusCode;
}
}
/// <summary>
/// Gets the detail.
/// </summary>
public string Detail
{
get
{
return detail;
}
}
}
public string Detail
{
get
{
return detail;
}
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
......@@ -28,9 +27,7 @@
// 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.
#endregion
using System;
using System.Runtime.InteropServices;
using System.Threading;
......@@ -38,25 +35,25 @@ using Grpc.Core;
namespace math
{
class MathClient
class MathClient
{
public static void Main (string[] args)
{
public static void Main(string[] args)
{
GrpcEnvironment.Initialize();
using (Channel channel = new Channel("127.0.0.1:23456"))
{
MathGrpc.IMathServiceClient stub = new MathGrpc.MathServiceClientStub(channel);
MathExamples.DivExample(stub);
using (Channel channel = new Channel("127.0.0.1:23456"))
{
MathGrpc.IMathServiceClient stub = new MathGrpc.MathServiceClientStub(channel);
MathExamples.DivExample(stub);
MathExamples.FibExample(stub);
MathExamples.SumExample(stub);
MathExamples.SumExample(stub);
MathExamples.DivManyExample(stub);
}
MathExamples.DivManyExample(stub);
}
GrpcEnvironment.Shutdown();
}
}
}
}
}
#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
......@@ -28,7 +27,6 @@
// 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.
#endregion
using System;
......@@ -39,59 +37,63 @@ using Grpc.Core.Utils;
namespace math
{
public static class MathExamples
{
public static void DivExample(MathGrpc.IMathServiceClient stub)
{
DivReply result = stub.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
Console.WriteLine("Div Result: " + result);
}
public static void DivAsyncExample(MathGrpc.IMathServiceClient stub)
{
Task<DivReply> call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
DivReply result = call.Result;
Console.WriteLine(result);
}
public static void DivAsyncWithCancellationExample(MathGrpc.IMathServiceClient stub)
{
Task<DivReply> call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
DivReply result = call.Result;
Console.WriteLine(result);
}
public static void FibExample(MathGrpc.IMathServiceClient stub)
{
public static class MathExamples
{
public static void DivExample(MathGrpc.IMathServiceClient stub)
{
DivReply result = stub.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build());
Console.WriteLine("Div Result: " + result);
}
public static void DivAsyncExample(MathGrpc.IMathServiceClient stub)
{
Task<DivReply> call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
DivReply result = call.Result;
Console.WriteLine(result);
}
public static void DivAsyncWithCancellationExample(MathGrpc.IMathServiceClient stub)
{
Task<DivReply> call = stub.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build());
DivReply result = call.Result;
Console.WriteLine(result);
}
public static void FibExample(MathGrpc.IMathServiceClient stub)
{
var recorder = new RecordingObserver<Num>();
stub.Fib(new FibArgs.Builder { Limit = 5 }.Build(), recorder);
List<Num> numbers = recorder.ToList().Result;
List<Num> numbers = recorder.ToList().Result;
Console.WriteLine("Fib Result: " + string.Join("|", recorder.ToList().Result));
}
}
public static void SumExample(MathGrpc.IMathServiceClient stub)
{
List<Num> numbers = new List<Num>{new Num.Builder { Num_ = 1 }.Build(),
new Num.Builder { Num_ = 2 }.Build(),
new Num.Builder { Num_ = 3 }.Build()};
public static void SumExample(MathGrpc.IMathServiceClient stub)
{
List<Num> numbers = new List<Num>
{new Num.Builder { Num_ = 1 }.Build(),
new Num.Builder { Num_ = 2 }.Build(),
new Num.Builder { Num_ = 3 }.Build()
};
var res = stub.Sum();
foreach (var num in numbers) {
foreach (var num in numbers)
{
res.Inputs.OnNext(num);
}
res.Inputs.OnCompleted();
Console.WriteLine("Sum Result: " + res.Task.Result);
}
Console.WriteLine("Sum Result: " + res.Task.Result);
}
public static void DivManyExample(MathGrpc.IMathServiceClient stub)
{
List<DivArgs> divArgsList = new List<DivArgs>{
new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
};
public static void DivManyExample(MathGrpc.IMathServiceClient stub)
{
List<DivArgs> divArgsList = new List<DivArgs>
{
new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(),
new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(),
new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build()
};
var recorder = new RecordingObserver<DivReply>();
......@@ -102,30 +104,30 @@ namespace math
}
inputs.OnCompleted();
Console.WriteLine("DivMany Result: " + string.Join("|", recorder.ToList().Result));
}
Console.WriteLine("DivMany Result: " + string.Join("|", recorder.ToList().Result));
}
public static void DependendRequestsExample(MathGrpc.IMathServiceClient stub)
{
var numberList = new List<Num>
{ new Num.Builder{ Num_ = 1 }.Build(),
new Num.Builder{ Num_ = 2 }.Build(), new Num.Builder{ Num_ = 3 }.Build()
};
public static void DependendRequestsExample(MathGrpc.IMathServiceClient stub)
{
var numberList = new List<Num>
{ new Num.Builder{ Num_ = 1 }.Build(),
new Num.Builder{ Num_ = 2 }.Build(), new Num.Builder{ Num_ = 3 }.Build()
};
numberList.ToObservable();
numberList.ToObservable();
//IObserver<Num> numbers;
//Task<Num> call = stub.Sum(out numbers);
//foreach (var num in numberList)
//{
// numbers.OnNext(num);
//}
//numbers.OnCompleted();
//IObserver<Num> numbers;
//Task<Num> call = stub.Sum(out numbers);
//foreach (var num in numberList)
//{
// numbers.OnNext(num);
//}
//numbers.OnCompleted();
//Num sum = call.Result;
//Num sum = call.Result;
//DivReply result = stub.Div(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numberList.Count }.Build());
}
}
//DivReply result = stub.Div(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numberList.Count }.Build());
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment