accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ctubb...@apache.org
Subject [08/53] [abbrv] ACCUMULO-656,ACCUMULO-658 Update package names
Date Fri, 06 Sep 2013 18:22:36 GMT
http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/monitor/src/main/resources/web/functions.js
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/web/functions.js b/server/monitor/src/main/resources/web/functions.js
new file mode 100644
index 0000000..f4bbdd1
--- /dev/null
+++ b/server/monitor/src/main/resources/web/functions.js
@@ -0,0 +1,21 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+function toggle(selection) {
+  var p = document.getElementById(selection);
+  var style = p.className;
+  p.className = style == "hide" ? "show" : "hide";
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/monitor/src/main/resources/web/screen.css
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/web/screen.css b/server/monitor/src/main/resources/web/screen.css
new file mode 100644
index 0000000..7af3af3
--- /dev/null
+++ b/server/monitor/src/main/resources/web/screen.css
@@ -0,0 +1,388 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+/* basic screen style for all pages */
+html,body {
+	height: 100%;
+	margin: 0;
+	padding: 0;
+	color: #333333;
+	font-size: 10pt;
+	font-family: verdana, arial, sans-serif;
+	text-align: center;
+}
+
+#content-wrapper {
+	position: relative;
+	min-height: 100%;
+}
+
+* #content-wrapper {
+	height: 100%;
+}
+
+#content {
+	position: absolute;
+	left: 0;
+	right: 0;
+	top: 0;
+	bottom: 0;
+	padding-bottom: 0;
+}
+
+#header {
+	position: absolute;
+	padding-top: 0;
+	top: 0;
+	left: 0;
+	right: 0;
+	height: 8.0em;
+	color: #c4c4c4;
+	background-color: #304065;
+	text-align: center;
+}
+
+#banner {
+	height: 1.5em;
+	font-size: 1.0em;
+}
+
+#headertitle {
+	position: absolute;
+	top: 0;
+	left: 0;
+	right: 0;
+}
+
+#subheader {
+	position: absolute;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	font-size: .92em;
+}
+
+#footer {
+	position: absolute;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	padding: 0;
+	height: 1.5em;
+	font-size: 1.0em;
+}
+
+#main {
+	position: absolute;
+	top: 8.0em;
+	left: 11em;
+	right: 0;
+	bottom: 1.5em;
+	padding: 0.6em;
+	overflow: scroll;
+}
+
+#nav {
+	position: absolute;
+	top: 8.0em;
+	left: 0;
+	bottom: 0;
+	padding: 0.5em;
+	width: 10em;
+	color: #304065;
+	background-color: #c4c4c4;
+	text-align: left;
+}
+
+#nav-title {
+	margin-left: auto;
+	margin-right: auto;
+	text-align: center;
+	font-size: 1.1em;
+}
+
+h1 {
+	font-size: 2.2em;
+	font-variant: small-caps;
+	text-align: center;
+}
+
+h2 {
+	width: 100%;
+	font-size: 1.3em;
+	text-align: center;
+}
+
+h2.error {
+	width: 100%;
+	color: #ff0000;
+	background-color: #000000;
+}
+
+h2.error a {
+	color: #ff0000;
+	background-color: #000000;
+}
+
+caption {
+	margin-left: auto;
+	margin-right: auto;
+}
+
+caption.error {
+	color: #ff0000;
+	background-color: #000000;
+}
+
+hr {
+	border: 0;
+	height: 1px;
+	background-color: #304065;
+	color: #304065;
+}
+
+table {
+	margin-left: auto;
+	margin-right: auto;
+	min-width: 60%;
+	border: 1px #333333 solid;
+	border-spacing-top: 0;
+	border-spacing-bottom: 0;
+	font-size: 9pt;
+	border: 1px #333333 solid;
+	border: 1px #333333 solid;
+}
+
+/*
+The following is to avoid a problem with the flot
+javascript library.  This file sets min-width to 60% 
+for all tables.  This make the html generated by
+flot.js not work.  Flot creates a class called legend
+used in a div that has a child table.  This sets 
+min-width to 0 for that child table enabling it
+to render correctly.  
+*/
+div.legend > table {
+        min-width: 0%;
+}
+
+table.sortable {
+	border-left: 0;
+	border-right: 0;
+	border-top: 1px #333333 dotted;
+	border-bottom: 1px #333333 dotted;
+}
+
+td {
+	border-top: 0;
+	border-bottom: 0;
+	border-left: 0;
+	border-right: 0;
+	border-spacing-top: 0;
+	border-spacing-bottom: 0;
+	padding-left: 0.5em;
+	padding-right: 0.5em;
+	padding-top: 0.15em;
+	padding-bottom: 0.15em;
+	color: #333333;
+}
+
+th {
+	border-top: 0;
+	border-bottom: 3px #333333 solid;
+	border-left: 1px #333333 dotted;
+	border-right: 0;
+	border-spacing-top: 0;
+	border-spacing-bottom: 0;
+	text-align: center;
+	font-variant: small-caps;
+	padding-left: 0.5em;
+	padding-right: 0.5em;
+	padding-top: 0.2em;
+	padding-bottom: 0.2em;
+	color: #333333;
+	font-size: 10pt;
+	vertical-align: bottom;
+}
+
+td.firstcell {
+	border-left: 0;
+}
+
+th.firstcell {
+	border-left: 0;
+}
+
+a {
+	text-decoration: none;
+	color: #0000ff;
+	line-height: 1.5em;
+}
+
+a:hover {
+	color: #004400;
+	text-decoration: underline;
+}
+
+a img {
+	border: 0px;
+}
+
+div.show {
+	display: block;
+}
+
+div.hide {
+	display: none;
+}
+
+div.progress-chart {
+	border: 1px solid #333333;
+	border-spacing: 0;
+	width: 150px;
+	float: left;
+}
+
+div.progress-chart>div {
+	height: 20px;
+	background-color: #0000ff;
+}
+
+pre.logevent {
+	margin: 0;
+}
+
+.noborder {
+	border: 0;
+	border-spacing: 0;
+	border-bottom: 0;
+	border-right: 0;
+}
+
+.noborder td {
+	vertical-align: top;
+}
+
+.table-caption {
+	font-size: 2em;
+	font-variant: small-caps;
+	text-align: center;
+}
+
+.table-subcaption {
+	font-size: 0.9em;
+}
+
+.left {
+	text-align: left;
+}
+
+.right {
+	text-align: right;
+	margin-right: 0;
+}
+
+.error {
+	color: #ffffff;
+	background-color: #ff0000;
+}
+
+.error a {
+	color: #ffffff;
+	background-color: #ff0000;
+}
+
+.warning {
+	background-color: #ffff33;
+}
+
+.highlight {
+	background-color: #cef4b5;
+}
+
+.smalltext {
+	font-size: 0.8em;
+}
+
+.center {
+	text-align: center;
+	padding: 0.5em;
+}
+
+.plotHeading {
+    text-align: center;
+    font-size: 1.5em;
+}
+.nowrap {
+    white-space:nowrap;
+}
+
+.viscontrol {
+    border: 1px solid #c4c4c4;
+    padding: 5px;
+}
+
+#vishoverinfo {
+    visibility: hidden;
+    position: absolute;
+    border: 1px solid #c4c4c4;
+    background-color: #ffffff;
+}
+
+#shell {
+    text-align: left;
+    color: #55d839;
+    border: 1px;
+    padding-left: 5px;
+    background-color: #000000;
+    height: 40em;
+    overflow: auto;
+    font-family: Monaco, monospace;
+    font-size: 100%;
+}
+
+#shell span {
+    display: inline;
+}
+
+#shell input {
+    display: inline;
+    border: none;
+    width: 60%;
+    color: #55d839;
+    background-color: #000000;
+    font-family: Monaco, monospace;
+    font-size: 100%;
+}
+
+#shell pre {
+    font-family: Monaco, monospace;
+    font-size: 100%;
+}
+
+#login {
+    text-align: left;
+}
+
+#login table {
+    margin-left: 0;
+    min-width: 0%;
+}
+
+#loginError {
+    text-align: left;
+    color: red;
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/monitor/src/main/resources/web/up.gif
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/web/up.gif b/server/monitor/src/main/resources/web/up.gif
new file mode 100644
index 0000000..b272cbb
Binary files /dev/null and b/server/monitor/src/main/resources/web/up.gif differ

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/monitor/src/main/resources/web/vis.js
----------------------------------------------------------------------
diff --git a/server/monitor/src/main/resources/web/vis.js b/server/monitor/src/main/resources/web/vis.js
new file mode 100644
index 0000000..c0f8b3f
--- /dev/null
+++ b/server/monitor/src/main/resources/web/vis.js
@@ -0,0 +1,409 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+// size and spacing variables
+var dotSpacing = 10; // spacing between centers of dots (radius)
+var dotPadding = 0.5; // dot padding
+var minDotRadius = 3; // min dot radius
+var maxDotRadius = dotSpacing - dotPadding;
+
+// arrays of information about each dot
+var stats = {'servers': []};
+var dots = new Array(0); // current sizes and change directions
+var mousedDot = -1; // the dot currently under the mouse
+
+var colorPalette = ['#0000CC', '#0014B8', '#0029A3', '#003D8F', '#00527A', '#006666', '#007A52', '#008F3D', '#00A329', '#00B814', '#00CC00', '#14D100', '#29D600', '#3DDB00', '#52E000', '#66E600', '#7AEB00', '#8FF000', '#A3F500', '#B8FA00', '#CCFF00', '#CCFF00', '#CCF200', '#CCE600', '#CCD900', '#CCCC00', '#CCBF00', '#CCB200', '#CCA600', '#CC9900', '#CC8C00', '#CC8000', '#CC7300', '#CC6600', '#CC5900', '#CC4C00', '#CC4000', '#CC3300', '#CC2600', '#CC1A00', '#CC0D00', '#CC0000'];
+
+var nullColor = '#F5F8FA';
+var deadColor = '#B000CC';
+
+// animation variables
+var drawing = false;
+var canvas = document.getElementById('visCanvas');
+var context = canvas.getContext('2d');
+
+// mouse handling for server information display
+document.getElementById('hoverable').addEventListener('mouseover', showId, false);
+document.getElementById('hoverable').addEventListener('mousemove', showId, false);
+document.getElementById('hoverable').addEventListener('mouseout', hideId, false);
+document.getElementById('vishoverinfo').addEventListener('click', goToServer, false);
+canvas.addEventListener('click', goToServer, false);
+
+// initialize settings based on request parameters
+var main = document.getElementById('main');
+var speedStatType;
+var colorStatType;
+var speedDisabled = true;
+var useCircles = true;
+setShape(document.getElementById('shape'));
+setSize(document.getElementById('size'));
+setMotion(document.getElementById('motion'));
+setColor(document.getElementById('color'));
+
+// xml loading variables
+var xmlReturned = true;
+var xmlhttp=new XMLHttpRequest(); // don't bother allowing for IE 5 or 6 since canvas won't work
+xmlhttp.onreadystatechange=function() {
+  handleNewData();
+}
+self.setInterval("getXML()",5000);
+//self.setInterval("drawDots()",20);
+
+window.requestAnimFrame = (function(callback){
+  return window.requestAnimationFrame ||
+  window.webkitRequestAnimationFrame ||
+  window.mozRequestAnimationFrame ||
+  window.oRequestAnimationFrame ||
+  window.msRequestAnimationFrame ||
+  function(callback){
+    window.setTimeout(callback, 1000 / 60);
+  };
+})();
+
+function handleNewData() {
+  if (xmlhttp.readyState!=4) {
+    return;
+  }
+  if (xmlhttp.status!=200 || xmlhttp.responseText==null) {
+    xmlReturned = true;
+    return;
+  }
+  var newstats = eval('(' + xmlhttp.responseText + ')');
+  for (var i in newstats.servers) {
+    for (var s in statNames) {
+      if (statNames[s])
+        continue;
+      newstats.servers[i][s] = Math.max(0,Math.floor(significance[s]*newstats.servers[i][s])/significance[s]);
+      if (adjustMax[s])
+        maxStatValues[s] = Math.max(newstats.servers[i][s],maxStatValues[s]);
+    }
+  }
+  
+  initDerivedInfo(newstats);
+  var oldstats = stats;
+  while(drawing) {}
+  stats = newstats;
+  delete oldstats;
+  xmlReturned = true;
+}
+
+// set max and average
+function setDerivedStats(serverStats) {
+  var avgStat = 0;
+  var maxStat = 0;
+  var maxIndex = 0;
+  for (var s in statNames) {
+    if (statNames[s])
+      continue;
+    normStat = serverStats[s]/maxStatValues[s];
+    if (normStat > 0)
+      avgStat += normStat;
+    if (maxStat < normStat) {
+      maxStat = normStat;
+      maxIndex = s;
+    }
+  }
+  serverStats.allmax = Math.floor(significance.allmax*Math.min(1,maxStat))/significance.allmax;
+  serverStats.allavg = Math.floor(significance.allavg*avgStat/numNormalStats)/significance.allavg;
+  serverStats.maxStat = maxIndex;
+}
+
+function initDerivedInfo(newstats) {
+  for (var i in newstats.servers) {
+    if ('dead' in newstats.servers[i] || 'bad' in newstats.servers[i]) {
+      continue;
+    }
+    if (i >= dots.length) {
+      dots.push({'size': maxDotRadius, 'growing': false});
+    }
+    setDerivedStats(newstats.servers[i]);
+  }
+}
+
+// construct server info for hover
+function getInfo(serverStats) {
+  var extra = '<strong>' + serverStats.ip + '</strong>';
+  if ('dead' in serverStats || 'bad' in serverStats)
+    return extra;
+  extra = extra + ' (' + serverStats.hostname + ')';
+  var j = 0;
+  for (var s in statNames) {
+    if (j % 4 == 0)
+      extra = extra + '<br>\n';
+    extra = extra + '&nbsp;&nbsp;' + s + ': <strong>' + serverStats[s] + '</strong>';
+    j++;
+  }
+  extra = extra + ' (' + serverStats.maxStat + ')';
+  return extra;
+}
+
+// reload xml
+function getXML() {
+  if (xmlReturned == true) {
+    xmlReturned = false;
+    xmlhttp.open('POST',jsonurl,true);
+    xmlhttp.send();
+  }
+}
+
+// redraw
+function drawDots() {
+  requestAnimFrame(drawDots);
+  
+  var width = Math.ceil(Math.sqrt(stats.servers.length));
+  var height = Math.ceil(stats.servers.length/width);
+  var x;
+  var y;
+  var server
+  var sizeChange;
+  drawing = true;
+  for (var i in stats.servers) {
+    server = stats.servers[i];
+    x = i % width;
+    y = Math.floor(i / width);
+    if ('bad' in server || 'dead' in server) {
+      strokeDot(x,y,maxDotRadius-1,deadColor);
+      continue;
+    }
+    if (speedDisabled || Math.floor(dots[i].size) > maxDotRadius) {
+      // check for resize by the user
+      dots[i].size = maxDotRadius;
+    } else if (server[speedStatType]<=0) {
+      // if not changing size, increase to max radius
+      if (dots[i].size < maxDotRadius)
+        dots[i].size = dots[i].size + 1;
+      if (dots[i].size > maxDotRadius)
+        dots[i].size = maxDotRadius;
+    } else {
+      sizeChange = getStat(i,speedStatType);
+      if (dots[i].growing) {
+        dots[i].size = dots[i].size + sizeChange;
+        if (dots[i].size + sizeChange > maxDotRadius) {
+          dots[i].growing = false;
+        }
+      }
+      else {
+        dots[i].size = dots[i].size - sizeChange;
+        if (dots[i].size - sizeChange < minDotRadius) {
+          dots[i].growing = true;
+        }
+      }
+    }
+    drawDot(x,y,Math.floor(dots[i].size),getColor(getStat(i,colorStatType)));
+  }
+  // mousedDot shouldn't be set to an invalid dot, but stats might have changed since then
+  if (mousedDot >= 0 && mousedDot < stats.servers.length)
+    document.getElementById('vishoverinfo').innerHTML=getInfo(stats.servers[mousedDot]);
+  drawing = false;
+}
+
+// fill in a few grey dots
+function drawGrid() {
+  context.clearRect(0, 0, canvas.width, canvas.height);
+  for (var i=0, k=0; i < canvas.width; i+=dotSpacing*2,k++) {
+    for (var j=0, l=0; j < canvas.height; j+=dotSpacing*2,l++) {
+      drawDot(k,l,maxDotRadius,nullColor);
+    }
+  }
+}
+
+// fill a dot specified by indices into dot grid
+function drawDot(i,j,r,c) {
+  var x = i*dotSpacing*2 + dotSpacing;
+  var y = j*dotSpacing*2 + dotSpacing;
+  context.clearRect(x-dotSpacing, y-dotSpacing, dotSpacing*2, dotSpacing*2);
+  if (useCircles)
+    fillCircle(x,y,r-dotPadding,c);
+  else
+    fillSquare(x-r,y-r,(r-dotPadding)*2,c);
+}
+
+// stroke a dot specified by indices into dot grid
+function strokeDot(i,j,r,c) {
+  var x = i*dotSpacing*2 + dotSpacing;
+  var y = j*dotSpacing*2 + dotSpacing;
+  context.clearRect(x-dotSpacing, y-dotSpacing, dotSpacing*2, dotSpacing*2);
+  if (useCircles)
+    strokeCircle(x,y,r-dotPadding,c);
+  else
+    strokeSquare(x-r,y-r,(r-dotPadding)*2,c);
+}
+
+function getStat(dotIndex,statIndex) {
+  return Math.min(1,stats.servers[dotIndex][statIndex]/maxStatValues[statIndex]);
+}
+
+// translate color between 0 and maxObservedColor into an html color code
+function getColor(normColor) {
+  return colorPalette[Math.round((colorPalette.length-1)*normColor)];
+}
+
+function strokeCircle(x,y,r,c) {
+  context.strokeStyle = c;
+  context.lineWidth = 2;
+  context.beginPath();
+  context.arc(x,y,r,0,Math.PI*2,true);
+  context.closePath();
+  context.stroke();
+}
+
+function fillCircle(x,y,r,c) {
+  context.fillStyle = c;
+  context.beginPath();
+  context.arc(x,y,r,0,Math.PI*2,true);
+  context.closePath();
+  context.fill();
+}
+
+function strokeSquare(x,y,d,c) {
+  context.strokeStyle = c;
+  context.lineWidth = 2;
+  context.strokeRect(x,y,d,d);
+}
+
+function fillSquare(x,y,d,c) {
+  context.fillStyle = c;
+  context.fillRect(x,y,d,d);
+}
+
+// callback for shape selection
+function setShape(obj) {
+  switch (obj.selectedIndex) {
+    case 0:
+      useCircles = true;
+      break;
+    case 1:
+      useCircles = false;
+      break;
+    default:
+      useCircles = true;
+  }
+  drawGrid();
+  setState();
+}
+
+// callback for size selection
+function setSize(obj) {
+  switch (obj.selectedIndex) {
+    case 0:
+      dotSpacing = 5;
+      minDotRadius = 1;
+      break;
+    case 1:
+      dotSpacing = 10;
+      minDotRadius = 3;
+      break;
+    case 2:
+      dotSpacing = 20;
+      minDotRadius = 5;
+      break;
+    case 3:
+      dotSpacing = 40;
+      minDotRadius = 7;
+      break;
+    default:
+      dotSpacing = 10;
+      minDotRadius = 3;
+  }
+  maxDotRadius = dotSpacing - dotPadding;
+  drawGrid();
+  setState();
+}
+
+// callback for motion selection
+function setMotion(obj) {
+  if (obj.selectedIndex==0) {
+    speedDisabled = true;
+    setState();
+    return;
+  }
+  var i = 1;
+  for (var s in statNames) {
+    if (i==obj.selectedIndex) {
+      speedStatType = s;
+      break;
+    }
+    i++;
+  }
+  speedDisabled = false;
+  setState();
+}
+
+// callback for color selection
+function setColor(obj) {
+  var i = 0;
+  for (var s in statNames) {
+    if (i==obj.selectedIndex) {
+      colorStatType = s;
+      break;
+    }
+    i++;
+  }
+  setState();
+}
+
+// hide server info on mouseout
+function hideId(e) {
+  document.getElementById('vishoverinfo').style.visibility='hidden';
+}
+
+// display server info on mouseover
+function showId(e) {
+  var x;
+  var y;
+  if (e.pageX || e.pageY) {
+    x = e.pageX + main.scrollLeft;
+    y = e.pageY + main.scrollTop;
+  }
+  else {
+    // clientX and clientY unimplemented
+    return;
+  }
+  var relx = x - canvas.offsetLeft - main.offsetLeft;
+  var rely = y - canvas.offsetTop - main.offsetTop;
+  var width = Math.ceil(Math.sqrt(stats.servers.length));
+  gotDot = Math.floor(relx/(dotSpacing*2)) + width*Math.floor(rely/(dotSpacing*2));
+  mousedDot = -1;
+  if (relx < (width*dotSpacing*2) && gotDot >= 0 && gotDot < stats.servers.length) {
+    mousedDot = gotDot;
+    document.getElementById('vishoverinfo').style.left=relx+canvas.offsetLeft;
+    document.getElementById('vishoverinfo').style.top=Math.max(0,rely+canvas.offsetTop-70);
+    document.getElementById('vishoverinfo').style.visibility='visible';
+  }
+  else {
+    document.getElementById('vishoverinfo').style.visibility='hidden';
+  }
+}
+
+function setState() {
+  var url = visurl+'?shape='+(useCircles?'circles':'squares')+'&size='+(dotSpacing*2)+(speedDisabled ? '' : '&motion='+speedStatType)+'&color='+colorStatType;
+  window.history.replaceState(window.history.state,'Server Activity',url);
+}
+
+// go to server page on click
+function goToServer(e) {
+  // mousedDot shouldn't be set to an invalid dot, but stats might have changed since then
+  if (mousedDot >= 0 && mousedDot < stats.servers.length)
+    window.location = serverurl + stats.servers[mousedDot].ip;
+}
+
+window.onload = function() {
+  drawGrid();
+  drawDots();
+  getXML();
+}
+

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/monitor/src/test/java/org/apache/accumulo/monitor/ShowTraceLinkTypeTest.java
----------------------------------------------------------------------
diff --git a/server/monitor/src/test/java/org/apache/accumulo/monitor/ShowTraceLinkTypeTest.java b/server/monitor/src/test/java/org/apache/accumulo/monitor/ShowTraceLinkTypeTest.java
new file mode 100644
index 0000000..a630434
--- /dev/null
+++ b/server/monitor/src/test/java/org/apache/accumulo/monitor/ShowTraceLinkTypeTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.monitor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.apache.accumulo.trace.thrift.RemoteSpan;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ShowTraceLinkTypeTest {
+  
+  @Test
+  public void testTraceSortingForMonitor() {
+    /*
+     * public RemoteSpan(String sender, String svc, long traceId, long spanId, long parentId, long start, long stop, String description, Map<String,String>
+     * data)
+     */
+    ArrayList<RemoteSpan> spans = new ArrayList<RemoteSpan>(10), expectedOrdering = new ArrayList<RemoteSpan>(10);
+    
+    // "Random" ordering
+    spans.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 55l, 75l, "desc5", Collections.<String,String> emptyMap()));
+    spans.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 25l, 30l, "desc2", Collections.<String,String> emptyMap()));
+    spans.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 85l, 90l, "desc8", Collections.<String,String> emptyMap()));
+    spans.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 45l, 60l, "desc4", Collections.<String,String> emptyMap()));
+    spans.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 35l, 55l, "desc3", Collections.<String,String> emptyMap()));
+    spans.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 95l, 110l, "desc9", Collections.<String,String> emptyMap()));
+    spans.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 65l, 80l, "desc6", Collections.<String,String> emptyMap()));
+    spans.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 100l, 120l, "desc10", Collections.<String,String> emptyMap()));
+    spans.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 15l, 25l, "desc1", Collections.<String,String> emptyMap()));
+    spans.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 75l, 100l, "desc7", Collections.<String,String> emptyMap()));
+    
+    // We expect them to be sorted by 'start'
+    expectedOrdering.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 15l, 25l, "desc1", Collections.<String,String> emptyMap()));
+    expectedOrdering.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 25l, 30l, "desc2", Collections.<String,String> emptyMap()));
+    expectedOrdering.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 35l, 55l, "desc3", Collections.<String,String> emptyMap()));
+    expectedOrdering.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 45l, 60l, "desc4", Collections.<String,String> emptyMap()));
+    expectedOrdering.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 55l, 75l, "desc5", Collections.<String,String> emptyMap()));
+    expectedOrdering.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 65l, 80l, "desc6", Collections.<String,String> emptyMap()));
+    expectedOrdering.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 75l, 100l, "desc7", Collections.<String,String> emptyMap()));
+    expectedOrdering.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 85l, 90l, "desc8", Collections.<String,String> emptyMap()));
+    expectedOrdering.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 95l, 110l, "desc9", Collections.<String,String> emptyMap()));
+    expectedOrdering.add(new RemoteSpan("sender", "svc", 0l, 0l, 0l, 100l, 120l, "desc10", Collections.<String,String> emptyMap()));
+    
+    Collections.sort(spans);
+    
+    Assert.assertEquals(expectedOrdering, spans);
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/monitor/src/test/java/org/apache/accumulo/monitor/ZooKeeperStatusTest.java
----------------------------------------------------------------------
diff --git a/server/monitor/src/test/java/org/apache/accumulo/monitor/ZooKeeperStatusTest.java b/server/monitor/src/test/java/org/apache/accumulo/monitor/ZooKeeperStatusTest.java
new file mode 100644
index 0000000..a90396b
--- /dev/null
+++ b/server/monitor/src/test/java/org/apache/accumulo/monitor/ZooKeeperStatusTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.monitor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.TreeSet;
+
+import org.apache.accumulo.monitor.ZooKeeperStatus.ZooKeeperState;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ZooKeeperStatusTest {
+  
+  @Test
+  public void zkHostSortingTest() {
+    List<String> expectedHosts = Arrays.asList("rack1node1", "rack2node1", "rack4node1", "rack4node4");
+    
+    // Add the states in a not correctly sorted order
+    TreeSet<ZooKeeperState> states = new TreeSet<ZooKeeperState>();
+    states.add(new ZooKeeperState("rack4node4", "leader", 10));
+    states.add(new ZooKeeperState("rack4node1", "follower", 10));
+    states.add(new ZooKeeperState("rack1node1", "follower", 10));
+    states.add(new ZooKeeperState("rack2node1", "follower", 10));
+    
+    List<String> actualHosts = new ArrayList<String>(4);
+    for (ZooKeeperState state : states) {
+      actualHosts.add(state.keeper);
+    }
+    
+    // Assert we have 4 of each
+    Assert.assertEquals(expectedHosts.size(), actualHosts.size());
+    
+    // Assert the ordering is correct
+    for (int i = 0; i < expectedHosts.size(); i++) {
+      Assert.assertEquals(expectedHosts.get(i), actualHosts.get(i));
+    }
+    
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/server/src/main/java/org/apache/accumulo/server/master/Master.java
----------------------------------------------------------------------
diff --git a/server/server/src/main/java/org/apache/accumulo/server/master/Master.java b/server/server/src/main/java/org/apache/accumulo/server/master/Master.java
index 9488c1b..ca2eea5 100644
--- a/server/server/src/main/java/org/apache/accumulo/server/master/Master.java
+++ b/server/server/src/main/java/org/apache/accumulo/server/master/Master.java
@@ -89,6 +89,7 @@ import org.apache.accumulo.fate.zookeeper.IZooReaderWriter.Mutator;
 import org.apache.accumulo.fate.zookeeper.ZooLock.LockLossReason;
 import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeExistsPolicy;
 import org.apache.accumulo.fate.zookeeper.ZooUtil.NodeMissingPolicy;
+import org.apache.accumulo.monitor.Monitor;
 import org.apache.accumulo.server.Accumulo;
 import org.apache.accumulo.server.ServerConstants;
 import org.apache.accumulo.server.ServerOpts;
@@ -127,7 +128,6 @@ import org.apache.accumulo.server.master.tableOps.RenameTable;
 import org.apache.accumulo.server.master.tableOps.TableRangeOp;
 import org.apache.accumulo.server.master.tableOps.TraceRepo;
 import org.apache.accumulo.server.master.tserverOps.ShutdownTServer;
-import org.apache.accumulo.server.monitor.Monitor;
 import org.apache.accumulo.server.security.AuditedSecurityOperation;
 import org.apache.accumulo.server.security.SecurityOperation;
 import org.apache.accumulo.server.security.SystemCredentials;

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/server/src/main/resources/web/down.gif
----------------------------------------------------------------------
diff --git a/server/server/src/main/resources/web/down.gif b/server/server/src/main/resources/web/down.gif
deleted file mode 100644
index 087da1d..0000000
Binary files a/server/server/src/main/resources/web/down.gif and /dev/null differ

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/server/src/main/resources/web/favicon.png
----------------------------------------------------------------------
diff --git a/server/server/src/main/resources/web/favicon.png b/server/server/src/main/resources/web/favicon.png
deleted file mode 100644
index a632dab..0000000
Binary files a/server/server/src/main/resources/web/favicon.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/server/src/main/resources/web/flot/LICENSE.txt
----------------------------------------------------------------------
diff --git a/server/server/src/main/resources/web/flot/LICENSE.txt b/server/server/src/main/resources/web/flot/LICENSE.txt
deleted file mode 100644
index 07d5b20..0000000
--- a/server/server/src/main/resources/web/flot/LICENSE.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-Copyright (c) 2007-2009 IOLA and Ole Laursen
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c67460ee/server/server/src/main/resources/web/flot/excanvas.js
----------------------------------------------------------------------
diff --git a/server/server/src/main/resources/web/flot/excanvas.js b/server/server/src/main/resources/web/flot/excanvas.js
deleted file mode 100644
index c40d6f7..0000000
--- a/server/server/src/main/resources/web/flot/excanvas.js
+++ /dev/null
@@ -1,1427 +0,0 @@
-// Copyright 2006 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-
-// Known Issues:
-//
-// * Patterns only support repeat.
-// * Radial gradient are not implemented. The VML version of these look very
-//   different from the canvas one.
-// * Clipping paths are not implemented.
-// * Coordsize. The width and height attribute have higher priority than the
-//   width and height style values which isn't correct.
-// * Painting mode isn't implemented.
-// * Canvas width/height should is using content-box by default. IE in
-//   Quirks mode will draw the canvas using border-box. Either change your
-//   doctype to HTML5
-//   (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
-//   or use Box Sizing Behavior from WebFX
-//   (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
-// * Non uniform scaling does not correctly scale strokes.
-// * Filling very large shapes (above 5000 points) is buggy.
-// * Optimize. There is always room for speed improvements.
-
-// Only add this code if we do not already have a canvas implementation
-if (!document.createElement('canvas').getContext) {
-
-(function() {
-
-  // alias some functions to make (compiled) code shorter
-  var m = Math;
-  var mr = m.round;
-  var ms = m.sin;
-  var mc = m.cos;
-  var abs = m.abs;
-  var sqrt = m.sqrt;
-
-  // this is used for sub pixel precision
-  var Z = 10;
-  var Z2 = Z / 2;
-
-  /**
-   * This funtion is assigned to the <canvas> elements as element.getContext().
-   * @this {HTMLElement}
-   * @return {CanvasRenderingContext2D_}
-   */
-  function getContext() {
-    return this.context_ ||
-        (this.context_ = new CanvasRenderingContext2D_(this));
-  }
-
-  var slice = Array.prototype.slice;
-
-  /**
-   * Binds a function to an object. The returned function will always use the
-   * passed in {@code obj} as {@code this}.
-   *
-   * Example:
-   *
-   *   g = bind(f, obj, a, b)
-   *   g(c, d) // will do f.call(obj, a, b, c, d)
-   *
-   * @param {Function} f The function to bind the object to
-   * @param {Object} obj The object that should act as this when the function
-   *     is called
-   * @param {*} var_args Rest arguments that will be used as the initial
-   *     arguments when the function is called
-   * @return {Function} A new function that has bound this
-   */
-  function bind(f, obj, var_args) {
-    var a = slice.call(arguments, 2);
-    return function() {
-      return f.apply(obj, a.concat(slice.call(arguments)));
-    };
-  }
-
-  function encodeHtmlAttribute(s) {
-    return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
-  }
-
-  function addNamespacesAndStylesheet(doc) {
-    // create xmlns
-    if (!doc.namespaces['g_vml_']) {
-      doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
-                         '#default#VML');
-
-    }
-    if (!doc.namespaces['g_o_']) {
-      doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
-                         '#default#VML');
-    }
-
-    // Setup default CSS.  Only add one style sheet per document
-    if (!doc.styleSheets['ex_canvas_']) {
-      var ss = doc.createStyleSheet();
-      ss.owningElement.id = 'ex_canvas_';
-      ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
-          // default size is 300x150 in Gecko and Opera
-          'text-align:left;width:300px;height:150px}';
-    }
-  }
-
-  // Add namespaces and stylesheet at startup.
-  addNamespacesAndStylesheet(document);
-
-  var G_vmlCanvasManager_ = {
-    init: function(opt_doc) {
-      if (/MSIE/.test(navigator.userAgent) && !window.opera) {
-        var doc = opt_doc || document;
-        // Create a dummy element so that IE will allow canvas elements to be
-        // recognized.
-        doc.createElement('canvas');
-        doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
-      }
-    },
-
-    init_: function(doc) {
-      // find all canvas elements
-      var els = doc.getElementsByTagName('canvas');
-      for (var i = 0; i < els.length; i++) {
-        this.initElement(els[i]);
-      }
-    },
-
-    /**
-     * Public initializes a canvas element so that it can be used as canvas
-     * element from now on. This is called automatically before the page is
-     * loaded but if you are creating elements using createElement you need to
-     * make sure this is called on the element.
-     * @param {HTMLElement} el The canvas element to initialize.
-     * @return {HTMLElement} the element that was created.
-     */
-    initElement: function(el) {
-      if (!el.getContext) {
-        el.getContext = getContext;
-
-        // Add namespaces and stylesheet to document of the element.
-        addNamespacesAndStylesheet(el.ownerDocument);
-
-        // Remove fallback content. There is no way to hide text nodes so we
-        // just remove all childNodes. We could hide all elements and remove
-        // text nodes but who really cares about the fallback content.
-        el.innerHTML = '';
-
-        // do not use inline function because that will leak memory
-        el.attachEvent('onpropertychange', onPropertyChange);
-        el.attachEvent('onresize', onResize);
-
-        var attrs = el.attributes;
-        if (attrs.width && attrs.width.specified) {
-          // TODO: use runtimeStyle and coordsize
-          // el.getContext().setWidth_(attrs.width.nodeValue);
-          el.style.width = attrs.width.nodeValue + 'px';
-        } else {
-          el.width = el.clientWidth;
-        }
-        if (attrs.height && attrs.height.specified) {
-          // TODO: use runtimeStyle and coordsize
-          // el.getContext().setHeight_(attrs.height.nodeValue);
-          el.style.height = attrs.height.nodeValue + 'px';
-        } else {
-          el.height = el.clientHeight;
-        }
-        //el.getContext().setCoordsize_()
-      }
-      return el;
-    }
-  };
-
-  function onPropertyChange(e) {
-    var el = e.srcElement;
-
-    switch (e.propertyName) {
-      case 'width':
-        el.getContext().clearRect();
-        el.style.width = el.attributes.width.nodeValue + 'px';
-        // In IE8 this does not trigger onresize.
-        el.firstChild.style.width =  el.clientWidth + 'px';
-        break;
-      case 'height':
-        el.getContext().clearRect();
-        el.style.height = el.attributes.height.nodeValue + 'px';
-        el.firstChild.style.height = el.clientHeight + 'px';
-        break;
-    }
-  }
-
-  function onResize(e) {
-    var el = e.srcElement;
-    if (el.firstChild) {
-      el.firstChild.style.width =  el.clientWidth + 'px';
-      el.firstChild.style.height = el.clientHeight + 'px';
-    }
-  }
-
-  G_vmlCanvasManager_.init();
-
-  // precompute "00" to "FF"
-  var decToHex = [];
-  for (var i = 0; i < 16; i++) {
-    for (var j = 0; j < 16; j++) {
-      decToHex[i * 16 + j] = i.toString(16) + j.toString(16);
-    }
-  }
-
-  function createMatrixIdentity() {
-    return [
-      [1, 0, 0],
-      [0, 1, 0],
-      [0, 0, 1]
-    ];
-  }
-
-  function matrixMultiply(m1, m2) {
-    var result = createMatrixIdentity();
-
-    for (var x = 0; x < 3; x++) {
-      for (var y = 0; y < 3; y++) {
-        var sum = 0;
-
-        for (var z = 0; z < 3; z++) {
-          sum += m1[x][z] * m2[z][y];
-        }
-
-        result[x][y] = sum;
-      }
-    }
-    return result;
-  }
-
-  function copyState(o1, o2) {
-    o2.fillStyle     = o1.fillStyle;
-    o2.lineCap       = o1.lineCap;
-    o2.lineJoin      = o1.lineJoin;
-    o2.lineWidth     = o1.lineWidth;
-    o2.miterLimit    = o1.miterLimit;
-    o2.shadowBlur    = o1.shadowBlur;
-    o2.shadowColor   = o1.shadowColor;
-    o2.shadowOffsetX = o1.shadowOffsetX;
-    o2.shadowOffsetY = o1.shadowOffsetY;
-    o2.strokeStyle   = o1.strokeStyle;
-    o2.globalAlpha   = o1.globalAlpha;
-    o2.font          = o1.font;
-    o2.textAlign     = o1.textAlign;
-    o2.textBaseline  = o1.textBaseline;
-    o2.arcScaleX_    = o1.arcScaleX_;
-    o2.arcScaleY_    = o1.arcScaleY_;
-    o2.lineScale_    = o1.lineScale_;
-  }
-
-  var colorData = {
-    aliceblue: '#F0F8FF',
-    antiquewhite: '#FAEBD7',
-    aquamarine: '#7FFFD4',
-    azure: '#F0FFFF',
-    beige: '#F5F5DC',
-    bisque: '#FFE4C4',
-    black: '#000000',
-    blanchedalmond: '#FFEBCD',
-    blueviolet: '#8A2BE2',
-    brown: '#A52A2A',
-    burlywood: '#DEB887',
-    cadetblue: '#5F9EA0',
-    chartreuse: '#7FFF00',
-    chocolate: '#D2691E',
-    coral: '#FF7F50',
-    cornflowerblue: '#6495ED',
-    cornsilk: '#FFF8DC',
-    crimson: '#DC143C',
-    cyan: '#00FFFF',
-    darkblue: '#00008B',
-    darkcyan: '#008B8B',
-    darkgoldenrod: '#B8860B',
-    darkgray: '#A9A9A9',
-    darkgreen: '#006400',
-    darkgrey: '#A9A9A9',
-    darkkhaki: '#BDB76B',
-    darkmagenta: '#8B008B',
-    darkolivegreen: '#556B2F',
-    darkorange: '#FF8C00',
-    darkorchid: '#9932CC',
-    darkred: '#8B0000',
-    darksalmon: '#E9967A',
-    darkseagreen: '#8FBC8F',
-    darkslateblue: '#483D8B',
-    darkslategray: '#2F4F4F',
-    darkslategrey: '#2F4F4F',
-    darkturquoise: '#00CED1',
-    darkviolet: '#9400D3',
-    deeppink: '#FF1493',
-    deepskyblue: '#00BFFF',
-    dimgray: '#696969',
-    dimgrey: '#696969',
-    dodgerblue: '#1E90FF',
-    firebrick: '#B22222',
-    floralwhite: '#FFFAF0',
-    forestgreen: '#228B22',
-    gainsboro: '#DCDCDC',
-    ghostwhite: '#F8F8FF',
-    gold: '#FFD700',
-    goldenrod: '#DAA520',
-    grey: '#808080',
-    greenyellow: '#ADFF2F',
-    honeydew: '#F0FFF0',
-    hotpink: '#FF69B4',
-    indianred: '#CD5C5C',
-    indigo: '#4B0082',
-    ivory: '#FFFFF0',
-    khaki: '#F0E68C',
-    lavender: '#E6E6FA',
-    lavenderblush: '#FFF0F5',
-    lawngreen: '#7CFC00',
-    lemonchiffon: '#FFFACD',
-    lightblue: '#ADD8E6',
-    lightcoral: '#F08080',
-    lightcyan: '#E0FFFF',
-    lightgoldenrodyellow: '#FAFAD2',
-    lightgreen: '#90EE90',
-    lightgrey: '#D3D3D3',
-    lightpink: '#FFB6C1',
-    lightsalmon: '#FFA07A',
-    lightseagreen: '#20B2AA',
-    lightskyblue: '#87CEFA',
-    lightslategray: '#778899',
-    lightslategrey: '#778899',
-    lightsteelblue: '#B0C4DE',
-    lightyellow: '#FFFFE0',
-    limegreen: '#32CD32',
-    linen: '#FAF0E6',
-    magenta: '#FF00FF',
-    mediumaquamarine: '#66CDAA',
-    mediumblue: '#0000CD',
-    mediumorchid: '#BA55D3',
-    mediumpurple: '#9370DB',
-    mediumseagreen: '#3CB371',
-    mediumslateblue: '#7B68EE',
-    mediumspringgreen: '#00FA9A',
-    mediumturquoise: '#48D1CC',
-    mediumvioletred: '#C71585',
-    midnightblue: '#191970',
-    mintcream: '#F5FFFA',
-    mistyrose: '#FFE4E1',
-    moccasin: '#FFE4B5',
-    navajowhite: '#FFDEAD',
-    oldlace: '#FDF5E6',
-    olivedrab: '#6B8E23',
-    orange: '#FFA500',
-    orangered: '#FF4500',
-    orchid: '#DA70D6',
-    palegoldenrod: '#EEE8AA',
-    palegreen: '#98FB98',
-    paleturquoise: '#AFEEEE',
-    palevioletred: '#DB7093',
-    papayawhip: '#FFEFD5',
-    peachpuff: '#FFDAB9',
-    peru: '#CD853F',
-    pink: '#FFC0CB',
-    plum: '#DDA0DD',
-    powderblue: '#B0E0E6',
-    rosybrown: '#BC8F8F',
-    royalblue: '#4169E1',
-    saddlebrown: '#8B4513',
-    salmon: '#FA8072',
-    sandybrown: '#F4A460',
-    seagreen: '#2E8B57',
-    seashell: '#FFF5EE',
-    sienna: '#A0522D',
-    skyblue: '#87CEEB',
-    slateblue: '#6A5ACD',
-    slategray: '#708090',
-    slategrey: '#708090',
-    snow: '#FFFAFA',
-    springgreen: '#00FF7F',
-    steelblue: '#4682B4',
-    tan: '#D2B48C',
-    thistle: '#D8BFD8',
-    tomato: '#FF6347',
-    turquoise: '#40E0D0',
-    violet: '#EE82EE',
-    wheat: '#F5DEB3',
-    whitesmoke: '#F5F5F5',
-    yellowgreen: '#9ACD32'
-  };
-
-
-  function getRgbHslContent(styleString) {
-    var start = styleString.indexOf('(', 3);
-    var end = styleString.indexOf(')', start + 1);
-    var parts = styleString.substring(start + 1, end).split(',');
-    // add alpha if needed
-    if (parts.length == 4 && styleString.substr(3, 1) == 'a') {
-      alpha = Number(parts[3]);
-    } else {
-      parts[3] = 1;
-    }
-    return parts;
-  }
-
-  function percent(s) {
-    return parseFloat(s) / 100;
-  }
-
-  function clamp(v, min, max) {
-    return Math.min(max, Math.max(min, v));
-  }
-
-  function hslToRgb(parts){
-    var r, g, b;
-    h = parseFloat(parts[0]) / 360 % 360;
-    if (h < 0)
-      h++;
-    s = clamp(percent(parts[1]), 0, 1);
-    l = clamp(percent(parts[2]), 0, 1);
-    if (s == 0) {
-      r = g = b = l; // achromatic
-    } else {
-      var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
-      var p = 2 * l - q;
-      r = hueToRgb(p, q, h + 1 / 3);
-      g = hueToRgb(p, q, h);
-      b = hueToRgb(p, q, h - 1 / 3);
-    }
-
-    return '#' + decToHex[Math.floor(r * 255)] +
-        decToHex[Math.floor(g * 255)] +
-        decToHex[Math.floor(b * 255)];
-  }
-
-  function hueToRgb(m1, m2, h) {
-    if (h < 0)
-      h++;
-    if (h > 1)
-      h--;
-
-    if (6 * h < 1)
-      return m1 + (m2 - m1) * 6 * h;
-    else if (2 * h < 1)
-      return m2;
-    else if (3 * h < 2)
-      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
-    else
-      return m1;
-  }
-
-  function processStyle(styleString) {
-    var str, alpha = 1;
-
-    styleString = String(styleString);
-    if (styleString.charAt(0) == '#') {
-      str = styleString;
-    } else if (/^rgb/.test(styleString)) {
-      var parts = getRgbHslContent(styleString);
-      var str = '#', n;
-      for (var i = 0; i < 3; i++) {
-        if (parts[i].indexOf('%') != -1) {
-          n = Math.floor(percent(parts[i]) * 255);
-        } else {
-          n = Number(parts[i]);
-        }
-        str += decToHex[clamp(n, 0, 255)];
-      }
-      alpha = parts[3];
-    } else if (/^hsl/.test(styleString)) {
-      var parts = getRgbHslContent(styleString);
-      str = hslToRgb(parts);
-      alpha = parts[3];
-    } else {
-      str = colorData[styleString] || styleString;
-    }
-    return {color: str, alpha: alpha};
-  }
-
-  var DEFAULT_STYLE = {
-    style: 'normal',
-    variant: 'normal',
-    weight: 'normal',
-    size: 10,
-    family: 'sans-serif'
-  };
-
-  // Internal text style cache
-  var fontStyleCache = {};
-
-  function processFontStyle(styleString) {
-    if (fontStyleCache[styleString]) {
-      return fontStyleCache[styleString];
-    }
-
-    var el = document.createElement('div');
-    var style = el.style;
-    try {
-      style.font = styleString;
-    } catch (ex) {
-      // Ignore failures to set to invalid font.
-    }
-
-    return fontStyleCache[styleString] = {
-      style: style.fontStyle || DEFAULT_STYLE.style,
-      variant: style.fontVariant || DEFAULT_STYLE.variant,
-      weight: style.fontWeight || DEFAULT_STYLE.weight,
-      size: style.fontSize || DEFAULT_STYLE.size,
-      family: style.fontFamily || DEFAULT_STYLE.family
-    };
-  }
-
-  function getComputedStyle(style, element) {
-    var computedStyle = {};
-
-    for (var p in style) {
-      computedStyle[p] = style[p];
-    }
-
-    // Compute the size
-    var canvasFontSize = parseFloat(element.currentStyle.fontSize),
-        fontSize = parseFloat(style.size);
-
-    if (typeof style.size == 'number') {
-      computedStyle.size = style.size;
-    } else if (style.size.indexOf('px') != -1) {
-      computedStyle.size = fontSize;
-    } else if (style.size.indexOf('em') != -1) {
-      computedStyle.size = canvasFontSize * fontSize;
-    } else if(style.size.indexOf('%') != -1) {
-      computedStyle.size = (canvasFontSize / 100) * fontSize;
-    } else if (style.size.indexOf('pt') != -1) {
-      computedStyle.size = fontSize / .75;
-    } else {
-      computedStyle.size = canvasFontSize;
-    }
-
-    // Different scaling between normal text and VML text. This was found using
-    // trial and error to get the same size as non VML text.
-    computedStyle.size *= 0.981;
-
-    return computedStyle;
-  }
-
-  function buildStyle(style) {
-    return style.style + ' ' + style.variant + ' ' + style.weight + ' ' +
-        style.size + 'px ' + style.family;
-  }
-
-  function processLineCap(lineCap) {
-    switch (lineCap) {
-      case 'butt':
-        return 'flat';
-      case 'round':
-        return 'round';
-      case 'square':
-      default:
-        return 'square';
-    }
-  }
-
-  /**
-   * This class implements CanvasRenderingContext2D interface as described by
-   * the WHATWG.
-   * @param {HTMLElement} surfaceElement The element that the 2D context should
-   * be associated with
-   */
-  function CanvasRenderingContext2D_(surfaceElement) {
-    this.m_ = createMatrixIdentity();
-
-    this.mStack_ = [];
-    this.aStack_ = [];
-    this.currentPath_ = [];
-
-    // Canvas context properties
-    this.strokeStyle = '#000';
-    this.fillStyle = '#000';
-
-    this.lineWidth = 1;
-    this.lineJoin = 'miter';
-    this.lineCap = 'butt';
-    this.miterLimit = Z * 1;
-    this.globalAlpha = 1;
-    this.font = '10px sans-serif';
-    this.textAlign = 'left';
-    this.textBaseline = 'alphabetic';
-    this.canvas = surfaceElement;
-
-    var el = surfaceElement.ownerDocument.createElement('div');
-    el.style.width =  surfaceElement.clientWidth + 'px';
-    el.style.height = surfaceElement.clientHeight + 'px';
-    el.style.overflow = 'hidden';
-    el.style.position = 'absolute';
-    surfaceElement.appendChild(el);
-
-    this.element_ = el;
-    this.arcScaleX_ = 1;
-    this.arcScaleY_ = 1;
-    this.lineScale_ = 1;
-  }
-
-  var contextPrototype = CanvasRenderingContext2D_.prototype;
-  contextPrototype.clearRect = function() {
-    if (this.textMeasureEl_) {
-      this.textMeasureEl_.removeNode(true);
-      this.textMeasureEl_ = null;
-    }
-    this.element_.innerHTML = '';
-  };
-
-  contextPrototype.beginPath = function() {
-    // TODO: Branch current matrix so that save/restore has no effect
-    //       as per safari docs.
-    this.currentPath_ = [];
-  };
-
-  contextPrototype.moveTo = function(aX, aY) {
-    var p = this.getCoords_(aX, aY);
-    this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
-    this.currentX_ = p.x;
-    this.currentY_ = p.y;
-  };
-
-  contextPrototype.lineTo = function(aX, aY) {
-    var p = this.getCoords_(aX, aY);
-    this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
-
-    this.currentX_ = p.x;
-    this.currentY_ = p.y;
-  };
-
-  contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
-                                            aCP2x, aCP2y,
-                                            aX, aY) {
-    var p = this.getCoords_(aX, aY);
-    var cp1 = this.getCoords_(aCP1x, aCP1y);
-    var cp2 = this.getCoords_(aCP2x, aCP2y);
-    bezierCurveTo(this, cp1, cp2, p);
-  };
-
-  // Helper function that takes the already fixed cordinates.
-  function bezierCurveTo(self, cp1, cp2, p) {
-    self.currentPath_.push({
-      type: 'bezierCurveTo',
-      cp1x: cp1.x,
-      cp1y: cp1.y,
-      cp2x: cp2.x,
-      cp2y: cp2.y,
-      x: p.x,
-      y: p.y
-    });
-    self.currentX_ = p.x;
-    self.currentY_ = p.y;
-  }
-
-  contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
-    // the following is lifted almost directly from
-    // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
-
-    var cp = this.getCoords_(aCPx, aCPy);
-    var p = this.getCoords_(aX, aY);
-
-    var cp1 = {
-      x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
-      y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
-    };
-    var cp2 = {
-      x: cp1.x + (p.x - this.currentX_) / 3.0,
-      y: cp1.y + (p.y - this.currentY_) / 3.0
-    };
-
-    bezierCurveTo(this, cp1, cp2, p);
-  };
-
-  contextPrototype.arc = function(aX, aY, aRadius,
-                                  aStartAngle, aEndAngle, aClockwise) {
-    aRadius *= Z;
-    var arcType = aClockwise ? 'at' : 'wa';
-
-    var xStart = aX + mc(aStartAngle) * aRadius - Z2;
-    var yStart = aY + ms(aStartAngle) * aRadius - Z2;
-
-    var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
-    var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
-
-    // IE won't render arches drawn counter clockwise if xStart == xEnd.
-    if (xStart == xEnd && !aClockwise) {
-      xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
-                       // that can be represented in binary
-    }
-
-    var p = this.getCoords_(aX, aY);
-    var pStart = this.getCoords_(xStart, yStart);
-    var pEnd = this.getCoords_(xEnd, yEnd);
-
-    this.currentPath_.push({type: arcType,
-                           x: p.x,
-                           y: p.y,
-                           radius: aRadius,
-                           xStart: pStart.x,
-                           yStart: pStart.y,
-                           xEnd: pEnd.x,
-                           yEnd: pEnd.y});
-
-  };
-
-  contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
-    this.moveTo(aX, aY);
-    this.lineTo(aX + aWidth, aY);
-    this.lineTo(aX + aWidth, aY + aHeight);
-    this.lineTo(aX, aY + aHeight);
-    this.closePath();
-  };
-
-  contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
-    var oldPath = this.currentPath_;
-    this.beginPath();
-
-    this.moveTo(aX, aY);
-    this.lineTo(aX + aWidth, aY);
-    this.lineTo(aX + aWidth, aY + aHeight);
-    this.lineTo(aX, aY + aHeight);
-    this.closePath();
-    this.stroke();
-
-    this.currentPath_ = oldPath;
-  };
-
-  contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
-    var oldPath = this.currentPath_;
-    this.beginPath();
-
-    this.moveTo(aX, aY);
-    this.lineTo(aX + aWidth, aY);
-    this.lineTo(aX + aWidth, aY + aHeight);
-    this.lineTo(aX, aY + aHeight);
-    this.closePath();
-    this.fill();
-
-    this.currentPath_ = oldPath;
-  };
-
-  contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
-    var gradient = new CanvasGradient_('gradient');
-    gradient.x0_ = aX0;
-    gradient.y0_ = aY0;
-    gradient.x1_ = aX1;
-    gradient.y1_ = aY1;
-    return gradient;
-  };
-
-  contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
-                                                   aX1, aY1, aR1) {
-    var gradient = new CanvasGradient_('gradientradial');
-    gradient.x0_ = aX0;
-    gradient.y0_ = aY0;
-    gradient.r0_ = aR0;
-    gradient.x1_ = aX1;
-    gradient.y1_ = aY1;
-    gradient.r1_ = aR1;
-    return gradient;
-  };
-
-  contextPrototype.drawImage = function(image, var_args) {
-    var dx, dy, dw, dh, sx, sy, sw, sh;
-
-    // to find the original width we overide the width and height
-    var oldRuntimeWidth = image.runtimeStyle.width;
-    var oldRuntimeHeight = image.runtimeStyle.height;
-    image.runtimeStyle.width = 'auto';
-    image.runtimeStyle.height = 'auto';
-
-    // get the original size
-    var w = image.width;
-    var h = image.height;
-
-    // and remove overides
-    image.runtimeStyle.width = oldRuntimeWidth;
-    image.runtimeStyle.height = oldRuntimeHeight;
-
-    if (arguments.length == 3) {
-      dx = arguments[1];
-      dy = arguments[2];
-      sx = sy = 0;
-      sw = dw = w;
-      sh = dh = h;
-    } else if (arguments.length == 5) {
-      dx = arguments[1];
-      dy = arguments[2];
-      dw = arguments[3];
-      dh = arguments[4];
-      sx = sy = 0;
-      sw = w;
-      sh = h;
-    } else if (arguments.length == 9) {
-      sx = arguments[1];
-      sy = arguments[2];
-      sw = arguments[3];
-      sh = arguments[4];
-      dx = arguments[5];
-      dy = arguments[6];
-      dw = arguments[7];
-      dh = arguments[8];
-    } else {
-      throw Error('Invalid number of arguments');
-    }
-
-    var d = this.getCoords_(dx, dy);
-
-    var w2 = sw / 2;
-    var h2 = sh / 2;
-
-    var vmlStr = [];
-
-    var W = 10;
-    var H = 10;
-
-    // For some reason that I've now forgotten, using divs didn't work
-    vmlStr.push(' <g_vml_:group',
-                ' coordsize="', Z * W, ',', Z * H, '"',
-                ' coordorigin="0,0"' ,
-                ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
-
-    // If filters are necessary (rotation exists), create them
-    // filters are bog-slow, so only create them if abbsolutely necessary
-    // The following check doesn't account for skews (which don't exist
-    // in the canvas spec (yet) anyway.
-
-    if (this.m_[0][0] != 1 || this.m_[0][1] ||
-        this.m_[1][1] != 1 || this.m_[1][0]) {
-      var filter = [];
-
-      // Note the 12/21 reversal
-      filter.push('M11=', this.m_[0][0], ',',
-                  'M12=', this.m_[1][0], ',',
-                  'M21=', this.m_[0][1], ',',
-                  'M22=', this.m_[1][1], ',',
-                  'Dx=', mr(d.x / Z), ',',
-                  'Dy=', mr(d.y / Z), '');
-
-      // Bounding box calculation (need to minimize displayed area so that
-      // filters don't waste time on unused pixels.
-      var max = d;
-      var c2 = this.getCoords_(dx + dw, dy);
-      var c3 = this.getCoords_(dx, dy + dh);
-      var c4 = this.getCoords_(dx + dw, dy + dh);
-
-      max.x = m.max(max.x, c2.x, c3.x, c4.x);
-      max.y = m.max(max.y, c2.y, c3.y, c4.y);
-
-      vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
-                  'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
-                  filter.join(''), ", sizingmethod='clip');");
-
-    } else {
-      vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
-    }
-
-    vmlStr.push(' ">' ,
-                '<g_vml_:image src="', image.src, '"',
-                ' style="width:', Z * dw, 'px;',
-                ' height:', Z * dh, 'px"',
-                ' cropleft="', sx / w, '"',
-                ' croptop="', sy / h, '"',
-                ' cropright="', (w - sx - sw) / w, '"',
-                ' cropbottom="', (h - sy - sh) / h, '"',
-                ' />',
-                '</g_vml_:group>');
-
-    this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join(''));
-  };
-
-  contextPrototype.stroke = function(aFill) {
-    var W = 10;
-    var H = 10;
-    // Divide the shape into chunks if it's too long because IE has a limit
-    // somewhere for how long a VML shape can be. This simple division does
-    // not work with fills, only strokes, unfortunately.
-    var chunkSize = 5000;
-
-    var min = {x: null, y: null};
-    var max = {x: null, y: null};
-
-    for (var j = 0; j < this.currentPath_.length; j += chunkSize) {
-      var lineStr = [];
-      var lineOpen = false;
-
-      lineStr.push('<g_vml_:shape',
-                   ' filled="', !!aFill, '"',
-                   ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
-                   ' coordorigin="0,0"',
-                   ' coordsize="', Z * W, ',', Z * H, '"',
-                   ' stroked="', !aFill, '"',
-                   ' path="');
-
-      var newSeq = false;
-
-      for (var i = j; i < Math.min(j + chunkSize, this.currentPath_.length); i++) {
-        if (i % chunkSize == 0 && i > 0) { // move into position for next chunk
-          lineStr.push(' m ', mr(this.currentPath_[i-1].x), ',', mr(this.currentPath_[i-1].y));
-        }
-
-        var p = this.currentPath_[i];
-        var c;
-
-        switch (p.type) {
-          case 'moveTo':
-            c = p;
-            lineStr.push(' m ', mr(p.x), ',', mr(p.y));
-            break;
-          case 'lineTo':
-            lineStr.push(' l ', mr(p.x), ',', mr(p.y));
-            break;
-          case 'close':
-            lineStr.push(' x ');
-            p = null;
-            break;
-          case 'bezierCurveTo':
-            lineStr.push(' c ',
-                         mr(p.cp1x), ',', mr(p.cp1y), ',',
-                         mr(p.cp2x), ',', mr(p.cp2y), ',',
-                         mr(p.x), ',', mr(p.y));
-            break;
-          case 'at':
-          case 'wa':
-            lineStr.push(' ', p.type, ' ',
-                         mr(p.x - this.arcScaleX_ * p.radius), ',',
-                         mr(p.y - this.arcScaleY_ * p.radius), ' ',
-                         mr(p.x + this.arcScaleX_ * p.radius), ',',
-                         mr(p.y + this.arcScaleY_ * p.radius), ' ',
-                         mr(p.xStart), ',', mr(p.yStart), ' ',
-                         mr(p.xEnd), ',', mr(p.yEnd));
-            break;
-        }
-  
-  
-        // TODO: Following is broken for curves due to
-        //       move to proper paths.
-  
-        // Figure out dimensions so we can do gradient fills
-        // properly
-        if (p) {
-          if (min.x == null || p.x < min.x) {
-            min.x = p.x;
-          }
-          if (max.x == null || p.x > max.x) {
-            max.x = p.x;
-          }
-          if (min.y == null || p.y < min.y) {
-            min.y = p.y;
-          }
-          if (max.y == null || p.y > max.y) {
-            max.y = p.y;
-          }
-        }
-      }
-      lineStr.push(' ">');
-  
-      if (!aFill) {
-        appendStroke(this, lineStr);
-      } else {
-        appendFill(this, lineStr, min, max);
-      }
-  
-      lineStr.push('</g_vml_:shape>');
-  
-      this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
-    }
-  };
-
-  function appendStroke(ctx, lineStr) {
-    var a = processStyle(ctx.strokeStyle);
-    var color = a.color;
-    var opacity = a.alpha * ctx.globalAlpha;
-    var lineWidth = ctx.lineScale_ * ctx.lineWidth;
-
-    // VML cannot correctly render a line if the width is less than 1px.
-    // In that case, we dilute the color to make the line look thinner.
-    if (lineWidth < 1) {
-      opacity *= lineWidth;
-    }
-
-    lineStr.push(
-      '<g_vml_:stroke',
-      ' opacity="', opacity, '"',
-      ' joinstyle="', ctx.lineJoin, '"',
-      ' miterlimit="', ctx.miterLimit, '"',
-      ' endcap="', processLineCap(ctx.lineCap), '"',
-      ' weight="', lineWidth, 'px"',
-      ' color="', color, '" />'
-    );
-  }
-
-  function appendFill(ctx, lineStr, min, max) {
-    var fillStyle = ctx.fillStyle;
-    var arcScaleX = ctx.arcScaleX_;
-    var arcScaleY = ctx.arcScaleY_;
-    var width = max.x - min.x;
-    var height = max.y - min.y;
-    if (fillStyle instanceof CanvasGradient_) {
-      // TODO: Gradients transformed with the transformation matrix.
-      var angle = 0;
-      var focus = {x: 0, y: 0};
-
-      // additional offset
-      var shift = 0;
-      // scale factor for offset
-      var expansion = 1;
-
-      if (fillStyle.type_ == 'gradient') {
-        var x0 = fillStyle.x0_ / arcScaleX;
-        var y0 = fillStyle.y0_ / arcScaleY;
-        var x1 = fillStyle.x1_ / arcScaleX;
-        var y1 = fillStyle.y1_ / arcScaleY;
-        var p0 = ctx.getCoords_(x0, y0);
-        var p1 = ctx.getCoords_(x1, y1);
-        var dx = p1.x - p0.x;
-        var dy = p1.y - p0.y;
-        angle = Math.atan2(dx, dy) * 180 / Math.PI;
-
-        // The angle should be a non-negative number.
-        if (angle < 0) {
-          angle += 360;
-        }
-
-        // Very small angles produce an unexpected result because they are
-        // converted to a scientific notation string.
-        if (angle < 1e-6) {
-          angle = 0;
-        }
-      } else {
-        var p0 = ctx.getCoords_(fillStyle.x0_, fillStyle.y0_);
-        focus = {
-          x: (p0.x - min.x) / width,
-          y: (p0.y - min.y) / height
-        };
-
-        width  /= arcScaleX * Z;
-        height /= arcScaleY * Z;
-        var dimension = m.max(width, height);
-        shift = 2 * fillStyle.r0_ / dimension;
-        expansion = 2 * fillStyle.r1_ / dimension - shift;
-      }
-
-      // We need to sort the color stops in ascending order by offset,
-      // otherwise IE won't interpret it correctly.
-      var stops = fillStyle.colors_;
-      stops.sort(function(cs1, cs2) {
-        return cs1.offset - cs2.offset;
-      });
-
-      var length = stops.length;
-      var color1 = stops[0].color;
-      var color2 = stops[length - 1].color;
-      var opacity1 = stops[0].alpha * ctx.globalAlpha;
-      var opacity2 = stops[length - 1].alpha * ctx.globalAlpha;
-
-      var colors = [];
-      for (var i = 0; i < length; i++) {
-        var stop = stops[i];
-        colors.push(stop.offset * expansion + shift + ' ' + stop.color);
-      }
-
-      // When colors attribute is used, the meanings of opacity and o:opacity2
-      // are reversed.
-      lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
-                   ' method="none" focus="100%"',
-                   ' color="', color1, '"',
-                   ' color2="', color2, '"',
-                   ' colors="', colors.join(','), '"',
-                   ' opacity="', opacity2, '"',
-                   ' g_o_:opacity2="', opacity1, '"',
-                   ' angle="', angle, '"',
-                   ' focusposition="', focus.x, ',', focus.y, '" />');
-    } else if (fillStyle instanceof CanvasPattern_) {
-      if (width && height) {
-        var deltaLeft = -min.x;
-        var deltaTop = -min.y;
-        lineStr.push('<g_vml_:fill',
-                     ' position="',
-                     deltaLeft / width * arcScaleX * arcScaleX, ',',
-                     deltaTop / height * arcScaleY * arcScaleY, '"',
-                     ' type="tile"',
-                     // TODO: Figure out the correct size to fit the scale.
-                     //' size="', w, 'px ', h, 'px"',
-                     ' src="', fillStyle.src_, '" />');
-       }
-    } else {
-      var a = processStyle(ctx.fillStyle);
-      var color = a.color;
-      var opacity = a.alpha * ctx.globalAlpha;
-      lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
-                   '" />');
-    }
-  }
-
-  contextPrototype.fill = function() {
-    this.stroke(true);
-  };
-
-  contextPrototype.closePath = function() {
-    this.currentPath_.push({type: 'close'});
-  };
-
-  /**
-   * @private
-   */
-  contextPrototype.getCoords_ = function(aX, aY) {
-    var m = this.m_;
-    return {
-      x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
-      y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
-    };
-  };
-
-  contextPrototype.save = function() {
-    var o = {};
-    copyState(this, o);
-    this.aStack_.push(o);
-    this.mStack_.push(this.m_);
-    this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
-  };
-
-  contextPrototype.restore = function() {
-    if (this.aStack_.length) {
-      copyState(this.aStack_.pop(), this);
-      this.m_ = this.mStack_.pop();
-    }
-  };
-
-  function matrixIsFinite(m) {
-    return isFinite(m[0][0]) && isFinite(m[0][1]) &&
-        isFinite(m[1][0]) && isFinite(m[1][1]) &&
-        isFinite(m[2][0]) && isFinite(m[2][1]);
-  }
-
-  function setM(ctx, m, updateLineScale) {
-    if (!matrixIsFinite(m)) {
-      return;
-    }
-    ctx.m_ = m;
-
-    if (updateLineScale) {
-      // Get the line scale.
-      // Determinant of this.m_ means how much the area is enlarged by the
-      // transformation. So its square root can be used as a scale factor
-      // for width.
-      var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
-      ctx.lineScale_ = sqrt(abs(det));
-    }
-  }
-
-  contextPrototype.translate = function(aX, aY) {
-    var m1 = [
-      [1,  0,  0],
-      [0,  1,  0],
-      [aX, aY, 1]
-    ];
-
-    setM(this, matrixMultiply(m1, this.m_), false);
-  };
-
-  contextPrototype.rotate = function(aRot) {
-    var c = mc(aRot);
-    var s = ms(aRot);
-
-    var m1 = [
-      [c,  s, 0],
-      [-s, c, 0],
-      [0,  0, 1]
-    ];
-
-    setM(this, matrixMultiply(m1, this.m_), false);
-  };
-
-  contextPrototype.scale = function(aX, aY) {
-    this.arcScaleX_ *= aX;
-    this.arcScaleY_ *= aY;
-    var m1 = [
-      [aX, 0,  0],
-      [0,  aY, 0],
-      [0,  0,  1]
-    ];
-
-    setM(this, matrixMultiply(m1, this.m_), true);
-  };
-
-  contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
-    var m1 = [
-      [m11, m12, 0],
-      [m21, m22, 0],
-      [dx,  dy,  1]
-    ];
-
-    setM(this, matrixMultiply(m1, this.m_), true);
-  };
-
-  contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
-    var m = [
-      [m11, m12, 0],
-      [m21, m22, 0],
-      [dx,  dy,  1]
-    ];
-
-    setM(this, m, true);
-  };
-
-  /**
-   * The text drawing function.
-   * The maxWidth argument isn't taken in account, since no browser supports
-   * it yet.
-   */
-  contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) {
-    var m = this.m_,
-        delta = 1000,
-        left = 0,
-        right = delta,
-        offset = {x: 0, y: 0},
-        lineStr = [];
-
-    var fontStyle = getComputedStyle(processFontStyle(this.font),
-                                     this.element_);
-
-    var fontStyleString = buildStyle(fontStyle);
-
-    var elementStyle = this.element_.currentStyle;
-    var textAlign = this.textAlign.toLowerCase();
-    switch (textAlign) {
-      case 'left':
-      case 'center':
-      case 'right':
-        break;
-      case 'end':
-        textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left';
-        break;
-      case 'start':
-        textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left';
-        break;
-      default:
-        textAlign = 'left';
-    }
-
-    // 1.75 is an arbitrary number, as there is no info about the text baseline
-    switch (this.textBaseline) {
-      case 'hanging':
-      case 'top':
-        offset.y = fontStyle.size / 1.75;
-        break;
-      case 'middle':
-        break;
-      default:
-      case null:
-      case 'alphabetic':
-      case 'ideographic':
-      case 'bottom':
-        offset.y = -fontStyle.size / 2.25;
-        break;
-    }
-
-    switch(textAlign) {
-      case 'right':
-        left = delta;
-        right = 0.05;
-        break;
-      case 'center':
-        left = right = delta / 2;
-        break;
-    }
-
-    var d = this.getCoords_(x + offset.x, y + offset.y);
-
-    lineStr.push('<g_vml_:line from="', -left ,' 0" to="', right ,' 0.05" ',
-                 ' coordsize="100 100" coordorigin="0 0"',
-                 ' filled="', !stroke, '" stroked="', !!stroke,
-                 '" style="position:absolute;width:1px;height:1px;">');
-
-    if (stroke) {
-      appendStroke(this, lineStr);
-    } else {
-      // TODO: Fix the min and max params.
-      appendFill(this, lineStr, {x: -left, y: 0},
-                 {x: right, y: fontStyle.size});
-    }
-
-    var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' +
-                m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0';
-
-    var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z);
-
-    lineStr.push('<g_vml_:skew on="t" matrix="', skewM ,'" ',
-                 ' offset="', skewOffset, '" origin="', left ,' 0" />',
-                 '<g_vml_:path textpathok="true" />',
-                 '<g_vml_:textpath on="true" string="',
-                 encodeHtmlAttribute(text),
-                 '" style="v-text-align:', textAlign,
-                 ';font:', encodeHtmlAttribute(fontStyleString),
-                 '" /></g_vml_:line>');
-
-    this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
-  };
-
-  contextPrototype.fillText = function(text, x, y, maxWidth) {
-    this.drawText_(text, x, y, maxWidth, false);
-  };
-
-  contextPrototype.strokeText = function(text, x, y, maxWidth) {
-    this.drawText_(text, x, y, maxWidth, true);
-  };
-
-  contextPrototype.measureText = function(text) {
-    if (!this.textMeasureEl_) {
-      var s = '<span style="position:absolute;' +
-          'top:-20000px;left:0;padding:0;margin:0;border:none;' +
-          'white-space:pre;"></span>';
-      this.element_.insertAdjacentHTML('beforeEnd', s);
-      this.textMeasureEl_ = this.element_.lastChild;
-    }
-    var doc = this.element_.ownerDocument;
-    this.textMeasureEl_.innerHTML = '';
-    this.textMeasureEl_.style.font = this.font;
-    // Don't use innerHTML or innerText because they allow markup/whitespace.
-    this.textMeasureEl_.appendChild(doc.createTextNode(text));
-    return {width: this.textMeasureEl_.offsetWidth};
-  };
-
-  /******** STUBS ********/
-  contextPrototype.clip = function() {
-    // TODO: Implement
-  };
-
-  contextPrototype.arcTo = function() {
-    // TODO: Implement
-  };
-
-  contextPrototype.createPattern = function(image, repetition) {
-    return new CanvasPattern_(image, repetition);
-  };
-
-  // Gradient / Pattern Stubs
-  function CanvasGradient_(aType) {
-    this.type_ = aType;
-    this.x0_ = 0;
-    this.y0_ = 0;
-    this.r0_ = 0;
-    this.x1_ = 0;
-    this.y1_ = 0;
-    this.r1_ = 0;
-    this.colors_ = [];
-  }
-
-  CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
-    aColor = processStyle(aColor);
-    this.colors_.push({offset: aOffset,
-                       color: aColor.color,
-                       alpha: aColor.alpha});
-  };
-
-  function CanvasPattern_(image, repetition) {
-    assertImageIsValid(image);
-    switch (repetition) {
-      case 'repeat':
-      case null:
-      case '':
-        this.repetition_ = 'repeat';
-        break
-      case 'repeat-x':
-      case 'repeat-y':
-      case 'no-repeat':
-        this.repetition_ = repetition;
-        break;
-      default:
-        throwException('SYNTAX_ERR');
-    }
-
-    this.src_ = image.src;
-    this.width_ = image.width;
-    this.height_ = image.height;
-  }
-
-  function throwException(s) {
-    throw new DOMException_(s);
-  }
-
-  function assertImageIsValid(img) {
-    if (!img || img.nodeType != 1 || img.tagName != 'IMG') {
-      throwException('TYPE_MISMATCH_ERR');
-    }
-    if (img.readyState != 'complete') {
-      throwException('INVALID_STATE_ERR');
-    }
-  }
-
-  function DOMException_(s) {
-    this.code = this[s];
-    this.message = s +': DOM Exception ' + this.code;
-  }
-  var p = DOMException_.prototype = new Error;
-  p.INDEX_SIZE_ERR = 1;
-  p.DOMSTRING_SIZE_ERR = 2;
-  p.HIERARCHY_REQUEST_ERR = 3;
-  p.WRONG_DOCUMENT_ERR = 4;
-  p.INVALID_CHARACTER_ERR = 5;
-  p.NO_DATA_ALLOWED_ERR = 6;
-  p.NO_MODIFICATION_ALLOWED_ERR = 7;
-  p.NOT_FOUND_ERR = 8;
-  p.NOT_SUPPORTED_ERR = 9;
-  p.INUSE_ATTRIBUTE_ERR = 10;
-  p.INVALID_STATE_ERR = 11;
-  p.SYNTAX_ERR = 12;
-  p.INVALID_MODIFICATION_ERR = 13;
-  p.NAMESPACE_ERR = 14;
-  p.INVALID_ACCESS_ERR = 15;
-  p.VALIDATION_ERR = 16;
-  p.TYPE_MISMATCH_ERR = 17;
-
-  // set up externs
-  G_vmlCanvasManager = G_vmlCanvasManager_;
-  CanvasRenderingContext2D = CanvasRenderingContext2D_;
-  CanvasGradient = CanvasGradient_;
-  CanvasPattern = CanvasPattern_;
-  DOMException = DOMException_;
-})();
-
-} // if


Mime
View raw message