View Issue Details

IDProjectCategoryView StatusLast Update
0007500ScribusPDFpublic2016-01-14 01:20
Reporterpspencer Assigned Tofschmid  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionfixed 
PlatformLinuxOSFedoraOS Version8
Product Version1.3.5svn 
Fixed in Version1.3.5svn 
Summary0007500: Documents with Render Frames Result in PDF Files With Invalid Closepath Operators
DescriptionWhen you export to PDF a document containing a render frame, the render frame is not visible when you view the PDF in Adobe Reader or Ghostscript. When you view it with XPDF/Evince, the error message "Error: No current point in closepath" is generated, but the document is viewable just fine.

The problem seems to be with the code in pdflib_core.cpp that attempts to clip the embedded pdf. It contains many occurrences of code similar to

 PutPage(SetClipPath(ite));
 PutPage("h\nW*\nn\n");

If ite is empty, the first PutPage outputs the empty string. The second PutPage generates the pdf commands "h", "W*", and "n" -- and "h" is apparently not a valid operator when no current point has been set.

I don't know why it's not valid, since the PostScript equivalent operator "closepath" is permitted (and does nothing) in the absence of a current point,
but apparently it's not, and causes Adobe Reader to choke on the whole object.

I would suggest moving the generation of "h" -- and perhaps of the other operators too -- to inside the SetClipPath routine, where they would be output conditionally on a path having been built.

The attached patch implements this as follows (but will require some checking for typos etc. due to the sheer number of similar lines involved):

(1) It adds an extra QString argument, opPath, to the SetClipPath, SetClipPathImage, and SetClipPathArray routines.

(2) It modifies each of those routines as follows:
      - Upon completion of the loop through the list, the "h" operator is
        added but ONLY if nPath is false (meaning a path segment has begun
        but is not yet closed). And, for the routines that take the optional
        "poly" argument, the "h" is added only when "poly && ! nPath".
      - Finally, if the routine produced code at all, it appends the
        opPath text, but if it has just generated the empty string,
        the opPath text is omitted.

(3) It changes each call to one of those routines, passing the appropriate
opPath. For example, the lines

PutPage(SetClipPath(ite));
PutPage("h\nW*\nn\n");

are replaced with

PutPage(SetClipPath(ite, "W*\nn\n")

I think this is probably the cleanest and safest way to solve the problem but I am completely new to Scribus so there may be a better solution.

  
TagsNo tags attached.
Patch

Relationships

related to 0013654 closedjghali Evince warning when outlining font : "Syntax Error: No current point in closepath" 
child of 0007647 acknowledgedHerm Metabug: Render Frames (LaTeX, GnuPlot, LilyPond, GraphViz, etc.) 

Activities

2008-10-15 22:31

 

scribus-pdf.patch (15,779 bytes)   
--- Scribus/scribus/pdflib_core.cpp.badpdf	2008-10-14 14:01:51.000000000 -0400
+++ Scribus/scribus/pdflib_core.cpp	2008-10-15 17:03:41.000000000 -0400
@@ -1870,18 +1870,15 @@
 							}
 							else
 							{
-								PutPage(SetClipPath(ite));
-								PutPage("h\nf*\n");
+								PutPage(SetClipPath(ite, "f*\n"));
 							}
 						}
 						PutPage("q\n");
 						if (ite->imageClip.size() != 0)
 						{
-							PutPage(SetClipPathImage(ite));
-							PutPage("h\nW*\nn\n");
+							PutPage(SetClipPathImage(ite, "W*\nn\n"));
 						}
-						PutPage(SetClipPath(ite));
-						PutPage("h\nW*\nn\n");
+						PutPage(SetClipPath(ite, "W*\nn\n"));
 						if (ite->imageFlippedH())
 							PutPage("-1 0 0 1 "+FToStr(ite->width())+" 0 cm\n");
 						if (ite->imageFlippedV())
@@ -1899,8 +1896,7 @@
 								PutPage(PDF_TransparenzStroke(ite));
 							if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
 							{
-								PutPage(SetClipPath(ite));
-								PutPage("h\nS\n");
+								PutPage(SetClipPath(ite, "S\n"));
 							}
 							else
 							{
@@ -1910,8 +1906,7 @@
 									if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
 									{
 										PutPage(setStrokeMulti(&ml[it]));
-										PutPage(SetClipPath(ite));
-										PutPage("h\nS\n");
+										PutPage(SetClipPath(ite, "S\n"));
 									}
 								}
 							}
@@ -1961,8 +1956,7 @@
 								PutPage("/"+ShName+" gs\n");
 							}
 							PutPage(putColor(ite->lineColor(), ite->lineShade(), true));
-							PutPage(SetClipPathArray(&arrow));
-							PutPage("h\nf*\n");
+							PutPage(SetClipPathArray(&arrow,"f*\n"));
 						}
 						if (ite->endArrowIndex() != 0)
 						{
@@ -1982,8 +1976,7 @@
 								PutPage("/"+ShName+" gs\n");
 							}
 							PutPage(putColor(ite->lineColor(), ite->lineShade(), true));
-							PutPage(SetClipPathArray(&arrow));
-							PutPage("h\nf*\n");
+							PutPage(SetClipPathArray(&arrow, "f*\n"));
 						}
 						break;
 					case PageItem::ItemType1:
@@ -2001,8 +1994,7 @@
 						{
 							if (ite->fillColor() != CommonStrings::None)
 							{
-								PutPage(SetClipPath(ite));
-								PutPage("h\nf*\n");
+								PutPage(SetClipPath(ite, "f*\n"));
 							}
 						}
 						if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()))
@@ -2011,8 +2003,7 @@
 								PutPage(PDF_TransparenzStroke(ite));
 							if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
 							{
-								PutPage(SetClipPath(ite));
-								PutPage("h\nS\n");
+								PutPage(SetClipPath(ite,"S\n"));
 							}
 							else
 							{
@@ -2022,8 +2013,7 @@
 									if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
 									{
 										PutPage(setStrokeMulti(&ml[it]));
-										PutPage(SetClipPath(ite));
-										PutPage("h\nS\n");
+										PutPage(SetClipPath(ite, "S\n"));
 									}
 								}
 							}
@@ -2044,8 +2034,7 @@
 							{
 								if (ite->fillColor() != CommonStrings::None)
 								{
-									PutPage(SetClipPath(ite));
-									PutPage("h\nf*\n");
+									PutPage(SetClipPath(ite, "f*\n"));
 								}
 							}
 						}
@@ -2055,8 +2044,7 @@
 								PutPage(PDF_TransparenzStroke(ite));
 							if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
 							{
-								PutPage(SetClipPath(ite, false));
-								PutPage("S\n");
+								PutPage(SetClipPath(ite, "S\n", false));
 							}
 							else
 							{
@@ -2066,8 +2054,7 @@
 									if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
 									{
 										PutPage(setStrokeMulti(&ml[it]));
-										PutPage(SetClipPath(ite, false));
-										PutPage("S\n");
+										PutPage(SetClipPath(ite, "S\n", false));
 									}
 								}
 							}
@@ -2098,8 +2085,7 @@
 										PutPage("/"+ShName+" gs\n");
 									}
 									PutPage(putColor(ite->lineColor(), ite->lineShade(), true));
-									PutPage(SetClipPathArray(&arrow));
-									PutPage("h\nf*\n");
+									PutPage(SetClipPathArray(&arrow, "f*\n"));
 									break;
 								}
 							}
@@ -2130,8 +2116,7 @@
 										PutPage("/"+ShName+" gs\n");
 									}
 									PutPage(putColor(ite->lineColor(), ite->lineShade(), true));
-									PutPage(SetClipPathArray(&arrow));
-									PutPage("h\nf*\n");
+									PutPage(SetClipPathArray(&arrow, "f*\n"));
 									break;
 								}
 							}
@@ -2149,8 +2134,7 @@
 										PutPage(PDF_TransparenzStroke(ite));
 									if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
 									{
-										PutPage(SetClipPath(ite, false));
-										PutPage("S\n");
+										PutPage(SetClipPath(ite, "S\n", false));
 									}
 									else
 									{
@@ -2160,8 +2144,7 @@
 											if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
 											{
 												PutPage(setStrokeMulti(&ml[it]));
-												PutPage(SetClipPath(ite, false));
-												PutPage("S\n");
+												PutPage(SetClipPath(ite, "S\n", false));
 											}
 										}
 									}
@@ -2522,8 +2505,7 @@
 //			PutPage(EncString("("+docTitle+")",ObjCounter)+" Tj\nET\n");
 			painter1.addText( QPointF(0.0,0.0), infoFont, docTitle );
 			textPath.fromQPainterPath(painter1);
-			PutPage(SetClipPathArray(&textPath, true));
-			PutPage("h\nf*\n");
+			PutPage(SetClipPathArray(&textPath, "f*\n", true));
 			PutPage("Q\n");
 			QDate d = QDate::currentDate();
 			QString docDate = tr("Date:")+" "+d.toString(Qt::TextDate);
@@ -2535,8 +2517,7 @@
 //			PutPage(EncString("("+ tr("Date:")+" "+d.toString(Qt::TextDate)+")",ObjCounter)+" Tj\nET\n");
 			painter2.addText( QPointF(0.0,0.0), infoFont, docDate );
 			textPath.fromQPainterPath(painter2);
-			PutPage(SetClipPathArray(&textPath, true));
-			PutPage("h\nf*\n");
+			PutPage(SetClipPathArray(&textPath, "f*\n", true));
 			PutPage("Q\n");
 		}
 	}
@@ -2859,8 +2840,7 @@
 							mm.rotate(ite->rotation());
 							cl.map( mm );
 							ite->PoLine = cl;
-							PutPage(SetClipPath(ite));
-							PutPage("h W* n\n");
+							PutPage(SetClipPath(ite, "W* n\n"));
 							groupStack.push(ite->groupsLastItem);
 							ite->PoLine = clb.copy();
 							continue;
@@ -2958,8 +2938,7 @@
 					mm.rotate(ite->rotation());
 					cl.map( mm );
 					ite->PoLine = cl;
-					grcon += SetClipPath(ite);
-					grcon += "h W* n\n";
+					grcon += SetClipPath(ite, "W* n\n");
 					groupStack.push(ite->groupsLastItem);
 					groupStackS.push(ite);
 					if (((ll.transparency != 1) || (ll.blendMode != 0)) && (Options.Version >= 14))
@@ -3415,18 +3394,15 @@
 				}
 				else
 				{
-					tmp += SetClipPath(ite);
-					tmp += "h\nf*\n";
+					tmp += SetClipPath(ite, "f*\n");
 				}
 			}
 			tmp += "q\n";
 			if (ite->imageClip.size() != 0)
 			{
-				tmp += SetClipPathImage(ite);
-				tmp += "h\nW*\nn\n";
+				tmp += SetClipPathImage(ite, "W*\nn");
 			}
-			tmp += SetClipPath(ite);
-			tmp += "h\nW*\nn\n";
+			tmp += SetClipPath(ite, "W*\nn\n");
 			if (ite->imageFlippedH())
 				tmp += "-1 0 0 1 "+FToStr(ite->width())+" 0 cm\n";
 			if (ite->imageFlippedV())
@@ -3444,8 +3420,7 @@
 					tmp += PDF_TransparenzStroke(ite);
 				if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
 				{
-					tmp += SetClipPath(ite);
-					tmp += "h\nS\n";
+					tmp += SetClipPath(ite, "S\n");
 				}
 				else
 				{
@@ -3455,8 +3430,7 @@
 						if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
 						{
 							tmp += setStrokeMulti(&ml[it]);
-							tmp += SetClipPath(ite);
-							tmp += "h\nS\n";
+							tmp += SetClipPath(ite, "S\n");
 						}
 					}
 				}
@@ -3483,8 +3457,7 @@
 				}
 				else
 				{
-					tmp += SetClipPath(ite);
-					tmp += "h\nf*\n";
+					tmp += SetClipPath(ite, "f*\n");
 				}
 			}
 			tmp += "q\n";
@@ -3500,8 +3473,7 @@
 					tmp += PDF_TransparenzStroke(ite);
 				if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
 				{
-					tmp += SetClipPath(ite);
-					tmp += "h\nS\n";
+					tmp += SetClipPath(ite, "S\n");
 				}
 				else
 				{
@@ -3511,8 +3483,7 @@
 						if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
 						{
 							tmp += setStrokeMulti(&ml[it]);
-							tmp += SetClipPath(ite);
-							tmp += "h\nS\n";
+							tmp += SetClipPath(ite, "S\n");
 						}
 					}
 				}
@@ -3560,8 +3531,7 @@
 					tmp += "/"+ShName+" gs\n";
 				}
 				tmp += putColor(ite->lineColor(), ite->lineShade(), true);
-				tmp += SetClipPathArray(&arrow);
-				tmp += "h\nf*\n";
+				tmp += SetClipPathArray(&arrow, "f*\n");
 			}
 			if (ite->endArrowIndex() != 0)
 			{
@@ -3581,8 +3551,7 @@
 					tmp += "/"+ShName+" gs\n";
 				}
 				tmp += putColor(ite->lineColor(), ite->lineShade(), true);
-				tmp += SetClipPathArray(&arrow);
-				tmp += "h\nf*\n";
+				tmp += SetClipPathArray(&arrow, "f*\n");
 			}
 			break;
 		case PageItem::ItemType1:
@@ -3600,11 +3569,7 @@
 			{
 				if (ite->fillColor() != CommonStrings::None)
 				{
-					tmp += SetClipPath(ite);
-					if (ite->fillRule)
-						tmp += "h\nf*\n";
-					else
-						tmp += "h\nf\n";
+					tmp += SetClipPath(ite, (ite->fillRule ? "f*\n" : "f\n"));
 				}
 			}
 			if ((ite->lineColor() != CommonStrings::None) || (!ite->NamedLStyle.isEmpty()))
@@ -3613,8 +3578,7 @@
 					tmp += PDF_TransparenzStroke(ite);
 				if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
 				{
-					tmp += SetClipPath(ite);
-					tmp += "h\nS\n";
+					tmp += SetClipPath(ite, "S\n");
 				}
 				else
 				{
@@ -3624,8 +3588,7 @@
 						if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
 						{
 							tmp += setStrokeMulti(&ml[it]);
-							tmp += SetClipPath(ite);
-							tmp += "h\nS\n";
+							tmp += SetClipPath(ite, "S\n");
 						}
 					}
 				}
@@ -3646,8 +3609,7 @@
 				{
 					if (ite->fillColor() != CommonStrings::None)
 					{
-						tmp += SetClipPath(ite);
-						tmp += "h\nf*\n";
+						tmp += SetClipPath(ite, "f*\n");
 					}
 				}
 			}
@@ -3657,8 +3619,7 @@
 					tmp += PDF_TransparenzStroke(ite);
 				if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
 				{
-					tmp += SetClipPath(ite, false);
-					tmp += "S\n";
+					tmp += SetClipPath(ite, "S\n", false);
 				}
 				else
 				{
@@ -3668,8 +3629,7 @@
 						if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
 						{
 							tmp += setStrokeMulti(&ml[it]);
-							tmp += SetClipPath(ite, false);
-							tmp += "S\n";
+							tmp += SetClipPath(ite, "S\n", false);
 						}
 					}
 				}
@@ -3700,8 +3660,7 @@
 							tmp += "/"+ShName+" gs\n";
 						}
 						tmp += putColor(ite->lineColor(), ite->lineShade(), true);
-						tmp += SetClipPathArray(&arrow);
-						tmp += "h\nf*\n";
+						tmp += SetClipPathArray(&arrow, "f*\n");
 						break;
 					}
 				}
@@ -3732,8 +3691,7 @@
 							tmp += "/"+ShName+" gs\n";
 						}
 						tmp += putColor(ite->lineColor(), ite->lineShade(), true);
-						tmp += SetClipPathArray(&arrow);
-						tmp += "h\nf*\n";
+						tmp += SetClipPathArray(&arrow, "f*\n");
 						break;
 					}
 				}
@@ -3751,8 +3709,7 @@
 							tmp += PDF_TransparenzStroke(ite);
 						if ((ite->NamedLStyle.isEmpty()) && (ite->lineWidth() != 0.0))
 						{
-							tmp += SetClipPath(ite, false);
-							tmp += "S\n";
+							tmp += SetClipPath(ite, "S\n", false);
 						}
 						else
 						{
@@ -3762,8 +3719,7 @@
 								if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
 								{
 									tmp += setStrokeMulti(&ml[it]);
-									tmp += SetClipPath(ite, false);
-									tmp += "S\n";
+									tmp += SetClipPath(ite, "S\n", false);
 								}
 							}
 						}
@@ -4352,8 +4308,7 @@
 				mm.rotate(embedded->rotation());
 				cl.map( mm );
 				embedded->PoLine = cl;
-				tmp2 += SetClipPath(embedded);
-				tmp2 += "h W* n\n";
+				tmp2 += SetClipPath(embedded, "W* n\n");
 				groupStack.push(embedded->groupsLastItem);
 				embedded->PoLine = clb.copy();
 				continue;
@@ -4886,7 +4841,7 @@
 	return tmp;
 }
 
-QString PDFLibCore::SetClipPathImage(PageItem *ite)
+QString PDFLibCore::SetClipPathImage(PageItem *ite, const QString &pathOp)
 {
 	QString tmp("");
 	if (ite->imageClip.size() > 3)
@@ -4896,7 +4851,7 @@
 		{
 			if (ite->imageClip.point(poi).x() > 900000)
 			{
-				tmp += "h\n";
+				if (! nPath) tmp += "h\n";
 				nPath = true;
 				continue;
 			}
@@ -4920,11 +4875,13 @@
 				tmp += FToStr(np3.x())+" "+FToStr(-np3.y())+" c\n";
 			}
 		}
+		if (! nPath) tmp += "h\n";
 	}
+	if (tmp.length()) tmp += pathOp;
 	return tmp;
 }
 
-QString PDFLibCore::SetClipPath(PageItem *ite, bool poly)
+QString PDFLibCore::SetClipPath(PageItem *ite, const QString &pathOp, bool poly)
 {
 	QString tmp("");
 	if (ite->PoLine.size() > 3)
@@ -4934,7 +4891,7 @@
 		{
 			if (ite->PoLine.point(poi).x() > 900000)
 			{
-				if (poly)
+				if (poly && ! nPath)
 					tmp += "h\n";
 				nPath = true;
 				continue;
@@ -4959,11 +4916,13 @@
 				tmp += FToStr(np3.x())+" "+FToStr(-np3.y())+" c\n";
 			}
 		}
+		if (poly && ! nPath) tmp += "h\n";
 	}
+	if (tmp.length()) tmp += pathOp;
 	return tmp;
 }
 
-QString PDFLibCore::SetClipPathArray(FPointArray *ite, bool poly)
+QString PDFLibCore::SetClipPathArray(FPointArray *ite, const QString &pathOp, bool poly)
 {
 	QString tmp("");
 	if (ite->size() > 3)
@@ -4973,7 +4932,7 @@
 		{
 			if (ite->point(poi).x() > 900000)
 			{
-				if (poly)
+				if (poly && ! nPath)
 					tmp += "h\n";
 				nPath = true;
 				continue;
@@ -4998,7 +4957,9 @@
 				tmp += FToStr(np3.x())+" "+FToStr(-np3.y())+" c\n";
 			}
 		}
+		if (poly && ! nPath) tmp += "h\n";
 	}
+	if (tmp.length()) tmp += pathOp;
 	return tmp;
 }
 
@@ -5044,8 +5005,7 @@
 				mm.rotate(item->rotation());
 				cl.map( mm );
 				item->PoLine = cl;
-				tmp2 += SetClipPath(item);
-				tmp2 += "h W* n\n";
+				tmp2 += SetClipPath(item, "W* n\n");
 				groupStack.push(item->groupsLastItem);
 				item->PoLine = clb.copy();
 				continue;
@@ -5250,11 +5210,7 @@
 		Patterns.insert("Pattern"+currItem->pattern()+QString::number(ResCount), patObject);
 		QString tmp = "/Pattern cs\n";
 		tmp += "/Pattern"+currItem->pattern()+QString::number(ResCount)+" scn\n";
-		tmp += SetClipPath(currItem);
-		if (currItem->fillRule)
-			tmp += "h\nf*\n";
-		else
-			tmp += "h\nf\n";
+		tmp += SetClipPath(currItem, (currItem->fillRule ? "f*\n" : "f\n"));
 		ResCount++;
 		output = tmp;
 		return true;
@@ -5391,7 +5347,7 @@
 			}
 			PutDoc(">>\n");
 			QString stre = "";
-			stre += "q\n"+SetClipPath(currItem)+"h\nW* n\n"+"/"+ShName+" sh\nQ\n";
+			stre += "q\n"+SetClipPath(currItem, "W* n\n")+"/"+ShName+" sh\nQ\n";
 			if (Options.Compress)
 				stre = CompressStr(&stre);
 			PutDoc("/Length "+QString::number(stre.length())+"\n");
@@ -5603,8 +5559,7 @@
 		tmp += "q\n";
 		if ((Options.Version >= 14) && ((Trans.at(c+1) != 1) || (Trans.at(c) != 1)))
 			tmp += "/"+TRes+" gs\n";
-		tmp += SetClipPath(currItem);
-		tmp += "h\nW* n\n";
+		tmp += SetClipPath(currItem, "W* n\n");
 		tmp += "/"+ShName+" sh\nQ\n";
 	}
 	return tmp;
--- Scribus/scribus/pdflib_core.h.badpdf	2008-10-14 14:01:50.000000000 -0400
+++ Scribus/scribus/pdflib_core.h	2008-10-15 17:01:51.000000000 -0400
@@ -104,9 +104,9 @@
 	QString FitKey(const QString & pass);
 
 	QString setStrokeMulti(struct SingleLine *sl);
-	QString SetClipPathArray(FPointArray *ite, bool poly = true);
-	QString SetClipPathImage(PageItem *ite);
-	QString SetClipPath(PageItem *ite, bool poly = true);
+	QString SetClipPathArray(FPointArray *ite, const QString& pathOp, bool poly = true);
+	QString SetClipPathImage(PageItem *ite, const QString& pathOp);
+	QString SetClipPath(PageItem *ite, const QString& pathOp, bool poly = true);
 	QString SetColor(const QString& farbe, double Shade);
 	QString SetColor(const ScColor& farbe, double Shade);
 	QString SetGradientColor(const QString& farbe, double Shade);
scribus-pdf.patch (15,779 bytes)   

fschmid

2008-10-16 07:34

administrator   ~0020445

This was fixed with committs r12698 and r12700. The whole issue was the fact that the render frames didn't get correctly initialized during creation. Now they have always correct clipping paths. Another issue was the fact that the PDF's generated by pdftex are needing a correct default graphics state (stroke & fill color set to black, linewidth = 1 etc..) in the PDF.

Issue History

Date Modified Username Field Change
2008-10-15 22:31 pspencer New Issue
2008-10-15 22:31 pspencer File Added: scribus-pdf.patch
2008-10-16 07:34 fschmid Note Added: 0020445
2008-10-16 07:34 fschmid Status new => resolved
2008-10-16 07:34 fschmid Fixed in Version => 1.3.5svn
2008-10-16 07:34 fschmid Resolution open => fixed
2008-10-16 07:34 fschmid Assigned To => fschmid
2008-12-10 16:26 mhanski Relationship added child of 0007647
2008-12-11 22:26 cbradney Status resolved => closed
2016-01-14 01:20 JLuc Relationship added related to 0013654