Performancing Stats for Blogsome

This post is a Blogsome specific post with information gleaned from HOWTO: Wordpress Visitor Count Plugin Using Metrics API. If you aren’t using Blogsome, then you’ll be better off visiting there. If you are using Performancing Metrics as your system for tracking usage patterns, you may wish to have a counter of some sort. It’s possible to do this, safely and securely with just a little bit of Smarty. First, you’ll need to get your current Performancing Authorisation Key. This will not change unless you change your password, so keep that in mind if this stops working at some stage… To get your API key, you’ll need to visit a URL like the following, but with your username and password. http://performancing.com/perfstats/api.php?action=getauth&uid;=some+user&pwd;=mypass If you put this into a Firefox address bar, it will display the XML, but the only part we need is the part inside the <auth> tags. Don’t give this to anyone, else they can see all of your Performancing stats. You can now use this key to get some stats. As a test, we’ll get the basic stats of your blog. Copy and paste the URL below, and insert it into the address bar. Then, replace KEY with your authorisation key, and schinckel with your blogsome ID:

http://performancing.com/perfstats/api.php?action=getvisitorstats&auth;=KEY&blog;_domain=schinckel.net

You’ll be presented with some XML that looks like:

    <response>
        <request>
            <auth>KEY</auth>
            <blog_domain>schinckel.net</blog_domain>
            <action>getvisitorstats</action>
        </request>
        <ChartURL>
            http://performancing.com/perfstats/api.php?action=getchart&blog_domain=schinckel.net&dtype=visitor_stats&ctype=line&m=today&d1=2006-04-17&d2=
        </ChartURL>
        <Visits>20</Visits>
        <AverageVisitsPerDay>20.0000</AverageVisitsPerDay>
        <AverageVisitLength>517.9500</AverageVisitLength>
        <RepeatVisitors>0</RepeatVisitors>
    </response>

You can then use the ChartURL to see a nice graph, something like: Performancing Stats If this doesn’t work, then check your API key, and all of the URLs you’ve typed in so far. Now, let’s imagine we just want a counter for total blog views. The URL will need to look a bit like (I’ve broken it onto seperate lines first to help you understand it): http://performancing.com/perfstats/api.php?action=getvisitorstats &auth;=KEY&blog;domain=_blogname.blogsome.com&m;=date_range &d1;=start_date&d2;=end_date We’ll look at how to get the current date a bit later: for now, put a date at some point in the future. Mine, sans the authorisation key was: http://performancing.com/perfstats/api.php?action=getvisitorstats&auth;=KEY&blog;_domain=schinckel.net&m;=date_range&d1;=2006-01-01&d2;=2007-01-01 Which generated the following XML:

    <response>
        <request>
            <auth>KEY</auth>
            <blog_domain>schinckel.net</blog_domain>
            <action>getvisitorstats</action>
        </request>
        <ChartURL>
            http://performancing.com/perfstats/api.php?action=getchart&blog_domain=schinckel.net&dtype=visitor_stats&ctype=line&m=date_range&d1=2006-01-01&d2=2007-01-01
        </ChartURL>
        <Visits>9204</Visits>
        <AverageVisitsPerDay>271.3529</AverageVisitsPerDay>
        <AverageVisitLength>289.5818</AverageVisitLength>
        <RepeatVisitors>242</RepeatVisitors>
    </response>

It’s possible to use the {fetch file="URL" assign="stats"} to grab this data and store it in a variable, so the whole lot isn’t displayed. You may have noticed that the Auth Key is included in the response! Now, the only bit we are really interested in is the

    <Visits>9204</Visits>

section, so we need some way to extract this. Smarty allows for Regular Expressions, and we want to use one that will match everything up to and including _, and discard this. We'll want to repeat that with _ onwards. Due to a limitation, we’ll need three regexes, since there are newlines in there that much with the simlest method.

    {$stats|regex_replace:"/[\r\t\n]/":""|regex_replace:"/.*<Visits>/":""|regex_replace:"/<\/Visits>.*/":""}

Thus, my final data is:

    <li>{fetch file="http://performancing.com/perfstats/api.php?action=getvisitorstats&auth=KEY&blog_domain=schinckel.net&m=date_range&d1=2006-01-01&d2=2007-01-01" assign="stats"}
        {$stats|regex_replace:"/[\r\t\n]/":""|regex_replace:"/.*<Visits>/":""|regex_replace:"/<\/Visits>.*/":""} Post views.
    </li>

Of course, that’s with a hard-coded finish date. What if we want to finish on today? Again, there’s a way to do it in $smarty: {$smarty.now|date_format:"%Y-%m-%d"} To add this to the end of the URL, use:

    {assign var="URL" value="http://performancing.com/perfstats/api.php?action=getvisitorstats&auth=KEY&blog_domain=schinckel.net&m=date_range&d1=2006-01-01&d2="}
    {assign var="today" value=$smarty.now|date_format:"%Y-%m-%d"}
    {fetch file=$URL|cat:$today assign="stats"}

It’s also simple to get a current day’s post hit count, using single_date instead of date_range. I’ll leave that one up to you.

Resizable Comment Area

I’ve already had resizable Textarea implemented in this blog - the two buttons that appear at the bottom of the comment box, next to Preview/Post Reply. However, today over on MacGeekery, I came across something even better. A resize widget, that can be dragged to resize the comment entry box. Getting this to work wasn’t quite as simple as just cutting and pasting code, however. Eventually, I rewrote the code from scratch, using some of my toolbox tools also. The script starts by finding every <textarea>, and then, if it has the class resizable, it adds an enclosing <div> tag, and a grippie <div> tag. This then allows for CSS to style the grippie tag.

    function ResizableComment(){
        textareas = document.getElementsByTagName('textarea');
        
        var textarea;
        for (var i=0; textarea = textareas[i]; i++){
            if (textarea.className.match(resizable)){
                // Insert resizable <div>
                ta = document.createElement('div');
                ta.className = resizable-textarea;
                textarea.parentNode.insertBefore(ta, textarea);
                ta.insertBefore(textarea,ta.firstChild);
                // Insert Grippie
                grippie = document.createElement('div');
                grippie.className = 'grippie';
                w = textarea.offsetWidth - 2;
                grippie.style.width = px(w);
                textarea.parentNode.insertBefore(grippie, textarea.nextSibling);
                grippie.onmousedown = beginResize;
                // Remove bottom border
                textarea.style.marginBottom = 0;
                textarea.style.borderBottom = 0;
            }
        }
    }

Notice also that it sets the onmousedown action for the grippie to a function called beginResize.

    function beginResize(e){
        var coords = getMousePos(e);
        window.resizing = eventTarget(e).parentNode.firstChild; // Textarea.
        window.resizing.style.height = px(window.resizing.offsetHeight);
        window.start_resizer = coords[1];
        document.body.onmouseup = endResize;
        document.body.onmousemove = duringResize;
        return false;
    }
    
    function duringResize(e){
        var coords = getMousePos(e);
        window.end_resizer = coords[1];
        if (window.start_resizer == window.end_resizer) return;
        window.height_change = window.end_resizer - window.start_resizer;
        if (window.resizing.offsetHeight + height_change - 1 < 115) return;
        window.resizing.style.height = px(window.resizing.offsetHeight + height_change - 1); // Need the -1 to work!
        window.start_resizer = window.end_resizer;
    }
    
    function endResize(e){
        duringResize(e);
        document.body.onmouseup = null;
        document.body.onmousemove = null;
    }

The beginResize function in turn sets up a few things, including which element needs to be resized, and the functions that need to be called as it happens. These functions use another pair of functions:

    function getMousePos(e) {
        var posx = 0; var posy = 0;
        if (!e) e = window.event;
        if (e.pageX || e.pageY){
            posx = e.pageX;
            posy = e.pageY;
        } else if (e.clientX || e.clientY){
            posx = e.clientX + document.body.scrollLeft;
            posy = e.clientY + document.body.scrollTop;
        }
    
        return new Array(posx, posy);
    }
    
    function px(val){return val + px;}

Don’t Believe Anymore • [The Whitlams][3] • [Torch The Moon][4] ★★½

[3]: ‘http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=The+Whitlams’ [4]: ‘http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?albumTerm=Torch+The+Moon&artistTerm=The+Whitlams’

Testing XMLRPC

This is a test of the XMLRPC interface. I think Ronan may have fixed it. This is a single quote ‘ This is a double quote “ This is an image: Matthew Schinckel

Seance On A Wet Afternoon • “Ultra-Lounge, Vol. 16: Mondo Hollywood” • John Barry

Image Scan

Here’s some amusing images that passed across my feed/email in the past couple of days: This first one is what one of M.C. Escher’s paintings may have looked like if done in primary school, complete with Teacher comments. Escher Child The next two came from Limbic Nutrition, and made me smile.

Better Performancing Stats

This is a Blogsome specific version of the post that can be found at Hack Metrics for More Detail. The default script that I modified to generate Performancing Metrics stats for my Blogsome blog has some pretty serious limitations. The main one is that there is no differentiation between single posts, and the various types of archive pages that can be view: Category, Author, and Date (which includes Yearly, Monthly and Daily archive pages). To overcome this, I’ve come up with the following rationale:

  • Test to see if it’s a Page. Set the title to the Page title, and the category to “Page”.
  • Test to see if it’s the Homepage. If so, the title should be “Homepage”, as should the category. I’ve also been thinking about whether to append the title of the newset post, which would then enable some idea of how often the front page is viewed with particular posts. Then, using the category “Homepage” would enable me to still see how many homepage views there are in total. This is turning out to be harder than expected, due to some apparent malfunctioning of {rewind_posts}.
  • Test to see if it’s a category page. This should have the title and the category both set to the category name.
  • Test to see if it’s a date archive page. If it is, set the category to Archive, and the title to the date. Be a bit clever, and have different titles for Monthly, Daily and Yearly archives.
  • Test to see if it’s a search page. If so, set the category to Search, and the title to the search terms, prefixed by Search:.
  • Finally, it must be a single post page. Set the title to the post title. This is where the system breaks a little, as there doesn’t seem to be the ability to have multiple categories. This seems to be a limitation of performancing metrics.

Anyway, here’s the code:

        <script type="text/javascript">
            {if $smarty.server.SCRIPT_NAME == "/wp-inst/pages"}
                z_post_title="{single_post_title}";
                z_post_category="Page";
            {elseif $smarty.server.REQUEST_URI == "/"}
                z_post_title="Homepage"; // ({rewind_posts}{the_title}) {* Fix - gets last post title, not first *}
                z_post_category="Homepage";
            {elseif $smarty.server.REQUEST_URI|truncate:10:"":1 == "/category/"}
                z_post_title="{single_cat_title}";
                z_post_category="{single_cat_title}";
            {elseif $smarty.request.s != ""}
                z_post_title = "Search: {$smarty.request.s}";
                z_post_category = "Search";
            {elseif $smarty.request.name == ""} {* Date Archive Page *}
                {if $smarty.request.day != ""} {* Daily Archive *}
                    z_post_title="{$smarty.request.day}{single_month_title prefix=' '}";
                {elseif $smarty.request.monthnum != ""} {* Monthly Archive *}
                    z_post_title="{single_month_title prefix=' '}";
                {else} {* Must be a Yearly Archive then! *}
                    z_post_title="{$smarty.request.year}";
                {/if}
                z_post_category="Archive";
            {else} {* Single Post, or unknown *}
                z_post_title="{single_post_title}";
                {capture name=cats}{the_category seperator=","}{/capture}
                {assign var=cats value=$smarty.capture.cats|strip_tags:false|replace:', ':'","'}
                z_post_category=Array("{$cats}");
                z_post_category="{$smarty.capture.cats|strip_tags:false}"; //Remove _this_ when performancing is fixed.
            {/if}
            //z_user_name=_"{$smarty.capture.author}"_;
            //z_user_email=_"{$smarty.capture.author_email}"_;
        </script>
        <script id="stats_script" type="text/javascript" src="http://metrics.performancing.com/wp.js"></script>
    

This may change at any time, as I tweak it and so on. Visit my Template page for the most recent version (click on Main Page, and then scroll down to the bottom).

Why JPEGs are not always good

I’m pedantic about some interesting things. The one I’m best known for amongst my RealWorld™ friends is probably improper apostrophe use (I was tempted to put in apostrophe’s), although your/you’re is close! One other thing I’m a bit tetchy about is correct image format selection. Now, as far as most casual computer users are concerned, computer images are computer images. However, there is one big difference between the two main types of image format. Lossless images, which includes formats such as PNG, BMP and TIFF, and Lossy images, which includes JPEG. Perhaps to enable readers to better understand the difference, we need to understand how images are stored on a computer, or other electronic device. If you zoom in on a computer image, you will find it is made up of a series of little blocks, called pixels. Pixels are “picture elements,” and each pixel has a particular colour. The number of pixels in an image is usually very large, particularly if it’s an image from a modern digital camera, which can often exceed 7 or 8 mega- (or million) pixels. Your computer monitor, on the other hand, can probably only display 1024 pixels on each row and 768 in each column, for around 3/4 of a megapixel. Digital cameras need a higher resolution (or number of pixels) in order to enable images printed from them to be free from pixellation, or the blocky effect you see if you zoom in on a digital image. Each pixel also has a colour, as indicated above, but it’s a little more complicated than that. An image can also have a “bit depth,” which is how many colours are “in” the picture. For a purely black and white image, this bit depth is 1 - this is how many “bits” of information are required to store the colour value, and eeach pixel is either black or white, so a bit, which can store a value of either 0 or 1, can accomodate this. For images that can have up to 8 colours, a bit depth of 3 is required. 8-bit images can store 256 colours, but even these are obviously not photographs. Full image quality is 24-bit, which can store around 16 million colours, about as many as the eye can distinguish. With 8 bits making up a byte, a full colour image from a 4 megapixel camera would take up around 12Mb in a raw format - 3 bytes for each pixel, 4 million pixels. Obviously, this is not a good way to store images. Even with cheaper memory storage, most cameras would not be able to store more than a few images. This is where Lossy compression techniques come in. JPEG, the format most people are familiar with, allows an image of this size to be compressed by around a factor of 5. That is, with an acceptable image quality, I can store 4MP images from my camera in files a bit larger than 2Mb. Note that these numbers are approximate - the quality of JPEG files can be altered by changing the compression rate. Higher compression results in smaller files, but poorer quality images. The main thing to note is that the compression technique is called Lossy for a reason. To save bytes, some image information is discarded. With a high quality setting, you might not notice it, but each time you modify and then re-save a file, you will lose some more quality. JPEG is really only designed as a final format. If you are planning on modifying files, save them in another format! Because the format is lossy, the image may not look exactly like the original. For instance, the compression algorithm isn’t designed to work with large areas of flat colour adjacent to other colours. It’s designed to cope with gradients and ranges that might appear in real life photographs, and can save heaps of space by compressing these well, but does a very poor job of compressing images that have a constant colour next to another colour, due to the way it averages out the colours in this border area. Areas of fixed colour can, on the other hand, be compressed very well by non-lossy, or lossless techniques, such as those used by PNG. Remembering that an image is a series of pixels, the compressor can instead of storing 150 bytes that are the same, store one copy of the bytes, and state that it is repeated 150 times. This is a simplification of the process, but it’s fairly representative. Lossless techniques are also found in ZIP archives. After all, when you decompress an archive of a program or text document, you want the data exactly the same, not just pretty close. The main place I see JPEGs being used where they shouldn’t be used is in screen captures. When you Cmd-Shift-3 on a Mac, or Alt-PrScr on a PC, there is a very good reason that the computer doesn’t save the image as a JPEG. For example, a screenshot from the iTunes source window, stored first as a PNG, and secondly as JPEG: Granted, the PNG file is 8,271 bytes, and the JPEG is 4,777 bytes, but the quality difference is obvious. The fuzziness you can see around the JPEG image is called artifacts, and I hate it! So, the moral of the story is: only use JPEGs when you really need them. Most definitely not for screenshots. I’m not bagging lossy compression. It has it’s place: it’s also very useful in music files. MPEG Layer 3 audio, or MP3, allows for about 10:1 compression, meaning files can be compressed to around 3-4Mb per song, which is very acceptable for transfer over most networks. Transferring the full amount would mean that home networks would struggle to cope with even one computer playing a song stored on another machine. Similarly, with a high quality, it’s possible to have screenshots that look acceptable. But file size savings are then not so great.

Technological Literacy Series

One thing I wrote about a year ago in an attempt to get some funding for a new piece of machinery for my classroom, entitled Technological Literacy and Computer Control, is now available on my website. I’ve put it in at the date I originally wrote it, which means it never made the front page, hence the reason for this post. And, I may write some others in the same vein about other topics related to Technological Literacy. May.

Dilbert back to good again

I toyed with writing a piece about how Dilbert became rather crap during the week. The whole sending of Asok away was somewhat ordinary, I thought. Having said that, the latest one is much better:

PostSecret Archive: I'm not that interested

From the PostSecret blog: As Jason says:

Look, I’m not really that interested.

Streamlining Script

I’ve got a heap of stuff in the toolbox script that does nothing anymore - at least on my site - so I think I might streamline it a bit by removing a large number of the functions that are no longer required. For instance, I don’t need to create Gravatars in JavaScript, since there’s a Smarty Plugin to do this - which also negates the need for the md5 stuff. At the moment, the script is 56k, which is a little too bulky.