Front End

Toggle CSS Effects with Browser JavaScript Speed Test

So you fired up all of these fancy CSS or JavaScript effects: gradients, shadows, animations, transitions. And things look great on your new hardware. But then you try things on a legacy iPhone or aging laptop. Ugh!

Of course you were smart enough to make your site function fine without them, but how do you disable them? Browser sniffing and separate stylesheets? No no no… don’t be silly. With a little bit of fast-running JavaScript you can easily target that CSS fanciness to only browsers that can handle it.

Here it goes…

// CPU Speed
var speedRating = (function() {
   // Test CPU Speed
   var init = new Date(),
   iterations = 25000;
   while (iterations--) {
      Math.sqrt(iterations * Math.random());
   }
   var score = new Date - init;
   // 1-5 star
   var rating = Math.ceil(((90 - score) / 100) * 5);
   return (rating < 1) ? 1 : rating;
})();

$('body').attr('data-stars',
   (function() {
      var stars = '*';
      for (var i = 1; i < speedRating; i++) {
            stars += '*';
      }
    return stars;
  })()
);

Once you’ve done that you can simply use a CSS starts-with attribute selector to target only devices meeting that rating or above on a five-star scale.

body[data-stars^='*'] {
 background: #eeeeee;
}

body[data-stars^='**'] {
 background: #cccccc;
}

body[data-stars^='***'] {
 background: #ffdddd;
}

body[data-stars^='****'] {
 background: #ffbbbb;
}

body[data-stars^='*****'] {
 background: #ff0000;
 color: #ffffff;
}

In theory, if you wanted to make the grading harder for more demanding CPU requirements, just change the 90 to something lower.

Couple this with a little LESS or SASS and it’s easy to target entire blocks of CSS to only the higher end devices!

Working Example

Cloud Developer

Query for Search Results with CloudSearch

This is a continuation of my last post: How to connect to CloudSearch with the AWS PHP SDK.

Once again, for all of the great things that Amazon does… their documentation is pathetic. They yammer on and on about things, but try to get some cold hard code examples of their SDK… forget about it.

So after pulling my hair out for HOURS today, you can benefit from my missteps. Doing a basic query was really easy and straight forward:

$result = $client->search(array(
	'query' 	=> $q
));

Even adding a little filter action on to my query was a breeze!

$result = $client->search(array(
	'query' 	=> $q,
	'filterQuery'	=> "state:'FL'"
));

So at this point I thought, nothing can stop me now! This is GREAT! And then I decided I wanted to find out what facets were available for a query and how many of each… just like they show on Amazon and in the Console.

That’s where the foul language began. After trying all sorts of combinations of things and trying to translate what facet.FIELD={} meant in terms of the PHP SDK, I finally got something that worked.

$facets = array ('city' => array('sort' => 'count', 'size' => 5));
$result = $client->search(array(
	'query' 	=> $q,
	'filterQuery'	=> "state:'FL'",
	'facet' 	=> json_encode($facets)
));

Now moving along, I wanted to use those facets that I retrieved to do a secondary filter query. Then there was a lot more yelling and angry keyboard pounding. I tried every combination that I could think of: parenthesis, ands, pluses, spaces, commas, arrays, and json. And nothing I tried would work!

I tried to replicate what worked in the previous query above. I even tried working in the AWS Console and searching and filtering there, but of course Amazon wasn’t thoughtful enough to show you the actual query. That would be too easy.

In the end, I have no idea why the query below worked and is so different from the one above. But I’m glad a co-worker of mine had already blazed this trail and pointed me in the right direction.

This is what worked:

$filterQuery = "(and (term field=state 'FL') (term field=city 'Orlando'))";

Important Side Note: It was also at this point that I found that facet values are case-sensitive. So you may want to consider normalizing the case as part of your indexing process.

Another important piece for me was field weighting. So here is a sample scheme

$queryOptions = json_encode(
      array('fields' => array('title^20', 'description^4', 'city^4',  'body'))
 );

Finally, pagination was pretty darn simple.  You just use the start (offset) and size (limit) arguments and you’re all set. So putting it all together…

$facets = array ('city' => array('sort' => 'count', 'size' => 5));
$filterQuery = "(and (term field=state 'FL') (term field=city 'Orlando'))";
$queryOptions = array('fields' => array('title^20', 'description^4', 'city^4',  'body'));
$result = $client->search(array(
    'query'     => $q,
    'filterQuery'    => $filterQuery,
    'facet'     => json_encode($facets),
    'queryOptions'    => json_encode($queryOptions),
    'start' => 0,
    'size' => 50
));

Hope this helps someone!

Cloud Developer

How to Connect to CloudSearch with PHP

If you’re like me, when you’re in the midst of coding the last thing you want to do is read wordy documentation. I get bored after a paragraph. Just give me code examples already!

Consequently, I have found Amazon AWS documentation to be stale and lacking. And on certain AWS products, like CloudSearch, event blogs have stark examples. So here we go, some examples with the AWS SDK for PHP…

Want to know more about CloudSearch or how to get it CloudSearch set up?
Watch this.

Connect to CloudSearch Domain

$csClient = CloudSearchClient::factory(array(
                'key'          => AWS_KEY,
                'secret'      => AWS_SECRET,
                'region'     =>  AWS_REGION
            ));
$csDomainClient = $csClient->getDomainClient(
            CLOUDSEARCH_DOMAIN,
            array(
                'credentials' => $csClient->getCredentials(),
            )
        );

As you can see above, there are two different types of clients. There is the generic CloudSearchClient and the CloudSearchDomainClient. You will use the former to do things with your CloudSearch account — set up new domains, list domains, etc.  You will use the latter to do things against that specific domain — searching, adding documents, etc.

Add Documents

In the example below, my domain only has two fields title and description. They are both text type. I am leaving out anything about how I pull the data from my database. So just imagine I have fetched the document data and have set the $id, $title, and $description variables. Most likely, you’ll watch to fetch more than one item and loop through it and push each into the $batch array.

$batch = array();
$batch[] = array(
            'type'        => 'add',
            'id'        => $id,
            'fields'     => array('title' => $title, 'description' => $description)
        );
$result = $csDomainClient->uploadDocuments(array(
                'documents'     => json_encode($batch),
                'contentType'     =>'application/json'
            ));

Json is by far the easiest route to go, but CloudSearch also supports XML. It is important that you batch multiple documents into a single uploadDocuments call or otherwise it will take much longer. However, each batch must be less than 5MB so you may want to keep track of the size as you go.

Once you upload, it will return (into $result in this case) three things about the batch: status (success if it went well), number of documents added, and number of documents deleted.

Searching CloudSearch

Now that we have data loaded into CloudSearch, we need to get it out! Once again, we’ll use the CloudSearchDomainClient to do so.

$result = $client->search(array(
                'query'         => 'hello'
            ));

That’s really it! Of course there is a lot more  you can do than just a simple query. You can do filtering, faceting, weighting of different fields, etc. But with the above you have just gotten your feet wet and done you first search!

Check out my follow-up post for getting more complex with your query:
Complex Queries with CloudSearch