X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FJalview2XML.java;h=8cad9ca474c857d83eb3ba0e8536e4fc249cea35;hb=c2214808f64b811a25cec10399dcff38db0c592c;hp=3bca941fc3f8a30988b197327cf14942b1a0dc87;hpb=baaf65b19f3dfea486da401fba610ac66bf36817;p=jalview.git diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index 3bca941..8cad9ca 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -1,19 +1,21 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1) + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2) * Copyright (C) 2014 The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with Jalview. If not, see . + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.gui; @@ -279,7 +281,7 @@ public class Jalview2XML return; } - Hashtable dsses = new Hashtable(); + Hashtable dsses = new Hashtable(); try { @@ -348,7 +350,8 @@ public class Jalview2XML SaveState(apanel, fileName, jout); - String dssid = getDatasetIdRef(af.getViewport().getAlignment().getDataset()); + String dssid = getDatasetIdRef(af.getViewport().getAlignment() + .getDataset()); if (!dsses.containsKey(dssid)) { dsses.put(dssid, af); @@ -358,8 +361,9 @@ public class Jalview2XML } } - writeDatasetFor(dsses, ""+jout.hashCode()+" "+uniqueSetSuffix, jout); - + writeDatasetFor(dsses, "" + jout.hashCode() + " " + uniqueSetSuffix, + jout); + try { jout.flush(); @@ -389,7 +393,7 @@ public class Jalview2XML int ap, apSize = af.alignPanels.size(); FileOutputStream fos = new FileOutputStream(jarFile); JarOutputStream jout = new JarOutputStream(fos); - Hashtable dsses = new Hashtable(); + Hashtable dsses = new Hashtable(); for (ap = 0; ap < apSize; ap++) { AlignmentPanel apanel = (AlignmentPanel) af.alignPanels @@ -400,7 +404,8 @@ public class Jalview2XML jfileName = jfileName + ".xml"; } SaveState(apanel, jfileName, jout); - String dssid = getDatasetIdRef(af.getViewport().getAlignment().getDataset()); + String dssid = getDatasetIdRef(af.getViewport().getAlignment() + .getDataset()); if (!dsses.containsKey(dssid)) { dsses.put(dssid, af); @@ -428,10 +433,10 @@ public class Jalview2XML String fileName, JarOutputStream jout) { - for (String dssids:dsses.keySet()) + for (String dssids : dsses.keySet()) { AlignFrame _af = dsses.get(dssids); - String jfileName = fileName + " Dataset for "+ _af.getTitle(); + String jfileName = fileName + " Dataset for " + _af.getTitle(); if (!jfileName.endsWith(".xml")) { jfileName = jfileName + ".xml"; @@ -456,25 +461,27 @@ public class Jalview2XML public JalviewModel SaveState(AlignmentPanel ap, String fileName, JarOutputStream jout) { - return SaveState(ap, fileName, false,jout); + return SaveState(ap, fileName, false, jout); } + /** - * create a JalviewModel from an algnment view and marshall it to a - * JarOutputStream - * - * @param ap - * panel to create jalview model for - * @param fileName - * name of alignment panel written to output stream - * @param storeDS - * when true, only write the dataset for the alignment, not the data associated with the view. - * @param jout - * jar output stream - * @param out - * jar entry name - */ - public JalviewModel SaveState(AlignmentPanel ap, String fileName, boolean storeDS, - JarOutputStream jout) + * create a JalviewModel from an algnment view and marshall it to a + * JarOutputStream + * + * @param ap + * panel to create jalview model for + * @param fileName + * name of alignment panel written to output stream + * @param storeDS + * when true, only write the dataset for the alignment, not the data + * associated with the view. + * @param jout + * jar output stream + * @param out + * jar entry name + */ + public JalviewModel SaveState(AlignmentPanel ap, String fileName, + boolean storeDS, JarOutputStream jout) { initSeqRefs(); Vector jmolViewIds = new Vector(); // @@ -486,7 +493,8 @@ public class Jalview2XML object.setVamsasModel(new jalview.schemabinding.version2.VamsasModel()); object.setCreationDate(new java.util.Date(System.currentTimeMillis())); - object.setVersion(jalview.bin.Cache.getDefault("VERSION","Development Build")); + object.setVersion(jalview.bin.Cache.getDefault("VERSION", + "Development Build")); jalview.datamodel.AlignmentI jal = av.getAlignment(); @@ -529,11 +537,12 @@ public class Jalview2XML // SAVE SEQUENCES String id = ""; - jalview.datamodel.SequenceI jds,jdatasq; + jalview.datamodel.SequenceI jds, jdatasq; for (int i = 0; i < jal.getHeight(); i++) { jds = jal.getSequenceAt(i); - jdatasq=jds.getDatasetSequence() == null ? jds : jds.getDatasetSequence(); + jdatasq = jds.getDatasetSequence() == null ? jds : jds + .getDatasetSequence(); id = seqHash(jds); if (seqRefIds.get(id) != null) @@ -877,17 +886,19 @@ public class Jalview2XML IdentityHashMap groupRefs = new IdentityHashMap(); if (storeDS) { - for (SequenceI sq:jal.getSequences()) + for (SequenceI sq : jal.getSequences()) + { + // Store annotation on dataset sequences only + jalview.datamodel.AlignmentAnnotation[] aa = sq.getAnnotation(); + if (aa != null && aa.length > 0) { - // Store annotation on dataset sequences only - jalview.datamodel.AlignmentAnnotation[] aa = sq.getAnnotation(); - if (aa!=null && aa.length>0) - { - storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS, - vamsasSet); - } + storeAlignmentAnnotation(aa, groupRefs, av, calcIdSet, storeDS, + vamsasSet); } - } else { + } + } + else + { if (jal.getAlignmentAnnotation() != null) { // Store the annotation shown on the alignment. @@ -933,10 +944,10 @@ public class Jalview2XML } else if (sg.cs instanceof jalview.schemes.AnnotationColourGradient) { - groups[i] - .setColour(ColourSchemeProperty - .getColourName(((jalview.schemes.AnnotationColourGradient) sg.cs) - .getBaseColour())); + groups[i].setColour("AnnotationColourGradient"); + groups[i].setAnnotationColours(constructAnnotationColours( + (jalview.schemes.AnnotationColourGradient) sg.cs, + userColours, jms)); } else if (sg.cs instanceof jalview.schemes.UserColourScheme) { @@ -1009,28 +1020,11 @@ public class Jalview2XML } else if (av.getGlobalColourScheme() instanceof jalview.schemes.AnnotationColourGradient) { - jalview.schemes.AnnotationColourGradient acg = (jalview.schemes.AnnotationColourGradient) av - .getGlobalColourScheme(); + AnnotationColours ac = constructAnnotationColours( + (jalview.schemes.AnnotationColourGradient) av + .getGlobalColourScheme(), + userColours, jms); - AnnotationColours ac = new AnnotationColours(); - ac.setAboveThreshold(acg.getAboveThreshold()); - ac.setThreshold(acg.getAnnotationThreshold()); - ac.setAnnotation(acg.getAnnotation()); - if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme) - { - ac.setColourScheme(SetUserColourScheme(acg.getBaseColour(), - userColours, jms)); - } - else - { - ac.setColourScheme(ColourSchemeProperty.getColourName(acg - .getBaseColour())); - } - - ac.setMaxColour(acg.getMaxColour().getRGB()); - ac.setMinColour(acg.getMinColour().getRGB()); - ac.setPerSequence(acg.isSeqAssociated()); - ac.setPredefinedColours(acg.isPredefinedColours()); view.setAnnotationColours(ac); view.setBgColour("AnnotationColourGradient"); } @@ -1250,7 +1244,35 @@ public class Jalview2XML return object; } - private void storeAlignmentAnnotation(AlignmentAnnotation[] aa, IdentityHashMap groupRefs, AlignmentViewport av, Set calcIdSet, boolean storeDS, SequenceSet vamsasSet) + private AnnotationColours constructAnnotationColours( + AnnotationColourGradient acg, Vector userColours, + JalviewModelSequence jms) + { + AnnotationColours ac = new AnnotationColours(); + ac.setAboveThreshold(acg.getAboveThreshold()); + ac.setThreshold(acg.getAnnotationThreshold()); + ac.setAnnotation(acg.getAnnotation()); + if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme) + { + ac.setColourScheme(SetUserColourScheme(acg.getBaseColour(), + userColours, jms)); + } + else + { + ac.setColourScheme(ColourSchemeProperty.getColourName(acg + .getBaseColour())); + } + + ac.setMaxColour(acg.getMaxColour().getRGB()); + ac.setMinColour(acg.getMinColour().getRGB()); + ac.setPerSequence(acg.isSeqAssociated()); + ac.setPredefinedColours(acg.isPredefinedColours()); + return ac; + } + + private void storeAlignmentAnnotation(AlignmentAnnotation[] aa, + IdentityHashMap groupRefs, AlignmentViewport av, + Set calcIdSet, boolean storeDS, SequenceSet vamsasSet) { for (int i = 0; i < aa.length; i++) @@ -1382,11 +1404,12 @@ public class Jalview2XML } if (!storeDS || (storeDS && !aa[i].autoCalculated)) { - // skip autocalculated annotation - these are only provided for alignments + // skip autocalculated annotation - these are only provided for + // alignments vamsasSet.addAnnotation(an); } } - + } private CalcIdParam createCalcIdParam(String calcId, AlignViewport av) @@ -1772,7 +1795,7 @@ public class Jalview2XML try { // create list to store references for any new Jmol viewers created - newStructureViewers=new Vector(); + newStructureViewers = new Vector(); // UNMARSHALLER SEEMS TO CLOSE JARINPUTSTREAM, MOST ANNOYING // Workaround is to make sure caller implements the JarInputStreamProvider // interface @@ -1780,13 +1803,13 @@ public class Jalview2XML jarInputStreamProvider jprovider = createjarInputStreamProvider(file); af = LoadJalviewAlign(jprovider); - + } catch (MalformedURLException e) { errorMessage = "Invalid URL format for '" + file + "'"; reportErrors(); - } - finally { + } finally + { try { SwingUtilities.invokeAndWait(new Runnable() @@ -1872,7 +1895,7 @@ public class Jalview2XML frefedSequence = new Vector(); } - jalview.gui.AlignFrame af= null,_af = null; + jalview.gui.AlignFrame af = null, _af = null; Hashtable gatherToThisFrame = new Hashtable(); final String file = jprovider.getFilename(); try @@ -1903,8 +1926,7 @@ public class Jalview2XML if (object.getJalviewModelSequence().getViewportCount() > 0) { af = _af; - if (object.getJalviewModelSequence().getViewportCount() > 1 - && af.viewport.gatherViewsHere) + if (af.viewport.gatherViewsHere) { gatherToThisFrame.put(af.viewport.getSequenceSetId(), af); } @@ -2130,8 +2152,9 @@ public class Jalview2XML JalviewModelSequence jms = object.getJalviewModelSequence(); - Viewport view = (jms.getViewportCount()>0) ? jms.getViewport(0) : null; - + Viewport view = (jms.getViewportCount() > 0) ? jms.getViewport(0) + : null; + // //////////////////////////////// // LOAD SEQUENCES @@ -2537,14 +2560,13 @@ public class Jalview2XML } } } - // /////////////////////// // LOAD GROUPS // Create alignment markup and styles for this view if (jms.getJGroupCount() > 0) { JGroup[] groups = jms.getJGroup(); - + boolean addAnnotSchemeGroup = false; for (int i = 0; i < groups.length; i++) { ColourSchemeI cs = null; @@ -2555,6 +2577,12 @@ public class Jalview2XML { cs = GetUserColourScheme(jms, groups[i].getColour()); } + else if (groups[i].getColour().equals("AnnotationColourGradient") + && groups[i].getAnnotationColours() != null) + { + addAnnotSchemeGroup = true; + cs = null; + } else { cs = ColourSchemeProperty.getColour(al, groups[i].getColour()); @@ -2653,10 +2681,15 @@ public class Jalview2XML } } al.addGroup(sg); - + if (addAnnotSchemeGroup) + { + // reconstruct the annotation colourscheme + sg.cs = constructAnnotationColour( + groups[i].getAnnotationColours(), null, al, jms, false); + } } } - if (view==null) + if (view == null) { // only dataset in this model, so just return. return null; @@ -2704,6 +2737,13 @@ public class Jalview2XML } } + /** + * indicate that annotation colours are applied across all groups (pre + * Jalview 2.8.1 behaviour) + */ + boolean doGroupAnnColour = isVersionStringLaterThan("2.8.1", + object.getVersion()); + AlignmentPanel ap = null; boolean isnewview = true; if (viewId != null) @@ -3168,25 +3208,84 @@ public class Jalview2XML // and finally return. return af; } - Vector newStructureViewers=null; + + /** + * + * @param supported + * - minimum version we are comparing against + * @param version + * - version of data being processsed. + * @return true if version is development/null or evaluates to the same or + * later X.Y.Z (where X,Y,Z are like [0-9]+b?[0-9]*) + */ + private boolean isVersionStringLaterThan(String supported, String version) + { + if (version == null || version.equalsIgnoreCase("DEVELOPMENT BUILD") + || version.equalsIgnoreCase("Test") + || version.equalsIgnoreCase("AUTOMATED BUILD")) + { + System.err.println("Assuming project file with " + + (version == null ? "null" : version) + + " is compatible with Jalview version " + supported); + return true; + } + else + { + StringTokenizer currentV = new StringTokenizer(supported, "."), fileV = new StringTokenizer( + version, "."); + while (currentV.hasMoreTokens() && fileV.hasMoreTokens()) + { + // convert b to decimal to catch bugfix releases within a series + String curT = currentV.nextToken().toLowerCase().replace('b', '.'); + String fileT = fileV.nextToken().toLowerCase().replace('b', '.'); + try + { + if (Float.valueOf(curT) > Float.valueOf(fileT)) + { + // current version is newer than the version that wrote the file + return false; + } + } catch (NumberFormatException nfe) + { + System.err + .println("** WARNING: Version comparison failed for tokens (" + + curT + + ") and (" + + fileT + + ")\n** Current: '" + + supported + "' and Version: '" + version + "'"); + } + } + if (currentV.hasMoreElements()) + { + // fileV has no minor version but identical series to current + return false; + } + } + return true; + } + + Vector newStructureViewers = null; + protected void addNewStructureViewer(AppJmol sview) { - if (newStructureViewers!=null) + if (newStructureViewers != null) { sview.jmb.setFinishedLoadingFromArchive(false); newStructureViewers.add(sview); } } + protected void setLoadingFinishedForNewStructureViewers() { - if (newStructureViewers!=null) + if (newStructureViewers != null) { - for (AppJmol sview:newStructureViewers) + for (AppJmol sview : newStructureViewers) { sview.jmb.setFinishedLoadingFromArchive(true); } newStructureViewers.clear(); - newStructureViewers=null; + newStructureViewers = null; } } @@ -3303,111 +3402,11 @@ public class Jalview2XML } else if (view.getBgColour().startsWith("Annotation")) { - // int find annotation - if (af.viewport.getAlignment().getAlignmentAnnotation() != null) - { - for (int i = 0; i < af.viewport.getAlignment() - .getAlignmentAnnotation().length; i++) - { - if (af.viewport.getAlignment().getAlignmentAnnotation()[i].label - .equals(view.getAnnotationColours().getAnnotation())) - { - if (af.viewport.getAlignment().getAlignmentAnnotation()[i] - .getThreshold() == null) - { - af.viewport.getAlignment().getAlignmentAnnotation()[i] - .setThreshold(new jalview.datamodel.GraphLine(view - .getAnnotationColours().getThreshold(), - "Threshold", java.awt.Color.black) - - ); - } + AnnotationColours viewAnnColour = view.getAnnotationColours(); + cs = constructAnnotationColour(viewAnnColour, af, al, jms, true); - if (view.getAnnotationColours().getColourScheme() - .equals("None")) - { - cs = new AnnotationColourGradient(af.viewport - .getAlignment().getAlignmentAnnotation()[i], - new java.awt.Color(view.getAnnotationColours() - .getMinColour()), new java.awt.Color(view - .getAnnotationColours().getMaxColour()), - view.getAnnotationColours().getAboveThreshold()); - } - else if (view.getAnnotationColours().getColourScheme() - .startsWith("ucs")) - { - cs = new AnnotationColourGradient(af.viewport - .getAlignment().getAlignmentAnnotation()[i], - GetUserColourScheme(jms, view - .getAnnotationColours().getColourScheme()), - view.getAnnotationColours().getAboveThreshold()); - } - else - { - cs = new AnnotationColourGradient(af.viewport - .getAlignment().getAlignmentAnnotation()[i], - ColourSchemeProperty.getColour(al, view - .getAnnotationColours().getColourScheme()), - view.getAnnotationColours().getAboveThreshold()); - } - if (view.getAnnotationColours().hasPerSequence()) - { - ((AnnotationColourGradient)cs).setSeqAssociated(view.getAnnotationColours().isPerSequence()); - } - if (view.getAnnotationColours().hasPredefinedColours()) - { - ((AnnotationColourGradient)cs).setPredefinedColours(view.getAnnotationColours().isPredefinedColours()); - } - // Also use these settings for all the groups - if (al.getGroups() != null) - { - for (int g = 0; g < al.getGroups().size(); g++) - { - jalview.datamodel.SequenceGroup sg = al.getGroups() - .get(g); - - if (sg.cs == null) - { - continue; - } + // annpos - /* - * if - * (view.getAnnotationColours().getColourScheme().equals("None" - * )) { sg.cs = new AnnotationColourGradient( - * af.viewport.getAlignment().getAlignmentAnnotation()[i], new - * java.awt.Color(view.getAnnotationColours(). - * getMinColour()), new - * java.awt.Color(view.getAnnotationColours(). - * getMaxColour()), - * view.getAnnotationColours().getAboveThreshold()); } else - */ - { - sg.cs = new AnnotationColourGradient(af.viewport - .getAlignment().getAlignmentAnnotation()[i], - sg.cs, view.getAnnotationColours() - .getAboveThreshold()); - if (cs instanceof AnnotationColourGradient) - { - if (view.getAnnotationColours().hasPerSequence()) - { - ((AnnotationColourGradient)cs).setSeqAssociated(view.getAnnotationColours().isPerSequence()); - } - if (view.getAnnotationColours().hasPredefinedColours()) - { - ((AnnotationColourGradient)cs).setPredefinedColours(view.getAnnotationColours().isPredefinedColours()); - } - } - } - - } - } - - break; - } - - } - } } else { @@ -3601,6 +3600,131 @@ public class Jalview2XML return af; } + private ColourSchemeI constructAnnotationColour( + AnnotationColours viewAnnColour, AlignFrame af, Alignment al, + JalviewModelSequence jms, boolean checkGroupAnnColour) + { + boolean propagateAnnColour = false; + ColourSchemeI cs = null; + AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al; + if (checkGroupAnnColour && al.getGroups() != null + && al.getGroups().size() > 0) + { + // pre 2.8.1 behaviour + // check to see if we should transfer annotation colours + propagateAnnColour = true; + for (jalview.datamodel.SequenceGroup sg : al.getGroups()) + { + if (sg.cs instanceof AnnotationColourGradient) + { + propagateAnnColour = false; + } + } + } + // int find annotation + if (annAlignment.getAlignmentAnnotation() != null) + { + for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++) + { + if (annAlignment.getAlignmentAnnotation()[i].label + .equals(viewAnnColour.getAnnotation())) + { + if (annAlignment.getAlignmentAnnotation()[i].getThreshold() == null) + { + annAlignment.getAlignmentAnnotation()[i] + .setThreshold(new jalview.datamodel.GraphLine( + viewAnnColour.getThreshold(), "Threshold", + java.awt.Color.black) + + ); + } + + if (viewAnnColour.getColourScheme().equals("None")) + { + cs = new AnnotationColourGradient( + annAlignment.getAlignmentAnnotation()[i], + new java.awt.Color(viewAnnColour.getMinColour()), + new java.awt.Color(viewAnnColour.getMaxColour()), + viewAnnColour.getAboveThreshold()); + } + else if (viewAnnColour.getColourScheme().startsWith("ucs")) + { + cs = new AnnotationColourGradient( + annAlignment.getAlignmentAnnotation()[i], + GetUserColourScheme(jms, + viewAnnColour.getColourScheme()), + viewAnnColour.getAboveThreshold()); + } + else + { + cs = new AnnotationColourGradient( + annAlignment.getAlignmentAnnotation()[i], + ColourSchemeProperty.getColour(al, + viewAnnColour.getColourScheme()), + viewAnnColour.getAboveThreshold()); + } + if (viewAnnColour.hasPerSequence()) + { + ((AnnotationColourGradient) cs).setSeqAssociated(viewAnnColour + .isPerSequence()); + } + if (viewAnnColour.hasPredefinedColours()) + { + ((AnnotationColourGradient) cs) + .setPredefinedColours(viewAnnColour + .isPredefinedColours()); + } + if (propagateAnnColour && al.getGroups() != null) + { + // Also use these settings for all the groups + for (int g = 0; g < al.getGroups().size(); g++) + { + jalview.datamodel.SequenceGroup sg = al.getGroups().get(g); + + if (sg.cs == null) + { + continue; + } + + /* + * if (viewAnnColour.getColourScheme().equals("None" )) { sg.cs = + * new AnnotationColourGradient( + * annAlignment.getAlignmentAnnotation()[i], new + * java.awt.Color(viewAnnColour. getMinColour()), new + * java.awt.Color(viewAnnColour. getMaxColour()), + * viewAnnColour.getAboveThreshold()); } else + */ + { + sg.cs = new AnnotationColourGradient( + annAlignment.getAlignmentAnnotation()[i], sg.cs, + viewAnnColour.getAboveThreshold()); + if (cs instanceof AnnotationColourGradient) + { + if (viewAnnColour.hasPerSequence()) + { + ((AnnotationColourGradient) cs) + .setSeqAssociated(viewAnnColour.isPerSequence()); + } + if (viewAnnColour.hasPredefinedColours()) + { + ((AnnotationColourGradient) cs) + .setPredefinedColours(viewAnnColour + .isPredefinedColours()); + } + } + } + + } + } + + break; + } + + } + } + return cs; + } + private void reorderAutoannotation(AlignFrame af, Alignment al, ArrayList autoAlan) { @@ -3847,14 +3971,18 @@ public class Jalview2XML { // make this dataset sequence sq's dataset sequence sq.setDatasetSequence(dsq); // and update the current dataset alignment - if (ds==null) { - if (dseqs!=null) { + if (ds == null) + { + if (dseqs != null) + { if (!dseqs.contains(dsq)) { dseqs.add(dsq); } - } else { - if (ds.findIndex(dsq)<0) + } + else + { + if (ds.findIndex(dsq) < 0) { ds.addSequence(dsq); } @@ -3890,7 +4018,8 @@ public class Jalview2XML } // TODO: merges will never happen if we 'know' we have the real dataset // sequence - this should be detected when id==dssid - System.err.println("DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // (" + System.err + .println("DEBUG Notice: Merged dataset sequence (if you see this often, post at http://issues.jalview.org/browse/JAL-1474)"); // (" // + (pre ? "prepended" : "") + " " // + (post ? "appended" : "")); }