Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
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
abdullh.alsoleman
Front-End
Commits
8998167d
Unverified
Commit
8998167d
authored
Oct 06, 2020
by
Michael Goderbauer
Committed by
GitHub
Oct 06, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make FlutterErrorDetails.exception non-nullable as documented (#67364)
parent
1271447b
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
46 additions
and
47 deletions
+46
-47
assertions.dart
packages/flutter/lib/src/foundation/assertions.dart
+7
-6
binding.dart
packages/flutter/lib/src/foundation/binding.dart
+1
-1
binding.dart
packages/flutter/lib/src/gestures/binding.dart
+1
-1
image_provider.dart
packages/flutter/lib/src/painting/image_provider.dart
+5
-5
image_stream.dart
packages/flutter/lib/src/painting/image_stream.dart
+5
-5
object.dart
packages/flutter/lib/src/rendering/object.dart
+1
-1
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+2
-2
image.dart
packages/flutter/lib/src/widgets/image.dart
+1
-1
layout_builder.dart
packages/flutter/lib/src/widgets/layout_builder.dart
+1
-1
sliver.dart
packages/flutter/lib/src/widgets/sliver.dart
+1
-1
assertions_test.dart
packages/flutter/test/foundation/assertions_test.dart
+6
-8
error_reporting_test.dart
packages/flutter/test/foundation/error_reporting_test.dart
+3
-3
aspect_ratio_test.dart
packages/flutter/test/rendering/aspect_ratio_test.dart
+1
-1
rendering_tester.dart
packages/flutter/test/rendering/rendering_tester.dart
+1
-1
viewport_test.dart
packages/flutter/test/rendering/viewport_test.dart
+1
-1
custom_multi_child_layout_test.dart
.../flutter/test/widgets/custom_multi_child_layout_test.dart
+1
-1
list_body_test.dart
packages/flutter/test/widgets/list_body_test.dart
+2
-2
binding.dart
packages/flutter_test/lib/src/binding.dart
+3
-3
bindings_async_gap_test.dart
packages/flutter_test/test/bindings_async_gap_test.dart
+1
-1
flutter_test_config.dart
...t/test/custom_exception_reporter/flutter_test_config.dart
+1
-1
widget_tester_test.dart
packages/flutter_test/test/widget_tester_test.dart
+1
-1
No files found.
packages/flutter/lib/src/foundation/assertions.dart
View file @
8998167d
...
...
@@ -390,20 +390,20 @@ class FlutterErrorDetails with Diagnosticable {
/// their default values. (`throw null` results in a
/// [NullThrownError] exception.)
const
FlutterErrorDetails
({
this
.
exception
,
required
this
.
exception
,
this
.
stack
,
this
.
library
=
'Flutter framework'
,
this
.
context
,
this
.
stackFilter
,
this
.
informationCollector
,
this
.
silent
=
false
,
});
})
:
assert
(
exception
!=
null
)
;
/// Creates a copy of the error details but with the given fields replaced
/// with new values.
FlutterErrorDetails
copyWith
({
DiagnosticsNode
?
context
,
dynamic
exception
,
Object
?
exception
,
InformationCollector
?
informationCollector
,
String
?
library
,
bool
?
silent
,
...
...
@@ -437,7 +437,7 @@ class FlutterErrorDetails with Diagnosticable {
/// The exception. Often this will be an [AssertionError], maybe specifically
/// a [FlutterError]. However, this could be any value at all.
final
dynamic
exception
;
final
Object
exception
;
/// The stack trace from where the [exception] was thrown (as opposed to where
/// it was caught).
...
...
@@ -552,7 +552,7 @@ class FlutterErrorDetails with Diagnosticable {
// some code snippets. This leads to ugly messages. To avoid this, we move
// the assertion message up to before the code snippets, separated by a
// newline, if we recognize that format is being used.
final
Object
?
message
=
exception
.
message
;
final
Object
?
message
=
(
exception
as
AssertionError
)
.
message
;
final
String
fullMessage
=
exception
.
toString
();
if
(
message
is
String
&&
message
!=
fullMessage
)
{
if
(
fullMessage
.
length
>
message
.
length
)
{
...
...
@@ -586,8 +586,9 @@ class FlutterErrorDetails with Diagnosticable {
}
Diagnosticable
?
_exceptionToDiagnosticable
()
{
final
Object
exception
=
this
.
exception
;
if
(
exception
is
FlutterError
)
{
return
exception
as
FlutterError
;
return
exception
;
}
if
(
exception
is
AssertionError
&&
exception
.
message
is
FlutterError
)
{
return
exception
.
message
as
FlutterError
;
...
...
packages/flutter/lib/src/foundation/binding.dart
View file @
8998167d
...
...
@@ -539,7 +539,7 @@ abstract class BindingBase {
return
Future
<
void
>.
delayed
(
Duration
.
zero
);
});
dynamic
caughtException
;
Object
?
caughtException
;
StackTrace
?
caughtStack
;
late
Map
<
String
,
dynamic
>
result
;
try
{
...
...
packages/flutter/lib/src/gestures/binding.dart
View file @
8998167d
...
...
@@ -432,7 +432,7 @@ class FlutterErrorDetailsForPointerEventDispatcher extends FlutterErrorDetails {
/// The gesture library calls this constructor when catching an exception
/// that will subsequently be reported using [FlutterError.onError].
const
FlutterErrorDetailsForPointerEventDispatcher
({
dynamic
exception
,
required
Object
exception
,
StackTrace
?
stack
,
String
?
library
,
DiagnosticsNode
?
context
,
...
...
packages/flutter/lib/src/painting/image_provider.dart
View file @
8998167d
...
...
@@ -22,7 +22,7 @@ import 'image_stream.dart';
typedef
_KeyAndErrorHandlerCallback
<
T
>
=
void
Function
(
T
key
,
ImageErrorListener
handleError
);
/// Signature used for error handling by [_createErrorHandlerAndKey].
typedef
_AsyncKeyErrorHandler
<
T
>
=
Future
<
void
>
Function
(
T
key
,
dynamic
exception
,
StackTrace
?
stack
);
typedef
_AsyncKeyErrorHandler
<
T
>
=
Future
<
void
>
Function
(
T
key
,
Object
exception
,
StackTrace
?
stack
);
/// Configuration information passed to the [ImageProvider.resolve] method to
/// select a specific image.
...
...
@@ -335,7 +335,7 @@ abstract class ImageProvider<T extends Object> {
(
T
key
,
ImageErrorListener
errorHandler
)
{
resolveStreamForKey
(
configuration
,
stream
,
key
,
errorHandler
);
},
(
T
?
key
,
dynamic
exception
,
StackTrace
?
stack
)
async
{
(
T
?
key
,
Object
exception
,
StackTrace
?
stack
)
async
{
await
null
;
// wait an event turn in case a listener has been added to the image stream.
final
_ErrorImageCompleter
imageCompleter
=
_ErrorImageCompleter
();
stream
.
setCompleter
(
imageCompleter
);
...
...
@@ -391,7 +391,7 @@ abstract class ImageProvider<T extends Object> {
(
T
key
,
ImageErrorListener
innerHandleError
)
{
completer
.
complete
(
PaintingBinding
.
instance
!.
imageCache
!.
statusForKey
(
key
));
},
(
T
?
key
,
dynamic
exception
,
StackTrace
?
stack
)
async
{
(
T
?
key
,
Object
exception
,
StackTrace
?
stack
)
async
{
if
(
handleError
!=
null
)
{
handleError
(
exception
,
stack
);
}
else
{
...
...
@@ -427,7 +427,7 @@ abstract class ImageProvider<T extends Object> {
)
{
T
?
obtainedKey
;
bool
didError
=
false
;
Future
<
void
>
handleError
(
dynamic
exception
,
StackTrace
?
stack
)
async
{
Future
<
void
>
handleError
(
Object
exception
,
StackTrace
?
stack
)
async
{
if
(
didError
)
{
return
;
}
...
...
@@ -1118,7 +1118,7 @@ class _ErrorImageCompleter extends ImageStreamCompleter {
void
setError
({
DiagnosticsNode
?
context
,
dynamic
exception
,
required
Object
exception
,
StackTrace
?
stack
,
InformationCollector
?
informationCollector
,
bool
silent
=
false
,
...
...
packages/flutter/lib/src/painting/image_stream.dart
View file @
8998167d
...
...
@@ -233,7 +233,7 @@ typedef ImageChunkListener = void Function(ImageChunkEvent event);
///
/// Used in [ImageStreamListener], as well as by [ImageCache.putIfAbsent] and
/// [precacheImage], to report errors.
typedef
ImageErrorListener
=
void
Function
(
dynamic
exception
,
StackTrace
?
stackTrace
);
typedef
ImageErrorListener
=
void
Function
(
Object
exception
,
StackTrace
?
stackTrace
);
/// An immutable notification of image bytes that have been incrementally loaded.
///
...
...
@@ -655,7 +655,7 @@ abstract class ImageStreamCompleter with Diagnosticable {
@protected
void
reportError
({
DiagnosticsNode
?
context
,
dynamic
exception
,
required
Object
exception
,
StackTrace
?
stack
,
InformationCollector
?
informationCollector
,
bool
silent
=
false
,
...
...
@@ -747,7 +747,7 @@ class OneFrameImageStreamCompleter extends ImageStreamCompleter {
/// FlutterErrorDetails]).
OneFrameImageStreamCompleter
(
Future
<
ImageInfo
>
image
,
{
InformationCollector
?
informationCollector
})
:
assert
(
image
!=
null
)
{
image
.
then
<
void
>(
setImage
,
onError:
(
dynamic
error
,
StackTrace
stack
)
{
image
.
then
<
void
>(
setImage
,
onError:
(
Object
error
,
StackTrace
stack
)
{
reportError
(
context:
ErrorDescription
(
'resolving a single-frame image stream'
),
exception:
error
,
...
...
@@ -819,7 +819,7 @@ class MultiFrameImageStreamCompleter extends ImageStreamCompleter {
_informationCollector
=
informationCollector
,
_scale
=
scale
{
this
.
debugLabel
=
debugLabel
;
codec
.
then
<
void
>(
_handleCodecReady
,
onError:
(
dynamic
error
,
StackTrace
stack
)
{
codec
.
then
<
void
>(
_handleCodecReady
,
onError:
(
Object
error
,
StackTrace
stack
)
{
reportError
(
context:
ErrorDescription
(
'resolving an image codec'
),
exception:
error
,
...
...
@@ -830,7 +830,7 @@ class MultiFrameImageStreamCompleter extends ImageStreamCompleter {
});
if
(
chunkEvents
!=
null
)
{
chunkEvents
.
listen
(
reportImageChunkEvent
,
onError:
(
dynamic
error
,
StackTrace
stack
)
{
onError:
(
Object
error
,
StackTrace
stack
)
{
reportError
(
context:
ErrorDescription
(
'loading an image'
),
exception:
error
,
...
...
packages/flutter/lib/src/rendering/object.dart
View file @
8998167d
...
...
@@ -1307,7 +1307,7 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
/// Used in debug messages.
Object
?
debugCreator
;
void
_debugReportException
(
String
method
,
dynamic
exception
,
StackTrace
stack
)
{
void
_debugReportException
(
String
method
,
Object
exception
,
StackTrace
stack
)
{
FlutterError
.
reportError
(
FlutterErrorDetails
(
exception:
exception
,
stack:
stack
,
...
...
packages/flutter/lib/src/widgets/framework.dart
View file @
8998167d
...
...
@@ -4526,7 +4526,7 @@ class ErrorWidget extends LeafRenderObjectWidget {
message
=
_stringify
(
details
.
exception
)
+
'
\n
See also: https://flutter.dev/docs/testing/errors'
;
return
true
;
}());
final
dynamic
exception
=
details
.
exception
;
final
Object
exception
=
details
.
exception
;
return
ErrorWidget
.
withDetails
(
message:
message
,
error:
exception
is
FlutterError
?
exception
:
null
);
}
...
...
@@ -6312,7 +6312,7 @@ class DebugCreator {
FlutterErrorDetails
_debugReportException
(
DiagnosticsNode
context
,
dynamic
exception
,
Object
exception
,
StackTrace
?
stack
,
{
InformationCollector
?
informationCollector
,
})
{
...
...
packages/flutter/lib/src/widgets/image.dart
View file @
8998167d
...
...
@@ -123,7 +123,7 @@ Future<void> precacheImage(
stream
.
removeListener
(
listener
!);
});
},
onError:
(
dynamic
exception
,
StackTrace
?
stackTrace
)
{
onError:
(
Object
exception
,
StackTrace
?
stackTrace
)
{
if
(!
completer
.
isCompleted
)
{
completer
.
complete
();
}
...
...
packages/flutter/lib/src/widgets/layout_builder.dart
View file @
8998167d
...
...
@@ -393,7 +393,7 @@ class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<Ren
FlutterErrorDetails
_debugReportException
(
DiagnosticsNode
context
,
dynamic
exception
,
Object
exception
,
StackTrace
stack
,
{
InformationCollector
?
informationCollector
,
})
{
...
...
packages/flutter/lib/src/widgets/sliver.dart
View file @
8998167d
...
...
@@ -1670,7 +1670,7 @@ class KeepAlive extends ParentDataWidget<KeepAliveParentDataMixin> {
}
// Return a Widget for the given Exception
Widget
_createErrorWidget
(
dynamic
exception
,
StackTrace
stackTrace
)
{
Widget
_createErrorWidget
(
Object
exception
,
StackTrace
stackTrace
)
{
final
FlutterErrorDetails
details
=
FlutterErrorDetails
(
exception:
exception
,
stack:
stackTrace
,
...
...
packages/flutter/test/foundation/assertions_test.dart
View file @
8998167d
...
...
@@ -57,10 +57,10 @@ void main() {
'
\n
'
'INFO
\n
'
'═════════════════════════════════════════════════════════════════
\n
'
,
);
expect
(
FlutterErrorDetails
(
exception:
NullThrownError
(),
library
:
'LIBRARY'
,
context:
ErrorDescription
(
'CONTEXTING'
),
informationCollector:
()
sync
*
{
...
...
@@ -68,11 +68,10 @@ void main() {
},
).
toString
(),
'══╡ EXCEPTION CAUGHT BY LIBRARY ╞════════════════════════════════
\n
'
'The following Null object was thrown CONTEXTING:
\n
'
' null
\n
'
'The null value was thrown CONTEXTING.
\n
'
'
\n
'
'INFO
\n
'
'═════════════════════════════════════════════════════════════════
\n
'
,
'═════════════════════════════════════════════════════════════════
\n
'
);
expect
(
FlutterErrorDetails
(
...
...
@@ -114,11 +113,10 @@ void main() {
'═════════════════════════════════════════════════════════════════
\n
'
,
);
expect
(
const
FlutterErrorDetails
(
).
toString
(),
FlutterErrorDetails
(
exception:
NullThrownError
()
).
toString
(),
'══╡ EXCEPTION CAUGHT BY FLUTTER FRAMEWORK ╞══════════════════════
\n
'
'The following Null object was thrown:
\n
'
' null
\n
'
'═════════════════════════════════════════════════════════════════
\n
'
,
'The null value was thrown.
\n
'
'═════════════════════════════════════════════════════════════════
\n
'
);
});
...
...
packages/flutter/test/foundation/error_reporting_test.dart
View file @
8998167d
...
...
@@ -7,7 +7,7 @@
import
'package:flutter/foundation.dart'
;
import
'../flutter_test_alternative.dart'
;
dynamic
getAssertionErrorWithMessage
(
)
{
Object
getAssertionErrorWithMessage
(
)
{
try
{
assert
(
false
,
'Message goes here.'
);
}
catch
(
e
)
{
...
...
@@ -16,7 +16,7 @@ dynamic getAssertionErrorWithMessage() {
throw
'assert failed'
;
}
dynamic
getAssertionErrorWithoutMessage
(
)
{
Object
getAssertionErrorWithoutMessage
(
)
{
try
{
assert
(
false
);
}
catch
(
e
)
{
...
...
@@ -25,7 +25,7 @@ dynamic getAssertionErrorWithoutMessage() {
throw
'assert failed'
;
}
dynamic
getAssertionErrorWithLongMessage
(
)
{
Object
getAssertionErrorWithLongMessage
(
)
{
try
{
assert
(
false
,
'word '
*
100
);
}
catch
(
e
)
{
...
...
packages/flutter/test/rendering/aspect_ratio_test.dart
View file @
8998167d
...
...
@@ -117,7 +117,7 @@ void main() {
});
expect
(
errors
,
hasLength
(
2
));
expect
(
errors
.
first
.
exception
,
isFlutterError
);
expect
(
errors
.
first
.
exception
.
toStringDeep
(),
expect
(
(
errors
.
first
.
exception
as
FlutterError
)
.
toStringDeep
(),
'FlutterError
\n
'
' RenderAspectRatio has unbounded constraints.
\n
'
' This RenderAspectRatio was given an aspect ratio of 0.5 but was
\n
'
...
...
packages/flutter/test/rendering/rendering_tester.dart
View file @
8998167d
...
...
@@ -27,7 +27,7 @@ class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, Ser
TestRenderingFlutterBinding
({
this
.
onErrors
})
{
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
FlutterError
.
dumpErrorToConsole
(
details
);
Zone
.
current
.
parent
!.
handleUncaughtError
(
details
.
exception
as
Object
,
details
.
stack
!);
Zone
.
current
.
parent
!.
handleUncaughtError
(
details
.
exception
,
details
.
stack
!);
};
}
...
...
packages/flutter/test/rendering/viewport_test.dart
View file @
8998167d
...
...
@@ -1627,7 +1627,7 @@ void main() {
}
expect
(
errors
,
isNotEmpty
);
expect
(
errors
.
first
.
exception
,
isFlutterError
);
expect
(
errors
.
first
.
exception
.
toStringDeep
(),
message
);
expect
(
(
errors
.
first
.
exception
as
FlutterError
)
.
toStringDeep
(),
message
);
}
testWidgets
(
'Horizontal viewport was given unbounded height'
,
(
WidgetTester
tester
)
async
{
...
...
packages/flutter/test/widgets/custom_multi_child_layout_test.dart
View file @
8998167d
...
...
@@ -301,7 +301,7 @@ void main() {
expect
(
errors
.
length
,
isNonZero
);
expect
(
errors
.
first
,
isNotNull
);
expect
(
errors
.
first
.
exception
,
isFlutterError
);
expect
(
errors
.
first
.
exception
.
toStringDeep
(),
equalsIgnoringHashCodes
(
message
));
expect
(
(
errors
.
first
.
exception
as
FlutterError
)
.
toStringDeep
(),
equalsIgnoringHashCodes
(
message
));
}
testWidgets
(
'layoutChild on non existent child'
,
(
WidgetTester
tester
)
async
{
...
...
packages/flutter/test/widgets/list_body_test.dart
View file @
8998167d
...
...
@@ -134,7 +134,7 @@ void main() {
}
expect
(
errors
,
isNotEmpty
);
expect
(
errors
.
first
.
exception
,
isFlutterError
);
expect
(
errors
.
first
.
exception
.
toStringDeep
(),
equalsIgnoringHashCodes
(
expect
(
(
errors
.
first
.
exception
as
FlutterError
)
.
toStringDeep
(),
equalsIgnoringHashCodes
(
'FlutterError
\n
'
' RenderListBody must have unlimited space along its main axis.
\n
'
' RenderListBody does not clip or resize its children, so it must
\n
'
...
...
@@ -183,7 +183,7 @@ void main() {
}
expect
(
errors
,
isNotEmpty
);
expect
(
errors
.
first
.
exception
,
isFlutterError
);
expect
(
errors
.
first
.
exception
.
toStringDeep
(),
equalsIgnoringHashCodes
(
expect
(
(
errors
.
first
.
exception
as
FlutterError
)
.
toStringDeep
(),
equalsIgnoringHashCodes
(
'FlutterError
\n
'
' RenderListBody must have a bounded constraint for its cross axis.
\n
'
' RenderListBody forces its children to expand to fit the
\n
'
...
...
packages/flutter_test/lib/src/binding.dart
View file @
8998167d
...
...
@@ -686,7 +686,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
};
final
Completer
<
void
>
testCompleter
=
Completer
<
void
>();
final
VoidCallback
testCompletionHandler
=
_createTestCompletionHandler
(
description
,
testCompleter
);
void
handleUncaughtError
(
dynamic
exception
,
StackTrace
stack
)
{
void
handleUncaughtError
(
Object
exception
,
StackTrace
stack
)
{
if
(
testCompleter
.
isCompleted
)
{
// Well this is not a good sign.
// Ideally, once the test has failed we would stop getting errors from the test.
...
...
@@ -765,7 +765,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
_parentZone
!.
run
<
void
>(
testCompletionHandler
);
}
final
ZoneSpecification
errorHandlingZoneSpecification
=
ZoneSpecification
(
handleUncaughtError:
(
Zone
self
,
ZoneDelegate
parent
,
Zone
zone
,
dynamic
exception
,
StackTrace
stack
)
{
handleUncaughtError:
(
Zone
self
,
ZoneDelegate
parent
,
Zone
zone
,
Object
exception
,
StackTrace
stack
)
{
handleUncaughtError
(
exception
,
stack
);
}
);
...
...
@@ -1013,7 +1013,7 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
return
realAsyncZone
.
run
<
Future
<
T
>>(()
{
_pendingAsyncTasks
=
Completer
<
void
>();
return
callback
().
catchError
((
dynamic
exception
,
StackTrace
stack
)
{
return
callback
().
catchError
((
Object
exception
,
StackTrace
stack
)
{
FlutterError
.
reportError
(
FlutterErrorDetails
(
exception:
exception
,
stack:
stack
,
...
...
packages/flutter_test/test/bindings_async_gap_test.dart
View file @
8998167d
...
...
@@ -28,7 +28,7 @@ Future<void> main() async {
completer
.
future
.
then
(
(
String
value
)
{},
onError:
(
dynamic
error
,
StackTrace
stack
)
{
onError:
(
Object
error
,
StackTrace
stack
)
{
assert
(
stack
is
stack_trace
.
Chain
);
FlutterError
.
reportError
(
FlutterErrorDetails
(
exception:
error
,
...
...
packages/flutter_test/test/custom_exception_reporter/flutter_test_config.dart
View file @
8998167d
...
...
@@ -10,7 +10,7 @@ import 'package:flutter_test/flutter_test.dart';
Future
<
void
>
main
(
FutureOr
<
void
>
testMain
())
async
{
reportTestException
=
(
FlutterErrorDetails
details
,
String
testDescription
)
{
expect
(
details
.
exception
,
isA
<
StateError
>());
expect
(
details
.
exception
.
message
,
'foo'
);
expect
(
(
details
.
exception
as
StateError
)
.
message
,
'foo'
);
expect
(
testDescription
,
'custom exception reporter'
);
};
...
...
packages/flutter_test/test/widget_tester_test.dart
View file @
8998167d
...
...
@@ -737,7 +737,7 @@ void main() {
},
()
{});
expect
(
flutterErrorDetails
.
exception
,
isA
<
AssertionError
>());
expect
(
flutterErrorDetails
.
exception
!
.
message
,
'A Timer is still pending even after the widget tree was disposed.'
);
expect
(
(
flutterErrorDetails
.
exception
as
AssertionError
)
.
message
,
'A Timer is still pending even after the widget tree was disposed.'
);
});
});
}
...
...
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