text:
(function($) {
	var menu,
		first,
		li,
		html = arrayToUl(links);

	function getVisible() {
		var result = [];
		menu.find('ul').filter(':visible').each(function() {
			result.push($(this).attr('data-index'));
		});
		return result;
	}

	module('#navgoco', {
		setup: function() {
			menu = $('
' + html + '
');
			menu.appendTo($('#qunit-fixture'));
			first = menu.find("li:has(ul) > a").first();
			li = first.parent();
			$.fn.navgoco.defaults.save = false;
			$.fn.navgoco.defaults.slide.duration = 1;
		}
	});

	test('chainability', function() {
		strictEqual(menu.navgoco(), menu, 'should be chainable');
	});

	test('caret', function() {
		expect(1);
		menu.navgoco();
		var link = menu.find("li:has(ul) > a").last();
		strictEqual(link.html(), 'Where to Buy', 'caret should be present');
	});

	test('mouse click', function() {
		expect(2);
		menu.navgoco();
		first.click();
		ok(li.hasClass('open'), 'should have class open');
		first.click();
		ok(!li.hasClass('open'), 'should not have class open');
	});

	test('manual toggle', function() {
		expect(2);
		menu.navgoco();
		menu.navgoco('toggle', true, 0);
		ok(li.hasClass('open'), 'should have class open');
		menu.navgoco('toggle', false, 0);
		ok(!li.hasClass('open'), 'should not have class open');
	});

	test('manual toggle also opens parents', function() {
		expect(1);
		menu.navgoco();
		menu.navgoco('toggle', true, 3);
		deepEqual(getVisible(), ['1', '3'], 'Both sub-menus 1 and 3 should be visible');
	});

	test('manual toggle all', function() {
		expect(1);
		menu.navgoco();
		menu.navgoco('toggle', true);
		deepEqual(getVisible(), ['0', '1', '2', '3', '4'], 'All sub-menus should be visible');
	});

	test('accordion #1', function() {
		expect(1);
		menu.navgoco({accordion: true});
		menu.navgoco('toggle', true, 0);
		menu.navgoco('toggle', true, 1);
		menu.navgoco('toggle', true, 0);
		stop();
		setTimeout(function() {
			deepEqual(getVisible(), ['0'], 'Only submenus 0 should be visible');
			start();
		}, 1000);
	});

	test('accordion #2', function() {
		expect(1);
		menu.navgoco({accordion: true});
		menu.navgoco('toggle', true, 0);
		var link = menu.find("li:has(ul) > a").first();
		link.click();
		stop();
		setTimeout(function() {
			deepEqual(getVisible(), [], 'No submenus should be visible');
			start();
		}, 1000);
	});

	test('accordion #3', function() {
		expect(1);
		menu.navgoco({accordion: true});
		$("a:contains('About')").click();
		$("a:contains('Contact Us')").click();
		$("a:contains('Support and Service')").click();
		stop();
		setTimeout(function() {
			deepEqual(getVisible(), ['1', '2'], 'Submenus 1 & 2 should be visible');
			start();
		}, 1000);
	});

	test('accordion #4', function() {
		expect(1);
		menu.navgoco({accordion: true});
		menu.navgoco('toggle', true, 2);
		$("a:contains('Environment')").click();
		stop();
		setTimeout(function() {
			deepEqual(getVisible(), ['1'], 'Only Submenu 1 should be visible');
			start();
		}, 1000);
	});
}(jQuery));


text:
package jrds;

//----------------------------------------------------------------------------
//$Id$

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedList;

import jrds.webapp.ACL;
import jrds.webapp.WithACL;

import org.rrd4j.graph.RrdGraphDef;

/**
 * @author bacchell
 * @version $Revision$
 * TODO
 */
public class GraphNode implements Comparable<GraphNode>, WithACL {

    protected Probe<?,?> probe;
    private String viewPath = null;
    private GraphDesc gd;
    private String name = null;
    private String graphTitle = null;
    private ACL acl = ACL.ALLOWEDACL;
    private PlottableMap customData = null;

    /**
     *
     */
    public GraphNode(Probe<?,?> theStore, GraphDesc gd) {
        this.probe = theStore;
        this.gd = gd;
        this.acl = gd.getACL();
    }

    /**
     * A protected constructor
     * child are allowed to build themselves in a strange way
     *
     */
    protected GraphNode() {
    }

    /**
     * @see java.lang.Object#hashCode()
     */
    public int hashCode() {
        return getQualifiedName().hashCode();
    }

    /**
     * @return Returns the theStore.
     */
    public Probe<?,?> getProbe() {
        return probe;
    }

    /**
     * To be called if the probe was not provided in the initial creation
     * This should be called as soon as possible
     * @param probe a custom generated probe
     */
    protected void setProbe(Probe<?,?> probe) {
        this.probe = probe;
    }

    public LinkedList<String> getTreePathByHost() {
        return gd.getHostTree(this);
    }

    public LinkedList<String> getTreePathByView() {
        return gd.getViewTree(this);
    }

    private final String parseTemplate(String template) {
        Object[] arguments = {
                "${graphdesc.name}",
                "${host}",
                "${index}",
                "${url}",
                "${probename}",
                "${index.signature}",
                "${url.signature}"
        };
        return jrds.Util.parseOldTemplate(template, arguments, probe, gd);
    }

    public String getGraphTitle() {
        if(graphTitle == null) {
            graphTitle = parseTemplate(gd.getGraphTitle());
        }
        return graphTitle;
    }

    public String getName() {
        if(name == null) {
            name = parseTemplate(gd.getGraphName());
        }
        return name;
    }

    /**
     * Return a uniq name for the graph
     * @return
     */
    public String getQualifiedName() {
        if (probe.getHost() != null) {
            return probe.getHost().getName() + "/"  + getName();
        } else {
            return "/"  + getName();
        }
    }

    public GraphDesc getGraphDesc() {
        return gd;
    }

    /**
     * To be called if the graphdesc was not provided in the initial creation
     * This should be called as soon as possible
     * @param gd A custom generated GraphDesc
     */
    protected void setGraphDesc(GraphDesc gd) {
        this.gd = gd;
        this.acl = gd.getACL();
    }

    /**
     * Provide a RrdGraphDef with template resolved for the node
     * @return a RrdGraphDef with some default values
     * @throws IOException
     */
    public RrdGraphDef getEmptyGraphDef() {
        RrdGraphDef retValue = getGraphDesc().getEmptyGraphDef();
        retValue.setTitle(getGraphTitle());
        return retValue;
    }

    public Graph getGraph() {
        Class<Graph>  gclass = gd.getGraphClass();

        //Exceptions can't happen, it was checked at configuration time
        try {
            return gclass.getConstructor(GraphNode.class).newInstance(this);
        } catch (IllegalArgumentException e) {
        } catch (SecurityException e) {
        } catch (InstantiationException e) {
        } catch (IllegalAccessException e) {
        } catch (InvocationTargetException e) {
        } catch (NoSuchMethodException e) {
        }
        return null;
    }

    /* (non-Javadoc)
     * @see java.lang.Comparable#compareTo(java.lang.Object)
     */
    public int compareTo(GraphNode arg0) {
        if (viewPath == null)
            viewPath = this.getTreePathByView().toString();

        String otherPath = arg0.getTreePathByView().toString();

        return String.CASE_INSENSITIVE_ORDER.compare(viewPath, otherPath);
    }

    @Override
    public String toString() {
        return probe.toString() + "/" + getName();
    }

    public void addACL(ACL acl) {
        this.acl = this.acl.join(acl);
    }

    public ACL getACL() {
        return acl;
    }

    /**
     * @return the customData
     */
    public PlottableMap getCustomData() {
        return customData;
    }

    /**
     * @param customData the customData to set
     */
    public void setCustomData(PlottableMap customData) {
        this.customData = customData;
    }

}

redpajama_set_name: RedPajamaGithub