@Test public void fromJson() throws TransformerException, ParserConfigurationException, SAXException, IOException, XPathExpressionException, InstantiationException, IllegalAccessException, TranscoderException { QualifiedResource maskResource = qualifiedSVGResourceFactory.fromSVGFile(new File(PATH_IN, mask)); SvgMask svgMask = new SvgMask(maskResource); Collection<QualifiedResource> maskedResources = svgMask.generatesMaskedResources(qualifiedSVGResourceFactory, dir, resources, useSameSvgOnlyOnceInMask, OverwriteMode.always); assertEquals(maskedResourcesNames.size(), maskedResources.size()); assertEquals(maskedResourcesNames.size(), dir.list().length); QualifiedResource qr; for (String maskedResource : maskedResourcesNames) { File masked = new File(dir, maskedResource); assertTrue(masked.getName() + " does not exists", masked.exists()); qr = qualifiedSVGResourceFactory.fromSVGFile(masked); assertTrue(qr.exists()); plugin.transcode(qr, mdpi, output, null); } }
public Collection<QualifiedResource> generatesMaskedResources( QualifiedSVGResourceFactory qualifiedSVGResourceFactory, File dest, final Collection<QualifiedResource> availableResources, final boolean useSameSvgOnlyOnceInMask, final OverwriteMode overwriteMode) throws TransformerException, ParserConfigurationException, SAXException, IOException, XPathExpressionException { dest.mkdirs(); DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); dfactory.setNamespaceAware(true); DocumentBuilder builder = dfactory.newDocumentBuilder(); Document svgmaskDom = builder.parse(svgMask); final String svgNamespace = svgmaskDom.getDocumentElement().getNamespaceURI(); XPath xPath = XPathFactory.newInstance().newXPath(); xPath.setNamespaceContext(new NamespaceContext() { public String getNamespaceURI(String prefix) { String uri = null; if (prefix.equals("_svgdrawable")) { uri = svgNamespace; } return uri; } @Override public Iterator<?> getPrefixes(String val) { throw new IllegalAccessError("Not implemented!"); } @Override public String getPrefix(String uri) { throw new IllegalAccessError("Not implemented!"); } }); NodeList value = (NodeList) xPath.evaluate(" List<MaskNode> maskNodes = new ArrayList<>(); for (int i = 0; i < value.getLength(); i++) { Node imageNode = value.item(i); Node href = imageNode.getAttributes().getNamedItemNS("http: if (href != null && href.getNodeValue() != null) { Matcher m = REF_PATTERN.matcher(href.getNodeValue()); if (m.matches()) { MaskNode maskNode = new MaskNode(href, m.group(1)); if (maskNode.accepts(availableResources)) { maskNodes.add(maskNode); } else { } } } } final Collection<QualifiedResource> maskedResources = new ArrayList<>(); if (!maskNodes.isEmpty()) { List<Iterator<QualifiedResource>> iterators = new ArrayList<>(maskNodes.size()); List<QualifiedResource> currents = new ArrayList<>(maskNodes.size()); for (MaskNode maskNode : maskNodes) { Iterator<QualifiedResource> i = maskNode.matchingResources.iterator(); iterators.add(i); currents.add(i.next()); } boolean hasNext = false; final Set<File> usedSvg = new HashSet<>(); do { usedSvg.clear(); usedSvg.addAll(currents); if (!useSameSvgOnlyOnceInMask || usedSvg.size() == currents.size()) { final AtomicLong lastModified = new AtomicLong(svgMask.lastModified()); final StringBuilder tmpFileName = new StringBuilder(svgMask.getName()); final EnumMap<Type, String> qualifiers = new EnumMap<>(Type.class); boolean skip = false; for (int i = 0; i < maskNodes.size(); i++) { QualifiedResource current = currents.get(i); MaskNode maskNode = maskNodes.get(i); maskNode.imageNode.setNodeValue("file: tmpFileName.append("_"); tmpFileName.append(currents.get(i).getName()); for (Entry<Type, String> e : qualifiers.entrySet()) { if (e.getKey() == Type.density) { continue; } String qualifierValue = current.getTypedQualifiers().get(e.getKey()); if (qualifierValue != null && !qualifierValue.equals(e.getValue())) { skip = true; break; } } qualifiers.putAll(current.getTypedQualifiers()); if (current.lastModified() > lastModified.get()) { lastModified.set(current.lastModified()); } } if (!skip) { qualifiers.remove(Type.density); final String name = tmpFileName.toString(); final File maskedFile = new File(dest, name + Qualifier.toQualifiedString(qualifiers) + "-" + svgMask.getDensity().toString() + ".svg") { @Override public long lastModified() { return lastModified.get(); } }; qualifiers.put(Type.density, svgMask.getDensity().getValue().name()); if (overwriteMode.shouldOverride(maskedFile, new File(maskedFile.getAbsolutePath()), null)) { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(svgmaskDom); if (!maskedFile.exists() && !maskedFile.createNewFile()) { continue; } StreamResult result = new StreamResult(new FileOutputStream(maskedFile)); transformer.transform(source, result); } else { } maskedResources.add(qualifiedSVGResourceFactory.fromSVGFile(maskedFile)); } } hasNext = false; for (int i = maskNodes.size() - 1; i >= 0; i--) { if (iterators.get(i).hasNext()) { currents.set(i, iterators.get(i).next()); hasNext = true; break; } else if (i > 0) { iterators.set(i, maskNodes.get(i).matchingResources.iterator()); currents.set(i, iterators.get(i).next()); } } } while (hasNext); } return maskedResources; }
SvgMask { public Collection<QualifiedResource> generatesMaskedResources( QualifiedSVGResourceFactory qualifiedSVGResourceFactory, File dest, final Collection<QualifiedResource> availableResources, final boolean useSameSvgOnlyOnceInMask, final OverwriteMode overwriteMode) throws TransformerException, ParserConfigurationException, SAXException, IOException, XPathExpressionException { dest.mkdirs(); DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); dfactory.setNamespaceAware(true); DocumentBuilder builder = dfactory.newDocumentBuilder(); Document svgmaskDom = builder.parse(svgMask); final String svgNamespace = svgmaskDom.getDocumentElement().getNamespaceURI(); XPath xPath = XPathFactory.newInstance().newXPath(); xPath.setNamespaceContext(new NamespaceContext() { public String getNamespaceURI(String prefix) { String uri = null; if (prefix.equals("_svgdrawable")) { uri = svgNamespace; } return uri; } @Override public Iterator<?> getPrefixes(String val) { throw new IllegalAccessError("Not implemented!"); } @Override public String getPrefix(String uri) { throw new IllegalAccessError("Not implemented!"); } }); NodeList value = (NodeList) xPath.evaluate(" List<MaskNode> maskNodes = new ArrayList<>(); for (int i = 0; i < value.getLength(); i++) { Node imageNode = value.item(i); Node href = imageNode.getAttributes().getNamedItemNS("http: if (href != null && href.getNodeValue() != null) { Matcher m = REF_PATTERN.matcher(href.getNodeValue()); if (m.matches()) { MaskNode maskNode = new MaskNode(href, m.group(1)); if (maskNode.accepts(availableResources)) { maskNodes.add(maskNode); } else { } } } } final Collection<QualifiedResource> maskedResources = new ArrayList<>(); if (!maskNodes.isEmpty()) { List<Iterator<QualifiedResource>> iterators = new ArrayList<>(maskNodes.size()); List<QualifiedResource> currents = new ArrayList<>(maskNodes.size()); for (MaskNode maskNode : maskNodes) { Iterator<QualifiedResource> i = maskNode.matchingResources.iterator(); iterators.add(i); currents.add(i.next()); } boolean hasNext = false; final Set<File> usedSvg = new HashSet<>(); do { usedSvg.clear(); usedSvg.addAll(currents); if (!useSameSvgOnlyOnceInMask || usedSvg.size() == currents.size()) { final AtomicLong lastModified = new AtomicLong(svgMask.lastModified()); final StringBuilder tmpFileName = new StringBuilder(svgMask.getName()); final EnumMap<Type, String> qualifiers = new EnumMap<>(Type.class); boolean skip = false; for (int i = 0; i < maskNodes.size(); i++) { QualifiedResource current = currents.get(i); MaskNode maskNode = maskNodes.get(i); maskNode.imageNode.setNodeValue("file: tmpFileName.append("_"); tmpFileName.append(currents.get(i).getName()); for (Entry<Type, String> e : qualifiers.entrySet()) { if (e.getKey() == Type.density) { continue; } String qualifierValue = current.getTypedQualifiers().get(e.getKey()); if (qualifierValue != null && !qualifierValue.equals(e.getValue())) { skip = true; break; } } qualifiers.putAll(current.getTypedQualifiers()); if (current.lastModified() > lastModified.get()) { lastModified.set(current.lastModified()); } } if (!skip) { qualifiers.remove(Type.density); final String name = tmpFileName.toString(); final File maskedFile = new File(dest, name + Qualifier.toQualifiedString(qualifiers) + "-" + svgMask.getDensity().toString() + ".svg") { @Override public long lastModified() { return lastModified.get(); } }; qualifiers.put(Type.density, svgMask.getDensity().getValue().name()); if (overwriteMode.shouldOverride(maskedFile, new File(maskedFile.getAbsolutePath()), null)) { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(svgmaskDom); if (!maskedFile.exists() && !maskedFile.createNewFile()) { continue; } StreamResult result = new StreamResult(new FileOutputStream(maskedFile)); transformer.transform(source, result); } else { } maskedResources.add(qualifiedSVGResourceFactory.fromSVGFile(maskedFile)); } } hasNext = false; for (int i = maskNodes.size() - 1; i >= 0; i--) { if (iterators.get(i).hasNext()) { currents.set(i, iterators.get(i).next()); hasNext = true; break; } else if (i > 0) { iterators.set(i, maskNodes.get(i).matchingResources.iterator()); currents.set(i, iterators.get(i).next()); } } } while (hasNext); } return maskedResources; } }
SvgMask { public Collection<QualifiedResource> generatesMaskedResources( QualifiedSVGResourceFactory qualifiedSVGResourceFactory, File dest, final Collection<QualifiedResource> availableResources, final boolean useSameSvgOnlyOnceInMask, final OverwriteMode overwriteMode) throws TransformerException, ParserConfigurationException, SAXException, IOException, XPathExpressionException { dest.mkdirs(); DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); dfactory.setNamespaceAware(true); DocumentBuilder builder = dfactory.newDocumentBuilder(); Document svgmaskDom = builder.parse(svgMask); final String svgNamespace = svgmaskDom.getDocumentElement().getNamespaceURI(); XPath xPath = XPathFactory.newInstance().newXPath(); xPath.setNamespaceContext(new NamespaceContext() { public String getNamespaceURI(String prefix) { String uri = null; if (prefix.equals("_svgdrawable")) { uri = svgNamespace; } return uri; } @Override public Iterator<?> getPrefixes(String val) { throw new IllegalAccessError("Not implemented!"); } @Override public String getPrefix(String uri) { throw new IllegalAccessError("Not implemented!"); } }); NodeList value = (NodeList) xPath.evaluate(" List<MaskNode> maskNodes = new ArrayList<>(); for (int i = 0; i < value.getLength(); i++) { Node imageNode = value.item(i); Node href = imageNode.getAttributes().getNamedItemNS("http: if (href != null && href.getNodeValue() != null) { Matcher m = REF_PATTERN.matcher(href.getNodeValue()); if (m.matches()) { MaskNode maskNode = new MaskNode(href, m.group(1)); if (maskNode.accepts(availableResources)) { maskNodes.add(maskNode); } else { } } } } final Collection<QualifiedResource> maskedResources = new ArrayList<>(); if (!maskNodes.isEmpty()) { List<Iterator<QualifiedResource>> iterators = new ArrayList<>(maskNodes.size()); List<QualifiedResource> currents = new ArrayList<>(maskNodes.size()); for (MaskNode maskNode : maskNodes) { Iterator<QualifiedResource> i = maskNode.matchingResources.iterator(); iterators.add(i); currents.add(i.next()); } boolean hasNext = false; final Set<File> usedSvg = new HashSet<>(); do { usedSvg.clear(); usedSvg.addAll(currents); if (!useSameSvgOnlyOnceInMask || usedSvg.size() == currents.size()) { final AtomicLong lastModified = new AtomicLong(svgMask.lastModified()); final StringBuilder tmpFileName = new StringBuilder(svgMask.getName()); final EnumMap<Type, String> qualifiers = new EnumMap<>(Type.class); boolean skip = false; for (int i = 0; i < maskNodes.size(); i++) { QualifiedResource current = currents.get(i); MaskNode maskNode = maskNodes.get(i); maskNode.imageNode.setNodeValue("file: tmpFileName.append("_"); tmpFileName.append(currents.get(i).getName()); for (Entry<Type, String> e : qualifiers.entrySet()) { if (e.getKey() == Type.density) { continue; } String qualifierValue = current.getTypedQualifiers().get(e.getKey()); if (qualifierValue != null && !qualifierValue.equals(e.getValue())) { skip = true; break; } } qualifiers.putAll(current.getTypedQualifiers()); if (current.lastModified() > lastModified.get()) { lastModified.set(current.lastModified()); } } if (!skip) { qualifiers.remove(Type.density); final String name = tmpFileName.toString(); final File maskedFile = new File(dest, name + Qualifier.toQualifiedString(qualifiers) + "-" + svgMask.getDensity().toString() + ".svg") { @Override public long lastModified() { return lastModified.get(); } }; qualifiers.put(Type.density, svgMask.getDensity().getValue().name()); if (overwriteMode.shouldOverride(maskedFile, new File(maskedFile.getAbsolutePath()), null)) { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(svgmaskDom); if (!maskedFile.exists() && !maskedFile.createNewFile()) { continue; } StreamResult result = new StreamResult(new FileOutputStream(maskedFile)); transformer.transform(source, result); } else { } maskedResources.add(qualifiedSVGResourceFactory.fromSVGFile(maskedFile)); } } hasNext = false; for (int i = maskNodes.size() - 1; i >= 0; i--) { if (iterators.get(i).hasNext()) { currents.set(i, iterators.get(i).next()); hasNext = true; break; } else if (i > 0) { iterators.set(i, maskNodes.get(i).matchingResources.iterator()); currents.set(i, iterators.get(i).next()); } } } while (hasNext); } return maskedResources; } SvgMask(final QualifiedResource svgMask); }
SvgMask { public Collection<QualifiedResource> generatesMaskedResources( QualifiedSVGResourceFactory qualifiedSVGResourceFactory, File dest, final Collection<QualifiedResource> availableResources, final boolean useSameSvgOnlyOnceInMask, final OverwriteMode overwriteMode) throws TransformerException, ParserConfigurationException, SAXException, IOException, XPathExpressionException { dest.mkdirs(); DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); dfactory.setNamespaceAware(true); DocumentBuilder builder = dfactory.newDocumentBuilder(); Document svgmaskDom = builder.parse(svgMask); final String svgNamespace = svgmaskDom.getDocumentElement().getNamespaceURI(); XPath xPath = XPathFactory.newInstance().newXPath(); xPath.setNamespaceContext(new NamespaceContext() { public String getNamespaceURI(String prefix) { String uri = null; if (prefix.equals("_svgdrawable")) { uri = svgNamespace; } return uri; } @Override public Iterator<?> getPrefixes(String val) { throw new IllegalAccessError("Not implemented!"); } @Override public String getPrefix(String uri) { throw new IllegalAccessError("Not implemented!"); } }); NodeList value = (NodeList) xPath.evaluate(" List<MaskNode> maskNodes = new ArrayList<>(); for (int i = 0; i < value.getLength(); i++) { Node imageNode = value.item(i); Node href = imageNode.getAttributes().getNamedItemNS("http: if (href != null && href.getNodeValue() != null) { Matcher m = REF_PATTERN.matcher(href.getNodeValue()); if (m.matches()) { MaskNode maskNode = new MaskNode(href, m.group(1)); if (maskNode.accepts(availableResources)) { maskNodes.add(maskNode); } else { } } } } final Collection<QualifiedResource> maskedResources = new ArrayList<>(); if (!maskNodes.isEmpty()) { List<Iterator<QualifiedResource>> iterators = new ArrayList<>(maskNodes.size()); List<QualifiedResource> currents = new ArrayList<>(maskNodes.size()); for (MaskNode maskNode : maskNodes) { Iterator<QualifiedResource> i = maskNode.matchingResources.iterator(); iterators.add(i); currents.add(i.next()); } boolean hasNext = false; final Set<File> usedSvg = new HashSet<>(); do { usedSvg.clear(); usedSvg.addAll(currents); if (!useSameSvgOnlyOnceInMask || usedSvg.size() == currents.size()) { final AtomicLong lastModified = new AtomicLong(svgMask.lastModified()); final StringBuilder tmpFileName = new StringBuilder(svgMask.getName()); final EnumMap<Type, String> qualifiers = new EnumMap<>(Type.class); boolean skip = false; for (int i = 0; i < maskNodes.size(); i++) { QualifiedResource current = currents.get(i); MaskNode maskNode = maskNodes.get(i); maskNode.imageNode.setNodeValue("file: tmpFileName.append("_"); tmpFileName.append(currents.get(i).getName()); for (Entry<Type, String> e : qualifiers.entrySet()) { if (e.getKey() == Type.density) { continue; } String qualifierValue = current.getTypedQualifiers().get(e.getKey()); if (qualifierValue != null && !qualifierValue.equals(e.getValue())) { skip = true; break; } } qualifiers.putAll(current.getTypedQualifiers()); if (current.lastModified() > lastModified.get()) { lastModified.set(current.lastModified()); } } if (!skip) { qualifiers.remove(Type.density); final String name = tmpFileName.toString(); final File maskedFile = new File(dest, name + Qualifier.toQualifiedString(qualifiers) + "-" + svgMask.getDensity().toString() + ".svg") { @Override public long lastModified() { return lastModified.get(); } }; qualifiers.put(Type.density, svgMask.getDensity().getValue().name()); if (overwriteMode.shouldOverride(maskedFile, new File(maskedFile.getAbsolutePath()), null)) { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(svgmaskDom); if (!maskedFile.exists() && !maskedFile.createNewFile()) { continue; } StreamResult result = new StreamResult(new FileOutputStream(maskedFile)); transformer.transform(source, result); } else { } maskedResources.add(qualifiedSVGResourceFactory.fromSVGFile(maskedFile)); } } hasNext = false; for (int i = maskNodes.size() - 1; i >= 0; i--) { if (iterators.get(i).hasNext()) { currents.set(i, iterators.get(i).next()); hasNext = true; break; } else if (i > 0) { iterators.set(i, maskNodes.get(i).matchingResources.iterator()); currents.set(i, iterators.get(i).next()); } } } while (hasNext); } return maskedResources; } SvgMask(final QualifiedResource svgMask); Collection<QualifiedResource> generatesMaskedResources(
			QualifiedSVGResourceFactory qualifiedSVGResourceFactory,
	        File dest, final Collection<QualifiedResource> availableResources,
			final boolean useSameSvgOnlyOnceInMask,
			final OverwriteMode overwriteMode); }
SvgMask { public Collection<QualifiedResource> generatesMaskedResources( QualifiedSVGResourceFactory qualifiedSVGResourceFactory, File dest, final Collection<QualifiedResource> availableResources, final boolean useSameSvgOnlyOnceInMask, final OverwriteMode overwriteMode) throws TransformerException, ParserConfigurationException, SAXException, IOException, XPathExpressionException { dest.mkdirs(); DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); dfactory.setNamespaceAware(true); DocumentBuilder builder = dfactory.newDocumentBuilder(); Document svgmaskDom = builder.parse(svgMask); final String svgNamespace = svgmaskDom.getDocumentElement().getNamespaceURI(); XPath xPath = XPathFactory.newInstance().newXPath(); xPath.setNamespaceContext(new NamespaceContext() { public String getNamespaceURI(String prefix) { String uri = null; if (prefix.equals("_svgdrawable")) { uri = svgNamespace; } return uri; } @Override public Iterator<?> getPrefixes(String val) { throw new IllegalAccessError("Not implemented!"); } @Override public String getPrefix(String uri) { throw new IllegalAccessError("Not implemented!"); } }); NodeList value = (NodeList) xPath.evaluate(" List<MaskNode> maskNodes = new ArrayList<>(); for (int i = 0; i < value.getLength(); i++) { Node imageNode = value.item(i); Node href = imageNode.getAttributes().getNamedItemNS("http: if (href != null && href.getNodeValue() != null) { Matcher m = REF_PATTERN.matcher(href.getNodeValue()); if (m.matches()) { MaskNode maskNode = new MaskNode(href, m.group(1)); if (maskNode.accepts(availableResources)) { maskNodes.add(maskNode); } else { } } } } final Collection<QualifiedResource> maskedResources = new ArrayList<>(); if (!maskNodes.isEmpty()) { List<Iterator<QualifiedResource>> iterators = new ArrayList<>(maskNodes.size()); List<QualifiedResource> currents = new ArrayList<>(maskNodes.size()); for (MaskNode maskNode : maskNodes) { Iterator<QualifiedResource> i = maskNode.matchingResources.iterator(); iterators.add(i); currents.add(i.next()); } boolean hasNext = false; final Set<File> usedSvg = new HashSet<>(); do { usedSvg.clear(); usedSvg.addAll(currents); if (!useSameSvgOnlyOnceInMask || usedSvg.size() == currents.size()) { final AtomicLong lastModified = new AtomicLong(svgMask.lastModified()); final StringBuilder tmpFileName = new StringBuilder(svgMask.getName()); final EnumMap<Type, String> qualifiers = new EnumMap<>(Type.class); boolean skip = false; for (int i = 0; i < maskNodes.size(); i++) { QualifiedResource current = currents.get(i); MaskNode maskNode = maskNodes.get(i); maskNode.imageNode.setNodeValue("file: tmpFileName.append("_"); tmpFileName.append(currents.get(i).getName()); for (Entry<Type, String> e : qualifiers.entrySet()) { if (e.getKey() == Type.density) { continue; } String qualifierValue = current.getTypedQualifiers().get(e.getKey()); if (qualifierValue != null && !qualifierValue.equals(e.getValue())) { skip = true; break; } } qualifiers.putAll(current.getTypedQualifiers()); if (current.lastModified() > lastModified.get()) { lastModified.set(current.lastModified()); } } if (!skip) { qualifiers.remove(Type.density); final String name = tmpFileName.toString(); final File maskedFile = new File(dest, name + Qualifier.toQualifiedString(qualifiers) + "-" + svgMask.getDensity().toString() + ".svg") { @Override public long lastModified() { return lastModified.get(); } }; qualifiers.put(Type.density, svgMask.getDensity().getValue().name()); if (overwriteMode.shouldOverride(maskedFile, new File(maskedFile.getAbsolutePath()), null)) { TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(svgmaskDom); if (!maskedFile.exists() && !maskedFile.createNewFile()) { continue; } StreamResult result = new StreamResult(new FileOutputStream(maskedFile)); transformer.transform(source, result); } else { } maskedResources.add(qualifiedSVGResourceFactory.fromSVGFile(maskedFile)); } } hasNext = false; for (int i = maskNodes.size() - 1; i >= 0; i--) { if (iterators.get(i).hasNext()) { currents.set(i, iterators.get(i).next()); hasNext = true; break; } else if (i > 0) { iterators.set(i, maskNodes.get(i).matchingResources.iterator()); currents.set(i, iterators.get(i).next()); } } } while (hasNext); } return maskedResources; } SvgMask(final QualifiedResource svgMask); Collection<QualifiedResource> generatesMaskedResources(
			QualifiedSVGResourceFactory qualifiedSVGResourceFactory,
	        File dest, final Collection<QualifiedResource> availableResources,
			final boolean useSameSvgOnlyOnceInMask,
			final OverwriteMode overwriteMode);  }