123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761 |
- /*
- * $Id$
- * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
- * For details on use and redistribution please refer to the
- * LICENSE file included with these sources.
- */
-
- package org.apache.fop.tools;
-
- import org.apache.fop.apps.*;
- import org.apache.fop.configuration.*;
- import org.apache.fop.area.*;
- import org.apache.fop.area.inline.*;
- import org.apache.fop.area.inline.Character;
- import org.apache.fop.render.*;
- import org.apache.fop.render.pdf.*;
- import org.apache.fop.render.svg.*;
- import org.apache.fop.render.xml.*;
- import org.apache.fop.layout.FontInfo;
- import org.apache.fop.layout.FontState;
- import org.apache.fop.fo.FOUserAgent;
-
- import org.apache.log.*;
- import org.apache.log.format.*;
- import org.apache.log.output.io.*;
- import org.apache.log.output.*;
-
- import java.io.*;
- import java.util.*;
-
- import java.awt.geom.Rectangle2D;
- import java.util.StringTokenizer;
-
- import javax.xml.parsers.DocumentBuilderFactory;
-
- import org.w3c.dom.*;
-
- import org.apache.batik.dom.svg.SVGDOMImplementation;
- import org.apache.batik.dom.util.DOMUtilities;
-
- /**
- * Area tree tester.
- * The purpose of this class is to create and render an area tree
- * for the purpose of testing the area tree and rendering.
- * This covers the set of possible properties that can be set
- * on the area tree for rendering.
- * As this is not for general purpose there is no attempt to handle
- * invalid area tree xml.
- *
- * Tests: different renderers, saving and loading pages with serialization
- * out of order rendering
- */
- public class AreaTreeBuilder {
- private Logger log;
-
- /**
- */
- public static void main(String[] args) {
- AreaTreeBuilder atb = new AreaTreeBuilder();
-
- atb.runTests(args[0], args[1], args[2]);
- System.exit(0);
- }
-
- public AreaTreeBuilder() {
- setupLogging();
- }
-
- private void setupLogging() {
- Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
- PatternFormatter formatter = new PatternFormatter("[%{priority}]: %{message}\n%{throwable}");
-
- LogTarget target = null;
- target = new StreamTarget(System.out, formatter);
-
- hierarchy.setDefaultLogTarget(target);
- log = hierarchy.getLoggerFor("test");
- log.setPriority(Priority.DEBUG);
- }
-
- /**
- *
- */
- protected void runTests(String in, String type, String out) {
- log.debug("Starting tests");
- runTest(in, type, out);
- log.debug("Finished");
- }
-
- /**
- */
- protected void runTest(String in, String type, String out) {
- Renderer rend = null;
- if ("xml".equals(type)) {
- rend = new XMLRenderer();
- } else if ("pdf".equals(type)) {
- rend = new PDFRenderer();
- } else if ("svg".equals(type)) {
- rend = new SVGRenderer();
- }
- FontInfo fi = new FontInfo();
- rend.setupFontInfo(fi);
- rend.setUserAgent(new FOUserAgent());
-
- AreaTree.StorePagesModel sm = AreaTree.createStorePagesModel();
- TreeLoader tl = new TreeLoader(fi);
- tl.setTreeModel(sm);
- try {
- InputStream is =
- new BufferedInputStream(new FileInputStream(in));
- tl.buildAreaTree(is);
- renderAreaTree(sm, rend, out);
- } catch (IOException e) {
- log.error("error reading file" + e.getMessage(), e);
- }
- }
-
- protected void renderAreaTree(AreaTree.StorePagesModel sm,
- Renderer rend, String out) {
- try {
- OutputStream os =
- new BufferedOutputStream(new FileOutputStream(out));
-
- rend.setLogger(log);
- rend.startRenderer(os);
-
- int count = 0;
- int seqc = sm.getPageSequenceCount();
- while (count < seqc) {
- Title title = sm.getTitle(count);
- rend.startPageSequence(title);
- int pagec = sm.getPageCount(count);
- int c = 0;
- while (c < pagec) {
- PageViewport page = sm.getPage(count, c);
- c++;
- // save the page to a stream for testing
- ObjectOutputStream tempstream = new ObjectOutputStream(
- new BufferedOutputStream(
- new FileOutputStream("temp.ser")));
- page.savePage(tempstream);
- tempstream.close();
- File temp = new File("temp.ser");
- log.debug("page serialized to: " + temp.length());
- temp = null;
- ObjectInputStream in = new ObjectInputStream(
- new BufferedInputStream(
- new FileInputStream("temp.ser")));
- page.loadPage(in);
- in.close();
-
- rend.renderPage(page);
- }
- count++;
- }
-
- rend.stopRenderer();
- os.close();
- } catch (Exception e) {
- log.error("error rendering output", e);
- }
- }
-
-
- }
-
- // this loads an area tree from an xml file
- // the xml format is the same as the xml renderer output
- class TreeLoader {
- AreaTree areaTree;
- AreaTree.AreaTreeModel model;
- FontInfo fontInfo;
- FontState currentFontState;
-
- TreeLoader(FontInfo fi) {
- fontInfo = fi;
- }
-
- public void setTreeModel(AreaTree.AreaTreeModel mo) {
- model = mo;
- }
-
- public void buildAreaTree(InputStream is) {
- Document doc = null;
- try {
- DocumentBuilderFactory fact =
- DocumentBuilderFactory.newInstance();
- fact.setNamespaceAware(true);
- doc = fact.newDocumentBuilder().parse(is);
- } catch (Exception e) {
- e.printStackTrace();
- }
- Element root = null;
- root = doc.getDocumentElement();
-
- areaTree = new AreaTree();
- areaTree.setTreeModel(model);
-
- readAreaTree(root);
- }
-
- public void readAreaTree(Element root) {
-
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("pageSequence")) {
- readPageSequence((Element) obj);
- }
- }
- }
-
- public void readPageSequence(Element root) {
- Title title = null;
- boolean started = false;
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("title")) {
- if (started) {
- // problem
- } else {
- title = readTitle((Element) obj);
- model.startPageSequence(title);
- started = true;
- }
- } else if (obj.getNodeName().equals("pageViewport")) {
- if (!started) {
- model.startPageSequence(null);
- started = true;
- }
- PageViewport viewport = readPageViewport((Element) obj);
- areaTree.addPage(viewport);
- }
- }
- }
-
- public Title readTitle(Element root) {
- Title title = new Title();
- List childs = getInlineAreas(root);
- for (int i = 0; i < childs.size(); i++) {
- InlineArea obj = (InlineArea) childs.get(i);
- title.addInlineArea(obj);
- }
- return title;
- }
-
- public PageViewport readPageViewport(Element root) {
- Rectangle2D bounds = getRectangle(root, "bounds");
- PageViewport viewport = null;
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("page")) {
- Page page = readPage((Element) obj);
- viewport = new PageViewport(page, bounds);
- }
- }
- return viewport;
- }
-
- public Page readPage(Element root) {
- String bounds = root.getAttribute("bounds");
- Page page = new Page();
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("regionViewport")) {
- readRegionViewport(page, (Element) obj);
- }
- }
- return page;
- }
-
- Rectangle2D getRectangle(Element root, String attr) {
- String rect = root.getAttribute(attr);
- StringTokenizer st = new StringTokenizer(rect, " ");
- int x = 0, y = 0, w = 0, h = 0;
- if (st.hasMoreTokens()) {
- String tok = st.nextToken();
- x = Integer.parseInt(tok);
- }
- if (st.hasMoreTokens()) {
- String tok = st.nextToken();
- y = Integer.parseInt(tok);
- }
- if (st.hasMoreTokens()) {
- String tok = st.nextToken();
- w = Integer.parseInt(tok);
- }
- if (st.hasMoreTokens()) {
- String tok = st.nextToken();
- h = Integer.parseInt(tok);
- }
- Rectangle2D r2d = new Rectangle2D.Float(x, y, w, h);
- return r2d;
- }
-
- public RegionViewport readRegionViewport(Page page, Element root) {
- RegionViewport reg = new RegionViewport(getRectangle(root, "rect"));
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("regionBefore")) {
- reg.setRegion(readRegion((Element) obj, Region.BEFORE));
- page.setRegion(Region.BEFORE, reg);
- } else if (obj.getNodeName().equals("regionStart")) {
- reg.setRegion(readRegion((Element) obj, Region.START));
- page.setRegion(Region.START, reg);
- } else if (obj.getNodeName().equals("regionBody")) {
- reg.setRegion(readRegion((Element) obj, Region.BODY));
- page.setRegion(Region.BODY, reg);
- } else if (obj.getNodeName().equals("regionEnd")) {
- reg.setRegion(readRegion((Element) obj, Region.END));
- page.setRegion(Region.END, reg);
- } else if (obj.getNodeName().equals("regionAfter")) {
- reg.setRegion(readRegion((Element) obj, Region.AFTER));
- page.setRegion(Region.AFTER, reg);
- }
- }
-
- return reg;
- }
-
- public Region readRegion(Element root, int type) {
- Region reg;
- if (type == Region.BODY) {
- BodyRegion br = new BodyRegion();
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("beforeFloat")) {
- BeforeFloat bf = readBeforeFloat((Element) obj);
- br.setBeforeFloat(bf);
- } else if (obj.getNodeName().equals("mainReference")) {
- MainReference mr = readMainReference((Element) obj);
- br.setMainReference(mr);
- } else if (obj.getNodeName().equals("footnote")) {
- Footnote foot = readFootnote((Element) obj);
- br.setFootnote(foot);
- }
- }
- reg = br;
- } else {
- reg = new Region(type);
- List blocks = getBlocks(root);
- for (int i = 0; i < blocks.size(); i++) {
- Block obj = (Block) blocks.get(i);
- reg.addBlock(obj);
- }
- }
- return reg;
- }
-
- public BeforeFloat readBeforeFloat(Element root) {
- BeforeFloat bf = new BeforeFloat();
- List blocks = getBlocks(root);
- for (int i = 0; i < blocks.size(); i++) {
- Block obj = (Block) blocks.get(i);
- bf.addBlock(obj);
- }
- return bf;
- }
-
- public MainReference readMainReference(Element root) {
- MainReference mr = new MainReference();
- List spans = getSpans(root);
- for (int i = 0; i < spans.size(); i++) {
- Span obj = (Span) spans.get(i);
- mr.addSpan(obj);
- }
- return mr;
- }
-
- List getSpans(Element root) {
- ArrayList list = new ArrayList();
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("span")) {
- List flows = getFlows((Element) obj);
- Span span = new Span(flows.size());
- for (int j = 0; j < flows.size(); j++) {
- Flow flow = (Flow) flows.get(j);
- span.addFlow(flow);
- }
- list.add(span);
- }
- }
- return list;
- }
-
- List getFlows(Element root) {
- ArrayList list = new ArrayList();
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("flow")) {
- Flow flow = new Flow();
- List blocks = getBlocks((Element) obj);
- for (int j = 0; j < blocks.size(); j++) {
- Block block = (Block) blocks.get(j);
- flow.addBlock(block);
- }
- list.add(flow);
- }
- }
- return list;
- }
-
- public Footnote readFootnote(Element root) {
- Footnote foot = new Footnote();
- List blocks = getBlocks(root);
- for (int i = 0; i < blocks.size(); i++) {
- Block obj = (Block) blocks.get(i);
- foot.addBlock(obj);
- }
- return foot;
- }
-
-
- List getBlocks(Element root) {
- ArrayList list = new ArrayList();
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("block")) {
- Block block = new Block();
- List props = getProperties((Element) obj);
- for (int count = 0; count < props.size(); count++) {
- block.addProperty((Property) props.get(count));
- }
- addBlockChildren(block, (Element) obj);
- list.add(block);
- }
- }
- return list;
- }
-
- protected void addBlockChildren(Block block, Element root) {
- NodeList childs = root.getChildNodes();
- int type = -1;
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("block")) {
- if (type == 2) {
- // error
- }
- Block b = new Block();
- addBlockChildren(b, (Element) obj);
- block.addBlock(b);
- type = 1;
- } else if (obj.getNodeName().equals("lineArea")) {
- if (type == 1) {
- // error
- }
- LineArea line = new LineArea();
- List props = getProperties((Element) obj);
- for (int count = 0; count < props.size(); count++) {
- line.addProperty((Property) props.get(count));
- }
- String height = ((Element) obj).getAttribute("height");
- int h = Integer.parseInt(height);
- line.setHeight(h);
-
- List inlines = getInlineAreas((Element) obj);
- for (int j = 0; j < inlines.size(); j++) {
- InlineArea inline = (InlineArea) inlines.get(j);
- line.addInlineArea(inline);
- }
-
- block.addLineArea(line);
- type = 2;
- }
- }
- }
-
- // children of element are inline areas
- List getInlineAreas(Element root) {
- ArrayList list = new ArrayList();
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("char")) {
- Character ch =
- new Character(getString((Element) obj).charAt(0));
- addProperties((Element) obj, ch);
- try {
- currentFontState =
- new FontState(fontInfo, "sans-serif", "normal",
- "normal", 12000, 0);
- } catch (FOPException e) {
-
- }
-
- ch.setWidth(currentFontState.width(ch.getChar()));
- ch.setOffset(currentFontState.getCapHeight());
- list.add(ch);
- } else if (obj.getNodeName().equals("space")) {
- Space space = new Space();
- String width = ((Element) obj).getAttribute("width");
- int w = Integer.parseInt(width);
- space.setWidth(w);
- list.add(space);
- } else if (obj.getNodeName().equals("viewport")) {
- Viewport viewport = getViewport((Element) obj);
- if (viewport != null) {
- list.add(viewport);
- }
- } else if (obj.getNodeName().equals("leader")) {
- Leader leader = getLeader((Element) obj);
- if (leader != null) {
- list.add(leader);
- }
- } else if (obj.getNodeName().equals("word")) {
- Word word = getWord((Element) obj);
- if (word != null) {
- list.add(word);
- }
- } else {
- }
- }
- return list;
- }
-
- Viewport getViewport(Element root) {
- Area child = null;
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj.getNodeName().equals("container")) {
- child = getContainer((Element) obj);
- } else if (obj.getNodeName().equals("foreignObject")) {
- child = getForeignObject((Element) obj);
- } else if (obj.getNodeName().equals("image")) {
- child = getImage((Element) obj);
- }
- }
- if (child == null) {
- return null;
- }
- Viewport viewport = new Viewport(child);
- String str = root.getAttribute("width");
- if (str != null && !"".equals(str)) {
- int width = Integer.parseInt(str);
- viewport.setWidth(width);
- }
- return viewport;
- }
-
- Container getContainer(Element root) {
- Container cont = new Container();
- List blocks = getBlocks(root);
- for (int i = 0; i < blocks.size(); i++) {
- Block obj = (Block) blocks.get(i);
- cont.addBlock(obj);
- }
- return cont;
- }
-
- ForeignObject getForeignObject(Element root) {
- Document doc;
- String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
-
- NodeList childs = root.getChildNodes();
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- if (obj instanceof Element) {
- //System.out.println(obj.getNodeName());
- Element rootEle = (Element) obj;
- String space = rootEle.getAttribute("xmlns");
- if (svgNS.equals(space)) {
- try {
- DocumentBuilderFactory fact =
- DocumentBuilderFactory.newInstance();
- fact.setNamespaceAware(true);
-
- doc = fact. newDocumentBuilder().newDocument();
- Node node = doc.importNode(obj, true);
- doc.appendChild(node);
- DOMImplementation impl =
- SVGDOMImplementation.getDOMImplementation();
- // due to namespace problem attributes are not cloned
- // serializing causes an npe
- //doc = DOMUtilities.deepCloneDocument(doc, impl);
-
- ForeignObject fo = new ForeignObject(doc, svgNS);
- return fo;
- } catch (Exception e) {
- e.printStackTrace();
- }
- } else {
- try {
- DocumentBuilderFactory fact =
- DocumentBuilderFactory.newInstance();
- fact.setNamespaceAware(true);
- doc = fact. newDocumentBuilder().newDocument();
- Node node = doc.importNode(obj, true);
- doc.appendChild(node);
- ForeignObject fo = new ForeignObject(doc, space);
- return fo;
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- return null;
- }
-
- Image getImage(Element root) {
- String url = root.getAttribute("url");
- Image image = new Image(url);
- return image;
- }
-
- Leader getLeader(Element root) {
- Leader leader = new Leader();
- String rs = root.getAttribute("ruleStyle");
- if ("solid".equals(rs)) {
- leader.setRuleStyle(Leader.SOLID);
- } else if ("dotted".equals(rs)) {
- leader.setRuleStyle(Leader.DOTTED);
- } else if ("dashed".equals(rs)) {
- leader.setRuleStyle(Leader.DASHED);
- } else if ("double".equals(rs)) {
- leader.setRuleStyle(Leader.DOUBLE);
- } else if ("groove".equals(rs)) {
- leader.setRuleStyle(Leader.GROOVE);
- } else if ("ridge".equals(rs)) {
- leader.setRuleStyle(Leader.RIDGE);
- }
- String rt = root.getAttribute("ruleThickness");
- int thick = Integer.parseInt(rt);
- leader.setRuleThickness(thick);
- rt = root.getAttribute("width");
- if (rt != null && !"".equals(rt)) {
- thick = Integer.parseInt(rt);
- leader.setWidth(thick);
- }
- leader.setOffset(currentFontState.getCapHeight());
- addProperties(root, leader);
- return leader;
- }
-
- Word getWord(Element root) {
- String str = getString(root);
- Word word = new Word();
- word.setWord(str);
- addProperties(root, word);
- int width = 0;
- for (int count = 0; count < str.length(); count++) {
- width += currentFontState.width(str.charAt(count));
- }
- word.setWidth(width);
- word.setOffset(currentFontState.getCapHeight());
-
- return word;
- }
-
- public void addProperties(Element ele, InlineArea inline) {
- List props = getProperties(ele);
- for (int count = 0; count < props.size(); count++) {
- inline.addProperty((Property) props.get(count));
- }
- String str = ele.getAttribute("width");
-
- }
-
- public List getProperties(Element ele) {
- ArrayList list = new ArrayList();
- String str = ele.getAttribute("props");
- StringTokenizer st = new StringTokenizer(str, ";");
- while (st.hasMoreTokens()) {
- String tok = st.nextToken();
- int index = tok.indexOf(":");
- String id = tok.substring(0, index);
- String val = tok.substring(index + 1);
- Property prop = new Property();
- if ("internal-link".equals(id)) {
- prop.propType = Property.INTERNAL_LINK;
- prop.data = val;
- list.add(prop);
- } else if ("external-link".equals(id)) {
- prop.propType = Property.EXTERNAL_LINK;
- prop.data = val;
- list.add(prop);
- } else if ("font-family".equals(id)) {
- prop.propType = Property.FONT_FAMILY;
- prop.data = val;
- list.add(prop);
- } else if ("font-size".equals(id)) {
- prop.propType = Property.FONT_SIZE;
- prop.data = Integer.valueOf(val);
- list.add(prop);
- } else if ("font-weight".equals(id)) {
- prop.propType = Property.FONT_WEIGHT;
- prop.data = val;
- list.add(prop);
- } else if ("font-style".equals(id)) {
- prop.propType = Property.FONT_STYLE;
- prop.data = val;
- list.add(prop);
- } else if ("color".equals(id)) {
- prop.propType = Property.COLOR;
- prop.data = val;
- list.add(prop);
- } else if ("background".equals(id)) {
- prop.propType = Property.BACKGROUND;
- prop.data = val;
- list.add(prop);
- } else if ("underline".equals(id)) {
- prop.propType = Property.UNDERLINE;
- prop.data = new Boolean(val);
- list.add(prop);
- } else if ("overline".equals(id)) {
- prop.propType = Property.OVERLINE;
- prop.data = new Boolean(val);
- list.add(prop);
- } else if ("linethrough".equals(id)) {
- prop.propType = Property.LINETHROUGH;
- prop.data = new Boolean(val);
- list.add(prop);
- } else if ("offset".equals(id)) {
- prop.propType = Property.OFFSET;
- prop.data = Integer.valueOf(val);
- list.add(prop);
- } else if ("shadow".equals(id)) {
- prop.propType = Property.SHADOW;
- prop.data = val;
- list.add(prop);
- }
- }
- return list;
- }
-
- public List getRanges(Element ele) {
- ArrayList list = new ArrayList();
- String str = ele.getAttribute("ranges");
- StringTokenizer st = new StringTokenizer(str, ";");
- while (st.hasMoreTokens()) {
- String tok = st.nextToken();
- }
- return list;
- }
-
- public String getString(Element ele) {
- String str = "";
- NodeList childs = ele.getChildNodes();
- if (childs.getLength() == 0) {
- return null;
- }
- for (int i = 0; i < childs.getLength(); i++) {
- Node obj = childs.item(i);
- str = str + obj.getNodeValue();
- }
- return str;
- }
-
- }
|