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 je...@apache.org on 2007/08/06 16:03:02 UTC

svn commit: r563142 [2/2] - in /xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop: image/ image/analyser/ pdf/ render/pdf/ svg/

Added: xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java?view=auto&rev=563142
==============================================================================
--- xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java (added)
+++ xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java Mon Aug  6 07:03:00 2007
@@ -0,0 +1,119 @@
+/*
+ * 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.render.pdf;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.xmlgraphics.util.Service;
+
+/**
+ * This class holds references to various image handlers used by the PDF renderer. It also
+ * supports automatic discovery of additional handlers available through
+ * the class path.
+ */
+public class PDFImageHandlerRegistry {
+
+    /** the logger */
+    private static Log log = LogFactory.getLog(PDFImageHandlerRegistry.class);
+    
+    /** Map containing PDF image handlers for various MIME types */
+    private Map handlers = new java.util.HashMap();
+    
+    /**
+     * Default constructor.
+     */
+    public PDFImageHandlerRegistry() {
+        discoverHandlers();
+    }
+    
+    /**
+     * Add an PDFImageHandler. The handler itself is inspected to find out what it supports.
+     * @param classname the fully qualified class name
+     */
+    public void addHandler(String classname) {
+        try {
+            PDFImageHandler handlerInstance
+                = (PDFImageHandler)Class.forName(classname).newInstance();
+            addHandler(handlerInstance);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException("Could not find "
+                                               + classname);
+        } catch (InstantiationException e) {
+            throw new IllegalArgumentException("Could not instantiate "
+                                               + classname);
+        } catch (IllegalAccessException e) {
+            throw new IllegalArgumentException("Could not access "
+                                               + classname);
+        } catch (ClassCastException e) {
+            throw new IllegalArgumentException(classname
+                                               + " is not an " 
+                                               + PDFImageHandler.class.getName());
+        }
+    }
+    
+    /**
+     * Add an image handler. The handler itself is inspected to find out what it supports.
+     * @param handler the PDFImageHandler instance
+     */
+    public void addHandler(PDFImageHandler handler) {
+        String mime = handler.getSupportedMimeType();
+        handlers.put(mime, handler);
+    }
+    
+    /**
+     * Returns an PDFImageHandler which handles an specific image type given the MIME type
+     * of the image.
+     * @param mime the requested MIME type
+     * @return the PDFImageHandler responsible for handling the image or null if none is available
+     */
+    public PDFImageHandler getHandler(String mime) {
+        PDFImageHandler handler;
+
+        handler = (PDFImageHandler)handlers.get(mime);
+        return handler;
+    }
+
+    /**
+     * Discovers PDFImageHandler implementations through the classpath and dynamically
+     * registers them.
+     */
+    private void discoverHandlers() {
+        // add mappings from available services
+        Iterator providers = Service.providers(PDFImageHandler.class);
+        if (providers != null) {
+            while (providers.hasNext()) {
+                PDFImageHandler handler = (PDFImageHandler)providers.next();
+                try {
+                    if (log.isDebugEnabled()) {
+                        log.debug("Dynamically adding PDFImageHandler: " 
+                                + handler.getClass().getName());
+                    }
+                    addHandler(handler);
+                } catch (IllegalArgumentException e) {
+                    log.error("Error while adding PDFImageHandler", e);
+                }
+
+            }
+        }
+    }
+}

Propchange: xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/render/pdf/PDFImageHandlerRegistry.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/render/pdf/PDFRenderer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/render/pdf/PDFRenderer.java?view=diff&rev=563142&r1=563141&r2=563142
==============================================================================
--- xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/render/pdf/PDFRenderer.java (original)
+++ xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/render/pdf/PDFRenderer.java Mon Aug  6 07:03:00 2007
@@ -20,58 +20,56 @@
 package org.apache.fop.render.pdf;
 
 // Java
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-import java.awt.geom.Point2D;
 import java.awt.Color;
 import java.awt.color.ColorSpace;
 import java.awt.color.ICC_Profile;
-import java.awt.geom.Rectangle2D;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
 import java.util.Iterator;
-import java.util.Map;
 import java.util.List;
+import java.util.Map;
 
 import javax.xml.transform.Source;
 import javax.xml.transform.stream.StreamSource;
 
-// XML
-import org.w3c.dom.Document;
-
-// Avalon
 import org.apache.commons.io.IOUtils;
-
-// FOP
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.apps.MimeConstants;
 import org.apache.fop.area.Area;
 import org.apache.fop.area.Block;
+import org.apache.fop.area.BookmarkData;
 import org.apache.fop.area.CTM;
+import org.apache.fop.area.DestinationData;
 import org.apache.fop.area.LineArea;
 import org.apache.fop.area.OffDocumentExtensionAttachment;
+import org.apache.fop.area.OffDocumentItem;
 import org.apache.fop.area.PageViewport;
 import org.apache.fop.area.RegionViewport;
 import org.apache.fop.area.Trait;
-import org.apache.fop.area.OffDocumentItem;
-import org.apache.fop.area.BookmarkData;
 import org.apache.fop.area.inline.AbstractTextArea;
-import org.apache.fop.area.inline.TextArea;
 import org.apache.fop.area.inline.Image;
-import org.apache.fop.area.inline.Leader;
 import org.apache.fop.area.inline.InlineArea;
 import org.apache.fop.area.inline.InlineParent;
-import org.apache.fop.area.inline.WordArea;
+import org.apache.fop.area.inline.Leader;
 import org.apache.fop.area.inline.SpaceArea;
-import org.apache.fop.fonts.Typeface;
+import org.apache.fop.area.inline.TextArea;
+import org.apache.fop.area.inline.WordArea;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.extensions.ExtensionAttachment;
+import org.apache.fop.fo.extensions.xmp.XMPMetadata;
 import org.apache.fop.fonts.Font;
+import org.apache.fop.fonts.Typeface;
 import org.apache.fop.image.FopImage;
 import org.apache.fop.image.ImageFactory;
 import org.apache.fop.image.XMLImage;
-import org.apache.fop.pdf.PDFAction;
 import org.apache.fop.pdf.PDFAMode;
+import org.apache.fop.pdf.PDFAction;
 import org.apache.fop.pdf.PDFAnnotList;
 import org.apache.fop.pdf.PDFColor;
 import org.apache.fop.pdf.PDFConformanceException;
@@ -102,14 +100,10 @@
 import org.apache.fop.render.RendererContext;
 import org.apache.fop.util.CharUtilities;
 import org.apache.fop.util.ColorProfileUtil;
-import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.extensions.ExtensionAttachment;
-import org.apache.fop.fo.extensions.xmp.XMPMetadata;
 import org.apache.xmlgraphics.xmp.Metadata;
 import org.apache.xmlgraphics.xmp.schemas.XMPBasicAdapter;
 import org.apache.xmlgraphics.xmp.schemas.XMPBasicSchema;
-
-import org.apache.fop.area.DestinationData;
+import org.w3c.dom.Document;
 
 /**
  * Renderer that renders areas to PDF.
@@ -256,6 +250,9 @@
      */
     protected boolean inTextMode = false;
 
+    /** Image handler registry */
+    private PDFImageHandlerRegistry imageHandlerRegistry = new PDFImageHandlerRegistry();
+    
     /**
      * create the PDF renderer
      */
@@ -1659,21 +1656,21 @@
     }
     
     /**
-     * Adds a PDF XObject (a bitmap) to the PDF that will later be referenced.
+     * Adds a PDF XObject (a bitmap or form) to the PDF that will later be referenced.
      * @param url URL of the bitmap
      * @param pos Position of the bitmap
      */
     protected void putImage(String url, Rectangle2D pos) {
-        PDFXObject xobject = pdfDoc.getImage(url);
+        url = ImageFactory.getURL(url);
+        PDFXObject xobject = pdfDoc.getXObject(url);
         if (xobject != null) {
             float w = (float) pos.getWidth() / 1000f;
             float h = (float) pos.getHeight() / 1000f;
             placeImage((float)pos.getX() / 1000f,
-                       (float)pos.getY() / 1000f, w, h, xobject.getXNumber());
+                       (float)pos.getY() / 1000f, w, h, xobject);
             return;
         }
 
-        url = ImageFactory.getURL(url);
         ImageFactory fact = userAgent.getFactory().getImageFactory();
         FopImage fopimage = fact.getImage(url, userAgent);
         if (fopimage == null) {
@@ -1683,7 +1680,24 @@
             return;
         }
         String mime = fopimage.getMimeType();
-        if ("text/xml".equals(mime)) {
+        
+        //First check for a dynamically registered handler
+        PDFImageHandler handler = imageHandlerRegistry.getHandler(mime);
+        if (handler != null) {
+            PDFXObject xobj;
+            try {
+                xobj = handler.generateImage(fopimage, url, pdfDoc);
+            } catch (IOException ioe) {
+                log.error("I/O error while handling " + mime + " image", ioe);
+                return;
+            }
+            fact.releaseImage(url, userAgent);
+            
+            float w = (float)pos.getWidth() / 1000f;
+            float h = (float)pos.getHeight() / 1000f;
+            placeImage((float) pos.getX() / 1000,
+                       (float) pos.getY() / 1000, w, h, xobj);
+        } else if ("text/xml".equals(mime)) {
             if (!fopimage.load(FopImage.ORIGINAL_DATA)) {
                 return;
             }
@@ -1701,7 +1715,7 @@
             renderDocument(doc, ns, pos, null);
         } else if ("image/eps".equals(mime)) {
             FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
-            int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber();
+            PDFXObject xobj = pdfDoc.addImage(currentContext, pdfimage);
             fact.releaseImage(url, userAgent);
             
             float w = (float)pos.getWidth() / 1000f;
@@ -1710,7 +1724,7 @@
                        (float) pos.getY() / 1000, w, h, xobj);
         } else if ("image/jpeg".equals(mime) || "image/tiff".equals(mime)) {
             FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
-            int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber();
+            PDFXObject xobj = pdfDoc.addImage(currentContext, pdfimage);
             fact.releaseImage(url, userAgent);
 
             float w = (float)pos.getWidth() / 1000f;
@@ -1722,7 +1736,7 @@
                 return;
             }
             FopPDFImage pdfimage = new FopPDFImage(fopimage, url);
-            int xobj = pdfDoc.addImage(currentContext, pdfimage).getXNumber();
+            PDFXObject xobj = pdfDoc.addImage(currentContext, pdfimage);
             fact.releaseImage(url, userAgent);
 
             float w = (float) pos.getWidth() / 1000f;
@@ -1745,15 +1759,15 @@
      * @param y Y coordinate
      * @param w width for image
      * @param h height for image
-     * @param xobj object number of the referenced image
+     * @param xobj the image XObject
      */
-    protected void placeImage(float x, float y, float w, float h, int xobj) {
+    protected void placeImage(float x, float y, float w, float h, PDFXObject xobj) {
         saveGraphicsState();
         currentStream.add(format(w) + " 0 0 "
                           + format(-h) + " "
                           + format(currentIPPosition / 1000f + x) + " "
                           + format(currentBPPosition / 1000f + h + y) 
-                          + " cm\n" + "/Im" + xobj + " Do\n");
+                          + " cm\n" + xobj.getName() + " Do\n");
         restoreGraphicsState();
     }
 

Modified: xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/svg/PDFGraphics2D.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/svg/PDFGraphics2D.java?view=diff&rev=563142&r1=563141&r2=563142
==============================================================================
--- xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/svg/PDFGraphics2D.java (original)
+++ xmlgraphics/fop/branches/Temp_PDF_in_PDF/src/java/org/apache/fop/svg/PDFGraphics2D.java Mon Aug  6 07:03:00 2007
@@ -19,80 +19,77 @@
 
 package org.apache.fop.svg;
 
-import org.apache.fop.pdf.PDFConformanceException;
-import org.apache.fop.pdf.PDFResourceContext;
-import org.apache.fop.pdf.PDFResources;
-import org.apache.fop.pdf.PDFGState;
-import org.apache.fop.pdf.PDFDeviceColorSpace;
-import org.apache.fop.pdf.PDFColor;
-import org.apache.fop.pdf.PDFState;
-import org.apache.fop.pdf.PDFNumber;
-import org.apache.fop.pdf.PDFText;
-import org.apache.fop.pdf.PDFXObject;
-import org.apache.fop.pdf.PDFPattern;
-import org.apache.fop.pdf.PDFDocument;
-import org.apache.fop.pdf.PDFLink;
-import org.apache.fop.pdf.PDFAnnotList;
-import org.apache.fop.pdf.BitmapImage;
-import org.apache.fop.fonts.FontInfo;
-import org.apache.fop.fonts.Font;
-import org.apache.fop.fonts.FontSetup;
-import org.apache.fop.fonts.FontTriplet;
-import org.apache.fop.fonts.LazyFont;
-import org.apache.fop.image.JpegImage;
-import org.apache.fop.fonts.CIDFont;
-import org.apache.fop.render.pdf.FopPDFImage;
-import org.apache.fop.util.ColorExt;
-
-import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
-import org.apache.xmlgraphics.java2d.GraphicContext;
-
-import org.apache.batik.ext.awt.RadialGradientPaint;
-import org.apache.batik.ext.awt.LinearGradientPaint;
-import org.apache.batik.ext.awt.MultipleGradientPaint;
-import org.apache.batik.ext.awt.RenderingHintsKeyExt;
-import org.apache.batik.gvt.PatternPaint;
-import org.apache.batik.gvt.GraphicsNode;
-
-import java.text.AttributedCharacterIterator;
-import java.text.CharacterIterator;
+import java.awt.AlphaComposite;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.GradientPaint;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
-import java.awt.Color;
 import java.awt.GraphicsConfiguration;
-/*  java.awt.Font is not imported to avoid confusion with
-    org.apache.fop.fonts.Font */
-import java.awt.GradientPaint;
 import java.awt.Image;
-import java.awt.Shape;
-import java.awt.Stroke;
 import java.awt.Paint;
 import java.awt.PaintContext;
 import java.awt.Rectangle;
-import java.awt.Dimension;
-import java.awt.BasicStroke;
-import java.awt.AlphaComposite;
-import java.awt.geom.AffineTransform;
+import java.awt.Shape;
+import java.awt.Stroke;
 import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.awt.image.ColorModel;
-import java.awt.image.DirectColorModel;
 import java.awt.image.DataBuffer;
 import java.awt.image.DataBufferInt;
+import java.awt.image.DirectColorModel;
 import java.awt.image.ImageObserver;
-import java.awt.image.RenderedImage;
 import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
 import java.awt.image.WritableRaster;
 import java.awt.image.renderable.RenderableImage;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.io.StringWriter;
 import java.io.IOException;
 import java.io.OutputStream;
-
-import java.util.Map;
+import java.io.StringWriter;
+import java.text.AttributedCharacterIterator;
+import java.text.CharacterIterator;
 import java.util.List;
+import java.util.Map;
+
+import org.apache.batik.ext.awt.LinearGradientPaint;
+import org.apache.batik.ext.awt.MultipleGradientPaint;
+import org.apache.batik.ext.awt.RadialGradientPaint;
+import org.apache.batik.ext.awt.RenderingHintsKeyExt;
+import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.gvt.PatternPaint;
+import org.apache.fop.fonts.CIDFont;
+import org.apache.fop.fonts.Font;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.fonts.FontSetup;
+import org.apache.fop.fonts.FontTriplet;
+import org.apache.fop.fonts.LazyFont;
+import org.apache.fop.image.JpegImage;
+import org.apache.fop.pdf.BitmapImage;
+import org.apache.fop.pdf.PDFAnnotList;
+import org.apache.fop.pdf.PDFColor;
+import org.apache.fop.pdf.PDFConformanceException;
+import org.apache.fop.pdf.PDFDeviceColorSpace;
+import org.apache.fop.pdf.PDFDocument;
+import org.apache.fop.pdf.PDFGState;
+import org.apache.fop.pdf.PDFImageXObject;
+import org.apache.fop.pdf.PDFLink;
+import org.apache.fop.pdf.PDFName;
+import org.apache.fop.pdf.PDFNumber;
+import org.apache.fop.pdf.PDFPattern;
+import org.apache.fop.pdf.PDFResourceContext;
+import org.apache.fop.pdf.PDFResources;
+import org.apache.fop.pdf.PDFState;
+import org.apache.fop.pdf.PDFText;
+import org.apache.fop.pdf.PDFXObject;
+import org.apache.fop.render.pdf.FopPDFImage;
+import org.apache.fop.util.ColorExt;
+import org.apache.xmlgraphics.java2d.AbstractGraphics2D;
+import org.apache.xmlgraphics.java2d.GraphicContext;
 
 /**
  * PDF Graphics 2D.
@@ -406,8 +403,8 @@
         String key = "__AddJPEG_" + hashCode() + "_" + jpegCount[0];
         jpegCount[0]++;
         FopPDFImage fopimage = new FopPDFImage(jpeg, key);
-        int xObjectNum = this.pdfDoc.addImage(resourceContext, 
-                                              fopimage).getXNumber();
+        PDFName imageName = this.pdfDoc.addImage(resourceContext, 
+                                              fopimage).getName();
         AffineTransform at = getTransform();
         double[] matrix = new double[6];
         at.getMatrix(matrix);
@@ -421,8 +418,8 @@
         currentStream.write("" + width + " 0 0 "
                           + (-height) + " "
                           + x + " "
-                          + (y + height) + " cm\n" + "/Im"
-                          + xObjectNum + " Do\nQ\n");
+                          + (y + height) + " cm\n"
+                          + imageName + " Do\nQ\n");
 
         if (outputStream != null) {
             try {
@@ -518,7 +515,7 @@
         // the pdf document. If so, we just reuse the reference;
         // otherwise we have to build a FopImage and add it to the pdf
         // document
-        PDFXObject imageInfo = pdfDoc.getImage("TempImage:" + img.toString());
+        PDFXObject imageInfo = pdfDoc.getXObject("TempImage:" + img.toString());
         if (imageInfo == null) {
             // OK, have to build and add a PDF image
 
@@ -579,7 +576,7 @@
                                              + img.toString(), buf.getWidth(),
                                              buf.getHeight(), mask, null);
                 fopimg.setColorSpace(new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_GRAY));
-                PDFXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
+                PDFImageXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
                 ref = xobj.referencePDF();
 
                 if (outputStream != null) {
@@ -623,7 +620,7 @@
         writeClip(imclip);
         currentStream.write("" + width + " 0 0 " + (-height) + " " + x
                             + " " + (y + height) + " cm\n" + "/Im"
-                            + imageInfo.getXNumber() + " Do\nQ\n");
+                            + imageInfo.getName() + " Do\nQ\n");
         return true;
     }
 
@@ -1193,7 +1190,7 @@
 
         PaintContext pctx = paint.createContext(rgbCM, devBounds, usrBounds, 
                                                 at, getRenderingHints());
-        PDFXObject imageInfo = pdfDoc.getImage
+        PDFXObject imageInfo = pdfDoc.getXObject
             ("TempImage:" + pctx.toString());
         if (imageInfo != null) {
             resourceContext.getPDFResources().addXObject(imageInfo);
@@ -1241,7 +1238,7 @@
                 BitmapImage fopimg = new BitmapImage
                     ("TempImageMask:" + pctx.toString(), devW, devH, mask, null);
                 fopimg.setColorSpace(new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_GRAY));
-                PDFXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
+                PDFImageXObject xobj = pdfDoc.addImage(resourceContext, fopimg);
                 maskRef = xobj.referencePDF();
 
                 if (outputStream != null) {
@@ -1269,8 +1266,8 @@
         currentStream.write("q\n");
         writeClip(shape);
         currentStream.write("" + usrW + " 0 0 " + (-usrH) + " " + usrX
-                            + " " + (usrY + usrH) + " cm\n" + "/Im"
-                            + imageInfo.getXNumber() + " Do\nQ\n");
+                            + " " + (usrY + usrH) + " cm\n"
+                            + imageInfo.getName() + " Do\nQ\n");
         return true;
     }
 



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