Sunday, December 22, 2013

Critters 2.0

Critters 2.0 is now ready for testing and we need your help. Contact us and tell us why you are interested. Top testers will be rewarded with a free lifetime multiple pet account. Testing is open to residents of the U.S, Canada, UK and Ireland.

Wednesday, December 4, 2013

Yiinfinite-scroll Paging Issues

I have been using Davi Alexandre's yiinfinite-scroll extension to add Twitter like scrolling to my pet health record project.

I was using yiinfinite-scroll version 1.2 and yii 1.1.14. I followed the instructions and at first it seemed to work. I had a model with 12 rows and that happened to be my page size. Everything works, scrolling produces no paging.

If I set the page size to 10, the first hit on the page shows all 12 rows not 10. Additional scrolling produces the same 12 rows an additional 2 times before stopping at 36 rows total. Well something was definitely wrong! I found one problem that was my fault where I was incorrectly calculating the total number of rows. I fixed that issue and re-ran my test. Now it was showing 10 rows as expected on page load, good. Scrolling to the bottom displayed the last two items in the list which was also good. Scrolling again appended the previous two rows which wasn't expected. A final scroll to the bottom produced the expected end of list message.

After digging into the source code for the extension, I found that the current page appeared to be incremented incorrectly, there were two pages produced which was correct; however, the current page count was off by one when a scroll event occurred. A simple fix was all that was needed to correct the problem, increment the currentPage by one in the YiinfiniteScroller.php run() function:

public function run() {
        if($this->pageCount > 1) {
            $this->registerClientScript();
            $this->createInfiniteScrollScript();
            $this->renderNavigation();
            $this->currentPage++;
        }

Tuesday, October 29, 2013

Critters - Project Module Progress

Just a quick post to let you know that we have an approximate module progress chart on our Critters project page to give you an idea of have far along we are with Critters.

Wednesday, September 25, 2013

Arvixe Hosting: Database Backups

Having just switched from ASP to Linux hosting at Arvixe, I needed to setup daily backups of my databases. ASP hosting made this very easy; however, the Linux move required me to dust the cobwebs off my shell scripting skills.

I had three MySQL databases to backup daily. I wanted to archive the backups and place the archive in a specific directory. I also wanted to delete any backup archives older than 7 days. The solution was quite easy starting with the backup script:

backup_databases.sh:

#!/bin/bash

# cd to the backup diretory
cd ~/backups/

# backup the databases
mysqldump -ukeidav_critters -pPassword keidav_critters > keidav_critters.sql
mysqldump -ukeidav_mant164 -pPassword keidav_mant164 > keidav_mant164.sql
mysqldump -ukeidav_pier357 -pPassword keidav_pier357 > keidav_pier357.sql

# place the backups in an archive
FILE=sqlbackup-day$(date +%w).bz2
tar -jcvf $FILE *.sql --remove-files

# delete any archives older than 7 days
find . -type f -mtime +7 -delete

I placed the script in ~/bin and set the file to be executable (this can also be accomplished using the cpanel file manager):

chmod 755 backup_databases.sh

The last step was to create a cron job set to run the script at the beginning of every day using cpanel:

There you have it! No hard at all, daily backups with a rolling week in a bzip archive.

Sunday, August 11, 2013

Kinvey - Simple Aggregates and Paging

I have been working with Kinvey as the backend for Critters 2.0 for about a month. I was having problems setting a filter on a paged query and getting a total count of results with it.

Getting the Data

The first part of getting the data was easy. The Kinvey documentation makes this a simple process. Note that I am using the blocking versions of the various methods available as I am making these calls from an AsyncTask:

   // Get the list
   AsyncLinkedData<PetEntity> pets = mKinveyClient.linkedData(
     "Pets", PetEntity.class);
   pets.setCache(new InMemoryLRUCache(), CachePolicy.CACHEFIRST);

   try {
    Get data = pets.getBlocking(q1, null, null, null, 0, false);
    mPetEntities = data.execute();
   } catch (IOException e) {
    Log.e(TAG, e.getMessage());
   }

Getting the Aggregate Row Count

The Kinvey documentation did not cover this very well; however, their excellent support was able to provide me with a solution (hint: access the undocumented "_result" field of the query result set). I know if I was staying sharp while debugging, I would have caught this myself:

 try {
     GenericJson[] ret = mKinveyClient
       .appData("Pets", PetEntity[].class)
       .countBlocking(fields, q1).execute();
     retval = Integer.valueOf((ret[0].get("_result"))
       .toString());
    } catch (IOException e) {
     Log.e(TAG, e.getMessage());
    }
   } else {
    retval = 0;
   }

Saturday, July 13, 2013

Fewer Future Posts - Critters 2.0

I will be taking a break from this Blog so I can finish my work on Critters 2.0. I have finally decided to stay with the Android platform after experimenting with a number of web technologies. None of them really played out quite as well as a native application. I have finished my basic framework for the new version of Critters and I am ready to start feature coding.

The new version of Critters will be significantly different from the first version. Critters 2.0 will use a cloud backend with synchronization for data storage and push notifications for various medical reminders. The application will no longer be free, but will be very reasonably priced. This decision was made as cloud services have a cost associated with the benefits they provide. I believe this will make Critters much more robust and allow users to access their data across multiple devices.

I will be blogging about my progress over on www.critterhealthrecords.com. This new website will provide online documentation for the application, FAQs and forums supporting the new version of Critters. The site will also have galleries and forums where users can post pictures and stories about their pets.

This site will still be the home of ZuniSoft and my technical blog.

Saturday, June 22, 2013

Facebook SDK for Android

Wow, the quality of SDKs have really gone downhill. I just spent two days trying to get past the poor documentation and non-compiling sample applications of the Facebook for Android SDK. I also had a similar experience with the Android SDK from Kinvey. The difference is Kinvey wants you to succeed and has awesome developer support whereas Facebook really doesn't care what they release. Facebook has become way too big, too fast to be able to release any sort of quality work. I look forward to good things from Kinvey.

Just a rant... there, I feel better.

Wednesday, May 8, 2013

SQL Server - Determine Column Uniqueness

This is a quick and dirty stored procedure that one can use to determine if a column or set of columns is a candidate for a primary key or unique index. The procedure takes a table name and a concatenated list of columns to be checked. Non-char columns must be CAST as VARCHAR.

Source

-------------------------------------------------------------------------------
-- Date:   November 10, 2010
-- Author: Keith R. Davis
-- Desc:   Shows the percentage of unique values in a column, so that one can
--         determine if it is a candidate for indexing.  Non-char columns must
--         be CAST. FOR DEVELOPMENT USE ONLY!
--         
--         Example:
--
--         EXEC UtilShowUniqueness 'MyTable', 'Col1 + CAST(Col3 AS varchar)'
--
-- Param:  @TableName - name of the table to analyze
--         @Columns   - columns to check for uniqueness
-- Return: Nothing
-------------------------------------------------------------------------------

CREATE PROCEDURE [dbo].[UtilShowUniqueness](
 @TableName sysname, 
 @Columns sysname
 )
AS

BEGIN
 SET NOCOUNT ON

 EXEC (
  'SELECT ((SELECT COUNT(DISTINCT ' + @Columns + ') 
   FROM ' + @TableName + ') * 100) /
   (SELECT rows FROM sysindexes 
  WHERE id = OBJECT_ID(''' + @TableName + ''') AND indid < 2) AS percent_unique'
 )
END;

Example

In this example we will check if the numeric columns DayNumInMonth and YearMonth create an unique combination.

EXEC UtilShowUniqueness 'DimDate', 'CAST(DayNumInMonth AS varchar) + CAST(YearMonth AS VARCHAR)'

Result

percent_unique
--------------
100

This stored procedure has been tested on SQL Server 2008 and 2008 R2, your mileage may vary on other versions of SQL Server.

Monday, May 6, 2013

Site Facelift

I don't have much to report other than if you are reading this, you are seeing a number a changes I have made to the site since the last time you were here:

  • New header
  • Image slider
  • Static home page
  • Theme color tweaks

I hope it makes discovering what we do easier. The blog is still intact with all the technical articles you expect. I am not sure if I am satisfied with the changes, so leave any comments and/or suggestions you might have here. Thank you for your feedback!

Tuesday, April 23, 2013

Introduction to Hadoop

Here is a short presentation that I gave as a guest speaker to a group of graduate level statisticians at the University of Utah. It is a very high level view of what Hadoop is, who is using it, when you should use it, and bit on how it works.

SQL Server - Index Defragmentation Stored Procedure

I don't remember who wrote the original code for this stored procedure; however, I found it useful enough I wanted to share it with my readers.

The following script does a fantastic job of allowing the user to defragment table indexes with a high degree of control. I have tested the procedure with SQL Server 2008 and 2008 R2. Your mileage on other versions of SQL Server may vary.

Example:

EXECUTE dbo.IndexDefrag
             @ExecuteSQL           = 1
            ,@PrintCommands        = 1
            ,@DebugMode            = 1
            ,@PrintFragmentation   = 1
            ,@ForceRescan          = 1
            ,@MaxDopRestriction    = 1
            ,@MinPageCount         = 8
            ,@MaxPageCount         = NULL
            ,@MinFragmentation     = 1
            ,@RebuildThreshold     = 30
            ,@DefragDelay          = '00:00:05'
            ,@DefragOrderColumn    = 'page_count'
            ,@DefragSortOrder      = 'DESC'
            ,@ExcludeMaxPartition  = 1
            ,@TimeLimit            = NULL
            ,@Database             = 'sandbox,sandbox_caseSensitive';

Source:

Sunday, February 3, 2013

WordPress Plugin Form Submissions

Development of my first WordPress plugin brought me to a basic piece of functionality, handling form submissions. I knew that I could submit a form via AJAX; however, that would not work for forms that allow file uploads without adding extra code and page markup. Being new to the world of WordPress, I went on a search for how this should be done. The search ended with a possible solution found on WordPress Answers.

The author of the solution explained that one needed to send the form action either to the site's homepage, or to a specific page URL. The author further explained that one can't have $_POST handling within a template because you need to redirect after your process it, and a redirect needs to be fired before any HTML output. It was suggested that this could be accomplished by adding a custom action by hooking into to the "template_redirect" action.

This made sense as it directly addressed my basic requirements:

  • All forms would need to be created from a single shortcode.
  • The shortcode that creates the forms would be added to a single page.
  • Form action attributes will be empty following WordPress practices.
  • Forms should be able to handle file uploads.
  • If the submission is successful, redirect the user to the correct page.
  • If the submission fails, redirect the user to an error page.

Custom Event Action

I implemented a custom action named "check_for_event_submissions" and hooked it to the "template_redirect" action. An event in this context could be more than a form submission. It could be any custom URL that triggers a plugin defined event that needs to be acted on and redirected. The example presented handles POST events only; however, it would be trivial to modify this function to handle a GET request if necessary. In short the function looks for two form post variables "event" and "view_redirect". The "event" variable describes the event to process and "view_redirect" the default redirection URL after the event is processed:

/**
  * Custom action that handles plugin event submissions.
  *
  * After the event is processed the action the redirects to the page
  * specified by the event.
  */
  public function check_for_event_submissions() {
     // Handle a form post event
     if(isset($_POST['event'])) {
         // Redirect to the specified page
         wp_redirect($_POST['view_redirect'])
         exit;
     } 
 }

 // Add Actions & Filters
 add_action('template_redirect', array(&$this, 'check_for_event_submissions'));

We will finish the custom event action later as we need to create an event controller to process the events first.