    function initImageZoom(_options) {
        var options = $extend({
            rel: 'imagezoom'
        }, _options || {});
        var elements = $$(document.links).filter(function(el) {
            if ((el.rel) && (el.rel.indexOf(options.rel) != -1)) 
                return true;
            else
                return false;
        });
        for (var i = 0; i < elements.length; i++) {
            var el = elements[i];
            el.addEvent("click", function() {
                this.blur();
                var sEl = this;
                var imgCap = "";
                if (this.getElements("img").length > 0)
                    sEl = this.getElements("img")[0];
                if ((sEl.alt) && (sEl.alt != ""))
                    imgCap = sEl.alt;
                else if (sEl.title)
                    imgCap = sEl.title;
                else if (sEl.parentNode.title)
                    imgCap = sEl.parentNode.title;
                var _options = $extend({
                    image: this.href,
                    caption: imgCap,
                    startElement: sEl
                }, options || {});
                _options.image = this.href;
                _options.caption = imgCap;
                var imagezoom = new Imagezoom(_options);
                imagezoom.preloadImage();
                imagezoom.show();
                return false;
            });
        }
    }
    
    var Imagezoom = function(_options) {        
        var options = $extend({
            image: false,
            caption: "",
            enableCaptions: true,
            startElement: false,
            x: 10,
            y: 10,
            initWidth: 50,
            initHeight: 50,
            draggable: true,
            loadImage: "imagezoom/images/loading.gif",
            loadDelay: 150,
            duration: 800,
            closeDuration: 500,
            transition: Fx.Transitions.Cubic.easeOut,
            startOpacity: 0.6,
            closeText: 'Close',
            rel: 'imagezoom',
            showCaptionBar: true,
            overlay: false,
            overlayColor: "#000",
            overlayOpacity: .75
        }, _options || {});
        
        var box = document.createElement("div");        
        var instance = this;
        
        /* shadow divs */
        var tl = document.createElement("div");
        tl.className = "s s_tl";
        var tr = document.createElement("div");
        tr.className = "s s_tr";
        var bl = document.createElement("div");
        bl.className = "s s_bl";
        var br = document.createElement("div");
        br.className = "s s_br";
        var top = document.createElement("div");
        top.className = "s s_top";
        var bottom = document.createElement("div");
        bottom.className = "s s_bottom";
        var left = document.createElement("div");
        left.className = "s s_left";
        var right = document.createElement("div");
        right.className = "s s_right";
        
        this.preloadImage = function() {
            if (options.image != false) {
                var img = new Image();
                img.src = options.image;
                img.style.visibility = "hidden";
                img.style.position = "absolute";
                img.style.top = "-9999999999px";
                img.setAttribute("id", "imagezoom-" + options.image);
                $$('body')[0].appendChild(img);
            }   
        }
        
        this.getImage = function() {
            if (($('imagezoom-' + options.image)) && ($('imagezoom-' + options.image).width != "0")) {
                var img = $('imagezoom-' + options.image).clone();
                img.setAttribute("id", "");
                img.style.position = "relative";
                img.style.top = "0px";
                img.style.visibility = "visible";
            } else {
                instance.preloadImage();
                window.setTimeout(function() {
                    instance.getImage();
                }, 50);
            }
            return img;
        }       
        
        this.show = function() {
            if (options.image != false) {
                box.style.position = "absolute";
                box.style.overflow = "hidden";
                box.setAttribute("id", "imagezoom-open-" + options.image);
                
                if (options.startElement != false)
                    options.startElement.blur();
                
                var x = options.x;
                var y = options.y;
                var boxWidth = options.initWidth;
                var boxHeight = options.initHeight;
                if (options.startElement != false) {
                    x = options.startElement.getPosition().x;
                    y = options.startElement.getPosition().y;
                    boxWidth = options.startElement.offsetWidth;
                    boxHeight = options.startElement.offsetHeight;
                }
                box.style.left = x + "px";
                box.style.top = y + "px";
                box.style.width = boxWidth + "px";
                box.style.height = boxHeight + "px";
                
                var fx = new Fx.Morph(box);
                fx.set({opacity: options.startOpacity});
                
                box.className = "imagezoom";
                $$('body')[0].appendChild(box);
                box.style.cursor = "pointer";
                box.addEvent("click", function() {
                    var fx = new Fx.Morph(box, {duration: 200});
                    fx.start({opacity: 0}).chain(function() {
                        $$('body')[0].removeChild(box);
                    });
                });

                this.loadImage();
            }
        }
        
        this.loadImage = function() {
            if (box.getElements(".loading").length == 0) {
                var loading = new Image();
                loading.src = options.loadImage;
                loading.className = "loading";
                box.appendChild(loading);
            }   
            if ($('imagezoom-' + options.image)) {
                var el = $('imagezoom-' + options.image);
                if (el.width != "0") {
                    var newEl = new Image();
                    newEl.src = options.image;
                    window.setTimeout(function() { instance.insertImage(newEl) }, options.loadDelay);
                } else {
                    window.setTimeout(function() { instance.loadImage(); }, 50);
                }
            } else {
                instance.preloadImage();
                window.setTimeout(function() { instance.loadImage(); }, 50);
            }
        }
        
        this.insertImage = function(img) {
            box.removeEvents("click");
            box.style.cursor = "default";
            box.style.overflow = "visible";
            var w = img.width;
            var h = img.height;
            img.style.width = w + "px";
            img.style.height = h + "px";
            img.className = 'image';
            var ptop = (window.getSize().y / 2) + window.getScroll().y - (h/2);
            var pleft = (window.getSize().x / 2) + window.getScroll().x - (w/2);
            var fx = new Fx.Morph(box, {duration: options.duration, transition: options.transition});
            fx.start({
                top: ptop,
                left: pleft,
                width: w,
                height: h,
                opacity: 1
            }).chain(function() {
                if (options.overlay == true) {
                    if (!$('imagezoom_overlay')) {
                        var overlay = $(document.createElement("div"));
                        overlay.setAttribute("id", "imagezoom_overlay");
                        overlay.style.backgroundColor = options.overlayColor;
                        overlay.setOpacity(0);
                        $$('body')[0].appendChild(overlay);
                    } else {
                        var overlay = $('imagezoom_overlay');
                    }
                    overlay.style.width = window.getScrollSize().x + "px";
                    overlay.style.height = window.getScrollSize().y + "px";
                    var overlayfx = new Fx.Morph(overlay, {duration: 10});
                    overlayfx.start({
                        opacity: options.overlayOpacity
                    });
                }
                var close = $(document.createElement("div"));
                close.innerHTML = "<span>" + options.closeText + "</span>";
                close.className = "close";
                close.addEvent("click", function() {
                    instance.close(true);
                });
                var loading = box.getElements(".loading");
                if (loading.length > 0)
                    box.removeChild(loading[0]);
                var elements = [close, tl, tr, bl, br, top, bottom, left, right, img];
                for (var i = 0; i < elements.length; i++) {
                    var elFx = new Fx.Morph(elements[i], {duration: 600});
                    elFx.set({opacity: 0});
                    box.adopt(elements[i]);
                    elFx.start({opacity: 1});
                }
                var caption;
                if ((options.caption != "") && (options.enableCaptions == true)) {
                    caption = document.createElement("div");
                    caption.className = "caption";
                    caption.innerHTML = "<p>" + options.caption + "</p>";
                    box.appendChild(caption);
                }
                instance.addSetNavigation();
                if (box.getElements(".caption").length > 0) {
                    caption = box.getElements(".caption")[0];
                    var cfx = new Fx.Morph(caption, {duration: 200});
                    cfx.set({opacity: 0});
                    if (options.showCaptionBar == true) {
                        caption.className += " visibleCaption";
                        var cStartFx = new Fx.Morph(caption, {duration: 600});
                        cStartFx.start({
                            opacity: 1
                        });
                    }
                    box.addEvent("mouseenter", function() {
                        cfx.start({opacity: 1}).chain(function() { caption.className += " visibleCaption"; });
                    });
                    box.addEvent("mouseleave", function() {
                        cfx.start({opacity: 0}).chain(function() { caption.className = caption.className.replace(/visibleCaption/g, ""); });
                    });
                    close.addEvent("mouseenter", function() {
                        cfx.start({opacity: 0}).chain(function() { caption.className = caption.className.replace(/visibleCaption/g, ""); });
                    });
                    box.getElements(".image")[0].addEvent("click", function() {
                        var action = "show";
                        if (caption.className.indexOf("visibleCaption") != -1)
                            action = "hide";
                        if (action == "show")
                            cfx.start({opacity: 1}).chain(function() { caption.className += " visibleCaption"; });
                        else
                            cfx.start({opacity: 0}).chain(function() { caption.className = caption.className.replace(/visibleCaption/g, ""); });
                    });             
                }
                top.style.width = box.offsetWidth + "px";
                bottom.style.width = box.offsetWidth + "px";
                left.style.height = box.offsetHeight + "px";
                right.style.height = box.offsetHeight + "px";
                if (options.draggable == true)
                    var move = new Drag.Move(box, {handle: img});
            });     
        }
        
        this.addSetNavigation = function() {
            var links = $$(document.links).filter(function(link) {
                if ((link.rel) && (link.rel.indexOf(options.rel) != -1))
                    return true;
                else
                    return false;
            });
            var set = false;
            for (var i = 0; i < links.length; i++) {
                if ((links[i].href.indexOf(options.image) != -1) && (links[i].rel) && (links[i].rel.indexOf(options.rel + '[' != -1))) {
                    var rel = links[i].getAttribute("rel");
                    set = instance.scanRel("after", options.rel + "[", this.scanRel("before", "]", rel));
                }
            }
            if (set != false) {
                var prevLink = false;
                var nextLink = false;
                var setLinks = new Array();
                for (i = 0; i < links.length; i++) {
                    if (links[i].rel.indexOf(options.rel + "[" + set + "]") != -1) {
                        setLinks[setLinks.length] = links[i];
                    }
                }
                for (i = 0; i < setLinks.length; i++) {
                    var link = setLinks[i];
                    if ((link.href.indexOf(options.image) != -1) && (link.rel) && (link.rel.indexOf(options.rel != -1))) {
                        if (i != 0)
                            prevLink = setLinks[i - 1];
                        if (i != setLinks.length - 1)
                            nextLink = setLinks[i + 1];
                    }
                }
                if ((prevLink != false) || (nextLink != false)) {
                    if (box.getElements(".caption").length == 0) {
                        var caption = document.createElement("div");
                        caption.className = "caption";
                        box.appendChild(caption);
                    } else {
                        var caption = box.getElements(".caption")[0];
                    }
                }
                if (prevLink != false) {
                    var previousButton = $(document.createElement("div"));
                    previousButton.className = "previous";
                    var prevCap = '';
                    if (prevLink.title)
                        prevCap = prevLink.title;
                    var prevEl = prevLink;
                    if (prevLink.getElements("img").length > 0)
                        prevEl = prevLink.getElements("img")[0];
                    previousButton.addEvent("click", function() {
                        var newOptions = $unlink(options);
                        var imagezoomPrev = new Imagezoom($extend(newOptions, {
                            image: prevLink.href,
                            caption: prevCap,
                            rel: options.rel,
                            startElement: prevEl,
                            showCaptionBar: true
                        }));
                        instance.close();
                        imagezoomPrev.show();
                    });
                    caption.appendChild(previousButton);
                }
                if (nextLink != false) {
                    var nextButton = $(document.createElement("div"));
                    nextButton.className = "next";
                    var nextCap = '';
                    if (nextLink.title)
                        nextCap = nextLink.title;
                    var nextEl = nextLink;
                    if (nextLink.getElements("img").length > 0)
                        nextEl = nextLink.getElements("img")[0];
                    nextButton.addEvent("click", function() {
                        var newOptions = $unlink(options);
                        var imagezoomNext = new Imagezoom($extend(newOptions, {
                            image: nextLink.href,
                            caption: nextCap,
                            rel: options.rel,
                            startElement: nextEl,
                            showCaptionBar: true
                        }));
                        instance.close();
                        imagezoomNext.show();
                    });
                    caption.appendChild(nextButton);                    
                }
            }
        }
        
        this.scanRel = function(where, needle, string) {
            var newstring = '';
            if (where == "after") {
                var startpos = string.indexOf(needle) + needle.length;
                var endpos = string.length;
            } else if (where == "before") {
                var startpos = 0;
                var endpos = string.indexOf(needle);
            }
            for (var i = startpos; i < endpos; i++) {
                newstring += string.charAt(i);
            }
            return newstring;
        }
        
        this.close = function(hideOverlay) {
            var img = box.getElements(".image")[0];
            box.removeChild(img);
            var close = box.getElements(".close")[0];
            box.removeChild(close);
            var caption = box.getElements(".caption");
            if (caption.length > 0)
                box.removeChild(caption[0]);
            var s = box.getElements(".s");
            for (var i = 0; i < s.length; i++)
                box.removeChild(s[i]);
            var x = options.x;
            var y = options.y;
            var boxWidth = options.initWidth;
            var boxHeight = options.initHeight;
            if (options.startElement != false) {
                x = options.startElement.getPosition().x;
                y = options.startElement.getPosition().y;
                boxWidth = options.startElement.offsetWidth;
                boxHeight = options.startElement.offsetHeight;
            }
            if ((hideOverlay == true) && ($('imagezoom_overlay'))) {
                var oFx = new Fx.Morph($('imagezoom_overlay'), {duration: options.closeDuration});
                oFx.start({opacity: 0}).chain(function() {
                    $$('body')[0].removeChild($('imagezoom_overlay'));
                });
            }
            var fx = new Fx.Morph(box, {duration: options.closeDuration});
            fx.start({
                left: x,
                top: y,
                width: boxWidth,
                height: boxHeight,
                opacity: options.startOpacity
            }).chain(function() {
                fx.start({
                    opacity: 0
                }).chain(function() {
                    $$('body')[0].removeChild(box);
                });
            });
        }   
    }

