Revision 180 org.gvsig.publish/trunk/org.gvsig.publish/org.gvsig.publish.mapserver/org.gvsig.publish.lib.impl.mapserver/src/main/java/org/gvsig/publish/impl/mapserver/utils/MapServer.java
MapServer.java | ||
---|---|---|
35 | 35 |
import org.apache.commons.lang.StringUtils; |
36 | 36 |
import org.cresques.cts.IDatum; |
37 | 37 |
import org.cresques.cts.IProjection; |
38 |
import org.slf4j.Logger; |
|
39 |
import org.slf4j.LoggerFactory; |
|
40 |
|
|
38 | 41 |
import org.gvsig.app.project.documents.view.ViewDocument; |
39 | 42 |
import org.gvsig.complexlabel.impl.DefaultComplexLabelClass; |
40 | 43 |
import org.gvsig.complexlegend.ComplexLegendItem; |
... | ... | |
74 | 77 |
import org.gvsig.publish.PublishProperties; |
75 | 78 |
import org.gvsig.publish.impl.DefaultPublishManager; |
76 | 79 |
import org.gvsig.publish.impl.mapserver.MapserverProperties; |
77 |
import org.gvsig.publish.impl.mapserver.MapserverService; |
|
78 | 80 |
import org.gvsig.publish.impl.mapserver.MapserverToDynObjectHelper; |
79 | 81 |
import org.gvsig.publish.impl.mapserver.ToMapserverConverter; |
80 | 82 |
import org.gvsig.publish.mapserver641.AlignEnum; |
... | ... | |
116 | 118 |
import org.gvsig.tools.dataTypes.DataTypes; |
117 | 119 |
import org.gvsig.tools.dynobject.DynField; |
118 | 120 |
import org.gvsig.tools.dynobject.DynObject; |
119 |
import org.slf4j.Logger; |
|
120 |
import org.slf4j.LoggerFactory; |
|
121 | 121 |
|
122 | 122 |
public class MapServer { |
123 | 123 |
|
... | ... | |
196 | 196 |
return null; |
197 | 197 |
} |
198 | 198 |
|
199 |
Map map = getPublishedMap(MapServerUtils.getCurrentViewDocument());
|
|
199 |
Map map = getPublishedMap(MapServerUtils.getCurrentViewDocument()); |
|
200 | 200 |
Web web = null; |
201 | 201 |
if(isEditedMapFile && !map.getWeb().isEmpty()){ |
202 | 202 |
web = map.getWeb().get(0); |
... | ... | |
248 | 248 |
IDatum datum = proj.getDatum(); |
249 | 249 |
map.getProjection().add(getCorrectProjection(proj.getAbrev())); |
250 | 250 |
map.setScaleDenom((double) doc.getMapContext().getScaleView()); |
251 |
if (!getPublishProperties().isDefaultPath() &&
|
|
251 |
if (!getPublishProperties().isDefaultPath() && |
|
252 | 252 |
!getPublishProperties().isAbsolutePath()) { |
253 | 253 |
map.setShapePath(getPublishProperties().getShapePath()); |
254 | 254 |
} |
... | ... | |
345 | 345 |
if(!MapServerUtils.isOutputLoaded(map.getOutputFormat(), auxOutputEdited.get(k))){ |
346 | 346 |
OutputFormat out = auxOutputEdited.get(k); |
347 | 347 |
out.setName(MapServerUtils.createUniqueOutputFormatName( |
348 |
map.getOutputFormat(),
|
|
348 |
map.getOutputFormat(), |
|
349 | 349 |
out.getName())); |
350 | 350 |
map.getOutputFormat().add(out); |
351 | 351 |
} |
... | ... | |
366 | 366 |
MapServerUtils.relativePath( |
367 | 367 |
new File( |
368 | 368 |
file.getParent() + File.separator + IMAGE_FOLDER) |
369 |
.getAbsolutePath(),
|
|
369 |
.getAbsolutePath(), |
|
370 | 370 |
file.getParent())); |
371 | 371 |
} |
372 | 372 |
if (usesFont) { |
... | ... | |
394 | 394 |
} |
395 | 395 |
//web.setTempPath(System.getProperty("java.io.tmpdir")); |
396 | 396 |
map.getWeb().add(web); |
397 |
}else{
|
|
397 |
}else{ |
|
398 | 398 |
web.setMetadata(getCorrectMetadata(web.getMetadata())); |
399 | 399 |
if(!isWCSService){ |
400 | 400 |
for(int i=map.getOutputFormat().size()-1; i>=0; i--){ |
... | ... | |
424 | 424 |
SymbolSet newsymbolset = new SymbolSet(); |
425 | 425 |
newsymbolset = (SymbolSet) parserFile(getSymbolSetFile(), newsymbolset); |
426 | 426 |
SymbolSet auxsset = new SymbolSet(); |
427 |
if(newsymbolset != null &&
|
|
428 |
auxsset.getSymbol() != null &&
|
|
427 |
if(newsymbolset != null && |
|
428 |
auxsset.getSymbol() != null && |
|
429 | 429 |
newsymbolset.getSymbol() != null){ |
430 | 430 |
auxsset.getSymbol().addAll(newsymbolset.getSymbol()); |
431 | 431 |
} |
... | ... | |
440 | 440 |
newsymbolset.getSymbol().add(symAux); |
441 | 441 |
auxsset.getSymbol().add(symAux); |
442 | 442 |
} |
443 |
|
|
443 |
|
|
444 | 444 |
loadSymbolsImages(newsymbolset); |
445 | 445 |
parserFile(newsymbolset, getSymbolSetFile()); |
446 |
}
|
|
446 |
} |
|
447 | 447 |
|
448 | 448 |
// }else{ |
449 | 449 |
// // TODO Merge de la definici?n en el mapfile.map |
... | ... | |
476 | 476 |
if(!StringUtils.isBlank(map.getSymbolSet())){ |
477 | 477 |
newmap.setSymbolSet(map.getSymbolSet()); |
478 | 478 |
} |
479 |
|
|
479 |
|
|
480 | 480 |
Web auxWeb = new Web(); |
481 | 481 |
boolean isNewWeb = true; |
482 |
if(!newmap.getWeb().isEmpty()
|
|
482 |
if(!newmap.getWeb().isEmpty() |
|
483 | 483 |
&& !StringUtils.isBlank(newmap.getWeb().get(0).getImagePath())){ |
484 | 484 |
auxWeb = newmap.getWeb().get(0); |
485 | 485 |
isNewWeb = false; |
... | ... | |
497 | 497 |
} |
498 | 498 |
} |
499 | 499 |
} |
500 |
|
|
500 |
|
|
501 | 501 |
newmap.getInclude().addAll(map.getInclude()); |
502 | 502 |
parserFile(newmap, file); |
503 | 503 |
|
... | ... | |
520 | 520 |
} |
521 | 521 |
} |
522 | 522 |
} |
523 |
|
|
523 |
|
|
524 | 524 |
protected String addImageUrl(String url) { |
525 | 525 |
File originalFile = new File(MapServerUtils.getCorrectFilePathFromUrl(url)); |
526 | 526 |
String legFileName = originalFile.getName(); |
527 | 527 |
|
528 | 528 |
PublishManager manager = PublishLocator.getServiceManager().getPublishManager(); |
529 |
|
|
529 |
|
|
530 | 530 |
File file = getCurrentFile(); |
531 |
|
|
531 |
|
|
532 | 532 |
if(file != null){ |
533 | 533 |
File parentFile = new File(getCorrectPath(file.getParent())); |
534 |
|
|
535 |
if(parentFile.isDirectory()
|
|
534 |
|
|
535 |
if(parentFile.isDirectory() |
|
536 | 536 |
&& parentFile.canWrite()){ |
537 | 537 |
File legfile = new File(getCorrectPath(parentFile.getAbsolutePath() |
538 | 538 |
+ File.separator + MapServer.IMAGE_FOLDER + File.separator + legFileName)); |
... | ... | |
581 | 581 |
} |
582 | 582 |
return null; |
583 | 583 |
} |
584 |
|
|
584 |
|
|
585 | 585 |
private void loadSymbolImages(Symbol newsymbol) { |
586 | 586 |
if(newsymbol.getImage() != null && newsymbol.getImage() != ""){ |
587 | 587 |
String fileImageURL = addImageUrl(newsymbol.getImage()); |
588 |
|
|
588 |
|
|
589 | 589 |
String path = ""; |
590 | 590 |
if(fileImageURL != null){ |
591 | 591 |
File imageFile = new File(fileImageURL); |
... | ... | |
596 | 596 |
}else{ |
597 | 597 |
path = newsymbol.getImage(); |
598 | 598 |
} |
599 |
|
|
599 |
|
|
600 | 600 |
newsymbol.setImage(path.replace(File.separator, "/")); |
601 | 601 |
} |
602 | 602 |
} |
... | ... | |
677 | 677 |
hasLabels = false; |
678 | 678 |
Layer lyr = new Layer(); |
679 | 679 |
ItemType itemType = new ItemType(); |
680 |
|
|
680 |
|
|
681 | 681 |
lyr.setTolerance(3.0); |
682 | 682 |
|
683 | 683 |
if(layer.getParentLayer() != null && layer.getParentLayer().getName() != null && layer.getParentLayer().getName() != "root layer"){ |
... | ... | |
693 | 693 |
Envelope env = layer.getFullEnvelope(); |
694 | 694 |
Point lower = env.getLowerCorner(); |
695 | 695 |
Point upper = env.getUpperCorner(); |
696 |
extent = MapServerUtils.getDecreasedMin(lower.getX()) + " " +
|
|
697 |
MapServerUtils.getDecreasedMin(lower.getY()) + " " +
|
|
698 |
MapServerUtils.getIncrementedMax(upper.getX())+ " " +
|
|
696 |
extent = MapServerUtils.getDecreasedMin(lower.getX()) + " " + |
|
697 |
MapServerUtils.getDecreasedMin(lower.getY()) + " " + |
|
698 |
MapServerUtils.getIncrementedMax(upper.getX())+ " " + |
|
699 | 699 |
MapServerUtils.getIncrementedMax(upper.getY()); |
700 | 700 |
lyr.getExtent().add(MapServerUtils.getDecreasedMin(lower.getX())); |
701 | 701 |
lyr.getExtent().add(MapServerUtils.getDecreasedMin(lower.getY())); |
... | ... | |
944 | 944 |
} |
945 | 945 |
} catch (Exception e1) { |
946 | 946 |
logger.debug("Error parsing MapServer project"); |
947 |
}
|
|
947 |
} |
|
948 | 948 |
|
949 | 949 |
if (flyrvect.getFeatureStore().getParameters() instanceof DBStoreParameters) { |
950 | 950 |
DBStoreParameters dbStore = (DBStoreParameters) flyrvect |
... | ... | |
973 | 973 |
while(it.hasNext()){ |
974 | 974 |
ComplexLegendItem item = (ComplexLegendItem) it.next(); |
975 | 975 |
getMapClass( |
976 |
layer,
|
|
977 |
lyr,
|
|
978 |
localSymbolSet,
|
|
979 |
item.getLegend(),
|
|
980 |
item.getMinScale(),
|
|
976 |
layer, |
|
977 |
lyr, |
|
978 |
localSymbolSet, |
|
979 |
item.getLegend(), |
|
980 |
item.getMinScale(), |
|
981 | 981 |
item.getMaxScale()); |
982 | 982 |
} |
983 | 983 |
}else{ |
... | ... | |
999 | 999 |
lyr.setConnectionType("RASTER"); |
1000 | 1000 |
|
1001 | 1001 |
if (flyrraster.getFileLayer() != null) { |
1002 |
lyr.setData(getCorrectPath(flyrraster.getURI())); |
|
1003 |
}
|
|
1002 |
lyr.setData(getCorrectPath(flyrraster.getURI().getPath()));
|
|
1003 |
} |
|
1004 | 1004 |
|
1005 | 1005 |
RasterDataStore rasterstore = flyrraster.getDataStore(); |
1006 | 1006 |
if(rasterstore != null && rasterstore.getProvider() != null){ |
... | ... | |
1012 | 1012 |
String mimeType = ""; |
1013 | 1013 |
if(outputName != "WMS" && extension != "WMS"){ |
1014 | 1014 |
mimeType = URLConnection.guessContentTypeFromStream( |
1015 |
new FileInputStream(flyrraster.getURI())); |
|
1015 |
new FileInputStream(flyrraster.getURI().getPath()));
|
|
1016 | 1016 |
if( mimeType == null){ |
1017 | 1017 |
File f = new File(flyrraster.getURI()); |
1018 | 1018 |
mimeType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(f); |
... | ... | |
1136 | 1136 |
replaceItemProperty(itemType, "wms_name", name2.substring(index1+1, index2)); |
1137 | 1137 |
} |
1138 | 1138 |
} |
1139 |
addItemProperty(itemType, "wms_onlineresource",
|
|
1139 |
addItemProperty(itemType, "wms_onlineresource", |
|
1140 | 1140 |
MapServerUtils.getHostWithoutParametersFromURL(explorer.getHost())); |
1141 | 1141 |
} |
1142 | 1142 |
addItemProperty(itemType, "wms_server_version", "1.1.1"); |
... | ... | |
1180 | 1180 |
} |
1181 | 1181 |
} |
1182 | 1182 |
|
1183 |
if(explorer.getVersion() == "1.1.1" ||
|
|
1183 |
if(explorer.getVersion() == "1.1.1" || |
|
1184 | 1184 |
explorer.getVersion() == "1.0.0"){ |
1185 | 1185 |
replaceItemProperty(itemType, "wms_server_version", explorer.getVersion()); |
1186 | 1186 |
} |
... | ... | |
1216 | 1216 |
|
1217 | 1217 |
|
1218 | 1218 |
private void getMapClass( |
1219 |
FLayer layer,
|
|
1220 |
Layer lyr,
|
|
1221 |
SymbolSet localSymbolSet,
|
|
1219 |
FLayer layer, |
|
1220 |
Layer lyr, |
|
1221 |
SymbolSet localSymbolSet, |
|
1222 | 1222 |
ILegend legend, |
1223 | 1223 |
double minScale, |
1224 | 1224 |
double maxScale){ |
... | ... | |
1248 | 1248 |
} |
1249 | 1249 |
|
1250 | 1250 |
try{ |
1251 |
if (legend instanceof IClassifiedVectorLegend &&
|
|
1251 |
if (legend instanceof IClassifiedVectorLegend && |
|
1252 | 1252 |
!(legend instanceof VectorFilterExpressionLegend)) { |
1253 | 1253 |
IClassifiedVectorLegend classvectLeg = (IClassifiedVectorLegend) legend; |
1254 | 1254 |
if(classvectLeg.getClassifyingFieldNames().length > 0){ |
... | ... | |
1256 | 1256 |
} |
1257 | 1257 |
ExpressionType expression = new ExpressionType(); |
1258 | 1258 |
expression.setType("String"); |
1259 |
expression.setValue("\"" + sy.getDescription() + "\"");
|
|
1259 |
expression.setValue("\"" + sy.getDescription() + "\""); |
|
1260 | 1260 |
List<ISymbol> symbolsleg = Arrays.asList(classvectLeg.getSymbols()); |
1261 | 1261 |
int indexleg = symbolsleg.indexOf(sy); |
1262 | 1262 |
if(indexleg >= 0){ |
... | ... | |
1284 | 1284 |
if(values.length > li){ |
1285 | 1285 |
ExpressionType expression = new ExpressionType(); |
1286 | 1286 |
expression.setType("String"); |
1287 |
expression.setValue("\"" + values[li].toString().replace("\"", "") + "\"");
|
|
1287 |
expression.setValue("\"" + values[li].toString().replace("\"", "") + "\""); |
|
1288 | 1288 |
mapClass.setExpression(expression); |
1289 | 1289 |
} |
1290 | 1290 |
} |
... | ... | |
1370 | 1370 |
label.setWrap(" "); |
1371 | 1371 |
label.setMaxLength(MapServerUtils.getBigInteger(15)); |
1372 | 1372 |
label.setAlign(AlignEnum.LEFT); |
1373 |
|
|
1373 |
|
|
1374 | 1374 |
SizeType labelOffset = new SizeType(); |
1375 | 1375 |
labelOffset.setX(MapServerUtils.getBigInteger(0)); |
1376 | 1376 |
labelOffset.setY(MapServerUtils.getBigInteger(9)); |
... | ... | |
1439 | 1439 |
label.setWrap(" "); |
1440 | 1440 |
label.setMaxLength(MapServerUtils.getBigInteger(15)); |
1441 | 1441 |
label.setAlign(AlignEnum.LEFT); |
1442 |
|
|
1442 |
|
|
1443 | 1443 |
label.setType("TRUETYPE"); |
1444 | 1444 |
SizeType labelOffset = new SizeType(); |
1445 | 1445 |
labelOffset.setX(MapServerUtils.getBigInteger(0)); |
... | ... | |
1481 | 1481 |
} |
1482 | 1482 |
|
1483 | 1483 |
|
1484 |
private org.gvsig.publish.mapserver641.Class createMapClassObject(ISymbol sy,
|
|
1484 |
private org.gvsig.publish.mapserver641.Class createMapClassObject(ISymbol sy, |
|
1485 | 1485 |
org.gvsig.publish.mapserver641.Class mapClass, SymbolSet localSymbolSet, FLayer layer, Layer lyr, int li){ |
1486 | 1486 |
MapserverSymbol mapserverSymbol = null; |
1487 | 1487 |
List<Style> classStyles = null; |
... | ... | |
1640 | 1640 |
|
1641 | 1641 |
} |
1642 | 1642 |
|
1643 |
// if(!StringUtils.isBlank(symbolStyle.getType()) &&
|
|
1644 |
// (symbolStyle.getType().equalsIgnoreCase("svg") ||
|
|
1643 |
// if(!StringUtils.isBlank(symbolStyle.getType()) && |
|
1644 |
// (symbolStyle.getType().equalsIgnoreCase("svg") || |
|
1645 | 1645 |
// symbolStyle.getType().equalsIgnoreCase("pixmap"))){ |
1646 | 1646 |
// MapserverToDynObjectHelper helper = new MapserverToDynObjectHelper(); |
1647 | 1647 |
// DynObject newDynStyle = helper.createStyle(classStyles.get(is)); |
1648 | 1648 |
// Style newStyle = new Style(); |
1649 | 1649 |
// helper.copyTo(newDynStyle, newStyle); |
1650 |
//
|
|
1651 |
//
|
|
1650 |
// |
|
1651 |
// |
|
1652 | 1652 |
// newStyle.setSymbol(null); |
1653 | 1653 |
// classStyles.get(is).setColor(null); |
1654 | 1654 |
// classStyles.get(is).setOutlineColor(null); |
1655 |
//
|
|
1655 |
// |
|
1656 | 1656 |
// mapClass.getStyle().remove(symbolStyle); |
1657 | 1657 |
// mapClass.getStyle().add(newStyle); |
1658 | 1658 |
// } |
... | ... | |
1761 | 1761 |
|
1762 | 1762 |
|
1763 | 1763 |
public Map getPublishedMap(ViewDocument viewDoc) { |
1764 |
if(viewDoc.getProperty(MAPSERVER_PANEL_PROPERTIES) != null &&
|
|
1764 |
if(viewDoc.getProperty(MAPSERVER_PANEL_PROPERTIES) != null && |
|
1765 | 1765 |
viewDoc.getProperty(MAPSERVER_PANEL_PROPERTIES) instanceof Boolean){ |
1766 | 1766 |
boolean active = (Boolean) viewDoc.getProperty(MAPSERVER_PANEL_PROPERTIES); |
1767 | 1767 |
if(active){ |
... | ... | |
1791 | 1791 |
|
1792 | 1792 |
private boolean isSymbolInSet(SymbolSet sset, Symbol sm){ |
1793 | 1793 |
for (int i = 0; i < sset.getSymbol().size(); i++) { |
1794 |
if (sset.getSymbol().get(i).getName() != null &&
|
|
1795 |
sset.getSymbol().get(i).getName().equals(sm.getName()) &&
|
|
1794 |
if (sset.getSymbol().get(i).getName() != null && |
|
1795 |
sset.getSymbol().get(i).getName().equals(sm.getName()) && |
|
1796 | 1796 |
sset.getSymbol().get(i).getType().equalsIgnoreCase(sm.getType())) { |
1797 | 1797 |
return true; |
1798 | 1798 |
} |
... | ... | |
1811 | 1811 |
SymbolSet aux = new SymbolSet(); |
1812 | 1812 |
if (this.symbolset != null) { |
1813 | 1813 |
for (int i = 0; i < symbolset.getSymbol().size(); i++) { |
1814 |
|
|
1814 |
|
|
1815 | 1815 |
Symbol sym = symbolset.getSymbol().get(i); |
1816 | 1816 |
MapserverToDynObjectHelper helper = new MapserverToDynObjectHelper(); |
1817 |
|
|
1818 |
|
|
1817 |
|
|
1818 |
|
|
1819 | 1819 |
Symbol sym2 = new Symbol(); |
1820 |
helper.copyTo(helper.createSymbol(sym), sym2);
|
|
1820 |
helper.copyTo(helper.createSymbol(sym), sym2); |
|
1821 | 1821 |
if (sym2.getImage() != null && sym2.getImage() != "") { |
1822 | 1822 |
if(file != null){ |
1823 | 1823 |
sym2.setImage(MapServerUtils.relativePath(sym.getImage(), file.getParent()).replace(File.separator, "/")); |
... | ... | |
1825 | 1825 |
} |
1826 | 1826 |
aux.getSymbol().add(sym2); |
1827 | 1827 |
} |
1828 |
}
|
|
1828 |
} |
|
1829 | 1829 |
return aux; |
1830 | 1830 |
} |
1831 | 1831 |
|
1832 | 1832 |
private SymbolSet getPublishedSymbol(FLayer layer) { |
1833 |
if (layer.getProperty(MAPSERVER_SYMBOL_PROPERTIES) != null &&
|
|
1833 |
if (layer.getProperty(MAPSERVER_SYMBOL_PROPERTIES) != null && |
|
1834 | 1834 |
layer.getProperty(MAPSERVER_SYMBOL_PROPERTIES) instanceof SymbolSet){ |
1835 | 1835 |
SymbolSet auxSymbols = (SymbolSet) layer.getProperty(MAPSERVER_SYMBOL_PROPERTIES); |
1836 | 1836 |
for(int i=0; i<auxSymbols.getSymbol().size(); i++){ |
... | ... | |
1914 | 1914 |
|
1915 | 1915 |
public String getCorrectPath(String fileFormat, File origen) { |
1916 | 1916 |
if (!getPublishProperties().isAbsolutePath()) { |
1917 |
if(!getPublishProperties().isDefaultPath()
|
|
1917 |
if(!getPublishProperties().isDefaultPath() |
|
1918 | 1918 |
&& !getPublishProperties().isAbsolutePath()){ |
1919 | 1919 |
String spath = getPublishProperties().getShapePath(); |
1920 | 1920 |
if(StringUtils.isBlank(getPublishProperties().getShapePath())){ |
... | ... | |
2145 | 2145 |
File originalFile = new File(sym.getImage()); |
2146 | 2146 |
// if(originalFile.isFile()){ |
2147 | 2147 |
// sym.setImage(MapServerUtils.relativePath( |
2148 |
// originalFile.getAbsolutePath(),
|
|
2148 |
// originalFile.getAbsolutePath(), |
|
2149 | 2149 |
// originalFile.getParentFile().getParent())); |
2150 | 2150 |
// } |
2151 | 2151 |
} |
... | ... | |
2166 | 2166 |
|
2167 | 2167 |
private Layer getPublishedLayer(FLayer flayer) { |
2168 | 2168 |
isEditedLayer = false; |
2169 |
if(flayer.getProperty(MAPSERVER_LAYERPANEL_PROPERTIES) != null &&
|
|
2169 |
if(flayer.getProperty(MAPSERVER_LAYERPANEL_PROPERTIES) != null && |
|
2170 | 2170 |
flayer.getProperty(MAPSERVER_LAYERPANEL_PROPERTIES) instanceof Boolean){ |
2171 | 2171 |
boolean active = (Boolean) flayer.getProperty(MAPSERVER_LAYERPANEL_PROPERTIES); |
2172 | 2172 |
if(active){ |
... | ... | |
2202 | 2202 |
Iterator<Style> it = styles.iterator(); |
2203 | 2203 |
while(it.hasNext()){ |
2204 | 2204 |
Style style = (Style) it.next(); |
2205 |
if(style.getSymbol() != null &&
|
|
2205 |
if(style.getSymbol() != null && |
|
2206 | 2206 |
!StringUtils.isBlank(style.getSymbol().getValue()) && |
2207 | 2207 |
style.getSymbol().getValue().equals("\""+oldName+"\"")){ |
2208 | 2208 |
style.getSymbol().setValue("\""+newName+"\""); |
Also available in: Unified diff