Commit 54c80a34 authored by Tom Lane's avatar Tom Lane

Adjust contrib/seg &< and &> operators so that r-tree indexing logic

works properly for 1-D comparisons.  Fix some other errors such as
bogus commutator specifications.
parent 06ae88a8
...@@ -214,7 +214,7 @@ have just 2 significant digits. ...@@ -214,7 +214,7 @@ have just 2 significant digits.
USAGE USAGE
===== =====
The access method for SEG is a GiST (gist_seg_ops), which is a The access method for SEG is a GiST index (gist_seg_ops), which is a
generalization of R-tree. GiSTs allow the postgres implementation of generalization of R-tree. GiSTs allow the postgres implementation of
R-tree, originally encoded to support 2-D geometric types such as R-tree, originally encoded to support 2-D geometric types such as
boxes and polygons, to be used with any data type whose data domain boxes and polygons, to be used with any data type whose data domain
...@@ -236,23 +236,27 @@ The operators supported by the GiST access method include: ...@@ -236,23 +236,27 @@ The operators supported by the GiST access method include:
[a, b] >> [c, d] Is right of [a, b] >> [c, d] Is right of
[a, b] is occurs entirely to the right of [c, d]. [a, b] is occurs entirely to the right of [c, d].
[a, b] >> [c, d] is true if b > c and false otherwise [a, b] >> [c, d] is true if a > d and false otherwise
[a, b] &< [c, d] Over left [a, b] &< [c, d] Overlaps or is left of
The segment [a, b] overlaps the segment [c, d] in such a way This might be better read as "does not extend to right of".
that a <= c <= b and b <= d It is true when b <= d.
[a, b] &> [c, d] Over right [a, b] &> [c, d] Overlaps or is right of
The segment [a, b] overlaps the segment [c, d] in such a way This might be better read as "does not extend to left of".
that a > c and b <= c <= d It is true when a >= c.
[a, b] = [c, d] Same as [a, b] = [c, d] Same as
The segments [a, b] and [c, d] are identical, that is, a == b The segments [a, b] and [c, d] are identical, that is, a == b
and c == d and c == d
[a, b] && [c, d] Overlaps
The segments [a, b] and [c, d] overlap.
[a, b] @ [c, d] Contains [a, b] @ [c, d] Contains
The segment [a, b] contains the segment [c, d], that is, The segment [a, b] contains the segment [c, d], that is,
......
...@@ -557,7 +557,7 @@ SELECT '1'::seg &< '1'::seg AS bool; ...@@ -557,7 +557,7 @@ SELECT '1'::seg &< '1'::seg AS bool;
SELECT '1'::seg &< '2'::seg AS bool; SELECT '1'::seg &< '2'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
SELECT '0 .. 1'::seg &< '0'::seg AS bool; SELECT '0 .. 1'::seg &< '0'::seg AS bool;
...@@ -575,7 +575,7 @@ SELECT '0 .. 1'::seg &< '1'::seg AS bool; ...@@ -575,7 +575,7 @@ SELECT '0 .. 1'::seg &< '1'::seg AS bool;
SELECT '0 .. 1'::seg &< '2'::seg AS bool; SELECT '0 .. 1'::seg &< '2'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
SELECT '0 .. 1'::seg &< '0 .. 0.5'::seg AS bool; SELECT '0 .. 1'::seg &< '0 .. 0.5'::seg AS bool;
...@@ -605,7 +605,7 @@ SELECT '0 .. 1'::seg &< '1 .. 2'::seg AS bool; ...@@ -605,7 +605,7 @@ SELECT '0 .. 1'::seg &< '1 .. 2'::seg AS bool;
SELECT '0 .. 1'::seg &< '2 .. 3'::seg AS bool; SELECT '0 .. 1'::seg &< '2 .. 3'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
-- overlap on the right -- overlap on the right
...@@ -625,7 +625,7 @@ SELECT '1'::seg &> '1'::seg AS bool; ...@@ -625,7 +625,7 @@ SELECT '1'::seg &> '1'::seg AS bool;
SELECT '2'::seg &> '1'::seg AS bool; SELECT '2'::seg &> '1'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
SELECT '0'::seg &> '0 .. 1'::seg AS bool; SELECT '0'::seg &> '0 .. 1'::seg AS bool;
...@@ -643,7 +643,7 @@ SELECT '1'::seg &> '0 .. 1'::seg AS bool; ...@@ -643,7 +643,7 @@ SELECT '1'::seg &> '0 .. 1'::seg AS bool;
SELECT '2'::seg &> '0 .. 1'::seg AS bool; SELECT '2'::seg &> '0 .. 1'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
SELECT '0 .. 0.5'::seg &> '0 .. 1'::seg AS bool; SELECT '0 .. 0.5'::seg &> '0 .. 1'::seg AS bool;
...@@ -673,7 +673,7 @@ SELECT '1 .. 2'::seg &> '0 .. 1'::seg AS bool; ...@@ -673,7 +673,7 @@ SELECT '1 .. 2'::seg &> '0 .. 1'::seg AS bool;
SELECT '2 .. 3'::seg &> '0 .. 1'::seg AS bool; SELECT '2 .. 3'::seg &> '0 .. 1'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
-- left -- left
......
...@@ -557,7 +557,7 @@ SELECT '1'::seg &< '1'::seg AS bool; ...@@ -557,7 +557,7 @@ SELECT '1'::seg &< '1'::seg AS bool;
SELECT '1'::seg &< '2'::seg AS bool; SELECT '1'::seg &< '2'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
SELECT '0 .. 1'::seg &< '0'::seg AS bool; SELECT '0 .. 1'::seg &< '0'::seg AS bool;
...@@ -575,7 +575,7 @@ SELECT '0 .. 1'::seg &< '1'::seg AS bool; ...@@ -575,7 +575,7 @@ SELECT '0 .. 1'::seg &< '1'::seg AS bool;
SELECT '0 .. 1'::seg &< '2'::seg AS bool; SELECT '0 .. 1'::seg &< '2'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
SELECT '0 .. 1'::seg &< '0 .. 0.5'::seg AS bool; SELECT '0 .. 1'::seg &< '0 .. 0.5'::seg AS bool;
...@@ -605,7 +605,7 @@ SELECT '0 .. 1'::seg &< '1 .. 2'::seg AS bool; ...@@ -605,7 +605,7 @@ SELECT '0 .. 1'::seg &< '1 .. 2'::seg AS bool;
SELECT '0 .. 1'::seg &< '2 .. 3'::seg AS bool; SELECT '0 .. 1'::seg &< '2 .. 3'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
-- overlap on the right -- overlap on the right
...@@ -625,7 +625,7 @@ SELECT '1'::seg &> '1'::seg AS bool; ...@@ -625,7 +625,7 @@ SELECT '1'::seg &> '1'::seg AS bool;
SELECT '2'::seg &> '1'::seg AS bool; SELECT '2'::seg &> '1'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
SELECT '0'::seg &> '0 .. 1'::seg AS bool; SELECT '0'::seg &> '0 .. 1'::seg AS bool;
...@@ -643,7 +643,7 @@ SELECT '1'::seg &> '0 .. 1'::seg AS bool; ...@@ -643,7 +643,7 @@ SELECT '1'::seg &> '0 .. 1'::seg AS bool;
SELECT '2'::seg &> '0 .. 1'::seg AS bool; SELECT '2'::seg &> '0 .. 1'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
SELECT '0 .. 0.5'::seg &> '0 .. 1'::seg AS bool; SELECT '0 .. 0.5'::seg &> '0 .. 1'::seg AS bool;
...@@ -673,7 +673,7 @@ SELECT '1 .. 2'::seg &> '0 .. 1'::seg AS bool; ...@@ -673,7 +673,7 @@ SELECT '1 .. 2'::seg &> '0 .. 1'::seg AS bool;
SELECT '2 .. 3'::seg &> '0 .. 1'::seg AS bool; SELECT '2 .. 3'::seg &> '0 .. 1'::seg AS bool;
bool bool
------ ------
f t
(1 row) (1 row)
-- left -- left
......
...@@ -204,7 +204,7 @@ gseg_consistent(GISTENTRY *entry, ...@@ -204,7 +204,7 @@ gseg_consistent(GISTENTRY *entry,
StrategyNumber strategy) StrategyNumber strategy)
{ {
/* /*
* * if entry is not leaf, use gseg_internal_consistent, * else use * if entry is not leaf, use gseg_internal_consistent, else use
* gseg_leaf_consistent * gseg_leaf_consistent
*/ */
if (GIST_LEAF(entry)) if (GIST_LEAF(entry))
...@@ -517,15 +517,19 @@ gseg_internal_consistent(SEG * key, ...@@ -517,15 +517,19 @@ gseg_internal_consistent(SEG * key,
switch (strategy) switch (strategy)
{ {
case RTLeftStrategyNumber: case RTLeftStrategyNumber:
retval = (bool) !seg_over_right(key, query);
break;
case RTOverLeftStrategyNumber: case RTOverLeftStrategyNumber:
retval = (bool) seg_over_left(key, query); retval = (bool) !seg_right(key, query);
break; break;
case RTOverlapStrategyNumber: case RTOverlapStrategyNumber:
retval = (bool) seg_overlap(key, query); retval = (bool) seg_overlap(key, query);
break; break;
case RTOverRightStrategyNumber: case RTOverRightStrategyNumber:
retval = (bool) !seg_left(key, query);
break;
case RTRightStrategyNumber: case RTRightStrategyNumber:
retval = (bool) seg_right(key, query); retval = (bool) !seg_over_left(key, query);
break; break;
case RTSameStrategyNumber: case RTSameStrategyNumber:
case RTContainsStrategyNumber: case RTContainsStrategyNumber:
...@@ -586,12 +590,12 @@ seg_overlap(SEG * a, SEG * b) ...@@ -586,12 +590,12 @@ seg_overlap(SEG * a, SEG * b)
); );
} }
/* seg_overleft -- is the right edge of (a) located to the left of the right edge of (b)? /* seg_overleft -- is the right edge of (a) located at or left of the right edge of (b)?
*/ */
bool bool
seg_over_left(SEG * a, SEG * b) seg_over_left(SEG * a, SEG * b)
{ {
return (a->upper <= b->upper && !seg_left(a, b) && !seg_right(a, b)); return (a->upper <= b->upper);
} }
/* seg_left -- is (a) entirely on the left of (b)? /* seg_left -- is (a) entirely on the left of (b)?
...@@ -610,12 +614,12 @@ seg_right(SEG * a, SEG * b) ...@@ -610,12 +614,12 @@ seg_right(SEG * a, SEG * b)
return (a->lower > b->upper); return (a->lower > b->upper);
} }
/* seg_overright -- is the left edge of (a) located to the right of the left edge of (b)? /* seg_overright -- is the left edge of (a) located at or right of the left edge of (b)?
*/ */
bool bool
seg_over_right(SEG * a, SEG * b) seg_over_right(SEG * a, SEG * b)
{ {
return (a->lower >= b->lower && !seg_left(a, b) && !seg_right(a, b)); return (a->lower >= b->lower);
} }
......
...@@ -32,23 +32,23 @@ COMMENT ON TYPE seg IS ...@@ -32,23 +32,23 @@ COMMENT ON TYPE seg IS
CREATE FUNCTION seg_over_left(seg, seg) CREATE FUNCTION seg_over_left(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_over_left(seg, seg) IS COMMENT ON FUNCTION seg_over_left(seg, seg) IS
'is over and left of'; 'overlaps or is left of';
CREATE FUNCTION seg_over_right(seg, seg) CREATE FUNCTION seg_over_right(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_over_right(seg, seg) IS COMMENT ON FUNCTION seg_over_right(seg, seg) IS
'is over and right of'; 'overlaps or is right of';
CREATE FUNCTION seg_left(seg, seg) CREATE FUNCTION seg_left(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_left(seg, seg) IS COMMENT ON FUNCTION seg_left(seg, seg) IS
'is left of'; 'is left of';
...@@ -56,18 +56,18 @@ COMMENT ON FUNCTION seg_left(seg, seg) IS ...@@ -56,18 +56,18 @@ COMMENT ON FUNCTION seg_left(seg, seg) IS
CREATE FUNCTION seg_right(seg, seg) CREATE FUNCTION seg_right(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_right(seg, seg) IS COMMENT ON FUNCTION seg_right(seg, seg) IS
'is right of'; 'is right of';
-- Comparison methods -- Scalar comparison methods
CREATE FUNCTION seg_lt(seg, seg) CREATE FUNCTION seg_lt(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_lt(seg, seg) IS COMMENT ON FUNCTION seg_lt(seg, seg) IS
'less than'; 'less than';
...@@ -75,7 +75,7 @@ COMMENT ON FUNCTION seg_lt(seg, seg) IS ...@@ -75,7 +75,7 @@ COMMENT ON FUNCTION seg_lt(seg, seg) IS
CREATE FUNCTION seg_le(seg, seg) CREATE FUNCTION seg_le(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_le(seg, seg) IS COMMENT ON FUNCTION seg_le(seg, seg) IS
'less than or equal'; 'less than or equal';
...@@ -83,7 +83,7 @@ COMMENT ON FUNCTION seg_le(seg, seg) IS ...@@ -83,7 +83,7 @@ COMMENT ON FUNCTION seg_le(seg, seg) IS
CREATE FUNCTION seg_gt(seg, seg) CREATE FUNCTION seg_gt(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_gt(seg, seg) IS COMMENT ON FUNCTION seg_gt(seg, seg) IS
'greater than'; 'greater than';
...@@ -91,7 +91,7 @@ COMMENT ON FUNCTION seg_gt(seg, seg) IS ...@@ -91,7 +91,7 @@ COMMENT ON FUNCTION seg_gt(seg, seg) IS
CREATE FUNCTION seg_ge(seg, seg) CREATE FUNCTION seg_ge(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_ge(seg, seg) IS COMMENT ON FUNCTION seg_ge(seg, seg) IS
'greater than or equal'; 'greater than or equal';
...@@ -99,7 +99,7 @@ COMMENT ON FUNCTION seg_ge(seg, seg) IS ...@@ -99,7 +99,7 @@ COMMENT ON FUNCTION seg_ge(seg, seg) IS
CREATE FUNCTION seg_contains(seg, seg) CREATE FUNCTION seg_contains(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_contains(seg, seg) IS COMMENT ON FUNCTION seg_contains(seg, seg) IS
'contains'; 'contains';
...@@ -107,7 +107,7 @@ COMMENT ON FUNCTION seg_contains(seg, seg) IS ...@@ -107,7 +107,7 @@ COMMENT ON FUNCTION seg_contains(seg, seg) IS
CREATE FUNCTION seg_contained(seg, seg) CREATE FUNCTION seg_contained(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_contained(seg, seg) IS COMMENT ON FUNCTION seg_contained(seg, seg) IS
'contained in'; 'contained in';
...@@ -115,7 +115,7 @@ COMMENT ON FUNCTION seg_contained(seg, seg) IS ...@@ -115,7 +115,7 @@ COMMENT ON FUNCTION seg_contained(seg, seg) IS
CREATE FUNCTION seg_overlap(seg, seg) CREATE FUNCTION seg_overlap(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_overlap(seg, seg) IS COMMENT ON FUNCTION seg_overlap(seg, seg) IS
'overlaps'; 'overlaps';
...@@ -123,7 +123,7 @@ COMMENT ON FUNCTION seg_overlap(seg, seg) IS ...@@ -123,7 +123,7 @@ COMMENT ON FUNCTION seg_overlap(seg, seg) IS
CREATE FUNCTION seg_same(seg, seg) CREATE FUNCTION seg_same(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_same(seg, seg) IS COMMENT ON FUNCTION seg_same(seg, seg) IS
'same as'; 'same as';
...@@ -131,7 +131,7 @@ COMMENT ON FUNCTION seg_same(seg, seg) IS ...@@ -131,7 +131,7 @@ COMMENT ON FUNCTION seg_same(seg, seg) IS
CREATE FUNCTION seg_different(seg, seg) CREATE FUNCTION seg_different(seg, seg)
RETURNS bool RETURNS bool
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_different(seg, seg) IS COMMENT ON FUNCTION seg_different(seg, seg) IS
'different'; 'different';
...@@ -141,36 +141,36 @@ COMMENT ON FUNCTION seg_different(seg, seg) IS ...@@ -141,36 +141,36 @@ COMMENT ON FUNCTION seg_different(seg, seg) IS
CREATE OR REPLACE FUNCTION seg_cmp(seg, seg) CREATE OR REPLACE FUNCTION seg_cmp(seg, seg)
RETURNS int4 RETURNS int4
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' STRICT; LANGUAGE 'C' STRICT IMMUTABLE;
COMMENT ON FUNCTION seg_cmp(seg, seg) IS 'btree comparison function'; COMMENT ON FUNCTION seg_cmp(seg, seg) IS 'btree comparison function';
CREATE FUNCTION seg_union(seg, seg) CREATE FUNCTION seg_union(seg, seg)
RETURNS seg RETURNS seg
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
CREATE FUNCTION seg_inter(seg, seg) CREATE FUNCTION seg_inter(seg, seg)
RETURNS seg RETURNS seg
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
CREATE FUNCTION seg_size(seg) CREATE FUNCTION seg_size(seg)
RETURNS float4 RETURNS float4
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
-- miscellaneous -- miscellaneous
CREATE FUNCTION seg_upper(seg) CREATE FUNCTION seg_upper(seg)
RETURNS float4 RETURNS float4
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
CREATE FUNCTION seg_lower(seg) CREATE FUNCTION seg_lower(seg)
RETURNS float4 RETURNS float4
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT IMMUTABLE;
-- --
...@@ -230,7 +230,6 @@ CREATE OPERATOR &< ( ...@@ -230,7 +230,6 @@ CREATE OPERATOR &< (
LEFTARG = seg, LEFTARG = seg,
RIGHTARG = seg, RIGHTARG = seg,
PROCEDURE = seg_over_left, PROCEDURE = seg_over_left,
COMMUTATOR = '&>',
RESTRICT = positionsel, RESTRICT = positionsel,
JOIN = positionjoinsel JOIN = positionjoinsel
); );
...@@ -240,15 +239,14 @@ CREATE OPERATOR && ( ...@@ -240,15 +239,14 @@ CREATE OPERATOR && (
RIGHTARG = seg, RIGHTARG = seg,
PROCEDURE = seg_overlap, PROCEDURE = seg_overlap,
COMMUTATOR = '&&', COMMUTATOR = '&&',
RESTRICT = positionsel, RESTRICT = areasel,
JOIN = positionjoinsel JOIN = areajoinsel
); );
CREATE OPERATOR &> ( CREATE OPERATOR &> (
LEFTARG = seg, LEFTARG = seg,
RIGHTARG = seg, RIGHTARG = seg,
PROCEDURE = seg_over_right, PROCEDURE = seg_over_right,
COMMUTATOR = '&<',
RESTRICT = positionsel, RESTRICT = positionsel,
JOIN = positionjoinsel JOIN = positionjoinsel
); );
...@@ -321,7 +319,7 @@ LANGUAGE 'C'; ...@@ -321,7 +319,7 @@ LANGUAGE 'C';
CREATE FUNCTION gseg_penalty(internal,internal,internal) CREATE FUNCTION gseg_penalty(internal,internal,internal)
RETURNS internal RETURNS internal
AS 'MODULE_PATHNAME' AS 'MODULE_PATHNAME'
LANGUAGE 'C' with (isstrict); LANGUAGE 'C' STRICT;
CREATE FUNCTION gseg_picksplit(internal, internal) CREATE FUNCTION gseg_picksplit(internal, internal)
RETURNS internal RETURNS internal
......
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