Programming

PHP rocks, JAVA sucks…what else can I say?

Call for Translations: Pending Release of Countdown Timer v2.2

The release of Countdown Timer v2.2 is just around the corner (May 15th at 18:00 GMT). In preparation, I released the PO files for translation last night and sent out an email to all the wonderful participants who’ve translated in the past. Here’s the basic jist of what’s going on:

I’ve updated the PO files and uploaded them to my website. All you should need to do is find the language that’d you like to translate and click on the link below. The page will load with the existing data filled in that has not changed. The blank fields represent data that has changed and needs to be updated.

Also, there are a couple of special fields you should be aware of: “translator_name” is for your name as you’d like it to appear in the credits within the plugin (if you want it displayed). “translator_url” is for the URL link that will be associated with you name (again, if you would like it included).

There are a handful of fields that go something like: %d years,
The %d is a place holder for an integer (such as 5 days,) and can be moved around if needed depending on the localization requirements.

Similarly, there is a %s ago and in %s. Where %s represents a string (in this case, the countdown). This allows the translation of “in” and “ago” to be put in its proper place depending on the localization.

I really hope all that makes sense. If it doesn’t, I’d be more then happy to answer any questions you have. If you’re unsure of the context of certain strings, you can also download the trunk version version at http://downloads.wordpress.org/plugin/countdown-timer.zip

Languages already (mostly) completed:

  • Czech (cs_CS)
  • German (de_DE)
  • Spanish (es_ES)
  • French (fr_FR)
  • Dutch/Holland (nl_NL)
  • Portuguese/Brazil (pt_BR)
  • Swedish/Sweden (sv_SE)
  • Turkish (tr_TR)

As always, if you’d like to add a new translation, you can start here: http://fergcorp.com/project/phPo/phPo.php?poFileName=afdn_countdownTimer.po

And stay tuned for the pending release on Thursday!

0

phPo Translator – Online PO Translator

One of the great things about being a programmer is that when I have a problem, it’s pretty easy to solve it myself1.

I recently began to seriously support i18n (internationalization) in the Countdown Timer. It’s actually a pretty slick system. Everywhere I have some text that’s output in the plugin, I wrap it in a WordPress defined function that handles the translation. Then I generate a PO file using poEdit and make a MO (which is just a binary/machine object file of the PO file, which is human readable).

The issue is, if someone wanted to translate the PO file, they’d have to download poEdit, figure out how to use it, grab the PO file, translate it, make the MO file, and then send the MO file to me. This works pretty well if the users is a computer guru. But that’s not often the case.

I was hoping there would be an online PO translator, but I couldn’t find one. So I decided to make my own. Thus I present, in the form of clever titles that mash two words together, phPo Translator (or just phPo for short).

I basically wrote the code over lunch today and then decided that I should version control it. So I threw it up on Google Code, which I knew about but had never, up until this point, actually used.

Google Code is simply amazing. It took less then a minute to register and it uses SVN, which I already have installed on my computer. So I upload the code, create the tag, and away we go!

In any event, you can:

See it in action: Translate afdn_countdownTimer.po
Download phPo Translator v0.1.1
View phPo Translator Google Code page

0
  1. Granted, most of my problems are probably caused because I am a programmer 

Automating SVN Tagging

I’ve been using the SVN version control system for a couple years now to maintain the code for the WordPress plugins I write. Using a version control system is a fantastic tool that allows me to write and release great code. However, this post is not about how SVN is spectacular and everyone should use it whenever they write code of any sort (although they should). This post is about automating SVN tagging.

But first, a quick overview of SVN and how things are done. There are three main directories for each plugin that I write: trunk, tag, branch.

‘Trunk’ is the main code area and is where all primary and active development of code occurs. The latest version of any plugin can be found in the Trunk folder.

‘Branch’ is similar to Trunk, however it’s mostly used for side development. It’s actually exactly the same as Tag, except that development continues in a Branch.

‘Tag’ is where copy of milestones are kept. For me, this means versions of plugins that I release. You can browse the tag folder and find all the versions of a plugin I’ve created and download them if you wanted. It’s similar to a Branch, but development is not continued.

I rarely create branches. I think this is mostly because I’m the only official contributor and there are not other developers working on them at the same time. So other then committing changes to the trunk, the only other operation I perform on a regular basis is tagging. The issue with tagging, though, is that it’s a tedious and repetitive process that should be automated in SVN for large sets of files, but isn’t.

This annoys me.

So I created a solution. I downloaded the SVN command line version and then wrote the following Batch file:

:input
set TAG=
set /P TAG=Version Tag: %=%
if "%TAG%"=="" goto input
echo Creating the version %TAG%
set BASEURL=http://svn.wp-plugins.org/countdown-timer
svn mkdir %BASEURL%/tags/%TAG%/ -m "Version %TAG% tag"
set FILE=afdn_countdownTimer.php
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"
set FILE=afdn_countdownTimer.po
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"
set FILE=afdn_countdownTimer.po
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"
set FILE=afdn_countdownTimer-es_ES.mo
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"
set FILE=afdn_countdownTimer-es_ES.po
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"
set FILE=afdn_countdownTimer-sv_SE.mo
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"
set FILE=afdn_countdownTimer-sv_SE.po
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"
set FILE=fergcorp_countdownTimer_java.js
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"
set FILE=readme.txt
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"
set FILE=screenshot-1.png
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"
set FILE=screenshot-2.png
svn copy %BASEURL%/trunk/%FILE% %BASEURL%/tags/%TAG%/%FILE% -m "Version %TAG% tag"

It’s not terribly pretty, in fact I’d argue that it’s downright ugly. But. It does get the job done. One of the things that I want to do is figure out a better way to do the “svn copy” part of the operation since it’s repetitive. However, Batch files don’t appear to handle arrays at all. Although they do handle loops (I believe) and I could just pass the file names in as parameters. I may end up converting the thing to VBScript or write little C++, although it’s been ages since I’ve done either.

0

Countdown Timer v2.1.1

After dilly dallying around for a couple months, I finally got serious about pushing the 2.1 version out the door. A couple of reasons for this actually.

First, the WordPress 2.5 is coming out end of March/beginning of April and I wanted to get out one more release (this one) before the next version of WordPress hits the streets.

Second, it’s fits with my development flow; releasing every few months when I can.

Here are the list of updates in Countdown Timer v2.1.1:

  • Fixed i18n translation issues where mo file would sometimes not be loaded
  • Updated UI (note: Based on UI code from Google XML Sitemaps)
  • Removed code dealing with recurring events (which has not been included for a few versions now)
  • Added js countdown ability to admin example (which doesn’t have wp_footer hook?)
  • Updated the link to the JS file to make it dynamic in case a folder gets renamed
  • Fixed a bug in the JS file that caused dates to be calculated incorrectly
  • Append a letter to the beginning of the unique id (as per XHTML requirement)…who knew?
  • Added two language files: Swedish (thanks to Mattias Tengblad) and Spanish (thanks to Google Translator)

The biggest change user will notice is the new UI. It’s based off the code from Google XML Sitemaps which I’m assuming is based off the code from WordPress itself. The great thing about the new design is that you can collapse, expand and move around the boxes to fit your work flow.

All the other changes are ‘under the hood’ and deal with code changes to make things work better in a larger variety of situations.

The Countdown Timer plugin is about three months shy of its third anniversary of public release! I’ve basically been maintaining it since the end of freshman year in college, which is when I switched to WordPress.

The first public version was v0.6. It had about 50 lines of code and used a text file to store the data. There was also no UI at all.

Version 2.1 is about 950 lines of code. Storing data in a text file is gone, instead using the WPDB. There are also several support files, including the javascript port of the countdown mechanism which is another 150 LoC.

Since the beginning of last March, there have been over 8700 downloads, which would almost pay for a semester of college if everyone gave a $1 (wink wink)!

Read more or download version 2.1.1!

Update: Had to increment the plugin to version 2.1.1 because of the way that WordPress does version numbers. In short, v2.01 is the same as v2.1. So I had to release this as 2.1.1.

0

RoboGolf

Over the 2003 summer, I had the pleasure of completing a two-week course on robotics at the UW. During those two weeks, I developed the following code:

// This program by Andrew Ferguson
// Copyright 2003 Andrew Ferguson
// The list below tells where the stuff should be plugged in
//Begin
int lt_bump = 7; //left bump sensor
int rt_bump = 8; //right bump sensor

int left_motor = 0; //left motor
int mill_motor = 1; //mill motor
int right_motor = 3; //right motor

int rear_bump = 9; //rear bump sensor

int alpha_pol = 0; //1st polarized light sensor
int beta_pol = 1; //2nd polarized light sensor, rotated 90 degrees

int lt_ir = 4; // first IR light sensor/emiter
int rt_ir = 3;// second IR light sensor/emiter
int break_beam_a = 15; //break beam sensor for detecting the balls
int break_beam_b = 14; //break beam sensor for detecting the balls

int rotation_left = 6; //left rotation sensor
int rotation_right = 5
; //right rotation sensor
//End

//The list below declares global variables, the varible does NOT need to be global, then do NOT put it here
//Begin
int foo_right = 0; // how many times bot has turned right
int foo_left = 0; // how many times bot has turned left

int last_turn = 0; // Which way the bot turned last; 0 = Left and 1 = Right

int lt_speed = 25; //how fast the left side is going
int rt_speed = 25; //how fast the right side is going

int ball_in_hopper = 1; //whether the a ball has been collected - 0 for no, 1 for yes

int pol_home = 1; //Which polorized light the sensor should look for/care about; possible values are 1 and -1

int sensor_value; //polarized sensor delta value

float system_time = seconds(); //time since epoch of system restart

float master_time = 0.; //This is the master start time, which is used to determine when it should start looking for home

int rt_cnt; //How many times the right rotation sensor has been hit
int lt_cnt; //How many times the left rotation sensor has been hit

int line_found; //This determines if the bot has detected the line for a given set of balls trying to be dropped...please no jokes

int in_motion = 1; //If the bot is in motion. This is normal set to 1 (i.e. Yes) until the game is over (180 seconds after boot), in which case the value is changed to 0 (no)
//End

void count_both (void) {
    int lt_previous_hole; //if the previous check on the left side was hole or not
    int rt_previous_hole; //if the previous check on the right side was a hole or not
    while(1) {
        if(lt_previous_hole == 0){ //the previous check was not a hole...
            if (analog(rotation_left) < 100){//... if the there is a hole now, then count that
                lt_cnt++; //counting the hole
                lt_previous_hole = 1; //setting the check to say there was a hole this time around
            }
        }
        else{
            if (analog(rotation_left) >= 100){ //if the previous check was a hole, then check to see if it's not a hole
                lt_cnt++;// counting the hole, or lack thereof
                lt_previous_hole = 0; //setting the check to say there was not a hole this time
            }
        }
        if(rt_previous_hole == 0){//the previous check was not a hole...
            if (analog(rotation_right) < 100){//... if the there is a hole now, then count that
                rt_cnt++;//counting the hole
                rt_previous_hole = 1;//setting the check to say there was a hole this time around
            }
        }
        else{
            if (analog(rotation_right) >= 100){//if the previous check was a hole, then check to see if it's not a hole
                rt_cnt++; //counting the hole, or lack thereof
                rt_previous_hole = 0; //setting the check to say there was not a hole this time
            }
        }
        defer();
    }
}

void stuck_master (void){
    int i;
    while(in_motion){
        lt_cnt = 0; //reset the left count to zero
        rt_cnt = 0; //reset the right count to zero
        sleep(2.0); //wait 2 seconds...now we have fresh count
        if ( (lt_cnt < 20) || (rt_cnt < 20) ) //if either the left or the right count is less then 10, then we just might be stuck
          {
            beep();
            stop();
            while ( (lt_cnt < 50) && (rt_cnt < 50) ){ //reverse for 20 counts
                lt_speed = -100;
                rt_speed = -100;             
                defer();
            }
            rt_speed = 25;
            lt_speed = 25;
          }
        defer();
    }
}

void go_home (void) //when time is up, try and find home!
{
    while(1) {
        while (seconds() <= 120.) { //if there are at least 2 minutes (120 seconds) left, we can go about our business
            defer();
            //beep();
        }
        while (seconds() <= 150. && (ball_in_hopper == 1) ) { //when there is a minute left, keep looking for balls
            defer();
            //beep();
        }       
        while (seconds() <= 150. && (ball_in_hopper == 0) ) { //when there is a minute left, start looking for the hole to drop of whatever balls we have...assuming we have balls
            ir_sense();
            //in_motion = 0;
            defer();
            //beep();
        }
        while (seconds() <180.) {  // when there are a 30 seconds left, start looking for the polarized light...note: there is no defer() or sleep(x.x) becuase this is a priority 1 process
            printf("Phoning Home\n");
            //in_motion = 0;
            beep();
            pol_sensor();
            defer();
        }
        while (seconds() > 180.) {  //when the game is over, shut down all motors and beep...how nice
            //printf("Shutting down\n");
            //beep();
            in_motion = 0;
            beeper_on();
            ao();
            defer();
        }
        defer();
    }
}

/*void ball (void){ //This checks to see if a ball is in the hopper or not
    while(1) {
        if (_raw_analog(break_beam) < 10)
          {
            ball_in_hopper = 0; // ball is NOT in hopper
        }
        else if (_raw_analog(break_beam) > 10) //ball IS in hopper
            {
              ball_in_hopper = 1;
              sleep(5.0);
          }
          sleep(.01);
    }
}
*/
void pol_sensor (void) // detects the polarization of the light source
{
    sensor_value = (_raw_analog(beta_pol) - _raw_analog(alpha_pol) ); // sets the delta value for the polarization
    lt_speed = 100; //full speed, left side
    rt_speed = 100; //full speed, right side
    if ( (sensor_value < -60) && (pol_home == 1 ) ){ //if the sensor value is less than 60 and the light is NOT home, turn around
        rt_speed = 100;
        lt_speed = -100;//lt_speed - 15;
    }
    if ( (sensor_value > -30) && (pol_home == -1) ){//if the sensor value is greater than -30 and the light is NOT home, turn around
        lt_speed = 100;
        rt_speed = -100;//rt_speed - 15;
    }
    sleep(.2);
    printf("%d\n", sensor_value);
}

void ir_sense(void) { //this tries to find the black line, which hopefully will lead to the hole. If not, the robot will turn around and go the other way, which HAS to lead to the black hole
    beep();
    printf("%d\n", line_found);
    while ( (analog(lt_ir) > 100) && (analog(rt_ir) > 100) ){ //if there are black lines under both the IR sensors :: this would happen if the robot approaced the line at a 90 degree angle
        lt_speed = 20;
        rt_speed = 20;
        //sleep(2.0);
        system_time = seconds();
        defer();
    }
    while( (analog(lt_ir) < 100) && (analog(rt_ir) < 100) && (line_found == 0) ){ //If there are no black lines and the line has NOT been found before
        lt_speed = 15;
        rt_speed = 25;
        defer();
    }
    while ( (analog(rt_ir) > 100) && (line_found == 0) ){ //if there is a black line under the right IR sensor and the line has not been found yet...
        rt_speed = 20;
        lt_speed = 20;//lt_speed - 15;
        system_time = seconds();
        line_found = 1;
        while(analog(lt_ir) < 100){ //...wait until the left IR sensor passes the line...
            defer();
        }
        while(analog(lt_ir) > 100){ //...then when it does hit the line, turn the other way
            rt_speed = -20;
            lt_speed = 20;
            sleep(1.5);
        }
        defer();
    }
    while ( (analog(lt_ir) > 100) && (line_found == 0) ){ //if there is a black line under the left IR sensor and the line has not been found yet...
        lt_speed = 20;
        rt_speed = 20;//rt_speed - 15;
        system_time = seconds();
        line_found = 1;
        while(analog(rt_ir) < 100){//...wait until the right IR sensor passes the line...
            defer();
        }
        while(analog(rt_ir) > 100){//...then when it does hit the line, turn the other way
            lt_speed = -20;
            rt_speed = 20;
            sleep(1.5);
        }
        defer();
    }
   
    while ( (analog(rt_ir) > 100) && (line_found == 1) && (analog(lt_ir) < 100) ){ //if the right IR sensor sees the black line, but the left one doesn't and the line has been found before, turn a bit the other way to get back on track
        rt_speed = 30;
        lt_speed = -10;//lt_speed - 15;
        system_time = seconds();
        defer();
    }
    while ( (analog(lt_ir) > 100) && (line_found == 1) && (analog(rt_ir) < 100) ){//if the left IR sensor sees the black line, but the right one doesn't and the line has been found before, turn a bit the other way to get back on track
        lt_speed = 30;
        rt_speed = -10;//rt_speed - 15;
        system_time = seconds();
        defer();
    }
    while( (analog(lt_ir) < 100) && (analog(rt_ir) < 100) && (line_found == 1) ) { // if both IR sensors don't see the black line :: this would happen if: A) The robot was on track or B) if the robot reached the end of the black line
        if( (seconds() - system_time) > 1.0) { // If more than 1 second has passed since the last course correction, start going in circles to try and reaquire the line
            lt_speed = -20;
            rt_speed = 20;
            while(analog(rt_ir)< 100) //while the right IR sensor doesn't seen the black line...
              {
                if( (seconds() - system_time) > 6.0) {//...and six seconds have passed, stop looking for the line...it's probably gone...
                    system_time = seconds();
                    break;
                }
                if (analog(lt_ir)> 100){//...or if the left line is seen, turn the other way :: the bot is really on track...just going straight
                    lt_speed = 20;
                    rt_speed = -20;
                    system_time = seconds();
                    while(analog(lt_ir)> 100){ //...wait while the left IR sensor is still on the black line...
                        defer();
                    }
                    while(analog(lt_ir)< 100) { //...when the left IR sensor gets off the back line...
                        if( (seconds() - system_time) > 4.) { //...wait until four seconds have passed and then break out
                            break;
                        }
                        defer();
                    }
                    break;
                }
                //system_time = seconds();
                break;
                defer();
            }
        }
        defer();
    }
}

void turn_left(void){ //turn the robot left
    //printf("Turning left:%d\n", foo_left);
    fd(left_motor);
    bk(right_motor);
    sleep(0.3);
    ao ();
    fd(mill_motor);
}

void turn_right(void){ //turn the robot right
    //printf("Turning right:%d\n", foo_right);
    bk(left_motor);
    fd(right_motor);
    sleep(0.3);
    ao ();
    fd(mill_motor);
}

void go_forward(void){ //make the robot go forward
    //printf("Going forward\n");
    motor(left_motor, lt_speed);
    motor(right_motor, rt_speed);
}

void go_backward(void){ //make the robot go backwards
    //printf("Going backwards\n");
    bk(left_motor);
    bk(right_motor);
    sleep (.5);
    ao ();
    fd(mill_motor);
}

void stop (void){ //make the robot stop
    //printf("Stopped\n");
    ao ();
    fd(mill_motor);
}

void main_movement (void) //main set of robot commands, pretty much just make sure it doesn't hit and thing and what to do if it does
{
    while (in_motion)
      {
        go_forward();
        //stuck_master(); //the ultimate in stuckness prevention!!
        /*while ( (digital(lt_bump) == 0) & (digital(rt_bump) == 0) )
          {
            //This section is commented out becuase it will be really hard for the robot get stuck on anything, esp. with the new physical collision avoidance system
            if( (seconds() - system_time) > 10.0)
              {
                stop();
                printf("10 second are up.  I'm going backwards");
                go_backward();
                printf("Turning %d\n", last_turn);
                if (last_turn == 1)
                  {
                    turn_right();
                    last_turn = 0;
                    system_time = seconds();
                }
                else{
                    turn_left();
                    last_turn = 1;
                    system_time = seconds();
                }
                go_forward();
                system_time = seconds();
            }
            defer();
        }
*/
        if ( (digital(lt_bump) == 1) ) //left turn
          {
            foo_left ++;
            stop();
            go_backward();
            if (foo_left%3 == 0)
              {
                turn_right();
                foo_right = 0;
                foo_left = 0;
            }
            else{
                turn_left();
            }
            last_turn = 0;
            system_time = seconds();
        }
        if ( (digital(rt_bump) == 1) ) //right turn
          {
            foo_right ++;
            stop();
            go_backward();
            if (foo_right%3 == 0)
              {
                turn_left();
                foo_right = 0;
                foo_left = 0;
            }
            else {
                turn_right();
                last_turn = 1;
                system_time = seconds();
            }
        }
        defer();
    }
}

void main() //Begin the main program
{
    printf("JCN v20.0 by Andrew and Mariah\n");
    //sleep(1.0);
    beep ();
    fd(mill_motor); //start the mill motor thingy
    start_process(main_movement() ); //start the main set of movements, including collision avoidance
    start_process(go_home() ); //start the master clock, and prepare to go home
    start_process(count_both() );
    start_process(stuck_master() );
   
    while (1)
      {
       
        line_found = 0;
        while ( (in_motion) && ( (digital(break_beam_a) == 0) || (digital(break_beam_b) == 0) )){
            //printf("%d - %d\n", digital(14), digital(15) );
            ir_sense(); //starts the black-line finding sub-routine
            sleep(.01);
        }
        printf("%d - %d\n", digital(14), digital(15) );
        //printf("Ball NOT in hopper\n");
        sleep(.01);
    }
}

I really like this part:
//stuck_master(); //the ultimate in stuckness prevention!!

Note: This was code that I originally had in a ‘Code’ page, but I’m moving it to a post now. This code is probably really old (years and years old). I enjoy laughing at myself and so should you.

0

SAAS Problem of the Week Quiz Decoder

Script that figures out the answers to SAAS POTW Quiz’s. As a note, this is only the processing end. In order for the script to work, you will need to build a front end.

<?
error_reporting  (E_ERROR | E_WARNING | E_PARSE);
$httpfile = $_POST['httpfile'];
$userfile = $_POST['userfile'];
if($httpfile != NULL){
$textarea = file_get_contents($httpfile);
}
else{
$textarea = file_get_contents($_FILES['userfile']['tmp_name']);
} 
    echo "1. ";
    $t = 2;
    $length = strlen($textarea);
    for($i = 0; $i < $length; $i++){
        if(($textarea[$i-1].$textarea[$i]) == "l["){
            while($textarea[$i+1].$textarea[$i+2] != ",#"){
                $i++;
                echo $textarea[$i];
            } 
            $i++;
            if($t > 10){
            die();
            }
            echo "$t. ";
            $t++;
        } 
    } 
?>

Note: This was code that I originally had in a ‘Code’ page, but I’m moving it to a post now. This code is probably really old (years and years old). I enjoy laughing at myself and so should you.

0

Handling Links

This is some code that I cooked up for handling links in my website. I was tired of prefacing every link with “”. This takes care of that and ensures that it will open in a new window. Easy as pie. I’m sure there is probably a better way to do it, but this is the way I figured out how to do it.

function redirect ($url)
{
$url = preg_replace(“#Note: This was code that I originally had in a ‘Code’ page, but I’m moving it to a post now. This code is probably really old (years and years old). I enjoy laughing at myself and so should you.

0

Making HTML XHTML Compliant with PHP

This is function I found on php.net that changes all HTML tags to lower case. You need this to make your HTML XHTML 1.0 Trans compliant.

function reformat ($content){
	$content = preg_replace("#(<\/?)(\w+)(&#91;^>]*>)#e", "''\1'.strtolower('\2').'\3'", $content);

	return $content;
}

Note: This was code that I originally had in a ‘Code’ page, but I’m moving it to a post now. This code is probably really old (years and years old). I enjoy laughing at myself and so should you.

0

Countdown Timer v2.0, Now with v2.01 goodness!

Update: There was a bug in the initial 2.0 version that required the plugin to have PHP5 or greater. This has now been fixed and it works with PHP4 and PHP5. Thanks to Jim Lynch for bug report.

Well, I finally managed to push Countdown Timer v2.0 out the door. It’s a bit later then I wanted, but it’s out and that’s all that matters for now. The biggest update for v2.0 is the ability to have the time automatically update using some Javascript. The idea for this has actually been around for a while and credit for it goes to Tobias (see: Ultimate Countdown Timer; 1-Up’d by a 14 Year Old). I was hoping I could use a lot of Tobias’ code, however I had changed a lot between then and now.

During the development phase, I wrote some code that basically took a look at what value the timer was at and then subtracted one second from that. Unfortunately, it quickly became clear that this method would not work. Because there are a variety of options in what units of time are displayed, screen scraping and then recalculating would have been pretty cumbersome. It also meant that I had two ways of calculating the time (the first way was the PHP-based fuzzyDate function I wrote, the second would have been this monstrosity). So I did what any code programmer does and copied myself. I converted the PHP-based fuzzyDate function into Javascript and then passed the needed values to the JS function. Voila!

In any event, here’s the changelog:

  • Updated plugin description line
  • Rearranged text in the installation notes to emphasize using the widget rather then the code
  • Fixed a bug that crashed the plugin if no dates were present (a PHP 5 problem??)
  • Implemented the ‘register_activation_hook’ function rather then the old way
  • Changed the way DB updates are handeled. Instead of having a specific update regimine for each version, the plugin will only update an option field if it doesn’t exist (if it exists, but is blank, it will NOT update…as it shouldn’t).
  • Updated fergcorp_countdownTimer_fuzzyDate with another variable so that the real target date is always known.
  • Removed code dealing with updates since WP 2.3 now does this automatically
  • Bug fix. Widget title isn’t saveable due to a programming error. Thanks to Michael Small for the catch.
  • Renamed some functions from afdn to fergcorp
  • Added JavaScript function for JS countdown
  • Tabbed $afdnOptions array to make it more readable
  • Fixed strtotime typo
  • Brought time display inline with current WordPress practice. This fixes the dreaded timezone glitch.
  • Strip non-sig zeros option added
  • Fixed bug where “No dates present” would _not_ show if the data was returned instead of echo’d
  • Renamed to $getOptions to $fergcorp_countdownTimer_getOptions to avoid clashing

Read more or download version 2.01!

Note: Comments moved and closed. Please leave future comments, questions, pleads for help, etc on the Countdown Timer page.

0

Countdown Timer v1.97 Technical Preview 2

It’s been many moons since I released the last technical preview of Countdown Timer 2.0. Honestly, things were stalled for a bit because I was busy with school and trying to figure out how I wanted to do what I wanted to do with the program.

The semester is over and I got it all figured out. So welcome to Countdown Timer version 1.97, better known as version 2.0 technical preview 2.

The Javascript that handles the updating of the countdown has been completely rewritten. I ended up scrapping what I had and then taking the PHP code I was already using and converted it to Javascript. This is the “elegant solution” I mentioned I was looking for earlier.

In terms of stability, everything seems fine; I am currently using this Technical Preview on AFdN. There are a couple known bugs that deal with stripping non significant digits and I haven’t fully tested the upgrade process. Other then that, everything is complete. I’m hoping to have 2.0 shipped before the New Year.

Go download it!

0