]> git.mjollnir.org Git - s9y.git/commitdiff
added flickr plugin
authorPenny Leach <penny@catalyst.net.nz>
Wed, 12 Mar 2008 06:13:47 +0000 (19:13 +1300)
committerPenny Leach <penny@catalyst.net.nz>
Wed, 12 Mar 2008 06:13:47 +0000 (19:13 +1300)
plugins/serendipity_plugin_flickr/README.txt [new file with mode: 0644]
plugins/serendipity_plugin_flickr/UTF-8/lang_de.inc.php [new file with mode: 0644]
plugins/serendipity_plugin_flickr/lang_de.inc.php [new file with mode: 0644]
plugins/serendipity_plugin_flickr/lang_en.inc.php [new file with mode: 0644]
plugins/serendipity_plugin_flickr/serendipity_plugin_flickr.php [new file with mode: 0644]

diff --git a/plugins/serendipity_plugin_flickr/README.txt b/plugins/serendipity_plugin_flickr/README.txt
new file mode 100644 (file)
index 0000000..9160fce
--- /dev/null
@@ -0,0 +1,2 @@
+Follow the steps on http://code.iamcal.com/php/flickr/readme.htm to
+install all required packages.
diff --git a/plugins/serendipity_plugin_flickr/UTF-8/lang_de.inc.php b/plugins/serendipity_plugin_flickr/UTF-8/lang_de.inc.php
new file mode 100644 (file)
index 0000000..61a2cdc
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+@define('PLUGIN_SIDEBAR_FLICKR', 'FLICKR Plugin');
+@define('PLUGIN_SIDEBAR_FLICKR_DESC', 'Zeigt die aktuellsten Bilder von beliebigen (üblicherweise ihren) FLICKR-Photostreams dar. Siehe http://www.flickr.com/.');
+@define('PLUGIN_SIDEBAR_FLICKR_TITLE_TITLE', 'Titel');
+@define('PLUGIN_SIDEBAR_FLICKR_TITLE_BLAHBLAH', 'Titel der Seitenleiste. Kann leer sein.');
+@define('PLUGIN_SIDEBAR_FLICKR_EMAIL_TITLE', 'E-Mail Adresse des FLICKR-Benutzers.');
+@define('PLUGIN_SIDEBAR_FLICKR_EMAIL_BLAHBLAH', 'E-Mail Adresse des Benutzers, der für den FLICKR-Service registriert ist');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_TITLE', 'Vorschaubildgröße');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_BLAHBLAH', 'Größe des Vorschaubildes');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_SQUARE', 'Quadratisch');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_THUMBNAIL', 'Vorschaubild');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_SMALL', 'Klein');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_PHOTOPAGE', 'Photopage (empfohlen)');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_MEDIUM', 'Mittlere Bildgröße (erfordert login)');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_LARGE', 'Große Bildgröße (erfordert login)');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_TITLE', 'Link');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_BLAHBLAH', 'Ziel des Links');
+@define('PLUGIN_SIDEBAR_FLICKR_NUM_TITLE', 'Anzahl der darzustellenden Bilder');
+@define('PLUGIN_SIDEBAR_FLICKR_NUM_BLAHBLAH', 'Min: 1, Max: 500');
+@define('PLUGIN_SIDEBAR_FLICKR_APIKEY_TITLE', 'FLICKR API Key');
+@define('PLUGIN_SIDEBAR_FLICKR_APIKEY_BLAHBLAH', 'Um dieses Plugin zu nutzen brauchen Sie Ihren eigenen FLICKR Services API Key via http://www.flickr.com/services/api/key.gne. Die Registrierung ist einfach und wird sofort ausgeführt.');
+@define('PLUGIN_SIDEBAR_FLICKR_FAILED_CACHELITE', 'Dieses Plugin benötigt PEAR:Cache_Lite.');
+@define('PLUGIN_SIDEBAR_FLICKR_FAILED_LOADING', 'Das <a href="http://code.iamcal.com/php/flickr/readme.htm">Flickr API module</a> konnte nicht geladen werden. Bitte stellen Sie sicher, dass es korrekt installiert wurde.');
diff --git a/plugins/serendipity_plugin_flickr/lang_de.inc.php b/plugins/serendipity_plugin_flickr/lang_de.inc.php
new file mode 100644 (file)
index 0000000..22928d7
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+@define('PLUGIN_SIDEBAR_FLICKR', 'FLICKR Plugin');
+@define('PLUGIN_SIDEBAR_FLICKR_DESC', 'Zeigt die aktuellsten Bilder von beliebigen (üblicherweise ihren) FLICKR-Photostreams dar. Siehe http://www.flickr.com/.');
+@define('PLUGIN_SIDEBAR_FLICKR_TITLE_TITLE', 'Titel');
+@define('PLUGIN_SIDEBAR_FLICKR_TITLE_BLAHBLAH', 'Titel der Seitenleiste. Kann leer sein.');
+@define('PLUGIN_SIDEBAR_FLICKR_EMAIL_TITLE', 'E-Mail Adresse des FLICKR-Benutzers.');
+@define('PLUGIN_SIDEBAR_FLICKR_EMAIL_BLAHBLAH', 'E-Mail Adresse des Benutzers, der für den FLICKR-Service registriert ist');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_TITLE', 'Vorschaubildgröße');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_BLAHBLAH', 'Größe des Vorschaubildes');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_SQUARE', 'Quadratisch');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_THUMBNAIL', 'Vorschaubild');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_SMALL', 'Klein');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_PHOTOPAGE', 'Photopage (empfohlen)');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_MEDIUM', 'Mittlere Bildgröße (erfordert login)');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_LARGE', 'Große Bildgröße (erfordert login)');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_TITLE', 'Link');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_BLAHBLAH', 'Ziel des Links');
+@define('PLUGIN_SIDEBAR_FLICKR_NUM_TITLE', 'Anzahl der darzustellenden Bilder');
+@define('PLUGIN_SIDEBAR_FLICKR_NUM_BLAHBLAH', 'Min: 1, Max: 500');
+@define('PLUGIN_SIDEBAR_FLICKR_APIKEY_TITLE', 'FLICKR API Key');
+@define('PLUGIN_SIDEBAR_FLICKR_APIKEY_BLAHBLAH', 'Um dieses Plugin zu nutzen brauchen Sie Ihren eigenen FLICKR Services API Key via http://www.flickr.com/services/api/key.gne. Die Registrierung ist einfach und wird sofort ausgeführt.');
+@define('PLUGIN_SIDEBAR_FLICKR_FAILED_CACHELITE', 'Dieses Plugin benötigt PEAR:Cache_Lite.');
+@define('PLUGIN_SIDEBAR_FLICKR_FAILED_LOADING', 'Das <a href="http://code.iamcal.com/php/flickr/readme.htm">Flickr API module</a> konnte nicht geladen werden. Bitte stellen Sie sicher, dass es korrekt installiert wurde.');
diff --git a/plugins/serendipity_plugin_flickr/lang_en.inc.php b/plugins/serendipity_plugin_flickr/lang_en.inc.php
new file mode 100644 (file)
index 0000000..3386fad
--- /dev/null
@@ -0,0 +1,36 @@
+<?php # $Id: lang_en.inc.php,v 1.1 2005/11/16 08:41:51 elf2000 Exp $
+
+/**
+ *  @version $Revision: 1.1 $
+ *  @author Translator Name <yourmail@example.com>
+ *  EN-Revision: Revision of lang_en.inc.php
+ */
+
+@define('PLUGIN_SIDEBAR_FLICKR', 'FLICKR Sidebar Plugin');
+@define('PLUGIN_SIDEBAR_FLICKR_DESC', 'Display the latest photos from any (usually means: your) FLICKR Photostream. See http://www.flickr.com/ for details.');
+@define('PLUGIN_SIDEBAR_FLICKR_TITLE_TITLE', 'Title');
+@define('PLUGIN_SIDEBAR_FLICKR_TITLE_BLAHBLAH', 'Title of this sidebar item. May be empty');
+@define('PLUGIN_SIDEBAR_FLICKR_EMAIL_TITLE', 'E-Mail address of FLICKR user.');
+@define('PLUGIN_SIDEBAR_FLICKR_EMAIL_BLAHBLAH', 'E-Mail address the user is currently registered with at FLICKR.');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_TITLE', 'Thumbnail size');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_BLAHBLAH', 'Size of the preview image');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_SQUARE', 'Square');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_THUMBNAIL', 'Thumbnail');
+@define('PLUGIN_SIDEBAR_FLICKR_SRCIMG_SMALL', 'Small');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_PHOTOPAGE', 'Photopage (recommended)');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_MEDIUM', 'Medium Image (requires user login)');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_LARGE', 'Large Image (requires user login)');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_TITLE', 'Link');
+@define('PLUGIN_SIDEBAR_FLICKR_TGTIMG_BLAHBLAH', 'Target of the Link');
+@define('PLUGIN_SIDEBAR_FLICKR_NUM_TITLE', 'Number of pictures to show');
+@define('PLUGIN_SIDEBAR_FLICKR_NUM_BLAHBLAH', 'Min: 1, Max: 500');
+@define('PLUGIN_SIDEBAR_FLICKR_APIKEY_TITLE', 'FLICKR API Key');
+@define('PLUGIN_SIDEBAR_FLICKR_APIKEY_BLAHBLAH', 'In order to use this plugin you need to get your own FLICKR Services API Key on http://www.flickr.com/services/api/key.gne. The registration is easy and you instantly get your key.');
+@define('PLUGIN_SIDEBAR_FLICKR_APISECRET_TITLE', 'FLICKR API Secret');
+@define('PLUGIN_SIDEBAR_FLICKR_APISECRET_DESC', 'The secret key is optional and allows for secure transmission of your data. You can get/configure the key via your Flickr profile page.');
+@define('PLUGIN_SIDEBAR_FLICKR_FAILED_CACHELITE', 'This package requires PEAR:Cache_Lite to be installed.');
+@define('PLUGIN_SIDEBAR_FLICKR_FAILED_LOADING', 'Loading the <a href="http://code.iamcal.com/php/flickr/readme.htm">Flickr API module</a> failed.  Please insure that the module is installed.');
+@define('PLUGIN_SIDEBAR_FLICKR_CACHE_TITLE', 'Cache timeout');
+@define('PLUGIN_SIDEBAR_FLICKR_CACHE_DESC', 'This plugins uses PEAR::Cache_Lite caching. Define the validity of the cache in seconds.');
+
+?>
diff --git a/plugins/serendipity_plugin_flickr/serendipity_plugin_flickr.php b/plugins/serendipity_plugin_flickr/serendipity_plugin_flickr.php
new file mode 100644 (file)
index 0000000..cd14110
--- /dev/null
@@ -0,0 +1,330 @@
+<?php
+
+  /* $Id: serendipity_plugin_flickr.php,v 1.13 2006/12/01 09:00:54 garvinhicking Exp $ */
+
+  /* TODO:
+   *
+   * - Check if there is an API-Call to get the "Photopage"-URL. If yes:
+   *   use it!
+   */
+
+
+if (IN_serendipity !== true) {
+    die ("Don't hack!");
+}
+
+// Probe for a language include with constants. Still include defines later on, if some constants were missing
+$probelang = dirname(__FILE__) . '/' . $serendipity['charset'] . 'lang_' . $serendipity['lang'] . '.inc.php';
+if (file_exists($probelang)) {
+    include $probelang;
+}
+
+include dirname(__FILE__) . '/lang_en.inc.php';
+
+class serendipity_plugin_flickr extends serendipity_plugin {
+
+    function introspect(&$propbag)
+    {
+        global $serendipity;
+
+        $propbag->add('name', PLUGIN_SIDEBAR_FLICKR);
+        $propbag->add('description', PLUGIN_SIDEBAR_FLICKR_DESC);
+        $propbag->add('requirements',  array(
+            'serendipity' => '0.8',
+            'smarty'      => '2.6.9',
+            'php'         => '4.3.0'
+        ));
+        $propbag->add('version',  '1.4');
+        $propbag->add('configuration', array(
+                         'title',
+                         'email',
+                         'sourceimgtype',
+                         'targetimgtype',
+                         'perpage',
+                         'apikey',
+                         'apisecret',
+                         'cachetimeout'
+                         )
+              );
+        $propbag->add('groups', array('FRONTEND_EXTERNAL_SERVICES', 'IMAGES'));
+    } // function
+
+    function introspect_config_item($name, &$propbag)
+    {
+        switch ($name) {
+
+        case 'title':
+            $propbag->add('type', 'string');
+            $propbag->add('name', PLUGIN_SIDEBAR_FLICKR_TITLE_TITLE);
+            $propbag->add('description', PLUGIN_SIDEBAR_FLICKR_TITLE_BLAHBLAH);
+            break;
+
+        case 'email':
+            $propbag->add('type', 'string');
+            $propbag->add('name', PLUGIN_SIDEBAR_FLICKR_EMAIL_TITLE);
+            $propbag->add('description', PLUGIN_SIDEBAR_FLICKR_EMAIL_BLAHBLAH);
+            break;
+
+        case 'cachetimeout':
+            $propbag->add('type', 'string');
+            $propbag->add('name', PLUGIN_SIDEBAR_FLICKR_CACHE_TITLE);
+            $propbag->add('description', PLUGIN_SIDEBAR_FLICKR_CACHE_DESC);
+            $propbag->add('default', 21600);
+            break;
+
+        case 'sourceimgtype':
+            $propbag->add('type', 'select');
+            $propbag->add('select_values',
+                array(
+                    '0' => PLUGIN_SIDEBAR_FLICKR_SRCIMG_SQUARE,
+                    '1' => PLUGIN_SIDEBAR_FLICKR_SRCIMG_THUMBNAIL,
+                    '2' => PLUGIN_SIDEBAR_FLICKR_SRCIMG_SMALL,
+                )
+            );
+            $propbag->add('default', 0);
+            $propbag->add('name', PLUGIN_SIDEBAR_FLICKR_SRCIMG_TITLE);
+            $propbag->add('description', PLUGIN_SIDEBAR_FLICKR_SRCIMG_BLAHBLAH);
+            break;
+
+        case 'targetimgtype':
+            $propbag->add('type', 'select');
+            $propbag->add('select_values',
+                array(
+                    '-1' => PLUGIN_SIDEBAR_FLICKR_TGTIMG_PHOTOPAGE,
+                    '3'  => PLUGIN_SIDEBAR_FLICKR_TGTIMG_MEDIUM,
+                    '4'  => PLUGIN_SIDEBAR_FLICKR_TGTIMG_LARGE,
+                )
+            );
+            $propbag->add('default', 0);
+            $propbag->add('name', PLUGIN_SIDEBAR_FLICKR_TGTIMG_TITLE);
+            $propbag->add('description', PLUGIN_SIDEBAR_FLICKR_TGTIMG_BLAHBLAH);
+            break;
+
+        case 'perpage':
+            $propbag->add('type', 'string');
+            $propbag->add('default', 5);
+            $propbag->add('name', PLUGIN_SIDEBAR_FLICKR_NUM_TITLE);
+            $propbag->add('description', PLUGIN_SIDEBAR_FLICKR_NUM_BLAHBLAH);
+            break;
+
+        case 'apikey':
+            $propbag->add('type', 'string');
+            $propbag->add('name', PLUGIN_SIDEBAR_FLICKR_APIKEY_TITLE);
+            $propbag->add('description', PLUGIN_SIDEBAR_FLICKR_APIKEY_BLAHBLAH);
+            break;
+
+        case 'apisecret':
+            $propbag->add('type', 'string');
+            $propbag->add('name', PLUGIN_SIDEBAR_FLICKR_APISECRET_TITLE);
+            $propbag->add('description', PLUGIN_SIDEBAR_FLICKR_APISECRET_DESC);
+            break;
+
+        default:
+            return false;
+        } // switch
+
+    return true;
+    } // function
+
+    function generate_content(&$title)
+    {
+        global $serendipity;
+
+        $title = $this->get_config('title');
+        $apikey = $this->get_config('apikey');
+
+        if (require_once("Cache/Lite.php")) {
+            $cache_id = 'serendipity_plugin_flickr_' . $this->get_config('email') . '_' . $this->get_config('perpage');
+            $options = array(
+                'cacheDir' => $serendipity['serendipityPath'] . 'templates_c/',
+                'lifeTime' => $this->get_config('cachetimeout')
+            );
+            $cache = new Cache_Lite($options);
+
+            if (!$content = $cache->get($id)) {
+                echo '<!-- serendipity_plugin_flickr Cache Miss -->';
+                if (require_once('Flickr/API.php')) {
+                    $api =& new Flickr_API(
+                        array(
+                            'api_key'    => $this->get_config('apikey'),
+                            'api_secret' => $this->get_config('apisecret')
+                        )
+                    );
+
+                    // Use API call to fetch your username object.
+                    $response_username = $api->callMethod('flickr.people.findByEmail',
+                        array(
+                            'find_email' => $this->get_config('email')
+                        )
+                    );
+
+                    // Walk the result node to find the node with your User ID. Once found, break out of looping.
+                    $nsid = null;
+                    if (is_object($response_username) && is_array($response_username->children)) {
+                        foreach((array)$response_username->children AS $nodeid => $node) {
+                            if (is_object($node) && !empty($node->attributes['nsid'])) {
+                                $nsid = $node->attributes['nsid'];
+                                break;
+                            }
+                        }
+                    }
+
+                    // Use API call to fetch your latest public photos.
+                    $response_photos = $api->callMethod('flickr.people.getPublicPhotos',
+                        array(
+                            'user_id'  => $nsid,
+                            'per_page' => $this->get_config('perpage')
+                        )
+                    );
+
+                    // Walk the result node to find the node with the photos inside. Once found, break out of looping.
+                    if (is_object($response_photos) && is_array($response_photos->children)) {
+                        $photos = array();
+                        foreach((array)$response_photos->children AS $node) {
+                            if (is_object($node) && $node->name == 'photos') {
+                                $photos = $node->children;
+                                break;
+                            }
+                        }
+
+                        $content = '<div id="serendipity_plugin_flickr" style="text-align: center;">' . "\n";
+                        $imgt    = $this->get_config('sourceimgtype');
+                        $imgt2   = $this->get_config('targetimgtype');
+
+                        // Walk the photo result set.
+                        foreach ($photos AS $photo) {
+                            $photo_id       = $photo->attributes['id'];
+                            $photo_title    = $photo->attributes['title'];
+
+                            if (empty($photo_id)) {
+                                continue;
+                            }
+
+                            // Use API Call to get the image size of a single photo result item..
+                            $response_sizes = $api->callMethod('flickr.photos.getSizes',
+                                array(
+                                    'photo_id' => $photo_id
+                                )
+                            );
+
+                            // Helper variables to initialize all needed attributes.
+                            $source_sizes = $target_sizes = array();
+                            $is_source    = $is_target = false;
+
+                            // If the target image is "photopage", we don't need to walk the whole photo result set to find the larger target sizes.
+                            if ($imgt2 == '-1') {
+                                $is_target = true;
+                            }
+
+                            // Walk the API call resultset of photosizes.
+                            if (is_object($response_sizes) && is_array($response_sizes->children)) {
+                                foreach($response_sizes->children AS $node) {
+
+                                    // Check if the current node is the result set.
+                                    if (is_object($node) && $node->name == 'sizes') {
+
+                                        // Walk each item and detect the item attribute (Square/Thumbnail/Small) and set the index appropriately.
+                                        // This is to NOT use fixed indices, as they might shift!
+                                        foreach($node->children AS $size_node) {
+
+                                            if ( isset($size_node->attributes['label']) &&
+                                                 ($size_node->attributes['label'] == 'Square'    && $imgt == 0) ||
+                                                 ($size_node->attributes['label'] == 'Thumbnail' && $imgt == 1) ||
+                                                 ($size_node->attributes['label'] == 'Small'     && $imgt == 2)
+                                                ) {
+
+                                                // Required node item found, set the array and set helper variable to allow break nesting.
+                                                $source_sizes = $size_node->attributes;
+                                                $is_source    = true;
+
+                                            } elseif ( isset($size_node->attributes['label']) &&
+                                                 ($size_node->attributes['label'] == 'Medium' && $imgt2 == 3) ||
+                                                 ($size_node->attributes['label'] == 'Large'  && $imgt2 == 4)
+                                                ) {
+
+                                                // Required node item found, set the array and set helper variable to allow break nesting.
+                                                $target_sizes = $size_node->attributes;
+                                                $is_target    = true;
+
+                                            }
+
+                                            if ($is_target && $is_source) {
+                                                // Break nesting, as both required node items have been found.
+                                                break;
+                                            }
+                                        }
+                                    }
+
+                                    if ($is_target && $is_source) {
+                                        break;
+                                    }
+                                }
+                            }
+
+                            // Get contents from helper variables which contain the item result set.
+                            $photo_thumb  = $source_sizes['source'];
+                            $photo_width  = $source_sizes['width'];
+                            $photo_height = $source_sizes['height'];
+
+                            if ($imgt2 == '-1') {
+                                // FIXXME: There should be an API-Call for this URL?
+                                $photo_url = 'http://www.flickr.com/photos/' . $nsid . '/' . $photo_id .'/';
+                            } else {
+                                $photo_url = $target_sizes['url'];
+                            }
+
+                            $content .= sprintf(
+                                '<a href="%s"><img src="%s" alt="%s" width="%d" height="%d" style="border: none" /></a> ' . "\n",
+
+                                $photo_url,
+                                $photo_thumb,
+                                $photo_title,
+                                $photo_width,
+                                $photo_height
+                            );
+                        }
+
+                        $content .= '</div>';
+
+                        $cache->save($content);
+                    } else {
+                        $code    = $api->getErrorCode();
+                        $content = $api->getErrorMessage();
+                    }
+                } else {
+                    $content = PLUGIN_SIDEBAR_FLICKR_FAILED_LOADING;
+                }
+            }
+        } else {
+            $content = PLUGIN_SIDEBAR_FLICKR_FAILED_CACHELITE;
+        }
+
+        if ($code) {
+            echo '<strong>' . $code . '</strong> ';
+        }
+
+        echo $content;
+    } // function
+
+    function cleanup() {
+        global $serendipity;
+
+        if (require_once("Cache/Lite.php")) {
+            $cache_id = 'serendipity_plugin_flickr_' . $this->get_config('email') . '_' . $this->get_config('perpage');
+            $options = array(
+                'cacheDir' => $serendipity['serendipityPath'] . 'templates_c/',
+                'lifeTime' => 21600
+            );
+            $cache = new Cache_Lite($options);
+            $cache->remove($cache_id);
+        } else {
+            $content = PLUGIN_SIDEBAR_FLICKR_FAILED_CACHELITE;
+        }
+
+        return true;
+    } // function cleanup()
+
+} // class
+
+/* vim: set sts=4 ts=4 expandtab : */
+?>