Commit 1f765366 authored by Richard Gibson's avatar Richard Gibson

No ticket: Revise unit tests in anticipation of Sizzle-free builds

(cherry picked from commit 59f5adb6)
parent dbf3056b
...@@ -172,11 +172,11 @@ var Globals = (function() { ...@@ -172,11 +172,11 @@ var Globals = (function() {
// instead of asserting every time a test has leaked sometime in the past // instead of asserting every time a test has leaked sometime in the past
var oldCacheLength = 0, var oldCacheLength = 0,
oldFragmentsLength = 0, oldFragmentsLength = 0,
oldTimersLength = 0,
oldActive = 0, oldActive = 0,
expectedDataKeys = {}, expectedDataKeys = {},
splice = [].splice,
reset = QUnit.reset, reset = QUnit.reset,
ajaxSettings = jQuery.ajaxSettings; ajaxSettings = jQuery.ajaxSettings;
...@@ -280,6 +280,20 @@ var Globals = (function() { ...@@ -280,6 +280,20 @@ var Globals = (function() {
// Reset data register // Reset data register
expectedDataKeys = {}; expectedDataKeys = {};
// Check for (and clean up, if possible) incomplete animations/requests/etc.
if ( jQuery.timers && jQuery.timers.length !== 0 ) {
equal( jQuery.timers.length, 0, "No timers are still running" );
splice.call( jQuery.timers, 0, jQuery.timers.length );
jQuery.fx.stop();
}
if ( jQuery.active !== undefined && jQuery.active !== oldActive ) {
equal( jQuery.active, oldActive, "No AJAX requests are still active" );
if ( ajaxTest.abort ) {
ajaxTest.abort("active requests");
}
oldActive = jQuery.active;
}
// Allow QUnit.reset to clean up any attached elements before checking for leaks // Allow QUnit.reset to clean up any attached elements before checking for leaks
QUnit.reset(); QUnit.reset();
...@@ -303,17 +317,6 @@ var Globals = (function() { ...@@ -303,17 +317,6 @@ var Globals = (function() {
equal( fragmentsLength, oldFragmentsLength, "No unit tests leak memory in jQuery.fragments" ); equal( fragmentsLength, oldFragmentsLength, "No unit tests leak memory in jQuery.fragments" );
oldFragmentsLength = fragmentsLength; oldFragmentsLength = fragmentsLength;
} }
if ( jQuery.timers && jQuery.timers.length !== oldTimersLength ) {
equal( jQuery.timers.length, oldTimersLength, "No timers are still running" );
oldTimersLength = jQuery.timers.length;
}
if ( jQuery.active !== undefined && jQuery.active !== oldActive ) {
equal( jQuery.active, 0, "No AJAX requests are still active" );
if ( ajaxTest.abort ) {
ajaxTest.abort("active requests");
}
oldActive = jQuery.active;
}
}; };
QUnit.done(function() { QUnit.done(function() {
......
...@@ -380,7 +380,7 @@ test( "attr(String, Object)", function() { ...@@ -380,7 +380,7 @@ test( "attr(String, Object)", function() {
}); });
var table = jQuery("#table").append("<tr><td>cell</td></tr><tr><td>cell</td><td>cell</td></tr><tr><td>cell</td><td>cell</td></tr>"), var table = jQuery("#table").append("<tr><td>cell</td></tr><tr><td>cell</td><td>cell</td></tr><tr><td>cell</td><td>cell</td></tr>"),
td = table.find("td:first"); td = table.find("td").eq(0);
td.attr( "rowspan", "2" ); td.attr( "rowspan", "2" );
equal( td[ 0 ]["rowSpan"], 2, "Check rowspan is correctly set" ); equal( td[ 0 ]["rowSpan"], 2, "Check rowspan is correctly set" );
td.attr( "colspan", "2" ); td.attr( "colspan", "2" );
......
...@@ -28,13 +28,12 @@ test("jQuery()", function() { ...@@ -28,13 +28,12 @@ test("jQuery()", function() {
var elem, i, var elem, i,
obj = jQuery("div"), obj = jQuery("div"),
main = jQuery("#qunit-fixture"),
code = jQuery("<code/>"), code = jQuery("<code/>"),
img = jQuery("<img/>"), img = jQuery("<img/>"),
div = jQuery("<div/><hr/><code/><b/>"), div = jQuery("<div/><hr/><code/><b/>"),
exec = false, exec = false,
lng = "", lng = "",
expected = 21, expected = 20,
attrObj = { attrObj = {
"text": "test", "text": "test",
"class": "test2", "class": "test2",
...@@ -78,8 +77,6 @@ test("jQuery()", function() { ...@@ -78,8 +77,6 @@ test("jQuery()", function() {
// can actually yield more than one, when iframes are included, the window is an array as well // can actually yield more than one, when iframes are included, the window is an array as well
equal( jQuery(window).length, 1, "Correct number of elements generated for jQuery(window)" ); equal( jQuery(window).length, 1, "Correct number of elements generated for jQuery(window)" );
deepEqual( jQuery("div p", main).get(), q("sndp", "en", "sap"), "Basic selector with jQuery object as context" );
/* /*
// disabled since this test was doing nothing. i tried to fix it but i'm not sure // disabled since this test was doing nothing. i tried to fix it but i'm not sure
// what the expected behavior should even be. FF returns "\n" for the text node // what the expected behavior should even be. FF returns "\n" for the text node
...@@ -154,6 +151,13 @@ test("jQuery()", function() { ...@@ -154,6 +151,13 @@ test("jQuery()", function() {
} }
}); });
test("jQuery(selector, context)", function() {
expect(3);
deepEqual( jQuery("div p", "#qunit-fixture").get(), q("sndp", "en", "sap"), "Basic selector with string as context" );
deepEqual( jQuery("div p", q("qunit-fixture")[0]).get(), q("sndp", "en", "sap"), "Basic selector with element as context" );
deepEqual( jQuery("div p", jQuery("#qunit-fixture")).get(), q("sndp", "en", "sap"), "Basic selector with jQuery object as context" );
});
test( "selector state", function() { test( "selector state", function() {
expect( 18 ); expect( 18 );
......
...@@ -656,12 +656,12 @@ test("jQuery.css(elem, 'height') doesn't clear radio buttons (bug #1095)", funct ...@@ -656,12 +656,12 @@ test("jQuery.css(elem, 'height') doesn't clear radio buttons (bug #1095)", funct
expect(4); expect(4);
var $checkedtest = jQuery("#checkedtest"); var $checkedtest = jQuery("#checkedtest");
// IE6 was clearing "checked" in jQuery.css(elem, "height");
jQuery.css($checkedtest[0], "height"); jQuery.css($checkedtest[0], "height");
ok( !! jQuery(":radio:first", $checkedtest).attr("checked"), "Check first radio still checked." );
ok( ! jQuery(":radio:last", $checkedtest).attr("checked"), "Check last radio still NOT checked." ); ok( jQuery("input[type='radio']", $checkedtest).first().attr("checked"), "Check first radio still checked." );
ok( !! jQuery(":checkbox:first", $checkedtest).attr("checked"), "Check first checkbox still checked." ); ok( !jQuery("input[type='radio']", $checkedtest).last().attr("checked"), "Check last radio still NOT checked." );
ok( ! jQuery(":checkbox:last", $checkedtest).attr("checked"), "Check last checkbox still NOT checked." ); ok( jQuery("input[type='checkbox']", $checkedtest).first().attr("checked"), "Check first checkbox still checked." );
ok( !jQuery("input[type='checkbox']", $checkedtest).last().attr("checked"), "Check last checkbox still NOT checked." );
}); });
test("internal ref to elem.runtimeStyle (bug #7608)", function () { test("internal ref to elem.runtimeStyle (bug #7608)", function () {
......
...@@ -296,8 +296,8 @@ test("getting dimensions shouldnt modify runtimeStyle see #9233", function() { ...@@ -296,8 +296,8 @@ test("getting dimensions shouldnt modify runtimeStyle see #9233", function() {
test( "table dimensions", 2, function() { test( "table dimensions", 2, function() {
var table = jQuery("<table><colgroup><col/><col/></colgroup><tbody><tr><td></td><td>a</td></tr><tr><td></td><td>a</td></tr></tbody></table>").appendTo("#qunit-fixture"), var table = jQuery("<table><colgroup><col/><col/></colgroup><tbody><tr><td></td><td>a</td></tr><tr><td></td><td>a</td></tr></tbody></table>").appendTo("#qunit-fixture"),
tdElem = table.find("tr:eq(0) td:eq(0)"), tdElem = table.find("td").first(),
colElem = table.find("col:eq(1)").width( 300 ); colElem = table.find("col").first().width( 300 );
table.find("td").css({ "margin": 0, "padding": 0 }); table.find("td").css({ "margin": 0, "padding": 0 });
......
if ( jQuery.fx ) { (function() {
module("effects", { teardown: moduleTeardown }); // Can't test what ain't there
if ( !jQuery.fx ) {
return;
}
var off = jQuery.fx.off;
module("effects", {
teardown: function() {
jQuery.fx.off = off;
return moduleTeardown.apply( this, arguments );
}
});
test("sanity check", function() { test("sanity check", function() {
expect(1); expect(1);
...@@ -1084,12 +1096,11 @@ test("jQuery.show('fast') doesn't clear radio buttons (bug #1095)", function () ...@@ -1084,12 +1096,11 @@ test("jQuery.show('fast') doesn't clear radio buttons (bug #1095)", function ()
stop(); stop();
var $checkedtest = jQuery("#checkedtest"); var $checkedtest = jQuery("#checkedtest");
// IE6 was clearing "checked" in jQuery(elem).show("fast");
$checkedtest.hide().show("fast", function() { $checkedtest.hide().show("fast", function() {
ok( !! jQuery(":radio:first", $checkedtest).attr("checked"), "Check first radio still checked." ); ok( jQuery("input[type='radio']", $checkedtest).first().attr("checked"), "Check first radio still checked." );
ok( ! jQuery(":radio:last", $checkedtest).attr("checked"), "Check last radio still NOT checked." ); ok( !jQuery("input[type='radio']", $checkedtest).last().attr("checked"), "Check last radio still NOT checked." );
ok( !! jQuery(":checkbox:first", $checkedtest).attr("checked"), "Check first checkbox still checked." ); ok( jQuery("input[type='checkbox']", $checkedtest).first().attr("checked"), "Check first checkbox still checked." );
ok( ! jQuery(":checkbox:last", $checkedtest).attr("checked"), "Check last checkbox still NOT checked." ); ok( !jQuery("input[type='checkbox']", $checkedtest).last().attr("checked"), "Check last checkbox still NOT checked." );
start(); start();
}); });
}); });
...@@ -1514,7 +1525,7 @@ test( "animate should set display for disconnected nodes", function() { ...@@ -1514,7 +1525,7 @@ test( "animate should set display for disconnected nodes", function() {
}); });
}); });
asyncTest("Animation callback should not show animated element as animated (#7157)", 1, function() { asyncTest("Animation callback should not show animated element as :animated (#7157)", 1, function() {
var foo = jQuery( "#foo" ); var foo = jQuery( "#foo" );
foo.animate({ foo.animate({
...@@ -2047,4 +2058,4 @@ test( ".finish() calls finish of custom queue functions", function() { ...@@ -2047,4 +2058,4 @@ test( ".finish() calls finish of custom queue functions", function() {
div.remove(); div.remove();
}); });
} // if ( jQuery.fx ) })();
...@@ -310,8 +310,10 @@ test("bind/one/unbind(Object)", function(){ ...@@ -310,8 +310,10 @@ test("bind/one/unbind(Object)", function(){
test("on/off(Object), delegate/undelegate(String, Object)", function() { test("on/off(Object), delegate/undelegate(String, Object)", function() {
expect(6); expect(6);
var clickCounter = 0, mouseoverCounter = 0, var clickCounter = 0,
$p = jQuery("#firstp"), $a = $p.find("a:first"); mouseoverCounter = 0,
$p = jQuery("#firstp"),
$a = $p.find("a").eq(0);
var events = { var events = {
"click": function( event ) { "click": function( event ) {
...@@ -326,7 +328,7 @@ test("on/off(Object), delegate/undelegate(String, Object)", function() { ...@@ -326,7 +328,7 @@ test("on/off(Object), delegate/undelegate(String, Object)", function() {
$a.trigger("click").trigger("mouseover"); $a.trigger("click").trigger("mouseover");
} }
jQuery( document ).on( events, "#firstp a:first" ); jQuery( document ).on( events, "#firstp a" );
$p.delegate( "a", events, 2 ); $p.delegate( "a", events, 2 );
trigger(); trigger();
...@@ -339,7 +341,7 @@ test("on/off(Object), delegate/undelegate(String, Object)", function() { ...@@ -339,7 +341,7 @@ test("on/off(Object), delegate/undelegate(String, Object)", function() {
equal( clickCounter, 4, "undelegate" ); equal( clickCounter, 4, "undelegate" );
equal( mouseoverCounter, 4, "undelegate" ); equal( mouseoverCounter, 4, "undelegate" );
jQuery( document ).off( events, "#firstp a:first" ); jQuery( document ).off( events, "#firstp a" );
trigger(); trigger();
equal( clickCounter, 4, "off" ); equal( clickCounter, 4, "off" );
...@@ -349,19 +351,21 @@ test("on/off(Object), delegate/undelegate(String, Object)", function() { ...@@ -349,19 +351,21 @@ test("on/off(Object), delegate/undelegate(String, Object)", function() {
test("on/delegate immediate propagation", function() { test("on/delegate immediate propagation", function() {
expect(2); expect(2);
var $p = jQuery("#firstp"), $a = $p.find("a:first"), lastClick; var lastClick,
$p = jQuery("#firstp"),
$a = $p.find("a").eq(0);
lastClick = ""; lastClick = "";
jQuery( document ).on( "click", "#firstp a:first", function(e) { jQuery( document ).on( "click", "#firstp a", function(e) {
lastClick = "click1"; lastClick = "click1";
e.stopImmediatePropagation(); e.stopImmediatePropagation();
}); });
jQuery( document ).on( "click", "#firstp a:first", function(e) { jQuery( document ).on( "click", "#firstp a", function(e) {
lastClick = "click2"; lastClick = "click2";
}); });
$a.trigger( "click" ); $a.trigger( "click" );
equal( lastClick, "click1", "on stopImmediatePropagation" ); equal( lastClick, "click1", "on stopImmediatePropagation" );
jQuery( document ).off( "click", "#firstp a:first" ); jQuery( document ).off( "click", "#firstp a" );
lastClick = ""; lastClick = "";
$p.delegate( "a", "click", function(e) { $p.delegate( "a", "click", function(e) {
...@@ -490,7 +494,7 @@ test("bind(), namespaced events, cloned events", 18, function() { ...@@ -490,7 +494,7 @@ test("bind(), namespaced events, cloned events", 18, function() {
// Make sure events stick with appendTo'd elements (which are cloned) #2027 // Make sure events stick with appendTo'd elements (which are cloned) #2027
jQuery("<a href='#fail' class='test'>test</a>").on( "click", function(){ return false; }).appendTo("#qunit-fixture"); jQuery("<a href='#fail' class='test'>test</a>").on( "click", function(){ return false; }).appendTo("#qunit-fixture");
ok( jQuery("a.test:first").triggerHandler("click") === false, "Handler is bound to appendTo'd elements" ); ok( jQuery("a.test").eq(0).triggerHandler("click") === false, "Handler is bound to appendTo'd elements" );
}); });
test("bind(), multi-namespaced events", function() { test("bind(), multi-namespaced events", function() {
...@@ -996,7 +1000,7 @@ test("trigger(type, [data], [fn])", function() { ...@@ -996,7 +1000,7 @@ test("trigger(type, [data], [fn])", function() {
var pass = true, elem2; var pass = true, elem2;
try { try {
elem2 = jQuery("#form input:first"); elem2 = jQuery("#form input").eq(0);
elem2.get(0).style.display = "none"; elem2.get(0).style.display = "none";
elem2.trigger("focus"); elem2.trigger("focus");
} catch(e) { } catch(e) {
...@@ -1006,7 +1010,7 @@ test("trigger(type, [data], [fn])", function() { ...@@ -1006,7 +1010,7 @@ test("trigger(type, [data], [fn])", function() {
pass = true; pass = true;
try { try {
jQuery("#qunit-fixture table:first").bind("test:test", function(){}).trigger("test:test"); jQuery("#qunit-fixture table").eq(0).bind("test:test", function(){}).trigger("test:test");
} catch (e) { } catch (e) {
pass = false; pass = false;
} }
...@@ -1772,10 +1776,24 @@ test("jQuery.off using dispatched jQuery.Event", function() { ...@@ -1772,10 +1776,24 @@ test("jQuery.off using dispatched jQuery.Event", function() {
test( "delegated event with delegateTarget-relative selector", function() { test( "delegated event with delegateTarget-relative selector", function() {
expect(3); expect(3);
var markup = jQuery("<ul><li><a id=\"a0\"></a><ul id=\"ul0\"><li class=test><a id=\"a0_0\"></a></li><li><a id=\"a0_1\"></a></li></ul></li></ul>").appendTo("#qunit-fixture"); var markup = jQuery("<div><ul><li><a id=\"a0\"></a><ul id=\"ul0\"><li class=test><a id=\"a0_0\"></a></li><li><a id=\"a0_1\"></a></li></ul></li></ul></div>").appendTo("#qunit-fixture");
// Non-positional selector (#12383)
markup.find("#ul0")
.on( "click", "div li a", function() {
ok( false, "div is ABOVE the delegation point!" );
})
.on( "click", "ul a", function() {
ok( false, "ul IS the delegation point!" );
})
.on( "click", "li.test a", function() {
ok( true, "li.test is below the delegation point." );
})
.find("#a0_0").trigger("click").end()
.off("click");
// Positional selector (#11315) // Positional selector (#11315)
markup markup.find("ul").eq(0)
.on( "click", ">li>a", function() { .on( "click", ">li>a", function() {
ok( this.id === "a0", "child li was clicked" ); ok( this.id === "a0", "child li was clicked" );
}) })
...@@ -1787,21 +1805,6 @@ test( "delegated event with delegateTarget-relative selector", function() { ...@@ -1787,21 +1805,6 @@ test( "delegated event with delegateTarget-relative selector", function() {
.find("a").trigger("click").end() .find("a").trigger("click").end()
.find("#ul0").off(); .find("#ul0").off();
// Non-positional selector (#12383)
markup = markup.wrap("<div />").parent();
markup
.find("#ul0")
.on( "click", "div li a", function() {
ok( false, "div is ABOVE the delegation point!" );
})
.on( "click", "ul a", function() {
ok( false, "ul is the delegation point!" );
})
.on( "click", "li.test a", function() {
ok( true, "li.test is below the delegation point." );
})
.find("#a0_0").trigger("click");
markup.remove(); markup.remove();
}); });
...@@ -2624,12 +2627,12 @@ test( "make sure events cloned correctly", 18, function() { ...@@ -2624,12 +2627,12 @@ test( "make sure events cloned correctly", 18, function() {
clone = fixture.clone( true ); clone = fixture.clone( true );
clone.find("p:first").trigger( "click", true ); // 3 events should fire clone.find("p").eq(0).trigger( "click", true ); // 3 events should fire
clone.find("#check1").trigger( "change", true ); // 3 events should fire clone.find("#check1").trigger( "change", true ); // 3 events should fire
clone.remove(); clone.remove();
clone = fixture.clone( true, true ); clone = fixture.clone( true, true );
clone.find("p:first").trigger( "click", true ); // 3 events should fire clone.find("p").eq(0).trigger( "click", true ); // 3 events should fire
clone.find("#check1").trigger( "change", true ); // 3 events should fire clone.find("#check1").trigger( "change", true ); // 3 events should fire
fixture.off(); fixture.off();
...@@ -2639,11 +2642,11 @@ test( "make sure events cloned correctly", 18, function() { ...@@ -2639,11 +2642,11 @@ test( "make sure events cloned correctly", 18, function() {
p.trigger("click"); // 0 should be fired p.trigger("click"); // 0 should be fired
checkbox.trigger("change"); // 0 should be fired checkbox.trigger("change"); // 0 should be fired
clone.find("p:first").trigger( "click", true ); // 3 events should fire clone.find("p").eq(0).trigger( "click", true ); // 3 events should fire
clone.find("#check1").trigger( "change", true ); // 3 events should fire clone.find("#check1").trigger( "change", true ); // 3 events should fire
clone.remove(); clone.remove();
clone.find("p:first").trigger("click"); // 0 should be fired clone.find("p").eq(0).trigger("click"); // 0 should be fired
clone.find("#check1").trigger("change"); // 0 events should fire clone.find("#check1").trigger("change"); // 0 events should fire
}); });
......
This diff is collapsed.
...@@ -64,15 +64,20 @@ test("attributes - jQuery only", function() { ...@@ -64,15 +64,20 @@ test("attributes - jQuery only", function() {
}); });
test("disconnected nodes", function() { test("disconnected nodes", function() {
expect( 4 ); expect( 1 );
var $div = jQuery("<div/>");
equal( $div.is("div"), true, "Make sure .is('nodeName') works on disconnected nodes." );
});
test("disconnected nodes - jQuery only", function() {
expect( 3 );
var $opt = jQuery("<option></option>").attr("value", "whipit").appendTo("#qunit-fixture").detach(); var $opt = jQuery("<option></option>").attr("value", "whipit").appendTo("#qunit-fixture").detach();
equal( $opt.val(), "whipit", "option value" ); equal( $opt.val(), "whipit", "option value" );
equal( $opt.is(":selected"), false, "unselected option" ); equal( $opt.is(":selected"), false, "unselected option" );
$opt.prop("selected", true); $opt.prop("selected", true);
equal( $opt.is(":selected"), true, "selected option" ); equal( $opt.is(":selected"), true, "selected option" );
var $div = jQuery("<div/>");
equal( $div.is("div"), true, "Make sure .is('nodeName') works on disconnected nodes." );
}); });
test("jQuery only - broken", 1, function() { test("jQuery only - broken", 1, function() {
...@@ -83,7 +88,7 @@ test("jQuery only - broken", 1, function() { ...@@ -83,7 +88,7 @@ test("jQuery only - broken", 1, function() {
// Sizzle.error will be called but no error will be seen in oldIE // Sizzle.error will be called but no error will be seen in oldIE
jQuery.call( null, " <div/> " ); jQuery.call( null, " <div/> " );
}, function( e ) { }, function( e ) {
return e.message.indexOf("Syntax error") >= 0; return (/syntax.err/i).test( e.message );
}, "leading space invalid: $(' <div/> ')" ); }, "leading space invalid: $(' <div/> ')" );
}); });
......
...@@ -121,7 +121,7 @@ test("serialize()", function() { ...@@ -121,7 +121,7 @@ test("serialize()", function() {
"action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3", "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3",
"Check form serialization as query string"); "Check form serialization as query string");
equal( jQuery("#form :input").serialize(), equal( jQuery("input,select,textarea,button", "#form").serialize(),
"action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3", "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3",
"Check input serialization as query string"); "Check input serialization as query string");
...@@ -129,7 +129,7 @@ test("serialize()", function() { ...@@ -129,7 +129,7 @@ test("serialize()", function() {
"T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", "T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=",
"Check form serialization as query string"); "Check form serialization as query string");
equal( jQuery("#testForm :input").serialize(), equal( jQuery("input,select,textarea,button", "#testForm").serialize(),
"T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", "T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=",
"Check input serialization as query string"); "Check input serialization as query string");
......
This diff is collapsed.
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