1,804 articles and 14,924 comments as of Monday, May 9th, 2011

EndUserSharePoint has combined resources with NothingButSharePoint.com. You can now find End User (Mark Miller), Developer (Jeremy Thake) and IT Pro SharePoint content all in one place!

This site is a historical archive and is no longer being updated. Please update your favorites, bookmarks and RSS feeds.

NothingButSharePoint.com
Tuesday, April 28, 2009

Finally: Dynamic charting in WSS, no code required! – Part 2

Dynamic Charts & Graphs Part 2

SharePoint allows you to define list views that calculate Sum, Average, Min, Max, Standard Dev, etc. on items, whenever your list has at least one numeric field or column.

The script below, combined with such a list view, will plot a Google Chart showing those totals dynamically. The chart scale is automatically adjusted with the maximum value to be charted so it fits the designated size in the script.

Once implemented, you can hide the list view web part so only the chart will render on the page. You can also play around with chart parameters within the script, to change chart type, style, size, colors or even build more complex charts. Take a look at the Google Chart API page for reference.

Hope this is useful.

Here’s a step-by-step screen capture series:

Dynamic Charts & Graphs Part 2

<Dynamic Charts & Graphs Part 2

Dynamic Charts & Graphs Part 2

Dynamic Charts & Graphs Part 2

Dynamic Charts & Graphs Part 2

Dynamic Charts & Graphs Part 2

Dynamic Charts & Graphs Part 2

Dynamic Charts & Graphs Part 2

    <div id="jLoadMe" class="content"></div>
    <script src="/jquery/jquery.js"  type="text/javascript">
    // To load jQuery (redefine the path  if necessary)
    </script>
    <script type="text/javascript">
    /*
    * Google Chart for list column totals
    * By Claudio Cabaleyro (2009)
    */
    Array.prototype.max = function() { //  function to get the maximum value of Y axis
    var max = this[0];
    var len = this.length;
    for (var i = 1; i < len; i++) if (this[i] > max) max = this[i];
    return max;
    }
    function BuildChartURL(Data, Names)  // Adjust Chart Properties below - See Google Charts API for reference
    {
    MaxData=  Math.round(1.1*Data.max()).toString();
    var  DataPoints= "&amp;amp;chd=t:"+Data.join(",");
    var  DataTitles= "&amp;amp;chl="+Names.join("|");
    var  ChType= "cht=bvs";  // Vertical bars type
    var  ChSize = "&amp;amp;chs=300x200"; //HeighxWidth in px
    var  ChScale = "&amp;amp;chds=0,"+MaxData; //Vertical scale: 0 through 10% over max  series value
    var  ChLabels ="&amp;amp;chm=N,000000,0,-1,11,-1";
    return ("<p><IMG  src='http://chart.apis.google.com/chart?"+ChType+ChSize+DataPoints+DataTitles+ChScale+ChLabels+"'/></p>");
    }
    var ArrayTitle= $('.ms-unselectedtitle:html');  //find all columns in titles row
    var TitleTxt = new (Array);
    $.each(ArrayTitle, function(i,e)
    {
    TitleTxt[i] = $(e).text(); // Store ALL column titles in TitleTxt
    });
    var ArrayTotal= $('.ms-vb2', $('#aggr'));  //find all columns in totals row
    var TotalTxt = new (Array);
    $.each(ArrayTotal, function(i,e)
    {
    TotalTxt[i] =  $(e).text().substr($(e).text().indexOf("= ")+2); // Store ALL column  totals in TotalTxt
    });
    var Titles = new (Array);
    var Totals = new (Array);
    $.each(TitleTxt, function(i,e) // clear  empty elements in totals row
    {
    if (TotalTxt[i] != ""  &amp;&amp; TotalTxt[i] != null)
    {
    Titles.push(TitleTxt[i]);
    Totals.push(TotalTxt[i]);
    }
    });
    $("#jLoadMe").append(BuildChartURL(Totals, Titles))
    </script>

Claudio Cabaleyro
MOSS 2007 – (almost) no-code solutions

View all entries in this series: ClaudioCabaleyro-Dynamic Charting»
 

Please Join the Discussion

44 Responses to “Finally: Dynamic charting in WSS, no code required! – Part 2”
  1. Cloudno9 says:

    I changed the code to point to the jQuery at the address shown below and I follow all the steps you mentioned in your post but cant seems to get the chart.

    am I missing something or doing something wrong?

    here is the code that I am using in CEWP:

    Bar Chart Using Google Charting API

    if(typeof jQuery=="undefined"){
    	var jQPath="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/";
    	document.write("");
    }
        /*
        * Google Chart for list column totals
        * By Claudio Cabaleyro (2009)
        */
        Array.prototype.max = function() { //  function to get the maximum value of Y axis
        var max = this[0];
        var len = this.length;
        for (var i = 1; i  max) max = this[i];
        return max;
        }
        function BuildChartURL(Data, Names)  // Adjust Chart Properties below - See Google Charts API for reference
        {
        MaxData=  Math.round(1.1*Data.max()).toString();
        var  DataPoints= "&amp;chd=t:"+Data.join(",");
        var  DataTitles= "&amp;chl="+Names.join("|");
        var  ChType= "cht=bvs";  // Vertical bars type
        var  ChSize = "&amp;chs=300x200"; //HeighxWidth in px
        var  ChScale = "&amp;chds=0,"+MaxData; //Vertical scale: 0 through 10% over max  series value
        var  ChLabels ="&amp;chm=N,000000,0,-1,11,-1";
        return ("");
        }
        var ArrayTitle= $('.ms-unselectedtitle:html');  //find all columns in titles row
        var TitleTxt = new (Array);
        $.each(ArrayTitle, function(i,e)
        {
        TitleTxt[i] = $(e).text(); // Store ALL column titles in TitleTxt
        });
        var ArrayTotal= $('.ms-vb2', $('#aggr'));  //find all columns in totals row
        var TotalTxt = new (Array);
        $.each(ArrayTotal, function(i,e)
        {
        TotalTxt[i] =  $(e).text().substr($(e).text().indexOf("= ")+2); // Store ALL column  totals in TotalTxt
        });
        var Titles = new (Array);
        var Totals = new (Array);
        $.each(TitleTxt, function(i,e) // clear  empty elements in totals row
        {
        if (TotalTxt[i] != ""  && TotalTxt[i] != null)
        {
        Titles.push(TitleTxt[i]);
        Totals.push(TotalTxt[i]);
        }
        });
        $("#jLoadMe").append(BuildChartURL(Totals, Titles))

  2. Cloudno9 says:

    Just wanted to let you know that I do have the div line at the top but when i submitt it here it took it out…

  3. John G says:

    I see it will take the total sum number in a list, but will it create a bar on the graph for each individual group sum from a list of values? Maybe to difficult w/o excel services?

  4. scott says:

    I was able to get the single pie chart and the multiple pie charts to work, but not this one.

  5. ryan says:

    i was unable to get the chart to render as well. i am using averages not totals but should pull into the chart all the same. Any help?

  6. Richard Duffy says:

    Hi,

    I also have been unable to get the chart to render. I have tried various methods to call in the jquery.js code but still no joy!

    Any help appreciated

  7. Craig says:

    I’ll add myself to the group above … i can get the first one and the multiples to work fine, but this one refuses to render.

    Any ideas?

    Thanks,

  8. Can u please send Code Through Mail Because i dont Chart is not display.

    Thanks in Advance…

  9. Mike Keenan says:

    Add my voice to the chorus. I can not get this to work either

  10. I’ll have Claudio take another look at this one to see where the problem is. For those of you who say it doesn’t work, can you be more specific? How far does it get before it bails? Does it break anything? What does “it doesn’t work” mean?

    Thanks,
    Mark

  11. Just to make sure… did everyone change the path to jQuery to the instance within their own environement? The code same points to the way I have it set. Yours is probably in a different location.

    Check your source attribute and make sure it's pointing to your instance of jQuery.

  12. Mike Keenan says:

    simple list: 3 columns title, Jan, Feb
    2 items: milk, 50, 100
    butter,40, 400
    summing Jan and Feb columns

        // To load jQuery (redefine the path  if necessary)
    
        /*
        * Google Chart for list column totals
        * By Claudio Cabaleyro (2009)
        */
        Array.prototype.max = function() { //  function to get the maximum value of Y axis
        var max = this[0];
        var len = this.length;
        for (var i = 1; i  max) max = this[i];
        return max;
        }
        function BuildChartURL(Data, Names)  // Adjust Chart Properties below - See Google Charts API for reference
        {
        MaxData=  Math.round(1.1*Data.max()).toString();
        var  DataPoints= "&amp;chd=t:"+Data.join(",");
        var  DataTitles= "&amp;chl="+Names.join("|");
        var  ChType= "cht=bvs";  // Vertical bars type
        var  ChSize = "&amp;chs=300x200"; //HeighxWidth in px
        var  ChScale = "&amp;chds=0,"+MaxData; //Vertical scale: 0 through 10% over max  series value
        var  ChLabels ="&amp;chm=N,000000,0,-1,11,-1";
        return ("");
        }
        var ArrayTitle= $('.ms-unselectedtitle:html');  //find all columns in titles row
        var TitleTxt = new (Array);
        $.each(ArrayTitle, function(i,e)
        {
        TitleTxt[i] = $(e).text(); // Store ALL column titles in TitleTxt
        });
        var ArrayTotal= $('.ms-vb2', $('#aggr'));  //find all columns in totals row
        var TotalTxt = new (Array);
        $.each(ArrayTotal, function(i,e)
        {
        TotalTxt[i] =  $(e).text().substr($(e).text().indexOf("= ")+2); // Store ALL column  totals in TotalTxt
        });
        var Titles = new (Array);
        var Totals = new (Array);
        $.each(TitleTxt, function(i,e) // clear  empty elements in totals row
        {
        if (TotalTxt[i] != ""  && TotalTxt[i] != null)
        {
        Titles.push(TitleTxt[i]);
        Totals.push(TotalTxt[i]);
        }
        });
        $("#jLoadMe").append(BuildChartURL(Totals, Titles))
    
  13. Mike Keenan says:

    sorry looks like src truncated, the jquery source defined as

    http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js
  14. Mike – Does that code work for you? — Mark

  15. Mike Keenan says:

    Well I got this working. Turned out it was mostly formatting from copying the code. Changes I made included:

    &amp; globally changed to &

    Math.round(1.1*Data.max()) globally changed to Math.round(1.1*Data.max()+1) //I found that if I didn’t add +1 to the end then value of max never displayed

    && globally changed to &&

    I suggest the code include an alert statement just before the return statement that prints out what is being returned.

    This is very cool now that it works!

  16. Claudio says:

    I am really sorry for the problems that I did not noticed on code transcription. I have just sent the right script to Mark so he can update it in the post.
    I have also corrected another potential problem you could find with the above version if numbers to be plotted are greater than 1,000 (include commas).

    Hope this time goes well.
    Claudio

  17. I am working with Claudio on the update. He has isolated the main problem and we can now get a graph/chart to show, but there is a slight problem with the label offset… stay tuned. — Mark

  18. Here’s the latest, updated script. There is still a problem with label names being off by one. Let us know if you find a solution before we do:

    <div id="jLoadMe" class="content"></div>
    
    <script src="/jquery/jquery.js" type="text/javascript">
       // To load jQuery (redefine the path if necessary)
    </script>
    
    <script type="text/javascript">
    /*
    * Google Chart for list column totals
    * By Claudio Cabaleyro (2009)
    */ 
    
    $("document").ready(function ($) { 
    
    Array.prototype.max = function() {							// function to get the maximum value of Y axis
    var max = this[0];
    var len = this.length;
    for (var i = 1; i < len; i++) if (this[i] > max) max = this[i];
    return max;
    }
    
    function BuildChartURL(Data, Names)							// Adjust Chart Properties below - See Google Charts API for reference
    	{
    		MaxData= Math.round(1.1*Data.max()).toString();
    	var 	DataPoints= "&amp;chd=t:"+Data.join(",");
    	var 	DataTitles= "&amp;chl="+Names.join("|");
    	var 	ChType= "cht=bvs";						// Vertical bars type
    	var 	ChSize = "&amp;chs=300x200";					//HeighxWidth in px
    	var 	ChScale = "&amp;chds=0,"+MaxData;				//Vertical scale: 0 through 10% over max series value
    	var	ChLabels ="&amp;chm=N,000000,0,-1,11,-1";
    	return	("<p><IMG src='http://chart.apis.google.com/chart?"+ChType+ChSize+DataPoints+DataTitles+ChScale+ChLabels+"'/></p>");
    	}
    
    var ArrayTitle= $('.ms-unselectedtitle .ms-vb');		//find all columns in titles row
    
    var TitleTxt = new (Array);
    $.each(ArrayTitle, function(i,e)
    	{
    	TitleTxt[i] = $(e).text();	// Store ALL column titles in TitleTxt
    	});
    
    var ArrayTotal=$(' #aggr .ms-vb2'); 	//find all columns in totals row
    var TotalTxt = new (Array);
    $.each(ArrayTotal, function(i,e)
    	{
    	TotalTxt[i] = $(e).text().substr($(e).text().indexOf("= ")+2);	// Store ALL column totals in TotalTxt
    	});
    
    var Titles = new (Array);
    var Totals = new (Array);
    $.each(TitleTxt, function(i,e)		// clear empty elements in totals row
    	{
    	if (TotalTxt[i] != "" && TotalTxt[i] != null)
    		{
    		Titles.push(TitleTxt[i]);
    		Totals.push(parseFloat(TotalTxt[i].replace(',','')));
    		}
    	});
    
    $("#jLoadMe").append(BuildChartURL(Totals, Titles))
    alert(BuildChartURL(Totals, Titles)); // debug line
    
    })(jQuery);
     </script>
    
  19. Been working on this for a couple days, troubleshooting and think I’ve got it worked out. Try this. If I get confirmation it is working, I’ll get it cleaned up a bit and publish a new article.

    <div id="jLoadMe" class="content"></div>
    
    <script type="text/javascript">
    if(typeof jQuery=="undefined"){
    	var jQPath="/javascripts/";
    	document.write("<script src='",jQPath,"jquery.min.js' type='text/javascript'><\/script>");
    }
    </script>
    
    <script type="text/javascript">
    /*
    * Google Chart for list column totals
    * By Claudio Cabaleyro (2009)
    */ 
    
    $("document").ready(function ($) { 
    
    Array.prototype.max = function() {							// function to get the maximum value of Y axis
    var max = this[0];
    var len = this.length;
    for (var i = 1; i < len; i++) if (this[i] > max) max = this[i];
    return max;
    }
    
    function BuildChartURL(Data, Names)							// Adjust Chart Properties below - See Google Charts API for reference
    	{
    		MaxData= Math.round(1.1*Data.max()).toString();
    	var 	DataPoints= "&amp;chd=t:"+Data.join(",");
    	var 	DataTitles= "&amp;chl="+Names.join("|");
    	var 	ChType= "cht=bvs";						// Vertical bars type
    	var 	ChSize = "&amp;chs=300x200";					//HeighxWidth in px
    	var 	ChScale = "&amp;chds=0,"+MaxData;				//Vertical scale: 0 through 10% over max series value
    	var	ChLabels ="&amp;chm=N,000000,0,-1,11,-1";
    	return	("<p><IMG src='http://chart.apis.google.com/chart?"+ChType+ChSize+DataPoints+DataTitles+ChScale+ChLabels+"'/></p>");
    	}
    
    var ArrayTitle= $(".ms-unselectedtitle .ms-vb",".ms-viewheadertr ");		//find all columns in titles row
    
    var TitleTxt = new (Array);
    $.each(ArrayTitle, function(i,e)
    	{
    	TitleTxt[i] = $(e).text();	// Store ALL column titles in TitleTxt
    	});
    
    var ArrayTotal=$('#aggr tr > td:not(.ms-vb)') 	//find all columns in totals row
    var TotalTxt = new (Array);
    $.each(ArrayTotal, function(i,e)
    	{
    	TotalTxt[i] = $(e).text().substr($(e).text().indexOf("= ")+2);	// Store ALL column totals in TotalTxt
    	});
    
    var Titles = new (Array);
    var Totals = new (Array);	
    
    $.each(TitleTxt, function(i,e)		// clear empty elements in totals row
    	{
    	if (TotalTxt[i] != "" && TotalTxt[i] != null)
    		{
    		Titles.push(TitleTxt[i]);
    		Totals.push(parseFloat(TotalTxt[i].replace(',','')));
    		}
    	});
    $("#jLoadMe").append(BuildChartURL(Totals, Titles))
    // alert(BuildChartURL(Totals, Titles)); // debug line
    
    })(jQuery);
     </script>
    
  20. Thanks Claudio.

    Now it is working smoothly.

  21. Mike Keenan says:

    This works very nicely Claudio. Now since I know Mark, and hopefully you, love a challenge….I had a request to make this functionality work in WSS 2 but the table structure is not the same, so a search for ms-unselecteditem in wss2 does not provide the totals row. I made a simple 3 column list in wss 2. (Department, Jan, Feb). Put one row in (Sales, 5, 4). The code for the view is (hopefully this makes it thru with this post, I changed the word java script to js):

    ctx = new ContextInfo();
    ctx.listBaseType = 0;
    ctx.listTemplate = 100;
    ctx.listName = “{D26B7171-29EC-404A-8558-6CA64AE0811D}”;
    ctx.listUrlDir = “Lists/Wins”;
    ctx.HttpPath = “/_vti_bin/owssvr.dll?CS=109″;
    ctx.HttpRoot = “”;
    ctx.imagesPath = “/_layouts/images/”;
    ctx.PortalUrl = “/mysite/”;
    if (ctx.PortalUrl == “”) ctx.PortalUrl = null;
    ctx.displayFormUrl = “/Lists/Wins/DispForm.aspx”;
    ctx.editFormUrl = “/Lists/Wins/EditForm.aspx”;
    ctx.isWebEditorPreview = 0;
    ctx.ctxId = 2;

    ctx2 = ctx;
    DepartmentJanFebSum = 5Sum = 4Sales54

    Any thoughts on how we can leverage this very cool solution in wss2?

    Thanks for everything.
    Mike

  22. Claudio says:

    Hi Mike,
    I unfortunately do not know WSS 2.0 builds the pages, but I think you can still try to find a pattern that allows you to get titles and totals with jQuery. I strongly recommend you to take a look at this debugging session from Paul Grenier:
    http://www.endusersharepoint.com/?p=1417
    Even if you cannot use Firefox and Firebug, you can review your page HTML source to find such patterns and try to build new selectors.
    Let me know how it was.

  23. Oscar says:

    Claudio, I have tried this and got to graph out data, but labels on the x axis are all overwritting eachohter. What happens if you x-axis is not 3 letter abbreviations for months? Is there a way to get it to space the bars so that the labels can fit?

  24. Claudio says:

    Oscar,
    One option is playing with spacing between bars, changing the following line (I am replacing the & symbol by the word AMPERSAND as it might be wrongly displayed in this comment):

    ChScale = “AMPERSANDamp;chds=0,”+MaxData;

    to:

    ChScale = “AMPERSANDamp;chds=0,”+MaxData + “AMPERSANDamp;chbh=a,8″;

    This will double the space between bars.
    Another option is to change to an horizontal bars chart. For this, you need to replace two lines in the code (I show the modified versions here):

    1) var ChType= “cht=bhs”;
    2) var DataTitles= “AMPERSANDamp;chxt=x,yAMPERSANDamp;chxl=0:||1:|”+Names.reverse().join(”|”)+”|”;

    If you want to experiment with other options, take a look at this page:
    http://code.google.com/apis/chart/styles.html#bar_width

    regards,
    Claudio

  25. Oscar says:

    Thanks for the quick reply.

    I tried the horizontal bar graph but I am having some trouble as the x-axis is not scaling coorectly or the bars are not placing right on the x-axis, although they are in the right proportions. Also the Y-axis is just pulling numbers from 0-X for as many items as I have, instead of the labels of those items. See the link here for an example:

    http://workspace.office.live.com/#oscarb2/Documents/chart1png.png

  26. Oscar says:

    Claudio sorry about the link in the above posting, here is the correct link to get to it example of what I am getting and my list view is here:
    https://cid-500e0ee3b4860486.skydrive.live.com/self.aspx/gsoc/chart1.jpg

  27. Claudio says:

    Hi Oscar,
    Just guessing: take another look at the syntax on the line 2) in my previous answer, as the quotes do not render quite right in the post. Use straight double quotes in your code editor and do not forget also to change back the word AMPERSAND by the & symbol.

  28. Jamen says:

    This is a great solution! I have had some luck with it to generate both pie charts and bar charts.

    However, I have been trying to get this code to work with Google Charts “Google-O-Meter”. I just have one averaged column that I wanted to display using the meter as a visual representation. The column shows overall satisfaction based on a 1-10 rating. Is there an easy way to get this to work for this type of chart???

  29. Jamen says:

    Nevermind, finally got this working nicely after manipulating the variables enough. Thanks again for the script.

  30. Dhamodaran says:

    hi.. i am new to sharepoint… i have the requirement as, to display a task list in a bar chart and to get it updated whenever there is a change in task list… i tried excel web services.. but it dint work.. found this post interesting… i am done with all the steps mentioned here… but still the chart is not displaying.. i doubt whether i shud do anything with jquery.. pls help me out

  31. Barbara Stroud says:

    I have two questions as this topic seems to have cooled for a while. There is mention of code to add to a CEWP as part of the instructions, but I sure can’t seem to find it. I see code examples from other people, but not the original post.

    Second, has anyone come up with a stacked bar chart solution? Even Google API didn’t appear to have anything. We want to provide execs with a chart that shows the number of Green, Amber and Red projects for each region.

    Any help appreciated!

  32. Barbara Stroud says:

    Thanks, Mark. I got it all. I’ll post if I have any additional questions.

  33. Joe Tobey says:

    Where is the latest code you refer to on July 11th? The Code I pulled down doesn’t have alerts and is not running in my SharePoint session.

  34. Joe Tobey says:

    Thanks Mark…I will work with that one.

  35. Tahir says:

    I have extended this technique to display the Intractive Charts

    if(typeof jQuery==”undefined”){
    var jQPath=”http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/”;
    document.write(”");
    }

    var ColValue = new Array();
    var ColName = new Array();

    // Getting the Data
    $(”document”).ready(function(){
    var arrayList=$(”td.ms-gb:contains(’:')”);
    var coord= new Array();
    var labels= new Array();
    $.each(arrayList, function(i,e)
    {
    var MyIf= $(e).text();
    var txt= MyIf.substring(MyIf.indexOf(’(')+1,MyIf.length-1); // Extract the ‘Y’ coordinates
    coord[i]=txt;
    var txt1= MyIf.substring(MyIf.indexOf(’:')+2,MyIf.indexOf(”(”)-1); // Extract the labels
    labels[i]=txt1+”(”+txt+”)”; //add also coordinates for better read
    });

    ColValue = coord;
    ColName = labels;
    });

    //Graph Rendering
    google.load(”visualization”, “1″, {packages:["columnchart"]});
    google.setOnLoadCallback(drawChart);
    function drawChart() {
    var data = new google.visualization.DataTable();

    data.addColumn(’string’, ‘Department’);
    data.addColumn(’number’, ‘Department’);

    data.addRows(ColValue.length);

    for (i=0; i<ColValue.length; i++)
    {
    data.setValue(i, 0, ColName[i]);
    data.setValue(i, 1, parseInt(ColValue[i]));
    }

    var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
    chart.draw(data, {width: 600, height: 240, is3D: true, title: 'Graph Title'});
    }

  36. Rajiv Vishwa says:

    Hi, I’m still having that offset label prob, can you please help. Check the screenshot http://img.a4apphack.com/other/sharepointdash-barchartsprob.jpg

    The code which I’m using is here, http://gist.github.com/394176, this code displays the graph properly except
    1. One less than the total columns
    2. Bar labels does not correspond to the value

    Claudio, I’m in need of your help.

  37. Luc says:

    Hello, is there any chance to split more charts in the same page?
    What i would like to do is having a stacked bar chart on the top of the page, and then a set of 3 different pie charts at the bottom. Whenever i try to add a new CEWP with the code to the page, the only result i achieve is to double the number of the charts visible…

    Thanks!

    /Luc

  38. Robby Thesman says:

    Hi,
    Does it work at all with WSS 2?

Trackbacks

Check out what others are saying about this post...
  1. [...] Finally: Dynamic charting in WSS, no code required! – Part 2 [...]

  2. [...] I found great interest in the charting solution recently proposed by Claudio Cabaleyro (and relayed on endusersharepoint.com). [...]




Notify me of comments to this article:


Speak and you will be heard.

We check comments hourly.
If you want a pic to show with your comment, go get a gravatar!