jsdata = {}
rendered = {}
templates = {}
nproject = null;
animals = ['hedgehogs', 'cows', 'geese', 'pigs', 'fluffy kittens', 'puppies', 'rabid dogs', 'ponies', 'weevils']
# This is faster than parseInt, and it's more obvious what is being done
toInt = (number) ->
return number | 0
makeSelect = (name, arr) ->
sel = new HTML('select', { name: name})
for val in arr
opt = new HTML('option', { value: val})
opt.inject(val)
sel.inject(opt)
return sel
getWednesdays = (mo, y) ->
d = new Date();
if not isNaN(mo)
d.setMonth(mo);
if y
d.setFullYear(y, d.getMonth(), d.getDate())
month = d.getMonth()
wednesdays = []
d.setDate(1)
# Get the first Wednesday (day 3 of week) in the month
while d.getDay() != 3
d.setDate(d.getDate() + 1)
# Get all the other Wednesdays in the month
while d.getMonth() == month
wednesdays.push(new Date(d.getTime()))
d.setDate(d.getDate() + 7)
return wednesdays;
# check if the entry is a wildcard month
everyMonth = (s) =>
s == 'Every month' or s.match(/next month/i)
m = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
# Format the report month array. Assumes that non-month values appear first
formatRm = (array) ->
first = array[0]
if array.length == 1
return first
if first not in m
return first.concat('; (default: ', array.slice(1).join(', '),')')
return array.join(', ')
# Called by: GetAsyncJSON("reportingcycles.json?" + Math.random(), [pmc, reportdate, json.pdata[pmc].name], setReportDate)
setReportDate = (json, x) ->
pmc = x[0]
reportdate = x[1]
fullname = (x[2] or "Unknown").replace(/Apache /, "")
today = new Date()
# the entries must be in date order
dates = []
if not pmc in json
pmc = fullname
#reporting months for the pmc
rm = json[pmc]
# First check if the list contains an every month indicator
# This is necessary to ensure that the dates are added to the list in order
for sm in json[pmc]
if everyMonth(sm)
# Reset to every month
rm = m
break
# Check the months in order, so it does not matter if the data is unordered
for x,y in m
for i in rm
if (x == i)
dates.push(getWednesdays(y)[2])
# Cannot combine with the code above because that would destroy the order
ny = today.getFullYear() + 1
for x,y in m
for i in rm
if (x == i)
dates.push(getWednesdays(y, ny)[2])
nextdate = dates[0];
while (nextdate < today)
nextdate = dates.shift()
reportdate.innerHTML += "Reporting schedule: " + (if json[pmc] then formatRm(json[pmc]) else "Unknown(?)") + "
"
reportdate.innerHTML += "Next report date: " + (if nextdate then nextdate.toDateString() else "Unknown(?)") + ""
if (nextdate)
link = "https://svn.apache.org/repos/private/foundation/board/board_agenda_" + nextdate.getFullYear() +
"_" + (if nextdate.getMonth() < 9 then "0" else "") + (nextdate.getMonth() + 1) + "_" + nextdate.getDate() + ".txt"
reportdate.innerHTML += "
File your report in " + link + " when it has been seeded."
buildPanel = (pmc, title) ->
parent = document.getElementById('tab_' + pmc);
toc = document.getElementById('toc_' + pmc);
if (!toc)
toc = document.createElement('cl')
toc.setAttribute("class", "sub-nav")
toc.setAttribute("id", "toc_" + pmc)
if (parent.firstChild.nextSibling)
parent.insertBefore(toc, parent.firstChild.nextSibling);
else
parent.appendChild(toc)
linkname = title.toLowerCase().replace(/[^a-z0-9]+/, "")
li = document.createElement('dd');
li.setAttribute("role", "menu-item")
li.innerHTML = "" + title + ""
toc.appendChild(li)
div = document.createElement('div')
div.setAttribute("id", linkname + "_" + pmc);
parent.appendChild(div)
titlebox = document.createElement('div');
titlebox.innerHTML = "
"
div.appendChild(titlebox);
return div
addLine = (pmc, line) ->
line = if line then line else " "
lines = line.split(/\n/)
for xline in lines
words = xline.split(" ")
len = 0
out = ""
for word, i in words
len += word.replace(/<.+?>/, "").length + (if i == words.length - 1 then 0 else 1)
if (len >= 78)
out += "\n "
len = words[i].replace(/<.+?>/, "").length + (if i == words.length - 1 then 0 else 1)
out += words[i] + " "
templates[pmc] += out + "\n"
isNewPMC = (json,pmc,after) ->
return json.pmcdates[pmc].pmc[1] >= (after.getTime() / 1000)
PMCchanges = (json, pmc, after) ->
changes = buildPanel(pmc, "PMC changes (from committee-info)");
roster = json.pmcdates[pmc].roster
nc = 0; # newest committer start date
np = 0; # newest pmc member start date
ncn = null; # newest committer name
npn = null; # newest pmc name
afterTime = after.getTime() / 1000
pmcStartTime = json.pmcdates[pmc].pmc[2]
addLine(pmc, "## PMC changes:")
addLine(pmc)
if (pmcStartTime > afterTime)
afterTime = pmcStartTime
changes.innerHTML += "Changes since PMC creation:
"
else
changes.innerHTML += "Changes within the last 3 months:
"
# pre-flight check
c = 0; # total number of pmc members
npmc = 0; # number of recent pmc members
for k, entry of roster
c++
if (entry[1] > afterTime)
npmc++;
addLine(pmc, " - Currently " + c + " PMC members.")
if (npmc > 1)
addLine(pmc, " - New PMC members:")
for k, entry of roster
if (entry[1] > np) # find most recent member
np = entry[1] # start date
npn = entry[0]; # full name
if (entry[1] > afterTime)
changes.innerHTML += "→ " + entry[0] + " was added to the PMC on " + new Date(entry[1] * 1000).toDateString() + "
";
addLine(pmc, (if npmc > 1 then " " else "") + " - " + entry[0] + " was added to the PMC on " + new Date(entry[1] * 1000).toDateString())
if (npmc == 0)
addLine(pmc, " - No new PMC members added in the last 3 months")
changes.innerHTML += "→ No new PMC members in the last 3 months.
";
if (npn)
if (np < afterTime)
addLine(pmc, " - Last PMC addition was " + npn + " on " + new Date(np * 1000).toDateString())
changes.innerHTML += "→ " + "Last PMC addition: " + new Date(np * 1000).toDateString() + " (" + npn + ")
"
changes.innerHTML += "→ " + "Currently " + c + " PMC members.
"
changes.innerHTML += "
PMC established: " + json.pmcdates[pmc].pmc[0]
if (pmcStartTime > 0) # don't use missing time
changes.innerHTML += " (assumed actual date: " + epochSecsYYYYMMDD(pmcStartTime) + ")"
addLine(pmc)
epochSecsYYYYMMDD = (t) =>
new Date(t * 1000).toISOString().slice(0, 10)
renderFrontPage = (tpmc) ->
thisHour = toInt(new Date().getTime() / (3600*1000)) # this changes once per hour
container = document.getElementById('contents')
json = jsdata
sproject = tpmc;
hcolors = ["#000070", "#007000", "#407000", "#70500", "#700000", "#A00000"]
hvalues = ["Super Healthy", "Healthy", "Mostly Okay", "Unhealthy", "Action required!", "URGENT ACTION REQUIRED!"]
container.innerHTML = ""
for pmc, i in json.pmcs
if pmc == tpmc or not tpmc
top = document.createElement('div');
container.appendChild(top)
# If we already rendered this, just re-add it
if rendered[pmc]
container.appendChild(rendered[pmc])
return
# Stuff has broken, check that we have dates!
if (not pmc in json.pmcdates)
continue
templates[pmc] = ""
addLine(pmc, "## Description:")
if ('shortdesc' in jsdata.pdata[pmc])
addLine(pmc, " " + json.pdata[pmc].shortdesc)
else
addLine(pmc, " - Description goes here")
addLine(pmc)
a = animals[Math.floor(Math.random()*animals.length*0.999)]
addLine(pmc, "## Issues:")
addLine(pmc, " - TODO - list any issues that require board attention, \n or say \"there are no issues requiring board attention at this time\" - if not, the " + a + " will get you.")
addLine(pmc)
addLine(pmc, "## Activity:")
addLine(pmc, " - TODO - the PMC MUST provide this information")
addLine(pmc)
a = animals[Math.floor(Math.random()*animals.length*0.999)]
addLine(pmc, "## Health report:")
addLine(pmc, " - TODO - Please use this paragraph to elaborate on why the current project activity (mails, commits, bugs etc) is at its current level - Maybe " + a + " took over and are now controlling the project?")
addLine(pmc)
obj = document.createElement('div');
rendered[pmc] = obj
obj.setAttribute("id", "tab_" + pmc)
obj.style = "padding: 10px; text-align: left !important;"
obj.setAttribute("aria-hidden", "true")
title = document.createElement('h2')
title.innerHTML = json.pdata[pmc].name or pmc
obj.appendChild(title)
health = document.createElement('p');
if (json.health[pmc] && !isNaN(json.health[pmc]['cscore']))
health.style.marginTop = "10px"
health.innerHTML = "Committee Health score: " + (6.33 + (json.health[pmc]['score'] * -1.00 * (20 / 12.25))).toFixed(2) + " (" + hvalues[json.health[pmc]['cscore']] + ") (This is an automatically generated score, it is NOT authoritative in any way!)"
obj.appendChild(health)
container.appendChild(obj)
# Report date
reportdate = buildPanel(pmc, "Report date")
if (json.pdata[pmc].chair)
reportdate.innerHTML += "Committee Chair: " + json.pdata[pmc].chair + "
"
fetch("reportingcycles.json?" + thisHour, [pmc, reportdate, json.pdata[pmc].name], setReportDate)
# LDAP committee + Committer changes
mo = new Date().getMonth() - 3;
after = new Date();
after.setMonth(mo); # This also works if mo is negative
PMCchanges(json, pmc, after);
changes = buildPanel(pmc, "PMC changes (From LDAP)");
c = 0; # total number of committer + pmc changes since establishment
cu = 0; # total number of committer (user) changes
for x,y of json.changes[pmc].committer
cu++;
c++;
for x,y of json.changes[pmc].pmc
c++;
nc = 0; # newest committer date
np = 0; # newest pmc date
ncn = null; # newest committer name
npn = null; # newest pmc name
addLine(pmc, "## Committer base changes:")
addLine(pmc)
addLine(pmc, " - Currently " + json.count[pmc][1] + " committers.")
if (cu == 0) # no new committers
if (isNewPMC(json,pmc,after))
addLine(pmc, " - No changes (the PMC was established in the last 3 months)")
else
addLine(pmc, " - No new changes to the committer base since last report.")
addLine(pmc)
if (c == 0) # no changes at all
if (isNewPMC(json,pmc,after))
changes.innerHTML += "No changes - the PMC was established in the last 3 months."
else
changes.innerHTML += "No new changes to the PMC or committer base detected - (LDAP error or no changes for >2 years)"
else
changes.innerHTML += "Changes within the last 3 months:
"
# pre-flight check
npmc = 0; # recent committee group additions
for k, entry of json.changes[pmc].pmc
if (entry[1] > after.getTime() / 1000)
npmc++;
for k, entry of json.changes[pmc].pmc
if (entry[1] > np) # latest pmc member date
np = entry[1]
npn = entry[0]; # latest pmc member name
if (entry[1] > after.getTime() / 1000)
changes.innerHTML += "→ " + entry[0] + " was added to the PMC on " + new Date(entry[1] * 1000).toDateString() + "
"
if (npmc == 0) # PMC older than 3 months itself
if (isNewPMC(json,pmc,after))
changes.innerHTML += "→ No new PMC members in the 3 months since the PMC was established
";
else
changes.innerHTML += "→ No new PMC members in the last 3 months.
";
if (npn)
changes.innerHTML += "→ " + "Last PMC addition: " + new Date(np * 1000).toDateString() + " (" + npn + ")
"
# pre-flight check
ncom = 0; # number of new committers
for k, entry of json.changes[pmc].committer
if (entry[1] > after.getTime() / 1000) # entry[1] is the first seen timestamp
ncom++;
if (ncom > 1)
addLine(pmc, " - New commmitters:")
for k, entry of json.changes[pmc].committer
if (entry[1] > nc) # find the most recent entry
nc = entry[1] # the timestamp
ncn = entry[0];# full name
if (entry[1] > after.getTime() / 1000)
changes.innerHTML += "→ " + entry[0] + " was added as a committer on " + new Date(entry[1] * 1000).toDateString() + "
"
addLine(pmc, (if ncom > 1 then " " else "") + " - " + entry[0] + " was added as a committer on " + new Date(entry[1] * 1000).toDateString())
if (ncom == 0)
changes.innerHTML += "→ No new committers in the last 3 months.
";
addLine(pmc, " - No new committers added in the last 3 months")
if (ncn)
if (nc < after.getTime() / 1000)
addLine(pmc, " - Last committer addition was " + ncn + " at " + new Date(nc * 1000).toDateString())
changes.innerHTML += "→ " + "Last committer addition: " + new Date(nc * 1000).toDateString() + " (" + ncn + ")
"
else
addLine(pmc, " - Last committer addition was more than 2 years ago")
changes.innerHTML += "→ " + "Last committer addition: more than two years ago (not in the archive!)
"
changes.innerHTML += "→ " + "Currently " + json.count[pmc][1] + " committers and " + json.count[pmc][0] + " PMC members."
addLine(pmc)
# Release data
releases = buildPanel(pmc, "Releases")
addLine(pmc, "## Releases:")
addLine(pmc)
nr = 0;
lr = null;
lrn = 0;
tr = 0
for version, date of json.releases[pmc]
tr++;
if (date > lrn)
lrn = date
lr = version
if (date >= after.getTime() / 1000)
err = ""
if (new Date(date * 1000) > new Date())
err = " (This seems wrong?!)"
releases.innerHTML += "→ " + "" + version + " was released on " + new Date(date * 1000).toDateString() + err + "
"
addLine(pmc, " - " + version + " was released on " + new Date(date * 1000).toDateString() + err)
nr++;
if (nr == 0)
if (lr)
releases.innerHTML += "→ " + "Last release was " + lr + ", released on " + new Date(lrn * 1000).toDateString() + "
"
addLine(pmc, " - Last release was " + lr + " on " + new Date(lrn * 1000).toDateString())
if (lr.match("incubat") && !isNewPMC(json,pmc,after))
releases.innerHTML += "
No release since graduation
"
addLine(pmc, " - No release since graduation??? [FIX!]")
else
releases.innerHTML += "No release data could be found.
"
addLine(pmc, " - No release data could be found [FIX!]")
releases.innerHTML += "(A total of " + (tr - nr) + " older release(s) were found for " + pmc + " in our db)
"
releases.innerHTML += "
Add a release"
releases.innerHTML += " - Fetch releases from JIRA"
releases.innerHTML += " - Manage release versions
"
if (tr > 0)
div = renderReleaseChart(json.releases[pmc], pmc, releases);
releases.appendChild(div)
addLine(pmc)
mlbox = buildPanel(pmc, "Mailing lists");
ul = document.createElement('ul')
ul.style.textAlign = "left;"
mlbox.appendChild(ul)
prev = ""
f = 0
addLine(pmc, "## Mailing list activity:")
addLine(pmc)
addLine(pmc, " - TODO Please explain what the following statistics mean for the project." +
" If there is nothing significant in the figures, omit this section.")
addLine(pmc)
first = ['users', 'dev', 'commits', 'private', 'bugs', 'modules-dev'];
for i,x of first
ml = pmc + ".apache.org-" + first[i]
if (ml != prev && ml.search("infra") < 0 && json.mail[pmc] && json.mail[pmc][ml])
f++;
prev = ml
d = ml.split(".org-");
mlname = d[1] + "@" + d[0] + ".org"
lookup = d[0].split(/\./)[0] + "-" + d[1]
x = renderChart(json.mail[pmc], ml, obj, if (json.delivery[pmc] && json.delivery[pmc][lookup]) then json.delivery[pmc][lookup].weekly else {})
total = x[0]
diff = x[1]
div = x[2]
add = ""
if (json.delivery[pmc] && json.delivery[pmc][lookup])
add = ":\n - " + json.delivery[pmc][lookup].quarterly[0] + " emails sent to list (" + json.delivery[pmc][lookup].quarterly[1] + " in previous quarter)";
text = "Currently: " + total + " subscribers (up " + diff + " in the last 3 months)"
if (diff < 0)
text = "Currently: " + total + " subscribers (down " + diff + " in the last 3 months)"
if (d[1] != "private" && d[1] != "security" && d[1] != "commits")
addLine(pmc, " - " + mlname + ": ")
addLine(pmc, " - " + total + " subscribers (down " + diff + " in the last 3 months)" + add)
addLine(pmc)
else
if (d[1] != "private" && d[1] != "security" && d[1] != "commits")
addLine(pmc, " - " + mlname + ": ")
addLine(pmc, " - " + total + " subscribers (up " + diff + " in the last 3 months)" + add)
addLine(pmc)
if (json.delivery[pmc] && json.delivery[pmc][lookup])
text += " (" + json.delivery[pmc][lookup].quarterly[0] + " emails sent in the past 3 months, " + json.delivery[pmc][lookup].quarterly[1] + " in the previous cycle)"
p = document.createElement('li');
p.innerHTML = "" + mlname + ":
" + text
p.appendChild(div)
ul.appendChild(p)
for ml of json.mail[pmc]
skip = false
for i in first
xml = pmc + ".apache.org-" + first[i]
if (ml.search(xml) == 0)
skip = true
if (!skip)
f++;
if (ml != prev && ml.search("infra") < 0)
prev = ml
d = ml.split(".org-");
mlname = d[1] + "@" + d[0] + ".org"
lookup = d[0].split(/\./)[0] + "-" + d[1]
x = renderChart(json.mail[pmc], ml, obj, if (json.delivery[pmc] && json.delivery[pmc][lookup]) then json.delivery[pmc][lookup].weekly else {})
total = x[0]
diff = x[1]
div = x[2]
add = ""
if (json.delivery[pmc] && json.delivery[pmc][lookup])
add = ":\n - " + json.delivery[pmc][lookup].quarterly[0] + " emails sent to list (" + json.delivery[pmc][lookup].quarterly[1] + " in previous quarter)";
text = "Currently: " + total + " subscribers (up " + diff + " in the last 3 months)"
if (diff < 0)
text = "Currently: " + total + " subscribers (down " + diff + " in the last 3 months)"
if (d[1] != "private" && d[1] != "security" && d[1] != "commits")
addLine(pmc, " - " + mlname + ": ")
addLine(pmc, " - " + total + " subscribers (down " + diff + " in the last 3 months)" + add)
addLine(pmc)
else
if (d[1] != "private" && d[1] != "security" && d[1] != "commits")
addLine(pmc, " - " + mlname + ": ")
addLine(pmc, " - " + total + " subscribers (up " + diff + " in the last 3 months)" + add)
addLine(pmc)
if (json.delivery[pmc] && json.delivery[pmc][lookup])
text += " (" + json.delivery[pmc][lookup].quarterly[0] + " emails sent in the past 3 months, " + json.delivery[pmc][lookup].quarterly[1] + " in the previous cycle)"
p = document.createElement('li');
p.innerHTML = "" + mlname + ":
" + text
p.appendChild(div)
ul.appendChild(p)
addLine(pmc)
if json.bugzilla[pmc][0] or json.bugzilla[pmc][1] > 0
renderBZ(pmc)
if json.jira[pmc][0] > 0 or json.jira[pmc][1] > 0
renderJIRA(pmc)
# Reporting example
template = buildPanel(pmc, "Report template");
template.innerHTML += "" + templates[pmc] + "
"
# Fetch from JIRA dialog
dialog = document.createElement('div');
dialog.setAttribute("id", "dialog_" + pmc);
dialog.setAttribute("title", "Fetch data from JIRA for " + pmc)
dialog.setAttribute("style", "display: none;")
if (jsdata.keys[pmc] && jsdata.keys[pmc].length > 0)
dialog.innerHTML = "Suggested JIRA Keys: " + jsdata.keys[pmc].join(", ") + "
"
else
dialog.innerHTML = "No JIRA keys found - are you sure this project uses JIRA?
"
dialog.innerHTML += ""+
"If you have multiple JIRA projects and they only have the version number in their release versions, please enter the component name in the 'prepend' field.
"
document.getElementById('tab_' + pmc).appendChild(dialog)
# Manually add release dialog
rdialog = document.createElement('div');
rdialog.setAttribute("id", "rdialog_" + pmc);
rdialog.setAttribute("title", "Add a release for " + pmc)
rdialog.setAttribute("style", "display: none;")
rdialog.innerHTML = ""
container.appendChild(rdialog)
renderJIRA = (pmc) ->
obj = buildPanel(pmc, "JIRA Statistics")
addLine(pmc, "## JIRA activity:")
addLine(pmc)
addLine(pmc, " - " + jsdata.jira[pmc][0] + " JIRA tickets created in the last 3 months");
addLine(pmc, " - " + jsdata.jira[pmc][1] + " JIRA tickets closed/resolved in the last 3 months");
addLine(pmc)
obj.innerHTML += jsdata.jira[pmc][0] + " JIRA tickets created in the last 3 months
";
obj.innerHTML += jsdata.jira[pmc][1] + " JIRA tickets closed/resolved in the last 3 months
";
if (jsdata.keys[pmc])
obj.innerHTML += "Keys used: " + jsdata.keys[pmc].join(", ") + "
"
obj.innerHTML += "Keys with tickets: " + jsdata.jira[pmc][2].join(", ") + ""
renderBZ = (pmc) ->
obj = buildPanel(pmc, "Bugzilla Statistics")
addLine(pmc, "## Bugzilla Statistics:")
addLine(pmc)
addLine(pmc, " - " + jsdata.bugzilla[pmc][0] + " Bugzilla tickets created in the last 3 months");
addLine(pmc, " - " + jsdata.bugzilla[pmc][1] + " Bugzilla tickets resolved in the last 3 months");
addLine(pmc)
obj.innerHTML += jsdata.bugzilla[pmc][0] + " Bugzilla tickets created in the last 3 months
";
obj.innerHTML += jsdata.bugzilla[pmc][1] + " Bugzilla tickets resolved in the last 3 months
";
obj.innerHTML += "Tickets were found for the following products:
" + Object.keys(jsdata.bugzilla[pmc][2]).sort().join(", ") + ""
renderChart = (json, name, container, delivery) ->
chartDiv = document.createElement('div')
chartDiv.setAttribute("id", name + "_chart")
dates = []
noweekly = 0;
for date, count of json[name]
dates.push(date)
for date, count of delivery
noweekly++;
d = name.split(".org-");
mlname = d[1] + "@" + d[0] + ".org"
dates.sort();
cu = 0;
narr = []
hitFirst = false
dp = new Date();
dp.setMonth(dp.getMonth() - 3);
odp = new Date();
odp.setMonth(odp.getMonth() - 6);
difference = 0
for date in dates
dateString = new Date(parseInt(date) * 1000);
if (dateString > dp)
difference += json[name][date]
cu = cu + json[name][date];
if (cu > 0)
hitFirst = true
if ((cu > 0 || hitFirst) && dateString >= odp)
if (noweekly > 0)
narr.push([dateString, cu, delivery[date] or 0])
else
narr.push([dateString, cu])
data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', "List members");
if (noweekly > 0)
data.addColumn('number', "Emails sent per week");
data.addRows(narr);
options = {
title: 'Mailing list stats for ' + mlname,
backgroundColor: 'transparent',
width: 900,
height: 260,
legend: {
position: 'none',
maxLines: 3
},
vAxis: {
format: "#"
},
vAxes: if (noweekly > 0) then [
{
title: 'Emails per week',
titleTextStyle: {
color: '#DD0000'
},
min: 0
}, {
title: 'Subscribers',
titleTextStyle: {
color: '#0000DD'
},
min: 0,
minValue: 0
},
] else [{
title: 'Subscribers',
titleTextStyle: {
color: '#0000DD'
}
},
],
series: {
0: {
type: "line",
pointSize: 4,
lineWidth: 2,
targetAxisIndex: if (noweekly > 0) then 1 else null
},
1: {
type: "bars",
targetAxisIndex: if (noweekly > 0) then 0 else [0, 1]
}
},
seriesType: "bars",
tooltip: {
isHtml: true
},
};
chart = new google.visualization.ComboChart(chartDiv);
chart.draw(data, options);
return [cu, difference, chartDiv];
renderReleaseChart = (releases, name, container) ->
chartDiv = null
if (document.getElementById(name + "_releasechart"))
chartDiv = document.getElementById(name + "_releasechart")
else
chartDiv = document.createElement('div')
chartDiv.setAttribute("id", name + "_releasechart")
narr = []
maxLen = 1;
for version, date of releases
x = version.match(/(\d+)\.(\d+)/)
if (x && x[2].length > maxLen)
maxLen = x[2].length;
for version, date of releases
if (new Date(releases[version] * 1000).getFullYear() >= 1999)
major = parseFloat(version) or 1
x = version.match(/(\d+)\.(\d+)/)
if (x)
while (x[2].length < maxLen)
x[2] = "0" + x[2]
major = parseFloat(x[1] + "." + x[2])
narr.push([new Date(releases[version] * 1000), major, version + " - " + new Date(releases[version] * 1000).toDateString()])
data = new google.visualization.DataTable();
data.addColumn('datetime', 'Date');
data.addColumn('number', 'Version')
data.addColumn('string', 'tooltip');
data.setColumnProperty(2, 'role', 'tooltip');
data.addRows(narr);
options = {
title: 'Release timeline for ' + name,
height: 240,
width: 800,
backgroundColor: 'transparent',
series: [{
pointSize: 15
},
],
pointShape: {
type: 'star',
sides: 5
}
};
chart = new google.visualization.ScatterChart(chartDiv);
chartDiv.style.marginLeft = "50px";
chart.draw(data, options);
return chartDiv
fetchJIRA = (pmc, project, prepend) ->
if (project && project.length > 1)
fetch("jiraversions.py?project=" + pmc + "&jiraname=" + project + "&prepend=" + prepend, null,
(json) ->
if json && json.versions
for version in json.versions
jsdata.releases[pmc][version] = json.versions[version]
$('#dialog_' + pmc).dialog("close")
nproject = pmc
alert("Fetched " + json.added + " releases from JIRA!")
renderFrontPage(jsdata)
else if (json && json.status)
alert(json.status)
else if (json)
alert(JSON.stringify(json))
else
alert("Couldn't find any release data :(")
)
addRelease = (pmc, version, date) ->
if (version && version.length > 1 && date.match(/^(\d\d\d\d)-(\d\d)-(\d\d)$/))
x = date.split("-");
y = new Date(x[0], parseInt(x[1]) - 1, parseInt(x[2]));
nn = parseInt(y.getTime() / 1000);
now = (new Date().getTime()) / 1000;
if (nn >= now)
alert("Date is in the future!")
return
fetch("addrelease.py?json=true&committee=" + pmc + "&version=" + escape(version) + "&date=" + nn, null,
(json) ->
if (json && json.versions)
n = 0;
for version in json.versions
n++;
jsdata.releases[pmc][version] = json.versions[version]
$('#rdialog_' + pmc).dialog("close")
nproject = pmc
alert("Release added!")
renderFrontPage(jsdata)
else if (json && json.status)
alert(json.status)
else if (json)
alert(JSON.stringify(json))
else
alert("Couldn't add release data :(")
)