Commit f804579a authored by weinig@apple.com's avatar weinig@apple.com

2008-04-22 Sam Weinig <sam@webkit.org>

        Reviewed by Geoffrey Garen.

        Make DOMAbstractView have a weak reference to the Frame instead of ref'ing
        the DOMWindow.

        To ensure that the WindowScriptObject (which is a DOMAbstractView) stays valid
        after a navigation once the split window is completed, the DOMAbstractView must
        wrap the Frame instead of a DOMWindow since the DOMWindow will change.

        * WebCore.xcodeproj/project.pbxproj:
        * bindings/objc/DOMAbstractView.mm: Added.
        (-[DOMAbstractView dealloc]):
        (-[DOMAbstractView finalize]):
        (-[DOMAbstractView document]):
        (-[DOMAbstractView _disconnectFrame]):
        (-[DOMAbstractView WebCore::]):
        (-[DOMAbstractView _initWithFrame:WebCore::]):
        (+[DOMAbstractView _wrapAbstractView:WebCore::]):
        Add custom implementation to implement weak reference semantics.

        * bindings/objc/DOMAbstractViewFrame.h: Added.
        Declare the [DOMAbstractView _disconectFrame] selector.
        * bindings/objc/DOMInternal.h:
        Remove DOMRGBColor Internal category since it is now generated.

        * bindings/objc/DOMUtility.mm:
        (KJS::createDOMWrapper):
        Don't ever create a DOMAbstractView from a JSDOMWindow, only from JSDOMWindowWrapper.

        * bindings/scripts/CodeGeneratorObjC.pm:
        Generate internal header for IDLs that want custom implementations.

        * css/RGBColor.idl:
        Make this a PODType as it really is in the implementation.

        * page/AbstractView.idl:
        This now needs a custom objective-c binding implementation.

        * page/Frame.cpp:
        (WebCore::Frame::~Frame):
        disconnect the weak frame reference in the WindowScriptObject.

        * page/Frame.h:
        * page/gtk/FrameGtk.cpp:
        (WebCore::Frame::disconnectPlatformScriptObjects): Dummy implementation.
        * page/mac/FrameMac.mm:
        (WebCore::Frame::windowScriptObject): ASSERT that the windowScriptObject is a DOMAbstractView.
        (WebCore::Frame::disconnectPlatformScriptObjects): Disconnect the frame pointer from the windowScriptObject.
        * page/qt/FrameQt.cpp:
        (WebCore::Frame::disconnectPlatformScriptObjects): Dummy implementation.
        * page/win/FrameWin.cpp:
        (WebCore::Frame::disconnectPlatformScriptObjects): Ditto.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@32405 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 9af89da0
2008-04-22 Sam Weinig <sam@webkit.org>
Reviewed by Geoffrey Garen.
Make DOMAbstractView have a weak reference to the Frame instead of ref'ing
the DOMWindow.
To ensure that the WindowScriptObject (which is a DOMAbstractView) stays valid
after a navigation once the split window is completed, the DOMAbstractView must
wrap the Frame instead of a DOMWindow since the DOMWindow will change.
* WebCore.xcodeproj/project.pbxproj:
* bindings/objc/DOMAbstractView.mm: Added.
(-[DOMAbstractView dealloc]):
(-[DOMAbstractView finalize]):
(-[DOMAbstractView document]):
(-[DOMAbstractView _disconnectFrame]):
(-[DOMAbstractView WebCore::]):
(-[DOMAbstractView _initWithFrame:WebCore::]):
(+[DOMAbstractView _wrapAbstractView:WebCore::]):
Add custom implementation to implement weak reference semantics.
* bindings/objc/DOMAbstractViewFrame.h: Added.
Declare the [DOMAbstractView _disconectFrame] selector.
* bindings/objc/DOMInternal.h:
Remove DOMRGBColor Internal category since it is now generated.
* bindings/objc/DOMUtility.mm:
(KJS::createDOMWrapper):
Don't ever create a DOMAbstractView from a JSDOMWindow, only from JSDOMWindowWrapper.
* bindings/scripts/CodeGeneratorObjC.pm:
Generate internal header for IDLs that want custom implementations.
* css/RGBColor.idl:
Make this a PODType as it really is in the implementation.
* page/AbstractView.idl:
This now needs a custom objective-c binding implementation.
* page/Frame.cpp:
(WebCore::Frame::~Frame):
disconnect the weak frame reference in the WindowScriptObject.
* page/Frame.h:
* page/gtk/FrameGtk.cpp:
(WebCore::Frame::disconnectPlatformScriptObjects): Dummy implementation.
* page/mac/FrameMac.mm:
(WebCore::Frame::windowScriptObject): ASSERT that the windowScriptObject is a DOMAbstractView.
(WebCore::Frame::disconnectPlatformScriptObjects): Disconnect the frame pointer from the windowScriptObject.
* page/qt/FrameQt.cpp:
(WebCore::Frame::disconnectPlatformScriptObjects): Dummy implementation.
* page/win/FrameWin.cpp:
(WebCore::Frame::disconnectPlatformScriptObjects): Ditto.
2008-04-22 Dan Bernstein <mitz@apple.com>
Reviewed by Sam Weinig.
This diff is collapsed.
/*
* Copyright (C) 2008 Apple 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
*/
#import "config.h"
#import "DOMAbstractView.h"
#import "DOMDocument.h"
#import "DOMInternal.h"
#import "DOMWindow.h"
#import "Document.h"
#import "ExceptionHandlers.h"
#import "Frame.h"
#import "ThreadCheck.h"
#import <wtf/GetPtr.h>
#define IMPL reinterpret_cast<WebCore::Frame*>(_internal)
@implementation DOMAbstractView
- (void)dealloc
{
{ DOM_ASSERT_MAIN_THREAD(); WebCoreThreadViolationCheck(); }
[super dealloc];
}
- (void)finalize
{
[super finalize];
}
- (DOMDocument *)document
{
if (!_internal)
return nil;
return [DOMDocument _wrapDocument:WTF::getPtr(IMPL->domWindow()->document())];
}
@end
@implementation DOMAbstractView (Frame)
- (void)_disconnectFrame
{
ASSERT(_internal);
WebCore::removeDOMWrapper(_internal);
_internal = 0;
}
@end
@implementation DOMAbstractView (WebCoreInternal)
- (WebCore::DOMWindow *)_abstractView
{
if (!_internal)
return nil;
return IMPL->domWindow();
}
- (id)_initWithFrame:(WebCore::Frame *)impl
{
{ DOM_ASSERT_MAIN_THREAD(); WebCoreThreadViolationCheck(); };
[super _init];
_internal = reinterpret_cast<DOMObjectInternal*>(impl);
WebCore::addDOMWrapper(self, impl);
return self;
}
+ (DOMAbstractView *)_wrapAbstractView:(WebCore::DOMWindow *)impl
{
{ DOM_ASSERT_MAIN_THREAD(); WebCoreThreadViolationCheck(); };
if (!impl)
return nil;
WebCore::Frame* frame = impl->frame();
if (!frame)
return nil;
id cachedInstance;
cachedInstance = WebCore::getDOMWrapper(frame);
if (cachedInstance)
return [[cachedInstance retain] autorelease];
return [[[self alloc] _initWithFrame:frame] autorelease];
}
@end
/*
* Copyright (C) 2008 Apple 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:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
*/
#import <WebCore/DOMAbstractView.h>
@interface DOMAbstractView (Frame)
- (void)_disconnectFrame;
@end
......@@ -27,9 +27,7 @@
#import "DOM.h"
#import "Color.h"
#import "DOMObject.h"
#import "DOMRGBColor.h"
#import "HitTestResult.h"
#if ENABLE(XPATH)
......@@ -136,12 +134,13 @@
#import "DOMNotationInternal.h"
#import "DOMOverflowEventInternal.h"
#import "DOMProcessingInstructionInternal.h"
#import "DOMRGBColorInternal.h"
#import "DOMRangeInternal.h"
#import "DOMRectInternal.h"
#import "DOMStyleSheetInternal.h"
#import "DOMStyleSheetListInternal.h"
#import "DOMTextInternal.h"
#import "DOMTextEventInternal.h"
#import "DOMTextInternal.h"
#import "DOMTreeWalkerInternal.h"
#import "DOMUIEventInternal.h"
#import "DOMWheelEventInternal.h"
......@@ -308,13 +307,6 @@ namespace WebCore {
- (id)_init;
@end
// CSS Internal Interfaces
@interface DOMRGBColor (WebCoreInternal)
+ (DOMRGBColor *)_wrapRGBColor:(WebCore::RGBA32)value;
- (WebCore::RGBA32)_RGBColor;
@end
// Traversal Internal Interfaces
@interface DOMNodeFilter : DOMObject <DOMNodeFilter>
......
......@@ -100,8 +100,6 @@ static inline id createDOMWrapper(KJS::JSObject* object)
#undef WRAP
if (object->inherits(&WebCore::JSDOMWindow::s_info))
return [DOMAbstractView _wrapAbstractView:static_cast<WebCore::JSDOMWindow*>(object)->impl()];
if (object->inherits(&WebCore::JSDOMWindowWrapper::s_info))
return [DOMAbstractView _wrapAbstractView:static_cast<WebCore::JSDOMWindowWrapper*>(object)->impl()];
......
......@@ -478,7 +478,7 @@ sub GetObjCTypeGetterName
my $type = $codeGenerator->StripModule(shift);
my $typeGetter = "";
if ($type =~ /^(HTML|CSS|SVG)/ or $type eq "DOMImplementation" or $type eq "CDATASection") {
if ($type =~ /^(HTML|CSS|SVG)/ or $type eq "DOMImplementation" or $type eq "CDATASection" or $type eq "RGBColor") {
$typeGetter = $type;
} elsif ($type =~ /^XPath(.+)/) {
$typeGetter = "xpath" . $1;
......@@ -508,6 +508,58 @@ sub GetObjCTypeGetter
return "[$argName $typeGetterMethodName]";
}
sub GetInternalTypeGetterSignature
{
my ($interfaceName, $podType) = @_;
my $implClassNameWithNamespace = "WebCore::" . GetImplClassName($interfaceName);
my $podTypeWithNamespace;
if ($podType) {
$podTypeWithNamespace = ($podType eq "float") ? "$podType" : "WebCore::$podType";
}
# - Type-Getter
# - (WebCore::FooBar *)_fooBar for implementation class FooBar
my $typeGetterName = GetObjCTypeGetterName($interfaceName);
return "- " . ($podType ? "($podTypeWithNamespace)" : "($implClassNameWithNamespace *)") . $typeGetterName;
}
sub GetInternalTypeMakerSignature
{
my ($interfaceName, $podType) = @_;
my $className = GetClassName($interfaceName);
my $implClassNameWithNamespace = "WebCore::" . GetImplClassName($interfaceName);
my $podTypeWithNamespace;
if ($podType) {
$podTypeWithNamespace = ($podType eq "float") ? "$podType" : "WebCore::$podType";
}
my @ivarsToRetain = ();
my $ivarsToInit = "";
my $typeMakerSigAddition = "";
if (@ivars > 0) {
my @ivarsInitSig = ();
my @ivarsInitCall = ();
foreach $attribute (@ivars) {
my $name = $attribute->signature->name;
my $memberName = "m_" . $name;
my $varName = "in" . $name;
my $type = GetObjCType($attribute->signature->type);
push(@ivarsInitSig, "$name:($type)$varName");
push(@ivarsInitCall, "$name:$varName");
push(@ivarsToRetain, " $memberName = [$varName retain];\n");
}
$ivarsToInit = " " . join(" ", @ivarsInitCall);
$typeMakerSigAddition = " " . join(" ", @ivarsInitSig);
}
my $typeMakerName = GetObjCTypeMaker($interfaceName);
return ("+ ($className *)$typeMakerName:(" . ($podType ? "$podTypeWithNamespace" : "$implClassNameWithNamespace *") . ")impl" . $typeMakerSigAddition,
$typeMakerSigAddition,
$ivarsToInit);
}
sub AddForwardDeclarationsForType
{
my $type = $codeGenerator->StripModule(shift);
......@@ -896,6 +948,42 @@ sub GenerateHeader
push(@privateHeaderContent, @privateHeaderFunctions) if @privateHeaderFunctions > 0;
push(@privateHeaderContent, "\@end\n");
}
unless ($isProtocol) {
# Generate internal interfaces
my $podType = $dataNode->extendedAttributes->{"PODType"};
my $typeGetterSig = GetInternalTypeGetterSignature($interfaceName, $podType);
my ($typeMakerSig, $typeMakerSigAddition, $ivarsToInit) = GetInternalTypeMakerSignature($interfaceName, $podType);
# Generate interface definitions.
@internalHeaderContent = split("\r", $implementationLicenceTemplate);
push(@internalHeaderContent, "\n#import <WebCore/$className.h>\n");
if ($interfaceName eq "Node") {
push(@internalHeaderContent, "\n\@protocol DOMEventTarget;\n");
}
if ($codeGenerator->IsSVGAnimatedType($interfaceName)) {
push(@internalHeaderContent, "#import <WebCore/SVGAnimatedTemplate.h>\n\n");
} elsif ($interfaceName eq "RGBColor") {
push(@internalHeaderContent, "#import <WebCore/Color.h>\n\n");
} else {
if ($podType and $podType ne "float") {
push(@internalHeaderContent, "\nnamespace WebCore { class $podType; }\n\n");
} elsif ($interfaceName eq "Node") {
push(@internalHeaderContent, "\nnamespace WebCore { class Node; class EventTarget; }\n\n");
} else {
my $implClassName = GetImplClassName($interfaceName);
push(@internalHeaderContent, "\nnamespace WebCore { class $implClassName; }\n\n");
}
}
push(@internalHeaderContent, "\@interface $className (WebCoreInternal)\n");
push(@internalHeaderContent, $typeGetterSig . ";\n");
push(@internalHeaderContent, $typeMakerSig . ";\n");
if ($interfaceName eq "Node") {
push(@internalHeaderContent, "+ (id <DOMEventTarget>)_wrapEventTarget:(WebCore::EventTarget *)eventTarget;\n");
}
push(@internalHeaderContent, "\@end\n");
}
}
sub GenerateImplementation
......@@ -1401,66 +1489,11 @@ sub GenerateImplementation
# Generate internal interfaces
# - Type-Getter
# - (WebCore::FooBar *)_fooBar for implementation class FooBar
my $typeGetterName = GetObjCTypeGetterName($interfaceName);
my $typeGetterSig = "- " . ($podType ? "($podTypeWithNamespace)" : "($implClassNameWithNamespace *)") . $typeGetterName;
my @ivarsToRetain = ();
my $ivarsToInit = "";
my $typeMakerSigAddition = "";
if (@ivars > 0) {
my @ivarsInitSig = ();
my @ivarsInitCall = ();
foreach $attribute (@ivars) {
my $name = $attribute->signature->name;
my $memberName = "m_" . $name;
my $varName = "in" . $name;
my $type = GetObjCType($attribute->signature->type);
push(@ivarsInitSig, "$name:($type)$varName");
push(@ivarsInitCall, "$name:$varName");
push(@ivarsToRetain, " $memberName = [$varName retain];\n");
}
$ivarsToInit = " " . join(" ", @ivarsInitCall);
$typeMakerSigAddition = " " . join(" ", @ivarsInitSig);
}
# - Type-Maker
my $typeMakerName = GetObjCTypeMaker($interfaceName);
my $typeMakerSig = "+ ($className *)$typeMakerName:($implClassNameWithNamespace *)impl" . $typeMakerSigAddition;
$typeMakerSig = "+ ($className *)$typeMakerName:($podTypeWithNamespace)impl" . $typeMakerSigAddition if $podType;
# Generate interface definitions.
@internalHeaderContent = split("\r", $implementationLicenceTemplate);
push(@internalHeaderContent, "\n#import <WebCore/$className.h>\n");
if ($interfaceName eq "Node") {
push(@internalHeaderContent, "\n\@protocol DOMEventTarget;\n");
}
if ($codeGenerator->IsSVGAnimatedType($interfaceName)) {
push(@internalHeaderContent, "#import <WebCore/SVGAnimatedTemplate.h>\n\n");
} else {
if ($podType and $podType ne "float") {
push(@internalHeaderContent, "\nnamespace WebCore { class $podType; }\n\n");
} elsif ($interfaceName eq "Node") {
push(@internalHeaderContent, "\nnamespace WebCore { class Node; class EventTarget; }\n\n");
} else {
push(@internalHeaderContent, "\nnamespace WebCore { class $implClassName; }\n\n");
}
}
push(@internalHeaderContent, "\@interface $className (WebCoreInternal)\n");
push(@internalHeaderContent, $typeGetterSig . ";\n");
push(@internalHeaderContent, $typeMakerSig . ";\n");
if ($interfaceName eq "Node") {
push(@internalHeaderContent, "+ (id <DOMEventTarget>)_wrapEventTarget:(WebCore::EventTarget *)eventTarget;\n");
}
push(@internalHeaderContent, "\@end\n");
unless ($dataNode->extendedAttributes->{ObjCCustomInternalImpl}) {
# - BEGIN WebCoreInternal category @implementation
push(@implContent, "\n\@implementation $className (WebCoreInternal)\n\n");
my $typeGetterSig = GetInternalTypeGetterSignature($interfaceName, $podType);
push(@implContent, "$typeGetterSig\n");
push(@implContent, "{\n");
......@@ -1472,6 +1505,8 @@ sub GenerateImplementation
push(@implContent, "}\n\n");
my ($typeMakerSig, $typeMakerSigAddition, $ivarsToInit) = GetInternalTypeMakerSignature($interfaceName, $podType);
if ($podType) {
# - (id)_initWithFooBar:(WebCore::FooBar)impl for implementation class FooBar
my $initWithImplName = "_initWith" . $implClassName;
......
/*
* Copyright (C) 2006 Apple Computer, Inc.
* Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
*
* This library is free software; you can redistribute it and/or
......@@ -23,6 +23,7 @@ module css {
// Introduced in DOM Level 2:
interface [
ObjCCustomImplementation,
PODType=RGBA32,
InterfaceUUID=2e3b1501-2cf7-4a4a-bbf7-d8843d1c3be7,
ImplementationUUID=cf779953-4898-4800-aa31-6c9e3f4711be
] RGBColor {
......
......@@ -27,7 +27,9 @@
module views {
// Introduced in DOM Level 2:
interface AbstractView {
interface [
ObjCCustomImplementation
] AbstractView {
readonly attribute Document document;
};
......
......@@ -185,7 +185,9 @@ Frame::~Frame()
d->m_view->hide();
d->m_view->clearFrame();
}
disconnectPlatformScriptObjects();
ASSERT(!d->m_lifeSupportTimer.isActive());
#if FRAME_LOADS_USER_STYLESHEET
......
......@@ -156,6 +156,7 @@ public:
private:
void clearPlatformScriptObjects();
void disconnectPlatformScriptObjects();
void lifeSupportTimerFired(Timer<Frame>*);
......
......@@ -46,6 +46,11 @@ void Frame::clearPlatformScriptObjects()
notImplemented();
}
void Frame::disconnectPlatformScriptObjects()
{
notImplemented();
}
DragImageRef Frame::dragImageForSelection()
{
notImplemented();
......
......@@ -38,6 +38,7 @@
#import "ClipboardMac.h"
#import "ColorMac.h"
#import "Cursor.h"
#import "DOMAbstractViewFrame.h"
#import "DOMInternal.h"
#import "DOMWindow.h"
#import "DocumentLoader.h"
......@@ -600,6 +601,7 @@ WebScriptObject* Frame::windowScriptObject()
d->m_windowScriptObject = [WebScriptObject scriptObjectForJSObject:toRef(win) originRootObject:root rootObject:root];
}
ASSERT([d->m_windowScriptObject.get() isKindOfClass:[DOMAbstractView class]]);
return d->m_windowScriptObject.get();
}
......@@ -611,6 +613,14 @@ void Frame::clearPlatformScriptObjects()
}
}
void Frame::disconnectPlatformScriptObjects()
{
if (d->m_windowScriptObject) {
ASSERT([d->m_windowScriptObject.get() isKindOfClass:[DOMAbstractView class]]);
[(DOMAbstractView *)d->m_windowScriptObject.get() _disconnectFrame];
}
}
void Frame::setUserStyleSheetLocation(const KURL& url)
{
delete d->m_userStyleSheetLoader;
......
......@@ -109,6 +109,10 @@ void Frame::clearPlatformScriptObjects()
{
}
void Frame::disconnectPlatformScriptObjects()
{
}
DragImageRef Frame::dragImageForSelection()
{
return 0;
......
......@@ -71,6 +71,10 @@ void Frame::clearPlatformScriptObjects()
{
}
void Frame::disconnectPlatformScriptObjects()
{
}
PassRefPtr<KJS::Bindings::Instance> Frame::createScriptInstanceForWidget(Widget* widget)
{
// FIXME: Ideally we'd have an isPluginView() here but we can't add that to the open source tree right now.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment