You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by db...@apache.org on 2001/01/09 21:32:58 UTC

cvs commit: xml-xalan/c/Tests/Performance perf.cpp perf.dsp perf.dsw

dbertoni    01/01/09 12:32:57

  Modified:    c/Tests/Harness Harness.dsp
               c/Tests/Performance perf.cpp perf.dsp
  Removed:     c/Tests/Harness Harness.dsw
               c/Tests/Performance perf.dsw
  Log:
  New workspace.  Fixed problems with link libraries.  Fixed lots of code problems.  Removed obsolete workspace files.
  
  Revision  Changes    Path
  1.3       +6 -3      xml-xalan/c/Tests/Harness/Harness.dsp
  
  Index: Harness.dsp
  ===================================================================
  RCS file: /home/cvs/xml-xalan/c/Tests/Harness/Harness.dsp,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Harness.dsp	2001/01/03 21:24:43	1.2
  +++ Harness.dsp	2001/01/09 20:32:50	1.3
  @@ -43,7 +43,7 @@
   # PROP Ignore_Export_Lib 0
   # PROP Target_Dir ""
   # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HARNESS_EXPORTS" /Yu"stdafx.h" /FD /c
  -# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HARNESS_EXPORTS" /FD /c
  +# ADD CPP /nologo /MD /W4 /GR /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HARNESS_EXPORTS" /FD /c
   # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
   # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
   # ADD BASE RSC /l 0x409 /d "NDEBUG"
  @@ -53,7 +53,8 @@
   # ADD BSC32 /nologo
   LINK32=link.exe
   # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
  -# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /incremental:yes /debug /machine:I386
  +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
  +# SUBTRACT LINK32 /incremental:yes /debug
   
   !ELSEIF  "$(CFG)" == "Harness - Win32 Debug"
   
  @@ -66,9 +67,10 @@
   # PROP Use_Debug_Libraries 1
   # PROP Output_Dir "..\..\Build\Win32\VC6\Debug"
   # PROP Intermediate_Dir "..\..\Build\Win32\VC6\Debug\Performance"
  +# PROP Ignore_Export_Lib 0
   # PROP Target_Dir ""
   # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HARNESS_EXPORTS" /Yu"stdafx.h" /FD /GZ /c
  -# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HARNESS_EXPORTS" /FD /GZ /c
  +# ADD CPP /nologo /MDd /W4 /Gm /GR /GX /Zi /Od /Gf /Gy /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "HARNESS_EXPORTS" /Yc /FD /GZ /c
   # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
   # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
   # ADD BASE RSC /l 0x409 /d "_DEBUG"
  @@ -79,6 +81,7 @@
   LINK32=link.exe
   # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
   # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
  +# SUBTRACT LINK32 /incremental:no
   
   !ENDIF 
   
  
  
  
  1.6       +235 -144  xml-xalan/c/Tests/Performance/perf.cpp
  
  Index: perf.cpp
  ===================================================================
  RCS file: /home/cvs/xml-xalan/c/Tests/Performance/perf.cpp,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- perf.cpp	2001/01/08 22:24:39	1.5
  +++ perf.cpp	2001/01/09 20:32:54	1.6
  @@ -118,7 +118,7 @@
   #endif
   
   
  -const char* 	xslStylesheets[] =
  +const char* const 	xslStylesheets[] =
   {
   	"v:\\xsl-test\\perf\\basic\\basic-all_well",
   	"v:\\xsl-test\\perf\\basic\\basic-datetranscode",
  @@ -134,28 +134,80 @@
   	"v:\\xsl-test\\perf\\xpath\\xpath-evans_tiny",
   	0
   };
  -const char* 	outputDir = "d:\\xslt-results\\perf\\test\\";
   
   
  -// Used to hold compiled stylesheet, and source document.
  -XalanNode*		glbSourceXML;
  -StylesheetRoot*	glbStylesheetRoot;
   
  -void outputMessage(int iter)
  +const char* const	outputDir = "\\xslt-results\\perf\\test\\";
  +
  +
  +
  +void
  +outputMessage(int	iter)
   {
   	cout << "\n" << "Starting Iteration: " << iter << '\0';
   }
  +
  +
  +
  +inline StylesheetRoot*
  +processStylesheet(
  +			const XalanDOMString&			theFileName,
  +			XSLTProcessor&					theProcessor,
  +			StylesheetConstructionContext&	theConstructionContext)
  +{
  +	const XSLTInputSource	theInputSource(c_wstr(theFileName));
  +
  +	return theProcessor.processStylesheet(theInputSource, theConstructionContext);
  +}
  +
  +
  +
  +inline XalanNode*
  +parseSourceDocument(
  +			const XalanDOMString&	theFileName,
  +			XSLTProcessor&			theProcessor)
  +{
  +	const XSLTInputSource	theInputSource(c_wstr(theFileName));
  +
  +	return theProcessor.getSourceTreeFromInput(theInputSource);
  +}
   
  -int main( int argc,	const char* argv [])
  +
  +
  +inline double
  +calculateElapsedTime(
  +			clock_t		theStartTime,
  +			clock_t		theEndTime)
   {
  -	XMLFileReporter theXMLFileReporter;
  +	return double(theEndTime - theStartTime) / CLOCKS_PER_SEC * 1000.0;
  +}
  +
  +
   
  +inline double
  +calculateAverageElapsedTime(
  +			clock_t			theStartTime,
  +			clock_t			theEndTime,
  +			long			theIterationCount)
  +{
  +	assert(theIterationCount > 0);
  +
  +	return calculateElapsedTime(theStartTime, theEndTime) / theIterationCount;
  +}
  +
  +
  +
  +int
  +main(
  +			int				argc,
  +			const char*		argv[])
  +{
  +	XMLFileReporter		theXMLFileReporter;
  +
   	theXMLFileReporter.setFileName("cpp.xml");
   	theXMLFileReporter.initialize();
   	theXMLFileReporter.logTestFileInit("Performance Testing - Reports performance times for single transform, and average for multiple transforms using compiled stylesheet");
   	
  -
  -
   #if !defined(NDEBUG) && defined(_MSC_VER)
   	_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
   
  @@ -165,153 +217,192 @@
   
   	if (argc > 2)
   	{
  -		cerr << "Usage: perf" << endl  << endl;
  +		cerr << "Usage: perf <count>" << endl  << endl;
   	}
   	else
   	{
  -		int	iterCount = 1;
  +		long	iterCount = 1;
  +
   		if (argc == 2)
   		{
  -			iterCount = atoi(argv[1]);
  +			iterCount = atol(argv[1]);
   		}
   
  -		try
  +		if (iterCount <= 0)
   		{
  -			// Call the static initializers... and define file suffixes
  -			XMLPlatformUtils::Initialize();
  -			const XalanDOMString  XSLSuffix(".xsl");
  -			const XalanDOMString  XMLSuffix(".xml");
  -			const XalanDOMString  outputSuffix(".out");
  -
  +			cerr << "Usage: perf <count>" << endl  << endl;
  +		}
  +		else
  +		{
  +			try
   			{
  -			  XSLTInit	theInit;
  +				// Call the static initializers... and define file suffixes
  +				XMLPlatformUtils::Initialize();
   
  -			  for(int i = 0; xslStylesheets[i] != 0; i++)
  -			  {
  -				// Output file name to result log.
  -				theXMLFileReporter.logTestCaseInit(xslStylesheets[i]);
  -
  -				// Create the necessary support objects to instantiate a processor.
  -				XalanSourceTreeDOMSupport		csDOMSupport;
  -				XalanSourceTreeParserLiaison	csParserLiaison(csDOMSupport);
  -
  -				csDOMSupport.setParserLiaison(&csParserLiaison);
  -
  -				XSLTProcessorEnvSupportDefault	csXSLTProcessorEnvSupport;
  -				XObjectFactoryDefault			csXObjectFactory;
  -				XPathFactoryDefault				csXPathFactory;
  -
  -				// Create a processor for stylesheet compilation and connect to 
  -				// ProcessorEnvSupport object
  -				XSLTEngineImpl	csProcessor(
  -						csParserLiaison,
  -						csXSLTProcessorEnvSupport,
  -						csDOMSupport,
  -						csXObjectFactory,   
  -						csXPathFactory);
  -				csXSLTProcessorEnvSupport.setProcessor(&csProcessor);
  -
  -				// Create separate factory support object, so the stylesheet's
  -				// factory-created XPath instance are independent from processor's.
  -				XPathFactoryDefault			ssXPathFactory;
  -
  -				// Create a stylesheet construction context, using the
  -				// stylesheet's factory support objects.
  -				StylesheetConstructionContextDefault	csConstructionContext(
  -														csProcessor,
  -														csXSLTProcessorEnvSupport,
  -														ssXPathFactory);
  -
  -
  -				const XalanDOMString  theXSLfile(XalanDOMString(xslStylesheets[i]) + XSLSuffix);
  -				const XalanDOMString  theXMLfile(XalanDOMString(xslStylesheets[i]) + XMLSuffix);
  -
  -				cout << endl << "Compiling: " << xslStylesheets[i] << endl;
  -
  -				//Generate the XML and XSL input objects.
  -				XSLTInputSource		csStylesheetSourceXSL(c_wstr(theXSLfile));
  -				XSLTInputSource		csSourceXML(c_wstr(theXMLfile));
  -
  -				// Ask the processor to create a compiled stylesheet (StylesheetRoot) for the 
  -				// specified input XSL. We don't have to delete it, since it is owned by the 
  -				// StylesheetConstructionContext instance.
  -
  -				const clock_t startTime = clock();
  -					glbStylesheetRoot= csProcessor.processStylesheet(csStylesheetSourceXSL,
  -												   csConstructionContext);
  -				const clock_t endTime = clock();
  -				assert(glbStylesheetRoot != 0);
  -
  -				// Output stats on stylesheet compliation to console and log file.
  -				cout << "Compliation of Stylesheet took: " << endTime - startTime << endl;
  -				theXMLFileReporter.logStatistic(60, endTime-startTime,0.0,"Compilation of stylesheet took: ");
  -
  -				// Have the processor create a compiled SourceDocument for the specified
  -				// input XML. 
  -				glbSourceXML = csProcessor.getSourceTreeFromInput(csSourceXML);
  -				assert(glbSourceXML != 0);
  -
  -				// The execution context uses the same factory support objects as
  -				// the processor, since those objects have the same lifetime as
  -				// other objects created as a result of the execution.
  -				StylesheetExecutionContextDefault	psExecutionContext(
  -							csProcessor,
  -							csXSLTProcessorEnvSupport,
  -							csDOMSupport,
  -							csXObjectFactory);
  -
  -				const XalanDOMString  outputfile(//XalanDOMString(outputDir) +
  -						                             XalanDOMString(xslStylesheets[i]) + 
  -													                outputSuffix);
  -
  -				//Generate the XML input and output objects.
  -				//XSLTInputSource		csSourceXML(glbSourceXML);
  -				XSLTResultTarget	theResultTarget(outputfile);
  -
  -				// Set the stylesheet to be the compiled stylesheet, then do a single transform.
  -				csProcessor.setStylesheetRoot(glbStylesheetRoot);
  -
  -				const clock_t singleStart = clock();
  -				csProcessor.process(csSourceXML, theResultTarget,psExecutionContext);
  -				const clock_t singleEnd = clock();
  -				psExecutionContext.reset();
  -				
  -				// Output stats on transform times to console and result log
  -				cout << "Single Transform time: " << singleEnd - singleStart << endl;
  -				theXMLFileReporter.logStatistic(60,singleEnd - singleStart,0,"Single transform took: ");
  -
  -				const clock_t multiStartTime = clock();
  -				for(int j = 0; j < iterCount; ++j)
  -				{	
  -					csProcessor.setStylesheetRoot(glbStylesheetRoot);
  -					csProcessor.process(csSourceXML, theResultTarget,psExecutionContext);
  -					psExecutionContext.reset();
  -				}
  +				{
  +					XSLTInit	theInit;
   
  -				csParserLiaison.reset();
  +					const XalanDOMString  XSLSuffix(".xsl");
  +					const XalanDOMString  XMLSuffix(".xml");
  +					const XalanDOMString  outputSuffix(".out");
   
  -				const clock_t multiEndTime = clock();
  -				const double millis = ((multiEndTime - multiStartTime) / CLOCKS_PER_SEC) * 1000.0;
  +					for(long i = 0; xslStylesheets[i] != 0; i++)
  +					{
  +						// Output file name to result log.
  +						theXMLFileReporter.logTestCaseInit(xslStylesheets[i]);
   
  -				char tmp[100];
  -				sprintf(tmp, "%s%d%s","Average transform time based on ", iterCount, "iterations."); 
  -				// Output stats on transform times to console and result log
  -				cout << "Averaged: " << millis / iterCount << " for " << iterCount << " iterations" << endl;
  -				theXMLFileReporter.logStatistic(60, millis/iterCount,0.0,tmp);
  -				theXMLFileReporter.logTestCaseClose(xslStylesheets[i], "Done");
  -  }
  -				
  -		}
  -			//theXMLFileReporter.logTestFileClose();
  -			theXMLFileReporter.logTestFileClose("Performance","Done");
  -			theXMLFileReporter.close();
  -			XMLPlatformUtils::Terminate();
  -		}
  -		catch(...)
  -		{
  -			cerr << "Exception caught!!!"
  -				 << endl
  -				 << endl;
  +						// Create the necessary support objects to instantiate a processor.
  +						XalanSourceTreeDOMSupport		csDOMSupport;
  +						XalanSourceTreeParserLiaison	csParserLiaison(csDOMSupport);
  +
  +						csDOMSupport.setParserLiaison(&csParserLiaison);
  +
  +						XSLTProcessorEnvSupportDefault	csXSLTProcessorEnvSupport;
  +						XObjectFactoryDefault			csXObjectFactory;
  +						XPathFactoryDefault				csXPathFactory;
  +
  +						// Create a processor for stylesheet compilation and connect to 
  +						// ProcessorEnvSupport object
  +						XSLTEngineImpl	csProcessor(
  +								csParserLiaison,
  +								csXSLTProcessorEnvSupport,
  +								csDOMSupport,
  +								csXObjectFactory,
  +								csXPathFactory);
  +
  +						// Hook up the processor the the support object.
  +						csXSLTProcessorEnvSupport.setProcessor(&csProcessor);
  +
  +						// Create separate factory support object, so the stylesheet's
  +						// factory-created XPath instance are independent from processor's.
  +						XPathFactoryDefault			ssXPathFactory;
  +
  +						// Create a stylesheet construction context, using the
  +						// stylesheet's factory support objects.
  +						StylesheetConstructionContextDefault	csConstructionContext(
  +																csProcessor,
  +																csXSLTProcessorEnvSupport,
  +																ssXPathFactory);
  +
  +						const XalanDOMString  theXSLFile(XalanDOMString(xslStylesheets[i]) + XSLSuffix);
  +
  +						cout << endl << "Compiling: " << xslStylesheets[i] << endl;
  +
  +						const clock_t startTime = clock();
  +
  +						// Create a compiled stylesheet (StylesheetRoot) for the
  +						// specified input XSL. We don't have to delete it, since
  +						// it is owned by the StylesheetConstructionContextDefault
  +						// instance.
  +						const StylesheetRoot* const		glbStylesheetRoot =
  +							processStylesheet(
  +									theXSLFile,
  +									csProcessor,
  +									csConstructionContext);
  +						assert(glbStylesheetRoot != 0);
  +
  +						const clock_t	endTime = clock();
  +
  +						const double	compilationMilliseconds =
  +							double(endTime - startTime) / CLOCKS_PER_SEC * 1000.0;
  +
  +						// Output stats on stylesheet compliation to console and log file.
  +						cout << "Compilation of the stylesheet took " << compilationMilliseconds << " milliseconds." << endl;
  +
  +						theXMLFileReporter.logStatistic(
  +								60,
  +								0,
  +								compilationMilliseconds,
  +								"Compilation of stylesheet took: ");
  +
  +						const XalanDOMString  theXMLFile(XalanDOMString(xslStylesheets[i]) + XMLSuffix);
  +
  +						// Parse the input XML.
  +						XalanNode* const	glbSourceXML =
  +							parseSourceDocument(theXMLFile, csProcessor);
  +						assert(glbSourceXML != 0);
  +
  +						// Put the parsed document into an XSLTInputSource.
  +						const XSLTInputSource	csSourceDocument(glbSourceXML);
  +
  +						// The execution context uses the same factory support objects as
  +						// the processor, since those objects have the same lifetime as
  +						// other objects created as a result of the execution.
  +						StylesheetExecutionContextDefault	psExecutionContext(
  +									csProcessor,
  +									csXSLTProcessorEnvSupport,
  +									csDOMSupport,
  +									csXObjectFactory);
  +
  +						const XalanDOMString  theOutputFile(//XalanDOMString(outputDir) +
  +															 XalanDOMString(xslStylesheets[i]) + 
  +																			outputSuffix);
  +
  +						// The result will go in the
  +						XSLTResultTarget	theResultTarget(theOutputFile);
  +
  +						// Set the stylesheet, and do a single transform.
  +						csProcessor.setStylesheetRoot(glbStylesheetRoot);
  +
  +						const clock_t singleStart = clock();
  +
  +						csProcessor.process(csSourceDocument, theResultTarget, psExecutionContext);
  +
  +						const clock_t singleEnd = clock();
  +
  +						// Reset the execution context to get ready for the next run...
  +						psExecutionContext.reset();
  +						
  +						const double	singleMilliseconds =
  +							calculateElapsedTime(singleStart, singleEnd);
  +
  +						// Output stats on transform times to console and result log
  +						cout << "Single transform took " << singleMilliseconds << " milliseconds." << endl;
  +
  +						theXMLFileReporter.logStatistic(
  +								60,
  +								0,
  +								singleMilliseconds,
  +								"Single transform took: ");
  +
  +						const clock_t	multiStartTime = clock();
  +
  +						for(long j = 0; j < iterCount; ++j)
  +						{	
  +							csProcessor.setStylesheetRoot(glbStylesheetRoot);
  +							csProcessor.process(csSourceDocument, theResultTarget, psExecutionContext);
  +							psExecutionContext.reset();
  +						}
  +
  +						csParserLiaison.reset();
  +
  +						const clock_t	multiEndTime = clock();
  +
  +						char tmp[100];
  +						sprintf(tmp, "%s%d%s","Average transform time based on ", iterCount, "iterations.");
  +
  +						const double	theAverage =
  +							calculateAverageElapsedTime(multiStartTime, multiEndTime, iterCount);
  +
  +						// Output stats on transform times to console and result log
  +						cout << "Averaged: " << theAverage << " for " << iterCount << " iterations" << endl;
  +
  +						theXMLFileReporter.logStatistic(60, 0, theAverage, tmp);
  +						theXMLFileReporter.logTestCaseClose(xslStylesheets[i], "Done");
  +					}
  +				}
  +
  +				theXMLFileReporter.logTestFileClose("Performance", "Done");
  +				theXMLFileReporter.close();
  +
  +				XMLPlatformUtils::Terminate();
  +			}
  +			catch(...)
  +			{
  +				cerr << "Exception caught!!!"
  +					 << endl
  +					 << endl;
  +			}
   		}
   	}
   
  
  
  
  1.6       +2 -2      xml-xalan/c/Tests/Performance/perf.dsp
  
  Index: perf.dsp
  ===================================================================
  RCS file: /home/cvs/xml-xalan/c/Tests/Performance/perf.dsp,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- perf.dsp	2001/01/03 21:24:24	1.5
  +++ perf.dsp	2001/01/09 20:32:55	1.6
  @@ -42,7 +42,7 @@
   # PROP Ignore_Export_Lib 0
   # PROP Target_Dir ""
   # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
  -# ADD CPP /nologo /W4 /GX /O2 /I "..\..\..\..\xml-xerces\c\src" /I "..\..\src\\" /I "..\harness\\" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
  +# ADD CPP /nologo /MD /W4 /GX /O2 /I "..\..\..\..\xml-xerces\c\src" /I "..\..\src\\" /I "..\harness\\" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
   # ADD BASE RSC /l 0x409 /d "NDEBUG"
   # ADD RSC /l 0x409 /d "NDEBUG"
   BSC32=bscmake.exe
  @@ -66,7 +66,7 @@
   # PROP Ignore_Export_Lib 0
   # PROP Target_Dir ""
   # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
  -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\src\\" /I "..\..\..\..\xml-xerces\c\src\\" /I "..\harness\\" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
  +# ADD CPP /nologo /MDd /W4 /Gm /GR /GX /Zi /Od /Gf /Gy /I "..\..\src\\" /I "..\..\..\..\xml-xerces\c\src\\" /I "..\harness\\" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
   # SUBTRACT CPP /X
   # ADD BASE RSC /l 0x409 /d "_DEBUG"
   # ADD RSC /l 0x409 /d "_DEBUG"