<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs 
title="DreamHost Charts"
author="Marco Abiuso"
author_location="Bergamo, Italy"
author_email="dh@mindsuburbia.net"
scaling="true"
scrolling="true"
height="300"
width="300"
thumbnail="http://farm4.static.flickr.com/3545/3549110434_34f68f2409_t.jpg"
screenshot="http://farm4.static.flickr.com/3545/3549110434_34f68f2409.jpg?v=0"
description="DreamHost API interface to generate PS usage charts"

/>

<UserPref name="dhuser" display_name="DreamHost username" default_value="apitest@dreamhost.com"/>
<UserPref name="dhkey" display_name="DreamHost API key (do not give write access to this key for security concerns)" default_value="6SHU5P2HLDAYECUM"/>
<UserPref name="chwidth" display_name="Charts width" default_value="280"/>
<UserPref name="chheight" display_name="Charts height" default_value="150"/>
<UserPref name="showtext" display_name="Show text data on top of the charts" datatype="bool" default_value="true"/>
<UserPref name="showdhlogo" display_name="Show DH logo on the top" datatype="bool" default_value="false"/>
<UserPref name="backgroundcol" display_name="Charts and frame background col #" default_value="EEEEEE"/>
<UserPref name="loadcol" display_name="Load line col #" default_value="444444"/>
<UserPref name="memusedcol" display_name="Used mem line col #" default_value="2222DD"/>
<UserPref name="memsizecol" display_name="Total memory line col #" default_value="66FF66"/>
<UserPref name="rebootcol" display_name="Reboot line col #" default_value="FF6699"/>

<Content type="html"><![CDATA[
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript">
/*
File: Math.uuid.js
Version: 1.3
Change History:
v1.0 - first release
v1.1 - less code and 2x performance boost (by minimizing calls to Math.random())
v1.2 - Add support for generating non-standard uuids of arbitrary length
v1.3 - Fixed IE7 bug (can't use []'s to access string chars. Thanks, Brian R.)
v1.4 - Changed method to be "Math.uuid". Added support for radix argument. Use module pattern for better encapsulation.

Latest version: http://www.broofa.com/Tools/Math.uuid.js
Information: http://www.broofa.com/blog/?p=151
Contact: robert@broofa.com
----
Copyright (c) 2008, Robert Kieffer
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Robert Kieffer nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS
SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*
* Generate a random uuid.
*
* USAGE: Math.uuid(length, radix)
* length - the desired number of characters
* radix - the number of allowable values for each character.
*
* EXAMPLES:
* // No arguments - returns RFC4122, version 4 ID
* >>> Math.uuid()
* "92329D39-6F5C-4520-ABFC-AAB64544E172"
*
* // One argument - returns ID of the specified length
* >>> Math.uuid(15) // 15 character ID (default base=62)
* "VcydxgltxrVZSTV"
*
* // Two arguments - returns ID of the specified length, and radix. (Radix must be <= 62)
* >>> Math.uuid(8, 2) // 8 character ID (base=2)
* "01001010"
* >>> Math.uuid(8, 10) // 8 character ID (base=10)
* "47473046"
* >>> Math.uuid(8, 16) // 8 character ID (base=16)
* "098F4D35"
*/
Math.uuid = (function() {
// Private array of chars to use
var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');

return function (len, radix) {
var chars = CHARS, uuid = [], rnd = Math.random;
radix = radix || chars.length;

if (len) {
// Compact form
for (var i = 0; i < len; i++) uuid[i] = chars[0 | rnd()*radix];
} else {
// rfc4122, version 4 form
var r;

// rfc4122 requires these characters
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';

// Fill in random data. At i==19 set the high bits of clock sequence as
// per rfc4122, sec. 4.1.5
for (var i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | rnd()*16;
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r & 0xf];
}
}
}

return uuid.join('');
};
})();
// Deprecated - only here for backward compatability
var randomUUID = Math.uuid;

// END OF File: Math.uuid.js
</script>
<script>
//
//Render the graphs 
//

var dhstats=new Array();//hold all the stats
var dhhover=new Array();//keep data for img hovering
var semaphore=0;//counts until finished receiving data
var spinner=new Array();
  
spinner['|']='/';
spinner['/']='-';
spinner['-']='\\';
spinner['\\']='|';



//kickstart the request for data  
function request() {
	var myUUID =Math.uuid();
	var url = "https://api.dreamhost.com/?username=__UP_dhuser__&key=__UP_dhkey__&cmd=dreamhost_ps-list_ps&unique_id="+myUUID+"&format=tab";
	_IG_FetchContent(url, response_list);
};

//manipulate the server list and ask for details
function response_list(responseText) {
        var ar=responseText.split("\n");
        var mTxt='';
        if (ar[0]=='success')
        for (i=2;i<ar.length;i++) {
          if (ar[i].length>0) {
              var ar2=ar[i].split("\t");
              if (ar2[1].length>0) {
                dhstats[ar2[1]]=new Array();
                //ask for size history
                request_size(ar2[1]);
  
                //ask for reboot history
                request_reboot(ar2[1]);
  
                //ask for usage history
                request_usage(ar2[1]);
  
              }

          }
  
  
        }
	document.getElementById('dhcontent_div').innerHTML += '|';

}
  
function request_reboot(ps) {
	var myUUID =Math.uuid();
	var url =
"https://api.dreamhost.com/?username=__UP_dhuser__&key=__UP_dhkey__&cmd=dreamhost_ps-list_reboot_history&ps="+ps+"&unique_id="+myUUID+"&format=tab";
        semaphore++;
	_IG_FetchContent(url, _IG_Callback(response_reboot, ps));
  
}

//parses reboot list response
//the response is in the format
//success
//header
//date time
function response_reboot(responseText, ps) {
  var ar=responseText.split("\n");
  var mTxt='';
  if (ar[0]=='success') {
    dhstats[ps]['history']=new Array();
    for (i=2;i<ar.length;i++) {
      if (ar[i].length>0) {
        mTxt=mTxt+" - " + dateToUnix(ar[i])+ "("+ar[i]+")";
        dhstats[ps]['history'][i-2]=dateToUnix(ar[i]);
      }
    }
  }
  semaphore--;
  spin();
  dhrender();//try to render data
}
  
  
function request_size(ps) {
	var myUUID =Math.uuid();
	var url =
"https://api.dreamhost.com/?username=__UP_dhuser__&key=__UP_dhkey__&cmd=dreamhost_ps-list_size_history&ps="+ps+"&unique_id="+myUUID+"&format=tab";
        semaphore++;
	_IG_FetchContent(url, _IG_Callback(response_size, ps));
  
}
  
  
//parses resize list response
//the response is in the format
//success
//header
//datetime seconds size ...
function response_size(responseText, ps) {
  var ar=responseText.split("\n");
  var mTxt='';
  if (ar[0]=='success') {
    dhstats[ps]['size']=new Array();
    for (i=2;i<ar.length;i++) {
      if (ar[i].length>0) {
        ar2=ar[i].split("\t");
        dhstats[ps]['size'][i-2]=new Array(dateToUnix(ar2[0]), ar2[1], ar2[2]);
      }
    }
  }
  semaphore--;
  spin();
  dhrender();//try to render data
}


function request_usage(ps) {
	var myUUID =Math.uuid();
	var url =
"https://api.dreamhost.com/?username=__UP_dhuser__&key=__UP_dhkey__&cmd=dreamhost_ps-list_usage&ps="+ps+"&unique_id="+myUUID+"&format=tab";
        semaphore++;
	_IG_FetchContent(url, _IG_Callback(response_usage, ps));
  
}

  
//parses usage list response
//the response is in the format
//success
//header
//datetime memory load
function response_usage(responseText, ps) {
  var ar=responseText.split("\n");
  //var mTxt=responseText;
  if (ar[0]=='success') {
    dhstats[ps]['usage']=new Array();
    for (i=2;i<ar.length;i++) {
      if (ar[i].length>0) {
        ar2=ar[i].split("\t");
        dhstats[ps]['usage'][i-2]=new Array(dateToUnix(ar2[0]), ar2[1], ar2[2]);
      }
    }
  }
  semaphore--;
  spin();
  dhrender();//try to render data
}



  
//parse a date in format yyyy-mm-dd hh:mm:ss to unix timestamp
function dateToUnix(date) {
  var d=date.split(" ");
  var d1=d[0].split("-"); //split date
  var d2=d[1].split(":"); //split h:m:s
  var d3=new Date(d1[0], d1[1]-1, d1[2], d2[0], d2[1], d2[2]);//generate date
  return (d3.getTime()/1000)
}
  
function unixToDate(timestamp) {
  var d= new Date(timestamp*1000);
  var res=d.getFullYear()+'-'+((d.getMonth()+1)<10?'0':'')+(d.getMonth()+1)+'-'+((d.getDate())<10?'0':'')+d.getDate();
  res+=' '+((d.getHours())<10?'0':'')+d.getHours()+':'+((d.getMinutes())<10?'0':'')+d.getMinutes()+':'+((d.getSeconds())<10?'0':'')+d.getSeconds();
  return res;
}
  
//print Google Charts urls for rendering graphs
function dhrender() {
  if (semaphore>0) return;//still waiting for data
  var mTxt='';
  if(__UP_showdhlogo__)
    mTxt='<img src="http://www.dreamhost.com/images/landings/logo.png"><br>';
  for (s in dhstats) {
  var mC1='';

  //usage
  var mC1x='';
  var mC1xtmp;
  var mC1y1tmp;
  var mC1y2tmp;
  var mC1y1='';
  var mC1y2='';
  
  //history
  var mC1x3tmp;
  var mC1x3='';
  var mC1y3='';
  
  //size
  var mC1x4='';
  var mC1x4tmp;
  var mC1y4='';
  var mC1y4max=0;
  var mC1y4min=Number.MAX_VALUE;
  var mC1y4tmp=-1;
  
  mC1='http://chart.apis.google.com/chart?cht=lxy&chf=bg,s,__UP_backgroundcol__&chs=__UP_chwidth__x__UP_chheight__&chco=__UP_rebootcol__,__UP_memsizecol__,__UP_loadcol__,__UP_memusedcol__&chd=e:'
  var mCTmax=0;
  var mCTmin=Number.MAX_VALUE;
  var mCMmax=0;
  var mCMmin=Number.MAX_VALUE;
     mTxt+=s+'<br>';
    if (dhstats[s]['usage']) {
        var count=0;
        for (u in dhstats[s]['usage']) {
          mCTmin=Math.min(mCTmin,dhstats[s]['usage'][u][0]);
          mCTmax=Math.max(mCTmax,dhstats[s]['usage'][u][0]);
          mCMmin=Math.min(mCMmin,dhstats[s]['usage'][u][1]);
          mCMmax=Math.max(mCMmax,dhstats[s]['usage'][u][1]);
          count++;
          if (count>256) break; //no more than 1024 events
        }
        count=0;
        for (u in dhstats[s]['usage']) {
          mC1xtmp=Math.round((dhstats[s]['usage'][u][0]-mCTmin)/(mCTmax-mCTmin)*4095);
          mC1x+=gencode(mC1xtmp)+'';
          mC1y1+=gencode(Math.round(dhstats[s]['usage'][u][2]*4095))+'';
          mC1y2+=gencode(Math.round((dhstats[s]['usage'][u][1]-mCMmin)/(mCMmax-mCMmin)*4095))+'';
          dhhover[mC1xtmp]=new Array(dhstats[s]['usage'][u][0], dhstats[s]['usage'][u][1], dhstats[s]['usage'][u][2]);
          count++;
          if (count>256) break; //no more than 1024 events
        }
    }
    count=0;
    if (dhstats[s]['history'])
        //dhstats[s]['history']=dhstats[s]['history'].reverse();
        for (h in dhstats[s]['history']) {
          mC1x3tmp=Math.round((dhstats[s]['history'][h]-mCTmin)/(mCTmax-mCTmin)*4095);
          if(!isNaN(mC1x3tmp-1)) {
            mC1x3+=gencode(mC1x3tmp-1);
            mC1y3+=gencode(0);
          }
          if(!isNaN(mC1x3tmp)) {
            mC1x3+=gencode(mC1x3tmp);
            mC1y3+=gencode(4095);
          }
          if(!isNaN(mC1x3tmp+1)) {
            mC1x3+=gencode(mC1x3tmp+1);
            mC1y3+=gencode(0);
          }
          count++;
          if (count>256) break; //no more than 1024 events
        }
    count=0;
    if (dhstats[s]['size'])
        for (z in dhstats[s]['size']) {
          mC1y4min=Math.min(mC1y4min,dhstats[s]['size'][z][2]);
          mC1y4max=Math.max(mC1y4max,dhstats[s]['size'][z][2]);
          count++;
          if (count>256) break; //no more than 1024 events
        }
        count=0;
        var lastmC1y4=0;
        for (z in dhstats[s]['size']) {
          mC1x4tmp=Math.round((dhstats[s]['size'][z][0]-mCTmin)/(mCTmax-mCTmin)*4095);
          if(!isNaN(mC1x4tmp-1) && mC1y4tmp>0) {
            mC1x4+=gencode(mC1x4tmp-1)+'';
            mC1y4+=gencode(mC1y4tmp)+'';
          }
          if(!isNaN(mC1x4tmp)) {
            mC1x4+=gencode(mC1x4tmp)+'';
            lastmC1y4=Math.round((dhstats[s]['size'][z][2])/(mC1y4max)*4095);
            mC1y4+=gencode(lastmC1y4)+'';
          }
          mC1y4tmp=Math.round((dhstats[s]['size'][z][2])/(mC1y4max)*4095);
          count++;
          if (count>256) break; //no more than 1024 events

        }
        mC1x4+=gencode(4095)+'';
        mC1y4+=gencode(lastmC1y4)+'';
 
     
    mTxt+='<a href="#" id="a_'+s+'" onclick="return false;" ';
    if(__UP_showtext__) mTxt+='class="tooltip"';
    mTxt+=' >';
    mTxt+='<img id="img_'+s+'" ';
    if(__UP_showtext__) mTxt+='onmousemove="moveImg(event, \''+s+'\')" ';
    mTxt+=' border="0" src="'+mC1+mC1x3+','+mC1y3+','+mC1x4+','+mC1y4+','+mC1x+','+mC1y1+','+mC1x+','+mC1y2+'">';
    if(__UP_showtext__) mTxt+='<span id="span_'+s+'">&nbsp;</span>';
    mTxt+='</a><br>';
   }
  mTxt+='<br><font color="#__UP_loadcol__">&#8212; Load </font>';
  mTxt+='<font color="#__UP_memusedcol__">&#8212; UseMem </font>';
  mTxt+='<font color="#__UP_memsizecol__">&#8212; MemChg </font>';
  mTxt+='<font color="#__UP_rebootcol__">&#8212; Boot </font>';

  document.getElementById('dhcontent_div').innerHTML = mTxt;
  
}
function moveImg(e,s) {
if(!e) e=window.event
var eX = (e.layerX) ? e.layerX : e.offsetX | 0
var minD=1000;
var curX=(eX+1)*4095/__UP_chwidth__;
var elem='span_'+s;
  for(a in dhhover)
    if (Math.abs(curX-a)<20 && Math.abs(curX-a)<minD) {
      minD=Math.abs(curX-a);
      var myd=new Date(dhhover[a][0]*1000);
    
      document.getElementById(elem).innerHTML=unixToDate(dhhover[a][0])+'<br>Mem: '+dhhover[a][1]+'<br>Load: '+Math.round(dhhover[a][2]*100)+'%';
    }
}
function spin() {
  var len=document.getElementById('dhcontent_div').innerHTML.length-1;
  var txt=document.getElementById('dhcontent_div').innerHTML.substring(0,len);
  document.getElementById('dhcontent_div').innerHTML=txt+spinner[document.getElementById('dhcontent_div').innerHTML[len]];
}

//google charts encoding 2bytes
function gencode(val) {
  var a=new Array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 
                  'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
                  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 
                  'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
                  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '.'
          );
  //val=val/100*4095;
  if (val>4095) val=4095;
  if (val<0) val=0;
  return (a[Math.floor(val/64)])+''+(a[Math.floor(val%64)]);
}

//google charts encoding 1byte
function gencode_1(val) {
  var a=new
Array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
                  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '.'
          );
  return (a[Math.floor((val*61)/100)]);
}

</script>
<style>
body {
  background-color:__UP_backgroundcol__;
  font-size:small;
  }
#dhcontent_div, #testspan {
  font-family: courier, serif;
  font-size:small;

}
  a.tooltip{
    position:relative; /*this is the key*/
    z-index:24;
    text-decoration:none;
}
    
a.tooltip img {
	text-decoration:none;
}

a.tooltip:hover{z-index:25; background-color:#eee}

a.tooltip span{display: none}

a.tooltip:hover span{ /*the span will display just on :hover state*/
    display:block;
    position:absolute;
    top:-120; left:0; width:__UP_chwidth__;
    border:1px solid #999;
    background-color:#eee; color:#444;
    text-align: center;
}
  
</style>
</head>
<body onLoad="request();">
<div id="dhcontent_div">Waiting for data...</div>
</body>
]]></Content>
</Module>
