<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<!-- Copyright (c) 2002-2010  Rally Software Development Corp. All rights reserved. -->
<html>
<head>
<title>Super Customizable Release Chart</title>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">
<meta name="Name" content="Mashup: Super Customizable Release Chart"/>
<meta name="Version" content="2010.2"/>
<meta name="Vendor" content="Rally Software"/>
<link rel="stylesheet" type="text/css" href="/slm/css/rally/core.css" charset="utf-8"/>
<link rel="stylesheet" type="text/css" href="/slm/css/slm.css" charset="utf-8"/>
<script type="text/javascript" src="/slm/js-lib/dojo/1.3.1/dojo/dojo.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript" src="/slm/js/help.js"></script>
<script type="text/javascript" src="/slm/js/slm.js"></script>
<script type="text/javascript" src="/slm/js-lib/ejsc/2.0.1/EJSChart.js"></script>
<script type="text/javascript" src="/slm/mashup/1.21/js/batch-toolkit.js"></script>
<script type="text/javascript" src="/slm/mashup/1.21/js/utilities.js"></script>
<script type="text/javascript" src="/slm/mashup/1.21/js/dropdown.js"></script>
<script type="text/javascript">
    var MASHUP_TYPE = RALLY.Mashup.RELEASE;
    var SETTINGS_COOKIE_NAME = 'mu_super_customizable_release_settings';
</script>

<script type="text/javascript">
/*
 Copyright (c) 2002-2010  Rally Software Development Corp. All rights reserved.
 SuperCustomizableUtilities.js
 */
var DEFINED_STATE = (typeof DEFINED_STATE === "undefined") ? "Defined" : DEFINED_STATE;
function addDaysToDate(a, b) {
    return(a.getTime() + RALLY.Mashup.Utilities.convertDaysToMilliseconds(b))
}
function isValidChartDate(b, c, a) {
    return(RALLY.Mashup.Utilities.isWorkDay(b) && b >= c && b <= a) ? true : false
}
function initTodayBurndownObj(a) {
    return{CardEstimateTotal:0,TaskEstimateTotal:0,CardToDoTotal:0,CreationDate:a}
}
function formatDateValue(a) {
    return(a < 10) ? "0" + a : a
}
function calcNumberOfWorkDays(e, a) {
    var b = 0;
    var d = RALLY.Mashup.Utilities.convertIsoDateOnly(e);
    var c = RALLY.Mashup.Utilities.convertIsoDateOnly(a);
    while (d <= c) {
        if (RALLY.Mashup.Utilities.isWorkDay(d)) {
            b = b + 1
        }
        d.setTime(addDaysToDate(d, 1))
    }
    return b
}
function findDateForDay(f, c) {
    var e,b,a,d;
    a = RALLY.Mashup.Utilities.convertIsoDateOnly(f);
    d = Math.round(c);
    if (d <= 0) {
        return a
    }
    e = RALLY.Mashup.Utilities.convertIsoDateOnly(f);
    b = 0;
    while (b < d) {
        if (RALLY.Mashup.Utilities.isWorkDay(e)) {
            b = b + 1;
            if (b === d) {
                return e
            }
        }
        e.setTime(addDaysToDate(e, 1))
    }
    return null
}
function getBeforeState(a) {
    if (a.length > 4 && a[0] !== DEFINED_STATE) {
        return a[0]
    } else {
        return null
    }
}
function getAfterState(a) {
    if (a.length <= 4) {
        return null
    } else {
        if (a.length === 5) {
            if (a[0] === DEFINED_STATE) {
                return a[4]
            } else {
                return null
            }
        } else {
            return a[5]
        }
    }
}
function initDataTuple(b, a) {
    newTuple = [];
    newTuple.CardEstimateTotal = 0;
    newTuple.TaskEstimateTotal = 0;
    newTuple.CardToDoTotal = 0;
    b[a] = newTuple
}
function incrementDataTuple(c, a, b) {
    if (typeof b !== "undefined") {
        c[a]["CardEstimateTotal"] += b.CardEstimateTotal
    }
    if (typeof b !== "undefined") {
        c[a]["TaskEstimateTotal"] += b.TaskEstimateTotal
    }
    if (typeof b !== "undefined") {
        c[a]["CardToDoTotal"] += b.CardToDoTotal
    }
}
function findFirstIndexForDate(d, b) {
    var a;
    for (var c = 0; c < d.length; c++) {
        if (typeof d[c] !== "undefined") {
            a = RALLY.Mashup.Utilities.convertIsoDateOnly(d[c]["CreationDate"]);
            if (a.valueOf() == b.valueOf()) {
                return c
            }
        }
    }
    return -1
}
function addTodayToBurndownData(d, b, a, c) {
    var e = b.getMonth() + 1;
    var f = b.getFullYear() + "-" + formatDateValue(e) + "-" + formatDateValue(b.getDate()) + "T" + formatDateValue(b.getHours()) + ":" + formatDateValue(b.getMinutes()) + ":" + formatDateValue(b.getSeconds()) + ".000Z";
    if (typeof d.definedData === "undefined") {
        d = {definedData:[initTodayBurndownObj(f)],inprogressData:[initTodayBurndownObj(f)],completedData:[initTodayBurndownObj(f)],acceptedData:[initTodayBurndownObj(f)]}
    } else {
        d.definedData.push(initTodayBurndownObj(f));
        d.inprogressData.push(initTodayBurndownObj(f));
        d.completedData.push(initTodayBurndownObj(f));
        d.acceptedData.push(initTodayBurndownObj(f))
    }
    if (a !== null) {
        if (typeof d[a + "Data"] === "undefined") {
            d[a + "Data"] = [initTodayBurndownObj(f)]
        } else {
            d[a + "Data"].push(initTodayBurndownObj(f))
        }
    }
    if (c !== null) {
        if (typeof d[c + "Data"] === "undefined") {
            d[c + "Data"] = [initTodayBurndownObj(f)]
        } else {
            d[c + "Data"].push(initTodayBurndownObj(f))
        }
    }
    return d
}
function sumTodayValues(k, j, m, d) {
    var l = ["HierarchicalRequirement","Defect","DefectSuite"];
    var b = ["PlanEstimate","TaskEstimateTotal","TaskRemainingTotal"];
    var g = {PlanEstimate:"CardEstimateTotal",TaskEstimateTotal:"TaskEstimateTotal",TaskRemainingTotal:"CardToDoTotal"};
    var e = {Defined:"defined","In-Progress":"inprogress",Completed:"completed",Accepted:"accepted"};
    var f,a;
    if (m !== null) {
        e[m] = m
    }
    if (d !== null) {
        e[d] = d
    }
    for (var h = 0; h < l.length; h++) {
        f = j[l[h]];
        for (var c = 0; c < f.length; c++) {
            a = e[f[c].ScheduleState];
            if (typeof a !== "undefined") {
                k[a + "Data"][k[a + "Data"].length - 1][g[b[0]]] += f[c][b[0]];
                k[a + "Data"][k[a + "Data"].length - 1][g[b[1]]] += f[c][b[1]];
                k[a + "Data"][k[a + "Data"].length - 1][g[b[2]]] += f[c][b[2]]
            }
        }
    }
    return k
}
function aggregateFlowDataPerDay(v, f, e, s, c) {
    var q = [];
    var p = [];
    var y = [];
    var x = [];
    var m = [];
    var w = [];
    var j = [];
    var t = RALLY.Mashup.Utilities.convertIsoDateOnly(f);
    var d = RALLY.Mashup.Utilities.convertIsoDateOnly(e);
    var h = 0;
    var k,l,g,n;
    var u,b,r,o;
    g = RALLY.Mashup.Utilities.convertIsoDateOnly(v.definedData[0].CreationDate);
    b = calcNumberOfWorkDays(f, v.definedData[0].CreationDate.slice(0, 10));
    if (RALLY.Mashup.Utilities.isWorkDay(g) && g >= t) {
        b = b - 1
    }
    k = new Date(t.getTime());
    h = 0;
    while (k <= g) {
        if (RALLY.Mashup.Utilities.isWorkDay(k)) {
            j[h] = new Date(k.getTime());
            h = h + 1
        }
        k.setTime(addDaysToDate(k, 1))
    }
    k = new Date(g.getTime());
    k.setTime(addDaysToDate(k, -1));
    h = b - 1;
    for (u = 0; u < v.definedData.length; u++) {
        l = RALLY.Mashup.Utilities.convertIsoDateOnly(v.definedData[u].CreationDate);
        if (l > k) {
            k = l;
            if (isValidChartDate(l, t, d)) {
                h = h + 1;
                r = h;
                j[h] = k;
                initDataTuple(q, h);
                initDataTuple(p, h);
                initDataTuple(y, h);
                initDataTuple(x, h);
                initDataTuple(m, h);
                initDataTuple(w, h);
                beforeCnt = 0;
                afterCnt = 0
            }
        }
        if (isValidChartDate(k, t, d)) {
            if (s !== null) {
                o = findFirstIndexForDate(v[s + "Data"], k);
                if (o >= 0) {
                    incrementDataTuple(m, h, v[s + "Data"][o + beforeCnt]);
                    beforeCnt += 1
                }
            }
            j[h] = k;
            incrementDataTuple(q, h, v.definedData[u]);
            incrementDataTuple(p, h, v.inprogressData[u]);
            incrementDataTuple(y, h, v.completedData[u]);
            incrementDataTuple(x, h, v.acceptedData[u]);
            if (c !== null) {
                o = findFirstIndexForDate(v[c + "Data"], k);
                if (o >= 0) {
                    incrementDataTuple(w, h, v[c + "Data"][o + afterCnt]);
                    afterCnt += 1
                }
            }
        }
    }
    n = j[r];
    k = new Date(n.getTime());
    k.setTime(addDaysToDate(k, 1));
    h = r + 1;
    while (k <= d) {
        if (RALLY.Mashup.Utilities.isWorkDay(k)) {
            j[h] = new Date(k.getTime());
            h = h + 1
        }
        k.setTime(addDaysToDate(k, 1))
    }
    var a = {firstDataDay:b,lastDataDay:r,dates:j,definedPerDay:q,inprogressPerDay:p,completedPerDay:y,acceptedPerDay:x};
    if (s !== null) {
        a[s + "PerDay"] = m
    }
    if (c !== null) {
        a[c + "PerDay"] = w
    }
    return a
}
;
/*
 Copyright (c) 2002-2010  Rally Software Development Corp. All rights reserved.
 SuperCustomizableChart.js
 */
var RALLY = RALLY || {};
RALLY.Mashup = RALLY.Mashup || {};
RALLY.Mashup.SuperCustomizableChart = function(g, r, E, h, f, V, B, e, s, ah, P) {
    var y = "Defined";
    var z = "In-Progress";
    var J = "Completed";
    var O = "Accepted";
    var w = 3;
    var M = this;
    var F = {};
    var j;
    var ab,af,ae,ac,Z,ad,L;
    var N = {ChartType:"stacked-bar",Units:"story",BeforeStateName:null,AfterStateName:null,BeforeVisible:false,DefinedVisible:true,InProgressVisible:true,CompletedVisible:true,AcceptedVisible:true,AfterVisible:false,BeforeColor:"#EF3F35",DefinedColor:"#E57E3A",InProgressColor:"#5C9ACB",CompletedColor:"#B2E3B6",AcceptedColor:"#6AB17D",AfterColor:"#3A874F",BeforeTrend:false,DefinedTrend:false,InProgressTrend:false,CompletedTrend:false,AcceptedTrend:false,AfterTrend:false,BurndownIdealVisible:false,BurndownIdealColor:"#BBBBBB",BurnupIdealVisible:false,BurnupIdealColor:"#BBBBBB",TableVisible:false,LeftAxisLabelVisible:true,BottomAxisLabelVisible:true,RightAxisLabelVisible:true,LeftAxisVisible:true,BottomAxisVisible:true,RightAxisVisible:true,scopeUp:false,scopeDown:true};
    var ai = [];

    function K() {
        if (typeof P !== "undefined") {
            P()
        }
    }

    function ak(al) {
        if (typeof N.scopeUp !== "undefined") {
            al.projectScopeUp = N.scopeUp
        }
        if (typeof N.scopeDown !== "undefined") {
            al.projectScopeDown = N.scopeDown
        }
    }

    function m(am) {
        for (var al in am) {
            if (am.hasOwnProperty(al)) {
                N[al] = am[al]
            }
        }
    }

    function b() {
        if (V === RALLY.Mashup.ITERATION) {
            return"StartDate"
        } else {
            return"ReleaseStartDate"
        }
    }

    function U() {
        if (V === RALLY.Mashup.ITERATION) {
            return"EndDate"
        } else {
            return"ReleaseDate"
        }
    }

    function T(ao, an) {
        var al = (V === RALLY.Mashup.ITERATION) ? "iterationCumulativeFlowData" : "releaseCumulativeFlowData";
        var am,ap;
        if (an === null || an.length === 0) {
            am = '( CardState = "' + ao + '" )'
        } else {
            am = "(" + an + ' AND ( CardState = "' + ao + '" ))'
        }
        ap = {key:"FlowData",type:al,fetch:"CreationDate,CardEstimateTotal,TaskEstimateTotal,CardToDoTotal",query:am,order:"CreationDate,ObjectID",project:null};
        ak(ap);
        return ap
    }

    function X(al) {
        return(al.getMonth() + 1) + "/" + al.getDate()
    }

    function A(aq, an, al, ao, ap) {
        var ar = [];
        for (var am = al; am <= ao; am++) {
            ar.push([am,an[am][ap],X(aq[am])])
        }
        return ar
    }

    function t(ar, aq, al, am, ap) {
        if (typeof ap === "undefined" || ap === null) {
            ap = "left"
        }
        var an = new EJSC.BarSeries(new EJSC.ArrayDataHandler(aq), {y_axis:ap,padding:{x_axis_min:w,x_axis_max:w,y_axis_min:w,y_axis_max:w}});
        an.title = ar;
        an.color = al;
        an.opacity = 100;
        an.lineWidth = 1;
        j.addSeries(an);
        if (am && aq.length > 1) {
            var ao = new EJSC.TrendSeries(an, "linear");
            ao.lineWidth = 1;
            ao.color = an.color;
            ao.opacity = 100;
            j.addSeries(ao)
        }
        return an
    }

    function d(am, ao, an) {
        var al;
        if (N[am + "Visible"]) {
            if (N.ChartType === "burndown" && am === "BurnupIdeal") {
                al = new EJSC.LineSeries(new EJSC.ArrayDataHandler(an), {y_axis:"right"})
            } else {
                al = new EJSC.LineSeries(new EJSC.ArrayDataHandler(an))
            }
            al.title = ao;
            al.color = N[am + "Color"];
            al.lineWidth = 3;
            al.opacity = 100;
            j.addSeries(al);
            return al
        } else {
            return null
        }
    }

    function S(aq, ap, al, am) {
        var an = new EJSC.LineSeries(new EJSC.ArrayDataHandler(ap));
        an.title = aq;
        an.color = al;
        an.lineWidth = 3;
        an.opacity = 100;
        j.addSeries(an);
        if (am && ap.length > 1) {
            var ao = new EJSC.TrendSeries(an, "linear");
            ao.lineWidth = 1;
            ao.color = an.color;
            ao.opacity = 100;
            j.addSeries(ao)
        }
        return an
    }

    function D(ao, an, al) {
        var am = new EJSC.AreaSeries(new EJSC.ArrayDataHandler(an));
        am.title = ao;
        am.color = al;
        am.lineWidth = 2;
        am.opacity = 100;
        j.addSeries(am);
        return am
    }

    function I(al, ar, aq, am, an) {
        var ao = new EJSC.BarSeries(new EJSC.ArrayDataHandler(aq), {groupedBars:false});
        ao.title = ar;
        ao.color = am;
        ao.lineWidth = 1;
        ao.opacity = 100;
        al.addSeries(ao);
        if (an && aq.length > 1) {
            var ap = new EJSC.TrendSeries(ao, "linear");
            ap.lineWidth = 1;
            ap.color = ao.color;
            ap.opacity = 100;
            j.addSeries(ap)
        }
        return ao
    }

    function C(aA, aq, am, an, ao, au) {
        var ay = [];
        var ax = [];
        var al = [];
        var aw = [];
        var az = [];
        var av = 0;
        var at;
        var ar;
        ay[0] = Array.init(aq, 0);
        if (N.BeforeStateName !== null && N.BeforeVisible) {
            av = av + 1;
            ay[av] = addArray(ay[av - 1], aA);
            ax[av] = N.BeforeStateName;
            al[av] = N.BeforeColor;
            aw[av] = N.BeforeTrend
        }
        if (N.DefinedVisible) {
            av = av + 1;
            ay[av] = addArray(ay[av - 1], aq);
            ax[av] = "Defined";
            al[av] = N.DefinedColor;
            aw[av] = N.DefinedTrend
        }
        if (N.InProgressVisible) {
            av = av + 1;
            ay[av] = addArray(ay[av - 1], am);
            ax[av] = "In-Progress";
            al[av] = N.InProgressColor;
            aw[av] = N.InProgressTrend
        }
        if (N.CompletedVisible) {
            av = av + 1;
            ay[av] = addArray(ay[av - 1], an);
            ax[av] = "Completed";
            al[av] = N.CompletedColor;
            aw[av] = N.CompletedTrend
        }
        if (N.AcceptedVisible) {
            av = av + 1;
            ay[av] = addArray(ay[av - 1], ao);
            ax[av] = "Accepted";
            al[av] = N.AcceptedColor;
            aw[av] = N.AcceptedTrend
        }
        if (N.AfterStateName !== null && N.AfterVisible) {
            av = av + 1;
            ay[av] = addArray(ay[av - 1], au);
            ax[av] = N.AfterStateName;
            al[av] = N.AfterColor;
            aw[av] = N.AfterTrend
        }
        for (ar = av; ar > 0; ar--) {
            at = D(ax[ar], ay[ar], al[ar]);
            az[ar] = at
        }
        for (ar = av; ar > 0; ar--) {
            if (aw[ar] && ay[ar].length > 1) {
                var ap = new EJSC.TrendSeries(az[ar], "linear");
                ap.lineWidth = 1;
                ap.color = az[ar].color;
                ap.opacity = 100;
                j.addSeries(ap)
            }
        }
        return ay
    }

    function R(ao, am, aq, al, an, ap) {
        L = j.addSeries(new EJSC.StackedBarSeries({intervalOffset:0.7,padding:{x_axis_min:w,x_axis_max:w,y_axis_min:w,y_axis_max:w}}));
        if (N.AfterStateName !== null && N.AfterVisible) {
            ad = I(L, N.AfterStateName, ap, N.AfterColor, N.AfterTrend)
        }
        if (N.AcceptedVisible) {
            ac = I(L, O, an, N.AcceptedColor, N.AcceptedTrend)
        }
        if (N.CompletedVisible) {
            ae = I(L, J, al, N.CompletedColor, N.CompletedTrend)
        }
        if (N.InProgressVisible) {
            af = I(L, z, aq, N.InProgressColor, N.InProgressTrend)
        }
        if (N.DefinedVisible) {
            ab = I(L, y, am, N.DefinedColor, N.DefinedTrend)
        }
        if (N.BeforeStateName !== null && N.BeforeVisible) {
            Z = I(L, N.BeforeStateName, ao, N.BeforeColor, N.BeforeTrend)
        }
    }

    function W(ao, am, aq, al, an, ap) {
        L = j.addSeries(new EJSC.StackedBarSeries({intervalOffset:0.7,padding:{x_axis_min:w,x_axis_max:w,y_axis_min:w,y_axis_max:w}}));
        if (N.BeforeStateName !== null && N.BeforeVisible) {
            Z = I(L, N.BeforeStateName, ao, N.BeforeColor, N.BeforeTrend)
        }
        if (N.DefinedVisible) {
            ab = I(L, y, am, N.DefinedColor, N.DefinedTrend)
        }
        if (N.InProgressVisible) {
            af = I(L, z, aq, N.InProgressColor, N.InProgressTrend)
        }
        if (N.CompletedVisible) {
            ae = I(L, J, al, N.CompletedColor, N.CompletedTrend)
        }
        if (N.AcceptedVisible) {
            ac = t(O, an, N.AcceptedColor, N.AcceptedTrend, "right")
        }
        if (N.AfterStateName !== null && N.AfterVisible) {
            ad = t(N.AfterStateName, ap, N.AfterColor, N.AfterTrend, "right")
        }
    }

    function x(ao, am, aq, al, an, ap) {
        if (N.BeforeStateName !== null && N.BeforeVisible) {
            Z = t(N.BeforeStateName, ao, N.BeforeColor, N.BeforeTrend)
        }
        if (N.DefinedVisible) {
            ab = t(y, am, N.DefinedColor, N.DefinedTrend)
        }
        if (N.InProgressVisible) {
            af = t(z, aq, N.InProgressColor, N.InProgressTrend)
        }
        if (N.CompletedVisible) {
            ae = t(J, al, N.CompletedColor, N.CompletedTrend)
        }
        if (N.AcceptedVisible) {
            ac = t(O, an, N.AcceptedColor, N.AcceptedTrend)
        }
        if (N.AfterStateName !== null && N.AfterVisible) {
            ad = t(N.AfterStateName, ap, N.AfterColor, N.AfterTrend)
        }
    }

    function H(ao, am, aq, al, an, ap) {
        if (N.BeforeStateName !== null && N.BeforeVisible) {
            Z = S(N.BeforeStateName, ao, N.BeforeColor, N.BeforeTrend)
        }
        if (N.DefinedVisible) {
            ab = S(y, am, N.DefinedColor, N.DefinedTrend)
        }
        if (N.InProgressVisible) {
            af = S(z, aq, N.InProgressColor, N.InProgressTrend)
        }
        if (N.CompletedVisible) {
            ae = S(J, al, N.CompletedColor, N.CompletedTrend)
        }
        if (N.AcceptedVisible) {
            ac = S(O, an, N.AcceptedColor, N.AcceptedTrend)
        }
        if (N.AfterStateName !== null && N.AfterVisible) {
            ad = S(N.AfterStateName, ap, N.AfterColor, N.AfterTrend)
        }
    }

    function aa(al) {
        var an = al.toUTCString().slice(5);
        var am = an.toString().split(/ /);
        return am[1] + " " + am[0] + ", " + am[2]
    }

    function Q(al) {
        return Math.round(al * 100) / 100
    }

    function p(am) {
        var an = new google.visualization.DataTable();
        var au,al,ap;
        var ar,aq,ao;
        ar = aj();
        if (N.ChartType === "burndown") {
            aq = "CardEstimateTotal"
        } else {
            aq = ar
        }
        an.addColumn("string", "Date");
        if (N.BeforeStateName !== null) {
            an.addColumn("number", N.BeforeStateName)
        }
        an.addColumn("number", y);
        an.addColumn("number", z);
        an.addColumn("number", J);
        an.addColumn("number", O);
        if (N.AfterStateName !== null) {
            an.addColumn("number", N.AfterStateName)
        }
        ap = am.lastDataDay - am.firstDataDay + 1;
        an.addRows(ap);
        au = 0;
        for (ao = am.firstDataDay; ao <= am.lastDataDay; ao++) {
            al = 0;
            an.setCell(au, al++, aa(am.dates[ao]));
            if (N.BeforeStateName !== null) {
                an.setCell(au, al++, Q(am[N.BeforeStateName + "PerDay"][ao][ar]))
            }
            an.setCell(au, al++, Q(am.definedPerDay[ao][ar]));
            an.setCell(au, al++, Q(am.inprogressPerDay[ao][ar]));
            an.setCell(au, al++, Q(am.completedPerDay[ao][ar]));
            an.setCell(au, al++, Q(am.acceptedPerDay[ao][aq]));
            if (N.AfterStateName !== null) {
                an.setCell(au, al++, Q(am[N.AfterStateName + "PerDay"][ao][aq]))
            }
            au = au + 1
        }
        document.getElementById(s).style.visibility = "visible";
        var at = new google.visualization.Table(document.getElementById(s));
        at.draw(an, {allowHtml:true,showRowNumber:false})
    }

    function aj() {
        if (N.Units === "story") {
            return"CardEstimateTotal"
        } else {
            if (N.Units === "task") {
                return"TaskEstimateTotal"
            } else {
                return"CardToDoTotal"
            }
        }
    }

    function n(an, am, ao) {
        var al;
        al = an.definedPerDay[ao][am] + an.inprogressPerDay[ao][am] + an.completedPerDay[ao][am] + an.acceptedPerDay[ao][am];
        if (N.BeforeStateName !== null) {
            al = al + an[N.BeforeStateName + "PerDay"][ao][am]
        }
        if (N.AfterStateName !== null) {
            al = al + an[N.AfterStateName + "PerDay"][ao][am]
        }
        return al
    }

    function l(am, an) {
        var al;
        al = am.acceptedPerDay[an]["CardEstimateTotal"];
        if (N.AfterStateName !== null) {
            al = al + am[N.AfterStateName + "PerDay"][an]["CardEstimateTotal"]
        }
        return al
    }

    function q(an, ao) {
        var al,am;
        am = aj();
        al = an.definedPerDay[ao][am] + an.inprogressPerDay[ao][am] + an.completedPerDay[ao][am];
        if (N.BeforeStateName !== null) {
            al = al + an[N.BeforeStateName + "PerDay"][ao][am]
        }
        return al
    }

    function ag(am) {
        var al;
        if (N.ChartType === "burndown") {
            al = "TaskEstimateTotal"
        } else {
            al = aj()
        }
        return n(am, al, am.firstDataDay)
    }

    function k(am) {
        var al;
        if (N.ChartType === "burndown") {
            al = "CardEstimateTotal"
        } else {
            al = aj()
        }
        return n(am, al, am.firstDataDay)
    }

    function c(ao, an) {
        var ap = 0,am = 0;
        for (var al = ao.firstDataDay; al <= ao.lastDataDay; al++) {
            if (N.ChartType === "burndown") {
                ap = Math.max(ap, q(ao, al));
                am = Math.max(am, l(ao, al))
            } else {
                ap = Math.max(ap, n(ao, an, al));
                am = ap
            }
        }
        if (ap < 0.01) {
            ap = 1
        }
        if (am < 0.01) {
            am = 1
        }
        return[ap,am]
    }

    function Y(an) {
        var aH = null,aI = null;
        var aD,aw,ay,am;
        var at,aF;
        var aq,ap,az,ax;
        var ar = an.dates.length - 1;
        var av,aC,aG,al;
        var ao = 300;
        av = aj();
        if (N.ChartType === "burndown") {
            aC = "CardEstimateTotal"
        } else {
            aC = av
        }
        aD = A(an.dates, an.definedPerDay, an.firstDataDay, an.lastDataDay, av);
        aw = A(an.dates, an.inprogressPerDay, an.firstDataDay, an.lastDataDay, av);
        ay = A(an.dates, an.completedPerDay, an.firstDataDay, an.lastDataDay, av);
        am = A(an.dates, an.acceptedPerDay, an.firstDataDay, an.lastDataDay, aC);
        if (N.BeforeStateName !== null) {
            aH = A(an.dates, an[N.BeforeStateName + "PerDay"], an.firstDataDay, an.lastDataDay, av)
        }
        if (N.AfterStateName !== null) {
            aI = A(an.dates, an[N.AfterStateName + "PerDay"], an.firstDataDay, an.lastDataDay, aC)
        }
        at = ag(an);
        aF = k(an);
        aG = c(an, av);
        var aE = X(an.dates[an.dates.length - 1]);
        var aB = [
            [0,at,an.dates[0]],
            [ar,0,aE]
        ];
        var aA = [
            [0,0,an.dates[0]],
            [ar,aF,aE]
        ];
        az = "Ideal Burndown To Do";
        ax = "Ideal Burn-up Accepted";
        document.getElementById(e).style.visibility = "visible";
        var au = function() {
            EJSC.Formatter.__extendTo(this);
            this.format = function(aJ) {
                if (Math.round(aJ) !== aJ) {
                    return""
                }
                if (aJ >= 0 && aJ < an.dates.length) {
                    return X(an.dates[aJ])
                } else {
                    return X(findDateForDay(h, aJ))
                }
            }
        };
        if (typeof j !== "undefined") {
            j.remove()
        }
        j = new EJSC.Chart(e, {show_legend:false,allow_zoom:false,show_titlebar:false,axis_bottom:{caption:"",caption_class:"AxisCaption",label_class:"AxisTickLabel",size:0,min_extreme:0,max_extreme:ar,extremes_ticks:true,major_ticks:{opacity:100,min_interval:3,show:true,thickness:1},visible:N.BottomAxisVisible},axis_left:{caption:"",caption_class:"AxisCaption",label_class:"AxisTickLabel",size:0,min_extreme:0,formatter:new EJSC.NumberFormatter({variable_decimals:1}),visible:N.LeftAxisVisible},axis_right:{caption:"",caption_class:"AxisCaption",label_class:"AxisTickLabel",size:0,min_extreme:0,grid:{show:false},formatter:new EJSC.NumberFormatter({variable_decimals:1}),visible:N.RightAxisVisible}});
        if (N.ChartType === "stacked-bar" || N.ChartType === "grouped-bar" || N.ChartType === "burndown") {
            j.axis_bottom.setExtremes(-0.35, ar + 0.35)
        }
        j.axis_left.setExtremes(0, Math.round(Math.max(at, aG[0])));
        if (N.ChartType === "burndown") {
            j.axis_right.setExtremes(0, Math.round(Math.max(aF, aG[1])))
        }
        al = parseInt(document.getElementById(e).style.width, 10);
        if (isNaN(al)) {
            al = 0
        }
        if (N.BottomAxisLabelVisible) {
            j.axis_bottom.caption = "Date";
            if (al > ao) {
            }
        }
        if (N.LeftAxisLabelVisible) {
            if (al > ao) {
                j.axis_left.size = Math.round(al * 0.06)
            }
            if (N.Units === "story") {
                j.axis_left.caption = "Plan Estimates"
            } else {
                if (N.Units === "task") {
                    j.axis_left.caption = "Task Estimates"
                } else {
                    j.axis_left.caption = "Task To Do"
                }
            }
        }
        if (N.ChartType === "burndown") {
            if (al > ao) {
                j.axis_right.size = Math.round(al * 0.07)
            }
            if (N.RightAxisLabelVisible) {
                j.axis_right.caption = "Plan Estimate"
            }
        }
        j.axis_bottom.formatter = new au();
        j.onShowHint = function(aJ, aK, aL, aN, aM) {
            if (aK.title.indexOf("Trend") >= 0) {
                return"[series_title]<br/>Value: " + Math.round(aJ.y * 100) / 100
            } else {
                if (aK.title.indexOf("Ideal") >= 0) {
                    return"[series_title]<br/>Date: [x]<br/>Value: " + Math.round(aJ.y * 100) / 100
                } else {
                    return"[series_title]<br/>Date: [label]<br/>" + v(aK.title) + ": " + Math.round(aJ.y * 100) / 100
                }
            }
        };
        if (N.ChartType === "stacked-bar") {
            R(aH, aD, aw, ay, am, aI)
        } else {
            if (N.ChartType === "grouped-bar") {
                x(aH, aD, aw, ay, am, aI)
            } else {
                if (N.ChartType === "area") {
                    C(aH, aD, aw, ay, am, aI)
                } else {
                    if (N.ChartType === "burndown") {
                        W(aH, aD, aw, ay, am, aI)
                    } else {
                        H(aH, aD, aw, ay, am, aI)
                    }
                }
            }
        }
        aq = d("BurndownIdeal", az, aB);
        ap = d("BurnupIdeal", ax, aA);
        if (N.TableVisible && s !== null) {
            p(an)
        }
    }

    function v(al) {
        if (N.ChartType === "burndown" && al.indexOf("Accepted") >= 0) {
            if (V === RALLY.Mashup.ITERATION) {
                return ai.IterationEstimateUnitName
            } else {
                return ai.ReleaseEstimateUnitName
            }
        } else {
            if (N.Units === "story") {
                if (V === RALLY.Mashup.ITERATION) {
                    return ai.IterationEstimateUnitName
                } else {
                    return ai.ReleaseEstimateUnitName
                }
            } else {
                return ai.TaskUnitName
            }
        }
    }

    function G(al) {
        function ap() {
            if (V === RALLY.Mashup.ITERATION) {
                return"Iteration.StartDate"
            } else {
                return"Release.ReleaseStartDate"
            }
        }

        function an() {
            if (V === RALLY.Mashup.ITERATION) {
                return"Iteration.EndDate"
            } else {
                return"Release.ReleaseDate"
            }
        }

        function ao() {
            if (V === RALLY.Mashup.ITERATION) {
                return"Iteration.Name"
            } else {
                return"Release.Name"
            }
        }

        var am = {key:al,type:al,query:"((( " + ap() + " = " + h + ") AND (" + an() + " = " + f + ")) AND (" + ao() + ' = "' + E + '"))',fetch:"PlanEstimate,TaskEstimateTotal,TaskRemainingTotal,ScheduleState"};
        if (ah !== null) {
            am.project = "/project/" + ah
        }
        ak(am);
        return am
    }

    function a(aq, an, am, ao) {
        var al = [];
        aq = addTodayToBurndownData(aq, an, am, ao);
        var ap = function(ar) {
            aq = sumTodayValues(aq, ar, am, ao);
            i()
        };
        al[0] = G("HierarchicalRequirement");
        al[1] = G("Defect");
        al[2] = G("DefectSuite");
        BATCH_TOOLKIT.findAll(al, ap)
    }

    function i() {
        var am;
        var al = new Date();
        if (s !== null) {
            document.getElementById(s).style.visibility = "hidden"
        }
        if (typeof F.definedData === "undefined" || (F.definedData.length + F.inprogressData.length + F.completedData.length + F.acceptedData.length) === 0 || al < RALLY.Mashup.Utilities.convertIsoDateOnly(h)) {
            document.getElementById(e).style.visibility = "visible";
            document.getElementById(e).innerHTML = "No Data";
            K()
        } else {
            am = aggregateFlowDataPerDay(F, h, f, N.BeforeStateName, N.AfterStateName);
            Y(am);
            K()
        }
    }

    function o(am) {
        var az = [],at = [],aq = {},ax;
        if (r !== null) {
            ax = r.split(",");
            for (var ar = 0; ar < ax.length; ar++) {
                aq = {};
                aq.ObjectID = ax[ar];
                at[ar] = aq
            }
        } else {
            at = am.timeboxOids
        }
        if (at.length === 0) {
            return
        }
        var aw = (V === RALLY.Mashup.ITERATION) ? "IterationObjectID" : "ReleaseObjectID";
        if (N.BeforeStateName !== null) {
            var av = T(N.BeforeStateName, RALLY.Mashup.Utilities.buildOrQueryString(at, aw, "ObjectID"));
            g.findAll(av, ay)
        } else {
            ay(az)
        }
        ai = am.estimateUnit[0];
        function ay(aA) {
            if (N.BeforeStateName !== null) {
                F[N.BeforeStateName + "Data"] = aA.FlowData
            }
            var aB = T(y, RALLY.Mashup.Utilities.buildOrQueryString(at, aw, "ObjectID"));
            g.findAll(aB, ap)
        }

        function ap(aA) {
            F.definedData = aA.FlowData;
            av = T(z, RALLY.Mashup.Utilities.buildOrQueryString(at, aw, "ObjectID"));
            g.findAll(av, al)
        }

        function al(aA) {
            F.inprogressData = aA.FlowData;
            av = T(J, RALLY.Mashup.Utilities.buildOrQueryString(at, aw, "ObjectID"));
            g.findAll(av, au)
        }

        function au(aA) {
            F.completedData = aA.FlowData;
            av = T(O, RALLY.Mashup.Utilities.buildOrQueryString(at, aw, "ObjectID"));
            g.findAll(av, ao)
        }

        function ao(aA) {
            F.acceptedData = aA.FlowData;
            if (N.AfterStateName !== null) {
                var aB = T(N.AfterStateName, RALLY.Mashup.Utilities.buildOrQueryString(at, aw, "ObjectID"));
                g.findAll(aB, an)
            } else {
                an(az)
            }
        }

        function an(aC) {
            if (N.AfterStateName !== null) {
                F[N.AfterStateName + "Data"] = aC.FlowData
            }
            var aA = RALLY.Mashup.Utilities.convertIsoDateOnly(h);
            var aD = RALLY.Mashup.Utilities.convertIsoDateOnly(f);
            aD.setHours(23, 59, 0, 0);
            var aB = new Date();
            if (isValidChartDate(aB, aA, aD) && V !== RALLY.Mashup.Program) {
                a(F, aB, N.BeforeStateName, N.AfterStateName)
            } else {
                i()
            }
        }
    }

    function u() {
        var an = b();
        var ao = U();
        var am = [];
        var al = "((( " + an + " = " + h + ") AND (" + ao + " = " + f + ')) AND (Name = "' + E + '"))';
        am[0] = {key:"timeboxOids",type:V,fetch:"ObjectID,Name,project," + an + "," + ao,query:al,order:ao + " desc,ObjectID"};
        ak(am[0]);
        am[1] = {key:"estimateUnit",type:"WorkspaceConfiguration",fetch:"TaskUnitName,IterationEstimateUnitName,ReleaseEstimateUnitName"};
        ak(am[1]);
        if (ah !== null) {
            am[0].project = "/project/" + ah
        }
        g.findAll(am, o)
    }

    this.display = function() {
        u()
    };
    this.redisplay = function(al) {
        m(al);
        i()
    };
    if (B !== null) {
        m(B)
    }
    return M
};
/*
 Copyright (c) 2002-2010  Rally Software Development Corp. All rights reserved.
 */
dojo.addOnLoad(initPage);
google.load("visualization", "1", {packages:["table"]});

var COLORS = {
    'red' : '#E92D34',
    'orange' : '#F39731',
    'yellow' : '#F4CA13',
    'green' : '#6AB17D',
    'blue' : '#5E70DE',
    'indigo' : "#4B0082",
    'violet' : "#EE82EE",
    'light_green' : '#B2E3B6',
    'gray' : '#BBBBBB'
};
var DEFINED_STATE = 'Defined';
var INPROGRESS_STATE = 'In-Progress';
var COMPLETED_STATE = 'Completed';
var ACCEPTED_STATE = 'Accepted';

var CHARTCOLORS = {
    DEFINED_STATE : "orange",
    INPROGRESS_STATE : "blue",
    COMPLETED_STATE : "light_green",
    ACCEPTED_STATE : "green",
    'BurndownIdeal' : "gray",
    'BurnupIdeal' : "gray"
};

var BATCH_TOOLKIT, DROPDOWN, BURNDOWN_CHART;
var NUM_SETTINGS = 31;
var SETTINGS_COOKIE_DEFAULT =
        't~f~f~f~f~f~t~f~f~t~t~t~t~f~f~f~f~orange~blue~light_green~green~f~f~red~f~f~indigo~f~gray~f~gray';
var NUM_CHART_TYPES = 5;
var theChart;
var dSeries, iSeries, cSeries, aSeries, bSeries, fSeries, theStack;

Array.init = function (template_array, initial) {
    var a = [], i;
    for (i = 0; i < template_array.length; i += 1) {
        a[i] = [template_array[i][0], initial, template_array[i][2]];
    }
    return a;
};

function addArray(first, second) {
    var i;
    var sum = [];
    for (i = 0; i < first.length; i += 1) {
        sum.push([first[i][0], first[i][1] + second[i][1], first[i][2]]);
    }
    return sum;
}

function getControlPanelElement(name) {
    return document.getElementById(name);
}

function getState(element) {
    if (element.checked) {
        return "~t";
    } else {
        return "~f";
    }
}

function getValue(element) {
    return "~" + element.value;
}

function buildConfig() {
    var config = {};
    var beforeState = getBeforeState(SCHEDULE_STATES);
    var afterState = getAfterState(SCHEDULE_STATES);

    if (getControlPanelElement('input0').checked) {
        config.ChartType = 'stacked-bar';
    } else if (getControlPanelElement('input1').checked) {
        config.ChartType = 'grouped-bar';
    } else if (getControlPanelElement('input2').checked) {
        config.ChartType = 'line';
    } else if (getControlPanelElement('input3').checked) {
        config.ChartType = 'area';
    } else {
        config.ChartType = 'burndown';
    }

    if (getControlPanelElement('rbStory').checked) {
        config.Units = 'story';
    } else if (getControlPanelElement('rbTask').checked) {
        config.Units = 'task';
    } else if (getControlPanelElement('rbToDo').checked) {
        config.Units = 'todo';
    }

    config.BeforeStateName = beforeState;
    config.AfterStateName = afterState;

    config[DEFINED_STATE + 'Visible'] = getControlPanelElement('cbDefined').checked;
    config['InProgressVisible'] = getControlPanelElement('cbIn-Progress').checked;
    config[COMPLETED_STATE + 'Visible'] = getControlPanelElement('cbCompleted').checked;
    config[ACCEPTED_STATE + 'Visible'] = getControlPanelElement('cbAccepted').checked;

    config[DEFINED_STATE + 'Color'] =
            COLORS[getControlPanelElement('selDefined').value];
    config['InProgressColor'] =
            COLORS[getControlPanelElement('selIn-Progress').value];
    config[COMPLETED_STATE + 'Color'] =
            COLORS[getControlPanelElement('selCompleted').value];
    config[ACCEPTED_STATE + 'Color'] =
            COLORS[getControlPanelElement('selAccepted').value];

    config[DEFINED_STATE + 'Trend'] = getControlPanelElement('cbDefinedTrend').checked;
    config['InProgressTrend'] = getControlPanelElement('cbIn-ProgressTrend').checked;
    config[COMPLETED_STATE + 'Trend'] = getControlPanelElement('cbCompletedTrend').checked;
    config[ACCEPTED_STATE + 'Trend'] = getControlPanelElement('cbAcceptedTrend').checked;

    if (beforeState !== null) {
        config.BeforeVisible = getControlPanelElement('cb' + beforeState).checked;
        config.BeforeColor =
                COLORS[getControlPanelElement('sel' + beforeState).value];
        config.BeforeTrend = getControlPanelElement('cb' + beforeState + 'Trend').checked;
    }

    if (afterState !== null) {
        config.AfterVisible = getControlPanelElement('cb' + afterState).checked;
        config.AfterColor =
                COLORS[getControlPanelElement('sel' + afterState).value];
        config.AfterTrend = getControlPanelElement('cb' + afterState + 'Trend').checked;
    }

    config.BurndownIdealVisible = getControlPanelElement('cbBurndownIdeal').checked;
    config.BurndownIdealColor =
            COLORS[getControlPanelElement('selBurndownIdeal').value];
    config.BurnupIdealVisible = getControlPanelElement('cbBurnupIdeal').checked;
    config.BurnupIdealColor =
            COLORS[getControlPanelElement('selBurnupIdeal').value];

    config.TableVisible = getControlPanelElement('cbTable').checked;

    if (config.ChartType === 'burndown') {
        config.RightAxisLabelVisible = true;
    }

    return config;
}

function getControlStates() {
    var initialVal = getControlPanelElement('input0').checked ? 't' : 'f';
    var beforeState = getBeforeState(SCHEDULE_STATES);
    var afterState = getAfterState(SCHEDULE_STATES);
    var cookieVal = initialVal +
            getState(getControlPanelElement('input1')) +
            getState(getControlPanelElement('input2')) +
            getState(getControlPanelElement('input3')) +
            getState(getControlPanelElement('input4')) +
            getState(getControlPanelElement('cbTable')) +
            getState(getControlPanelElement('rbStory')) +
            getState(getControlPanelElement('rbTask')) +
            getState(getControlPanelElement('rbToDo')) +
            getState(getControlPanelElement('cbDefined')) +
            getState(getControlPanelElement('cbIn-Progress')) +
            getState(getControlPanelElement('cbCompleted')) +
            getState(getControlPanelElement('cbAccepted')) +
            getState(getControlPanelElement('cbDefinedTrend')) +
            getState(getControlPanelElement('cbIn-ProgressTrend')) +
            getState(getControlPanelElement('cbCompletedTrend')) +
            getState(getControlPanelElement('cbAcceptedTrend')) +
            getValue(getControlPanelElement('selDefined')) +
            getValue(getControlPanelElement('selIn-Progress')) +
            getValue(getControlPanelElement('selCompleted')) +
            getValue(getControlPanelElement('selAccepted'));
    if (beforeState !== null) {
        cookieVal = cookieVal + getState(getControlPanelElement('cb' + beforeState));
        cookieVal = cookieVal + getState(getControlPanelElement('cb' + beforeState + 'Trend'));
        cookieVal = cookieVal + getValue(getControlPanelElement('sel' + beforeState));
    } else {
        cookieVal = cookieVal + '~f~f~gray';
    }
    if (afterState !== null) {
        cookieVal = cookieVal + getState(getControlPanelElement('cb' + afterState));
        cookieVal = cookieVal + getState(getControlPanelElement('cb' + afterState + 'Trend'));
        cookieVal = cookieVal + getValue(getControlPanelElement('sel' + afterState));
    } else {
        cookieVal = cookieVal + '~f~f~gray';
    }

    cookieVal = cookieVal + getState(getControlPanelElement('cbBurndownIdeal'));
    cookieVal = cookieVal + getValue(getControlPanelElement('selBurndownIdeal'));
    cookieVal = cookieVal + getState(getControlPanelElement('cbBurnupIdeal'));
    cookieVal = cookieVal + getValue(getControlPanelElement('selBurnupIdeal'));
    return cookieVal;
}

function updateColor(name, colorIndex) {
    CHARTCOLORS[colorIndex] = getControlPanelElement('sel' + name).value;
    getControlPanelElement('sq' + name).style.background =
            COLORS[CHARTCOLORS[colorIndex]];
}

function updateColors() {
    var beforeState = getBeforeState(SCHEDULE_STATES);
    var afterState = getAfterState(SCHEDULE_STATES);
    updateColor('Accepted', ACCEPTED_STATE);
    updateColor('Completed', COMPLETED_STATE);
    updateColor('In-Progress', INPROGRESS_STATE);
    updateColor('Defined', DEFINED_STATE);
    updateColor('BurndownIdeal', 'BurndownIdeal');
    updateColor('BurnupIdeal', 'BurnupIdeal');
    if (beforeState !== null) {
        updateColor(beforeState, beforeState);
    }
    if (afterState !== null) {
        updateColor(afterState, afterState);
    }
}

function updateUnitRadioButtons() {
    if (getControlPanelElement('input4').checked) {
        getControlPanelElement('rbStory').disabled = true;
        getControlPanelElement('rbTask').disabled = true;
        getControlPanelElement('rbToDo').checked = true;
        getControlPanelElement('rbToDo').disabled = true;
    } else {
        getControlPanelElement('rbStory').disabled = false;
        getControlPanelElement('rbTask').disabled = false;
        getControlPanelElement('rbToDo').disabled = false;
    }
}

function onColorChange(e) {
    RALLY.Mashup.Utilities.updateMashupCookie(SETTINGS_COOKIE_NAME, getControlStates(), 30);
    updateColors();
    RALLY.Mashup.Utilities.showWait('chart_div');
    BURNDOWN_CHART.redisplay(buildConfig());
}

function onDatasetChange(e) {
    RALLY.Mashup.Utilities.updateMashupCookie(SETTINGS_COOKIE_NAME, getControlStates(), 30);
    updateTrendIdealChkBoxes();
    RALLY.Mashup.Utilities.showWait('chart_div');
    BURNDOWN_CHART.redisplay(buildConfig());
}

function addCheckBox(row, id) {
    var cell = document.createElement("TD");
    var checkBox = document.createElement("input");

    checkBox.type = "checkbox";
    checkBox.id = id;
    if (document.addEventListener) { // For most browsers
        checkBox.addEventListener('change', onDatasetChange, false);
    } else if (document.attachEvent) { // For IE
        checkBox.attachEvent('onclick', onDatasetChange);
    }
    cell.width = 25;
    cell.appendChild(checkBox);
    row.appendChild(cell);
}

function addLabel(row, labeltext) {
    var label;
    var cell = document.createElement("TD");
    if (labeltext !== null && labeltext.length > 0) {
        label = document.createElement("label");
        label.appendChild(document.createTextNode(labeltext));
        cell.appendChild(label);
    }
    row.appendChild(cell);
}

function addLegendSquare(row, id) {
    var cell = document.createElement("TD");
    cell.id = id;
    cell.height = 5;
    cell.width = 20;
    cell.border = 1;
    row.appendChild(cell);
}

function addSelectList(row, id) {
    var option;
    var cell = document.createElement("TD");
    var selectList = document.createElement("select");
    selectList.id = id;
    if (document.addEventListener) { // For most browsers
        selectList.addEventListener('change', onColorChange, false);
    } else if (document.attachEvent) { // For IE
        selectList.attachEvent('onchange', onColorChange);
    }

    for (var colorName in COLORS) {
        if (COLORS.hasOwnProperty(colorName)) {
            option = document.createElement('option');
            option.text = colorName;
            option.value = colorName;
            //option.style.background=COLORS[colorName];
            try {
                selectList.add(option, null); // standards compliant; doesn't work in IE
            }
            catch(ex) {
                selectList.add(option); // IE only
            }
        }
    }
    cell.appendChild(selectList);
    row.appendChild(cell);
}

function addHeader(tablebody) {
    var cell, label;
    var row = document.createElement("TR");

    cell = document.createElement("TH");
    row.appendChild(cell);

    cell = document.createElement("TH");
    row.appendChild(cell);

    cell = document.createElement("TH");
    row.appendChild(cell);

    cell = document.createElement("TH");
    row.appendChild(cell);

    cell = document.createElement("TH");
    label = document.createElement("label");
    label.appendChild(document.createTextNode("Trend"));

    cell.appendChild(label);
    row.appendChild(cell);

    tablebody.appendChild(row);
}

function addDatasetControlPanel(results) {
    var tablebody, table, row, cell, checkBox, selectList, option;

    SCHEDULE_STATES = results.storyStates;

    table = document.createElement("TABLE");
    table.cellSpacing = 5;
    tablebody = document.createElement("TBODY");

    addHeader(tablebody);

    for (var i = 0; i < SCHEDULE_STATES.length; i++) {
        row = document.createElement("TR");
        addCheckBox(row, "cb" + SCHEDULE_STATES[i]);
        addLegendSquare(row, "sq" + SCHEDULE_STATES[i]);
        addLabel(row, SCHEDULE_STATES[i]);
        addSelectList(row, "sel" + SCHEDULE_STATES[i]);
        addCheckBox(row, "cb" + SCHEDULE_STATES[i] + "Trend", null);
        tablebody.appendChild(row);
    }

    table.appendChild(tablebody);
    document.getElementById('datasetPanel').appendChild(table);

    addIdealControlPanel();
}

function addIdealControlPanel() {
    var tablebody, table, row, cell, label;
    table = document.createElement("TABLE");
    table.cellSpacing = 5;
    tablebody = document.createElement("TBODY");

    row = document.createElement("TR");
    cell = document.createElement("TH");
    label = document.createElement("label");
    label.appendChild(document.createTextNode("Ideal Lines"));
    cell.appendChild(label);
    cell.colSpan = 3;
    cell.align = "left";
    row.appendChild(cell);
    tablebody.appendChild(row);

    row = document.createElement("TR");
    addCheckBox(row, "cbBurndownIdeal");
    addLegendSquare(row, "sqBurndownIdeal");
    addLabel(row, "Burndown To Do");
    addSelectList(row, "selBurndownIdeal");
    tablebody.appendChild(row);

    row = document.createElement("TR");
    addCheckBox(row, "cbBurnupIdeal");
    addLegendSquare(row, "sqBurnupIdeal");
    addLabel(row, "Burn-up Accepted");
    addSelectList(row, "selBurnupIdeal");
    tablebody.appendChild(row);

    table.appendChild(tablebody);
    document.getElementById('idealPanel').appendChild(table);
}

function setControlStates(cookieVal) {
    var stuff = cookieVal.split(/~/);
    var beforeState = getBeforeState(SCHEDULE_STATES);
    var afterState = getAfterState(SCHEDULE_STATES);
    if (stuff.length != NUM_SETTINGS) {
        stuff = SETTINGS_COOKIE_DEFAULT.split(/~/);
    }

    getControlPanelElement('input0').checked = (stuff[0] === 't') ? true : false;
    getControlPanelElement('input1').checked = (stuff[1] === 't') ? true : false;
    getControlPanelElement('input2').checked = (stuff[2] === 't') ? true : false;
    getControlPanelElement('input3').checked = (stuff[3] === 't') ? true : false;
    getControlPanelElement('input4').checked = (stuff[4] === 't') ? true : false;
    getControlPanelElement('cbTable').checked = (stuff[5] === 't') ? true : false;
    getControlPanelElement('rbStory').checked = (stuff[6] === 't') ? true : false;
    getControlPanelElement('rbTask').checked = (stuff[7] === 't') ? true : false;
    getControlPanelElement('rbToDo').checked = (stuff[8] === 't') ? true : false;
    getControlPanelElement('cbDefined').checked = (stuff[9] === 't') ? true : false;
    getControlPanelElement('cbIn-Progress').checked = (stuff[10] === 't') ? true : false;
    getControlPanelElement('cbCompleted').checked = (stuff[11] === 't') ? true : false;
    getControlPanelElement('cbAccepted').checked = (stuff[12] === 't') ? true : false;
    getControlPanelElement('cbDefinedTrend').checked = (stuff[13] === 't') ? true : false;
    getControlPanelElement('cbIn-ProgressTrend').checked = (stuff[14] === 't') ? true : false;
    getControlPanelElement('cbCompletedTrend').checked = (stuff[15] === 't') ? true : false;
    getControlPanelElement('cbAcceptedTrend').checked = (stuff[16] === 't') ? true : false;
    getControlPanelElement('selDefined').value = stuff[17];
    getControlPanelElement('sqDefined').style.background = COLORS[stuff[17]];
    getControlPanelElement('selIn-Progress').value = stuff[18];
    getControlPanelElement('sqIn-Progress').style.background = COLORS[stuff[18]];
    getControlPanelElement('selCompleted').value = stuff[19];
    getControlPanelElement('sqCompleted').style.background = COLORS[stuff[19]];
    getControlPanelElement('selAccepted').value = stuff[20];
    getControlPanelElement('sqAccepted').style.background = COLORS[stuff[20]];
    if (beforeState !== null) {
        getControlPanelElement('cb' + beforeState).checked = (stuff[21] === 't') ? true : false;
        getControlPanelElement('cb' + beforeState + 'Trend').checked = (stuff[22] === 't') ? true : false;
        getControlPanelElement('sel' + beforeState).value = stuff[23];
        getControlPanelElement('sq' + beforeState).style.background = COLORS[stuff[23]];
    }
    if (afterState !== null) {
        getControlPanelElement('cb' + afterState).checked = (stuff[24] === 't') ? true : false;
        getControlPanelElement('cb' + afterState + 'Trend').checked = (stuff[25] === 't') ? true : false;
        getControlPanelElement('sel' + afterState).value = stuff[26];
        getControlPanelElement('sq' + afterState).style.background = COLORS[stuff[26]];
    }
    getControlPanelElement('cbBurndownIdeal').checked = (stuff[27] === 't') ? true : false;
    getControlPanelElement('selBurndownIdeal').value = stuff[28];
    getControlPanelElement('sqBurndownIdeal').style.background = COLORS[stuff[28]];

    getControlPanelElement('cbBurnupIdeal').checked = (stuff[29] === 't') ? true : false;
    getControlPanelElement('selBurnupIdeal').value = stuff[30];
    getControlPanelElement('sqBurnupIdeal').style.background = COLORS[stuff[30]];

    updateTrendIdealChkBoxes();
}

function updateTrendIdealChkBoxes() {
    var beforeState = getBeforeState(SCHEDULE_STATES);
    var afterState = getAfterState(SCHEDULE_STATES);
    setRelatedCheckbox(getControlPanelElement('cbDefinedTrend'),
            getControlPanelElement('cbDefined'));
    setRelatedCheckbox(getControlPanelElement('cbIn-ProgressTrend'),
            getControlPanelElement('cbIn-Progress'));
    setRelatedCheckbox(getControlPanelElement('cbCompletedTrend'),
            getControlPanelElement('cbCompleted'));
    setRelatedCheckbox(getControlPanelElement('cbAcceptedTrend'),
            getControlPanelElement('cbAccepted'));
    if (beforeState !== null) {
        setRelatedCheckbox(getControlPanelElement('cb' + beforeState + 'Trend'),
                getControlPanelElement('cb' + beforeState));
    }
    if (afterState !== null) {
        setRelatedCheckbox(getControlPanelElement('cb' + afterState + 'Trend'),
                getControlPanelElement('cb' + afterState));
    }
}

function setRelatedCheckbox(checkboxToSet, masterCheckbox) {
    if (masterCheckbox.checked) {
        checkboxToSet.disabled = false;
    } else {
        checkboxToSet.disabled = true;
    }
}

function createChart() {

    if (!RALLY.Mashup.Utilities.cookieExists(SETTINGS_COOKIE_NAME)) {
        RALLY.Mashup.Utilities.updateMashupCookie(SETTINGS_COOKIE_NAME, SETTINGS_COOKIE_DEFAULT, 30);
    }
    setControlStates(RALLY.Mashup.Utilities.readMashupCookie(SETTINGS_COOKIE_NAME));

    document.getElementById('table_div').style.visibility = "hidden";
    RALLY.Mashup.Utilities.showWait('chart_div');

    BURNDOWN_CHART = new RALLY.Mashup.SuperCustomizableChart(BATCH_TOOLKIT, DROPDOWN.getSelectedOids(),
            DROPDOWN.getSelectedName(), DROPDOWN.getSelectedStart(), DROPDOWN.getSelectedEnd(),
            MASHUP_TYPE, buildConfig(), 'chart_div', 'table_div', null);

    BURNDOWN_CHART.display();

}

function runScheduleStateQuery() {
    var queryObject = {
        key: 'storyStates',
        type: 'Hierarchical Requirement',
        attribute: 'Schedule State'
    };
    BATCH_TOOLKIT.findAll(queryObject, addDatasetControlPanel);
}

function addEventListeners() {
    var i;
    if (document.addEventListener) { // For most browsers
        getControlPanelElement('cbTable').addEventListener('change', onDatasetChange, false);
        getControlPanelElement('rbStory').addEventListener('change', onDatasetChange, false);
        getControlPanelElement('rbTask').addEventListener('change', onDatasetChange, false);
        getControlPanelElement('rbToDo').addEventListener('change', onDatasetChange, false);
        for (i = 0; i < NUM_CHART_TYPES; i++) {
            getControlPanelElement('input' + i).addEventListener('change', nowClear, false);
            getControlPanelElement('span' + i).addEventListener('mouseup', nowCheck, false);
        }
        document.onmouseup = nowClear;
    } else if (document.attachEvent) { // For IE
        getControlPanelElement('cbTable').attachEvent('onclick', onDatasetChange);
        getControlPanelElement('rbStory').attachEvent('onclick', onDatasetChange);
        getControlPanelElement('rbTask').attachEvent('onclick', onDatasetChange);
        getControlPanelElement('rbToDo').attachEvent('onclick', onDatasetChange);
        for (i = 0; i < NUM_CHART_TYPES; i++) {
            getControlPanelElement('input' + i).attachEvent('onclick', nowClear);
            getControlPanelElement('span' + i).attachEvent('onclick', nowCheck);
        }
        document.attachEvent('onmouseup', nowClear);
    }
}

function getTarget(e) {
    e = e || window.event;
    if (typeof e.target !== 'undefined') {
        return e.target;
    } else if (typeof e.srcElement !== 'undefined') {
        return e.srcElement;
    } else {
        return null;
    }
}

function nowClear(e) {
    var t = getTarget(e);
    if (t.nodeName.toLowerCase() === "span") {
        for (var i = 0; i < NUM_CHART_TYPES; i++) {

            if (getControlPanelElement('input' + i).checked) {
                getControlPanelElement('span' + i).style.backgroundPosition = "0 -49px";
            } else {
                getControlPanelElement('span' + i).style.backgroundPosition = "0 -0";
            }
        }
    }
}

function nowCheck(e) {
    var t = getTarget(e);
    for (var i = 0; i < NUM_CHART_TYPES; i++) {
        if (t.id === "span" + i) {
            getControlPanelElement('input' + i).checked = true;
            getControlPanelElement('span' + i).style.backgroundPosition = "0 -49px";
        } else {
            getControlPanelElement('span' + i).style.backgroundPosition = "0 -0";
        }
    }
    updateUnitRadioButtons();
    onDatasetChange();
}

function initChartTypeButtons() {
    for (var i = 0; i < NUM_CHART_TYPES; i++) {
        if (getControlPanelElement('input' + i).checked) {
            getControlPanelElement('span' + i).style.backgroundPosition = "0 -49px";
        }
    }
}

function initPage() {
    BATCH_TOOLKIT = new RALLY.Mashup.BatchToolkit('__WORKSPACE_OID__', '__PROJECT_OID__',
            '__PROJECT_SCOPING_UP__', '__PROJECT_SCOPING_DOWN__');

    runScheduleStateQuery();
    RALLY.Mashup.Utilities.showHelpIcon(165);
    RALLY.Mashup.Utilities.showPrintButton();
    initChartTypeButtons();
    addEventListeners();

    DROPDOWN = new RALLY.Mashup.Dropdown(BATCH_TOOLKIT, MASHUP_TYPE, 'timeboxList', 'timeboxLabel',
            'mu_super_customizable_' + MASHUP_TYPE.toLowerCase());
    DROPDOWN.invoke(createChart);
}
</script>

<style type="text/css">
    body {
        background: white;
    }

    .lbl {
        text-align: left;
        font-size: 14px;
    }

    .AxisCaption {
        font-size: 12px;
        font-style: normal;
    }

    .AxisTickLabel {
        font-size: 10px;
        font-style: normal;
    }
</style>
<style type="text/css">
    span.stackedbar {
        width: 36px;
        height: 49px;
        padding: 0 5px 0 0;
        background: url(/slm/mashup/1.21/images/stackedbar.gif) no-repeat;
        display: block;
        clear: left;
        float: left;
    }
</style>
<style type="text/css">
    span.bar {
        width: 36px;
        height: 49px;
        padding: 0 5px 0 0;
        background: url(/slm/mashup/1.21/images/bar.gif) no-repeat;
        display: block;
        clear: left;
        float: left;
    }
</style>
<style type="text/css">
    span.line {
        width: 36px;
        height: 49px;
        padding: 0 5px 0 0;
        background: url(/slm/mashup/1.21/images/line.gif) no-repeat;
        display: block;
        clear: left;
        float: left;
    }
</style>
<style type="text/css">
    span.area {
        width: 36px;
        height: 49px;
        padding: 0 5px 0 0;
        background: url(/slm/mashup/1.21/images/area.gif) no-repeat;
        display: block;
        clear: left;
        float: left;
    }
</style>
<style type="text/css">
    span.burndown {
        width: 36px;
        height: 49px;
        padding: 0 5px 0 0;
        background: url(/slm/mashup/1.21/images/burndown.gif) no-repeat;
        display: block;
        clear: left;
        float: left;
    }
</style>
<style type="text/css">
    input.nodisplay {
        display: none;
    }
</style>
</head>
<body>
<div style="float:right" id="help"></div>
<div style="float:left" id="title" class="titlebar">Super Customizable Release Chart</div>
<table>
    <tr>
        <td style="text-align: left; width: 99%;">
        <td style="text-align: right; width: 1%;">
            <img id="do" onmouseover="RALLY.Mashup.Utilities.showcbButton();" onmouseout="hidecbMenu('buttons',event);"
                 style="vertical-align: middle;"
                 src="/slm/images/menu_actions.gif"/>

            <div style="position:relative;top:5px" align="left">
                <div id="buttons" class="do-menu" style="left:0px;"
                     onmouseover="document.body.style.cursor='pointer';"
                     onmouseout="document.body.style.cursor='default';hidecbMenu('buttons',event);">
                    <a id="print" onclick="RALLY.Mashup.Utilities.printPage()">Print...</a>
                </div>
            </div>
        </td>
    </tr>
</table>
<div style="clear:both"></div>

<table>
    <tr>
        <td id="timeboxLabel" class="lbl">Release Name</td>
        <td><select id="timeboxList"></select></td>
    </tr>
</table>

<table cellspacing="10" border="1">
    <tr>
        <td valign="top">

            <fieldset>
                <legend>Chart Type</legend>
                <table>
                    <tr>
                        <th width=80 align="left">Stacked Bar</th>
                        <th width=80 align="left">Bar</th>
                    </tr>
                    <tr>
                        <td width=80>
                            <span id="span0" class="stackedbar"/>
                            <input type="radio" class="nodisplay" id="input0" name="ctGroup" checked="checked">
                        </td>
                        <td width=80>
                            <span id="span1" class="bar"/>
                            <input type="radio" class="nodisplay" id="input1" name="ctGroup">
                        </td>
                    </tr>
                    <tr>
                        <th width=80 align="left">Line</th>
                        <th width=80 align="left">Area</th>
                        <th width=80 align="left">Burndown</th>
                    </tr>
                    <tr>
                        <td width=80>
                            <span id="span2" class="line"/>
                            <input type="radio" class="nodisplay" id="input2" name="ctGroup">
                        </td>
                        <td width=80>
                            <span id="span3" class="area"/>
                            <input type="radio" class="nodisplay" id="input3" name="ctGroup">
                        </td>
                        <td width=80>
                            <span id="span4" class="burndown"/>
                            <input type="radio" class="nodisplay" id="input4" name="ctGroup">
                        </td>
                    </tr>
                </table>
            </fieldset>

            <fieldset>
                <legend>Data Options</legend>

                <div id="datasetPanel">
                </div>

                <p>
                <hr>
                <div id="idealPanel">
                </div>
                </p>

                <p>
                <hr>
                Units
                <input type="radio" name="unit_type_group" id="rbStory" value="story" checked="checked"/>
                <label for="rbStory">Story</label>

                <input type="radio" name="unit_type_group" id="rbTask" value="task"/>
                <label for="rbTask">Task</label>

                <input type="radio" name="unit_type_group" id="rbToDo" value="todo"/>
                <label for="rbToDo">To Do</label>
                </p>

                <p>
                <hr>
                <input type="checkbox" name="cbTable" id="cbTable"/>
                <label for="cbTable">Show Data Table</label>
                <br/>
                </p>

            </fieldset>

        </td>
        <td>
            <table>
                <tr>
                    <td class="lbl">
                        <div id="info_msg"></div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div id="chart_div" style="width:600px; height:400px;"></div>
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>
<br/>

<div id="table_div"></div>
</body>
</html>