You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2009/09/22 13:49:06 UTC

svn commit: r817617 - in /xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop: accessibility/ apps/ render/intermediate/ render/pdf/

Author: vhennebert
Date: Tue Sep 22 11:49:06 2009
New Revision: 817617

URL: http://svn.apache.org/viewvc?rev=817617&view=rev
Log:
Factorized into a new class the parsing of the reduced FO tree, that was duplicated in IFSerializer and PDFDocumentHandler.

Added:
    xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/StructureTree.java   (with props)
Modified:
    xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java
    xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/apps/FOUserAgent.java
    xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFSerializer.java
    xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java

Added: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/StructureTree.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/StructureTree.java?rev=817617&view=auto
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/StructureTree.java (added)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/StructureTree.java Tue Sep 22 11:49:06 2009
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.accessibility;
+
+import java.util.Iterator;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * A reduced version of the document's FO tree, containing only its logical
+ * structure. Used by accessible output formats.
+ */
+public final class StructureTree {
+
+    private final Node reducedFOTree;
+
+    private static class NamespaceContextImpl implements NamespaceContext {
+
+        private String uri;
+        private String prefix;
+
+        public NamespaceContextImpl() {
+        }
+
+        public NamespaceContextImpl(String prefix, String uri) {
+            this.uri = uri;
+            this.prefix = prefix;
+        }
+
+        public String getNamespaceURI(String prefix) {
+            return uri;
+        }
+
+        public void setNamespaceURI(String uri) {
+            this.uri = uri;
+        }
+
+        public String getPrefix(String uri) {
+            return prefix;
+        }
+
+        public void setPrefix(String prefix) {
+            this.prefix = prefix;
+        }
+
+        public Iterator getPrefixes(String uri) {
+            return null;
+        }
+    }
+
+    StructureTree(Node reducedFOTree) {
+        this.reducedFOTree = reducedFOTree;
+    }
+
+    /**
+     * Returns the list of nodes that are the children of the given page sequence.
+     *
+     * @param number number of the page sequence, 1-based
+     * @return its children nodes
+     */
+    public NodeList getPageSequence(int number) {
+        XPath xpath = XPathFactory.newInstance().newXPath();
+        NamespaceContext namespaceContext = new NamespaceContextImpl("fo",
+                "http://www.w3.org/1999/XSL/Format");
+        xpath.setNamespaceContext(namespaceContext);
+        String xpathExpr = "/fo:root/fo:page-sequence[" + Integer.toString(number) + "]/*";
+
+        try {
+            return (NodeList) xpath.evaluate(xpathExpr, reducedFOTree, XPathConstants.NODESET);
+        } catch (XPathExpressionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

Propchange: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/StructureTree.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/StructureTree.java
------------------------------------------------------------------------------
    svn:keywords = Revision Id

Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java?rev=817617&r1=817616&r2=817617&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/accessibility/TransformerNodeEndProcessing.java Tue Sep 22 11:49:06 2009
@@ -28,14 +28,14 @@
 import javax.xml.transform.Source;
 import javax.xml.transform.Templates;
 import javax.xml.transform.Transformer;
+import javax.xml.transform.dom.DOMResult;
 import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
 
+import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
-import org.apache.commons.io.output.ByteArrayOutputStream;
-
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.apps.FOUserAgent;
 
@@ -76,10 +76,9 @@
             byte[] enrichedFO = enrichedFOBuffer.toByteArray();
             Transformer transformer = AccessibilityUtil.getReduceFOTreeTemplates().newTransformer();
             Source src = new StreamSource(new ByteArrayInputStream(enrichedFO));
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            Result res = new StreamResult(out);
+            DOMResult res = new DOMResult();
             transformer.transform(src, res);
-            userAgent.setReducedFOTree(out.toByteArray());
+            userAgent.setStructureTree(new StructureTree(res.getNode()));
 
             SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
             saxParserFactory.setNamespaceAware(true);

Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/apps/FOUserAgent.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/apps/FOUserAgent.java?rev=817617&r1=817616&r2=817617&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/apps/FOUserAgent.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/apps/FOUserAgent.java Tue Sep 22 11:49:06 2009
@@ -38,6 +38,7 @@
 
 import org.apache.fop.Version;
 import org.apache.fop.accessibility.AccessibilityUtil;
+import org.apache.fop.accessibility.StructureTree;
 import org.apache.fop.events.DefaultEventBroadcaster;
 import org.apache.fop.events.Event;
 import org.apache.fop.events.EventBroadcaster;
@@ -100,8 +101,7 @@
     private boolean conserveMemoryPolicy = false;
     private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster();
 
-    //TODO Verify that a byte array is the best solution here
-    private byte[] reducedFOTree;  // accessibility: reduced FO
+    private StructureTree structureTree;
 
     /** Producer:  Metadata element for the system/software that produces
      * the document. (Some renderers can store this in the document.)
@@ -664,20 +664,24 @@
     }
 
     /**
-     * Used for accessibility. Stores the reduced FO tree (the result from the second transform)
-     * for later use.
-     * @param reducedFOTree the result from 2nd transform
+     * Sets the document's structure tree, for use by accessible output formats.
+     *
+     * @param structureTree a simplified version of the FO tree, retaining only
+     * its logical structure
      */
-    public void setReducedFOTree(byte[] reducedFOTree) {
-        this.reducedFOTree = reducedFOTree;
+    public void setStructureTree(StructureTree structureTree) {
+        this.structureTree = structureTree;
     }
 
     /**
-     * Used for accessibility. Returns the reduced FO tree.
-     * @return result from 2nd transform as byte array
+     * Returns the document's structure tree, for use by accessible output
+     * formats.
+     *
+     * @return a simplified version of the FO tree, retaining only its logical
+     * structure
      */
-    public byte[] getReducedFOTree() {
-        return this.reducedFOTree;
+    public StructureTree getStructureTree() {
+        return this.structureTree;
     }
 }
 

Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFSerializer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFSerializer.java?rev=817617&r1=817616&r2=817617&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFSerializer.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/intermediate/IFSerializer.java Tue Sep 22 11:49:06 2009
@@ -25,33 +25,22 @@
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Stack;
 
-import javax.xml.namespace.NamespaceContext;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
-
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.AttributesImpl;
 
 import org.apache.xmlgraphics.util.QName;
 import org.apache.xmlgraphics.util.XMLizable;
 
+import org.apache.fop.accessibility.StructureTree;
 import org.apache.fop.fonts.FontInfo;
 import org.apache.fop.render.PrintRendererConfigurator;
 import org.apache.fop.render.RenderingContext;
@@ -76,45 +65,10 @@
 
     private IFDocumentHandler mimicHandler;
     private int pageSequenceCounter; // used for accessibility
-    private DocumentBuilder parser = null; // used for accessibility
-    private Document doc = null;  // used for accessibility
 
     /** Holds the intermediate format state */
     private IFState state;
 
-    private static class NamespaceContextImpl implements NamespaceContext {
-
-         public String uri;
-         public String prefix;
-
-         public NamespaceContextImpl() {
-         }
-
-         public NamespaceContextImpl(String prefix, String uri) {
-             this.uri = uri;
-             this.prefix = prefix;
-            }
-
-         public String getNamespaceURI(String prefix) {
-           return uri;
-         }
-         public void setNamespaceURI(String uri) {
-           this.uri = uri;
-         }
-
-         public String getPrefix(String uri) {
-           return prefix;
-         }
-
-         public void setPrefix(String prefix) {
-           this.prefix = prefix;
-         }
-         public Iterator getPrefixes(String uri) {
-             return null;
-         }
-
-    }
-
     /**
      * Default constructor.
      */
@@ -202,16 +156,8 @@
             handler.startPrefixMapping(DocumentNavigationExtensionConstants.PREFIX,
                     DocumentNavigationExtensionConstants.NAMESPACE);
             handler.startElement(EL_DOCUMENT);
-            if (this.getUserAgent().isAccessibilityEnabled()) {
-                pageSequenceCounter = 0;
-                DocumentBuilderFactory  factory = DocumentBuilderFactory.newInstance();
-                factory.setNamespaceAware(true);
-                parser = factory.newDocumentBuilder();
-            }
         } catch (SAXException e) {
             throw new IFException("SAX error in startDocument()", e);
-        } catch (ParserConfigurationException pce) {
-            throw new IFException("Error creating new DocumentBuilder", pce);
         }
     }
 
@@ -273,18 +219,9 @@
             addForeignAttributes(atts);
             handler.startElement(EL_PAGE_SEQUENCE, atts);
             if (this.getUserAgent().isAccessibilityEnabled()) {
-                if (doc == null) {
-                    doc = parser.parse(
-                            new ByteArrayInputStream(this.getUserAgent().getReducedFOTree()));
-                }
+                StructureTree structureTree = getUserAgent().getStructureTree();
                 handler.startElement(EL_STRUCTURE_TREE); // add structure tree
-                String xpathExpr
-                   = "/fo:root/fo:page-sequence[" + Integer.toString(++pageSequenceCounter) + "]/*";
-                XPath xpath = XPathFactory.newInstance().newXPath();
-                NamespaceContext namespaceContext
-                    = new NamespaceContextImpl("fo", "http://www.w3.org/1999/XSL/Format");
-                xpath.setNamespaceContext(namespaceContext);
-                NodeList nodes = (NodeList)xpath.evaluate(xpathExpr, doc, XPathConstants.NODESET);
+                NodeList nodes = structureTree.getPageSequence(++pageSequenceCounter);
                 for (int i = 0, n = nodes.getLength(); i < n; i++) {
                     Node node = nodes.item(i);
                     new DOM2SAX(handler).writeFragment(node);
@@ -293,10 +230,6 @@
             }
         } catch (SAXException e) {
             throw new IFException("SAX error in startPageSequence()", e);
-        } catch (XPathExpressionException e) {
-            throw new IFException("Error while evaluating XPath expression", e);
-        } catch (IOException ioe) {
-            throw new IFException("I/O error while parsing structure tree", ioe);
         }
     }
 

Modified: xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java?rev=817617&r1=817616&r2=817617&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java (original)
+++ xmlgraphics/fop/branches/Temp_Accessibility/src/java/org/apache/fop/render/pdf/PDFDocumentHandler.java Tue Sep 22 11:49:06 2009
@@ -25,31 +25,19 @@
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.Rectangle2D.Double;
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import javax.xml.namespace.NamespaceContext;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
 
 import org.apache.xmlgraphics.xmp.Metadata;
 
+import org.apache.fop.accessibility.StructureTree;
 import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.fo.extensions.xmp.XMPMetadata;
 import org.apache.fop.pdf.PDFAnnotList;
@@ -86,8 +74,6 @@
 
     /** the following variables are used for accessibility */
     private int pageSequenceCounter;
-    private DocumentBuilder parser = null;
-    private Document reducedFOTree = null;
     private Map structElemType = new HashMap();
     private boolean accessEnabled = false;
     private int parentTreeKey = -1;
@@ -97,41 +83,6 @@
     private Map structTreeMap = new HashMap();
     private List parentTreeList = new java.util.ArrayList();
 
-    private static class NamespaceContextImpl implements NamespaceContext {
-
-        private String uri;
-        private String prefix;
-
-        public NamespaceContextImpl() {
-        }
-
-        public NamespaceContextImpl(String prefix, String uri) {
-            this.uri = uri;
-            this.prefix = prefix;
-        }
-
-        public String getNamespaceURI(String prefix) {
-            return uri;
-        }
-
-        public void setNamespaceURI(String uri) {
-            this.uri = uri;
-        }
-
-        public String getPrefix(String uri) {
-            return prefix;
-        }
-
-        public void setPrefix(String prefix) {
-            this.prefix = prefix;
-        }
-
-        public Iterator getPrefixes(String uri) {
-            return null;
-        }
-
-    }
-
     private static final class ParentTreeEntry {
         private final int position;
         private final PDFObject object;
@@ -233,14 +184,9 @@
 
                 parentTree = new PDFParentTree();
                 pageSequenceCounter = 0;
-                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-                factory.setNamespaceAware(true);
-                parser = factory.newDocumentBuilder();
             }
         } catch (IOException e) {
             throw new IFException("I/O error in startDocument()", e);
-        } catch (ParserConfigurationException pce) {
-            throw new IFException("Error creating new DocumentBuilder", pce);
         }
     }
 
@@ -271,8 +217,6 @@
                 parentTree.setNums(nums);
                 getStructTreeRoot().addParentTree(parentTree);
                 pdfDoc.outputTrailer(this.outputStream);
-                parser = null;
-                reducedFOTree = null;
                 structElemType = null;
                 parentTree = null;
                 structTreeMap = null;
@@ -308,65 +252,46 @@
         }
 
         if (getUserAgent().isAccessibilityEnabled()) {
-            try {
-                if (this.pdfDoc.getRoot().getLanguage() == null) {
-                    String fallbackLanguage;
-                    if (this.pdfDoc.getProfile().getPDFAMode().isPDFA1LevelA()) {
-                        //According to Annex B of ISO-19005-1:2005(E), section B.2
-                        fallbackLanguage = "x-unknown";
-                    } else {
-                        //No language has been set on the first page-sequence, so fall back to "en".
-                        fallbackLanguage = "en";
-                    }
-                    this.pdfDoc.getRoot().setLanguage(fallbackLanguage);
+            if (this.pdfDoc.getRoot().getLanguage() == null) {
+                String fallbackLanguage;
+                if (this.pdfDoc.getProfile().getPDFAMode().isPDFA1LevelA()) {
+                    //According to Annex B of ISO-19005-1:2005(E), section B.2
+                    fallbackLanguage = "x-unknown";
+                } else {
+                    //No language has been set on the first page-sequence, so fall back to "en".
+                    fallbackLanguage = "en";
                 }
+                this.pdfDoc.getRoot().setLanguage(fallbackLanguage);
+            }
 
-                if (reducedFOTree == null) {
-                    reducedFOTree = parser.parse(
-                            new ByteArrayInputStream(this.getUserAgent().getReducedFOTree()));
-                }
-                PDFStructElem parent = (PDFStructElem)getStructTreeRoot().getFirstChild();
-                PDFStructElem structElemPart = new PDFStructElem(parent,
-                        FOToPDFRoleMap.mapFormattingObject("page-sequence", parent));
-                if (getContext().getLanguage() != null) {
-                    structElemPart.setLanguage(getContext().getLanguage());
-                }
-                this.pdfDoc.assignObjectNumber(structElemPart);
-                this.pdfDoc.addTrailerObject(structElemPart);
-                parent.addKid(structElemPart);
-
-                String xpathExpr = "/fo:root/fo:page-sequence["
-                        + Integer.toString(++pageSequenceCounter) + "]/*";
-                XPath xpath = XPathFactory.newInstance().newXPath();
-                NamespaceContext namespaceContext = new NamespaceContextImpl("fo",
-                        "http://www.w3.org/1999/XSL/Format");
-                xpath.setNamespaceContext(namespaceContext);
-
-                NodeList nodes = (NodeList) xpath.evaluate(xpathExpr, reducedFOTree,
-                        XPathConstants.NODESET);
-
-                for (int i = 0, n = nodes.getLength(); i < n; i++) {
-                    Node node = nodes.item(i);
-                    if (node.getNodeName().equals("fo:flow")
-                            || node.getNodeName().equals("fo:static-content")) {
-                        PDFStructElem structElemSect = new PDFStructElem(structElemPart,
-                                FOToPDFRoleMap.mapFormattingObject(node.getLocalName(),
-                                        structElemPart));
-                        this.pdfDoc.assignObjectNumber(structElemSect);
-                        this.pdfDoc.addTrailerObject(structElemSect);
-                        structElemPart.addKid(structElemSect);
-                        NodeList iNodes = node.getChildNodes();
-                        for (int j = 0, m = iNodes.getLength(); j < m; j++) {
-                            processContent(iNodes.item(j), structElemSect, 1);
-                        }
+            StructureTree structureTree = getUserAgent().getStructureTree();
+            PDFStructElem parent = (PDFStructElem)getStructTreeRoot().getFirstChild();
+            PDFStructElem structElemPart = new PDFStructElem(parent,
+                    FOToPDFRoleMap.mapFormattingObject("page-sequence", parent));
+            if (getContext().getLanguage() != null) {
+                structElemPart.setLanguage(getContext().getLanguage());
+            }
+            this.pdfDoc.assignObjectNumber(structElemPart);
+            this.pdfDoc.addTrailerObject(structElemPart);
+            parent.addKid(structElemPart);
+
+            NodeList nodes = structureTree.getPageSequence(++pageSequenceCounter);
+
+            for (int i = 0, n = nodes.getLength(); i < n; i++) {
+                Node node = nodes.item(i);
+                if (node.getNodeName().equals("fo:flow")
+                        || node.getNodeName().equals("fo:static-content")) {
+                    PDFStructElem structElemSect = new PDFStructElem(structElemPart,
+                            FOToPDFRoleMap.mapFormattingObject(node.getLocalName(),
+                                    structElemPart));
+                    this.pdfDoc.assignObjectNumber(structElemSect);
+                    this.pdfDoc.addTrailerObject(structElemSect);
+                    structElemPart.addKid(structElemSect);
+                    NodeList iNodes = node.getChildNodes();
+                    for (int j = 0, m = iNodes.getLength(); j < m; j++) {
+                        processContent(iNodes.item(j), structElemSect, 1);
                     }
                 }
-            } catch (SAXException e) {
-                throw new IFException("SAX error in startPageSequence()", e);
-            } catch (XPathExpressionException e) {
-                throw new IFException("Error while evaluating XPath expression", e);
-            } catch (IOException ioe) {
-                throw new IFException("I/O error while parsing structure tree", ioe);
             }
         }
     }



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org