Skip to content

Archive

Category: Technical Musings

Recently I needed to style the input[type=checkbox] element for a project at work. It used to be notoriously difficult to get default input elements looking the same across multiple browsers. Checking the web showed a utility at csscheckbox.com which helps to generate some code using CSS only, but in using the following HTML structure, it requires the use of id attribute tags in every input element.

<input type="checkbox" id="chk1" /><label for="chk1">Input label</label></code>

The CSS for this is pretty simple because it hides the input box completely and relies on the label to display the state. The “for” attribute is required so the useragent will trigger the state change for the referenced input. As such, you MUST have an “id” tag in your input and the corresponding “for” in your labels. This is ok for a few input checkboxes, but if you have a large list of options, tries the following approach instead.

<label class="chk"><input type="checkbox" />Input label</label>

By wrapping the <input> inside the <label>, you no longer need to specify the “id” and “for” attributes because the <label> always corresponds to the contained <input>. The CSS gets a little bit more complicated though because CSS does not allow you to specify rules for a parent that has a child.

label > input.chk {
// can't specify CSS rule for parent label.
}

Having the label precede the input makes the CSS slightly convoluted. Here is a jsfiddle sample that demonstrates the idea:

label > input[type=checkbox] {
width:20px;
height:20px;
margin:0px;
padding:0px;
vertical-align:middle
}
label.ck > input[type=checkbox]:before {
content:'';
display:inline-block;
width:20px;
height:20px;
background-color:green;
vertical-align:middle;
}

label.ck > input[type=checkbox]:checked:before {
content:'';
display:inline-block;
width:20px;
height:20px;
background-color:black;
vertical-align:middle;
}
label.ck > input:checked {
display:inline-block;
appearance:none;
-webkit-appearance:none;
-moz-appearance:none;
background-color:red;
}

I’ve recently started playing with the Parse.com JS api for building apps. It’s a pretty simple API and I love how easy it is to create and add new data to each object. The one thing I kept running into was having to check if an object already existed on the server. The save() function in the API simply creates the object unless you’ve already retrieved it. Seeing as often times I don’t want to remember to check, and the objects will pretty much always have the unique column, I wrote a little class to allow me to forget the unique constraint.

The code is sitting on github as a single .js file

Basically, if an object has a column that needs to be unique, just specify it when the class is declared.

var myUniqueClass = Parse.UniqueObject("uniqueClass", {uniqueKey:"keyColumnName"});
var obj = new myUniqueClass();
obj.keyColumnName = 'uniqueValue';
obj.saveUnique();

The saveUnique function does much of the heavy lifting and checks prior to calling the Parse.Object.save. Of course this isn’t always the easiest way, if there was an array of objects, it’s possible to use the saveAllUnique function to save all in one go. It checks each type of objects for their unique column and queries each before saving.

Of course the best laid plans can go astray. The above simply checks before attempting to save, but that means if there are multiple processes trying to save, a few requests may get thru. Having a Parse.Cloud.beforeSave function in place means any that get thru to the server will get one last check before it gets saved as a duplicate.

Go ahead, give it a try.

If you’re thinking about buying anything on eBay, you might want to do a little research first. Checking their closed item search will give you a pretty good idea of what you should (or should not) be paying for the item you want. That is assuming you’re not looking for a one of a kind item.

Most items like iPods or macbook pro laptops are commodities and the pricing is therefore somewhat uniform. But scrolling thru that long list of (up to) 200 items with sold/unsold items makes it hard for you to get an idea of what you should be paying. Sure, you could try to remember the cheapest item you saw, or the 2 or three that seemed more reasonable. What if there was a better way to get some research on those items? Now there is! Just add the bookmarklet on this page to your toolbar and you can easily see what the run down on those listings are.

When you search for your item, try to get as specific as possible using negative keywords (-notThisKeyWord), category filtering, price range, and product specifications. This will help to make removing trash items much easier. Don’t make it too specific either because then you may leave out an item where someone listed it wrong (which usually results in a bargain buy). Once you’re happy with the closed item results, just click the bookmarklet in your toolbar and it will take you to the research tool page. Here is a screenshot of what it looks like: Tool screenshot

There are a few things you can do now. The three top boxes show you summary information. The first box shows the breakdown of number of sold vs unsold items and how many items were found. Currently the tool only takes the first page of data from your search, but I am planning to add a feature to allow multi-pages. The second box shows the average, minimum, and maximum sale price for sold items along with the standard deviation in the sample set. The third box is the same as the second except for unsold items. The minimum and maximum values are clickable and will filter the data table by that value. So if the minimum is $9.99, clicking it will filter out any prices not containing 9.99. You can sort on the price column to see the lowest/highest prices. Clicking on a row will select that row and you can remove it from the data set by then clicking “Delete Selected Row”. You can also select multiple rows by holding down the SHIFT key for your second click.

Using the standard normal distribution table, we can remove any prices outside of 1.645 standard deviations away. That removes the 10% of samples that are outliers both low and high. You can do this in one step by clicking the “90% Sold Range” or “90% Unsold Range”.

There are plenty of secure deletion software out there, but yesterday I had a need to securely erase my id_rsa file copied to a thumb drive. I didn’t want to have to download some software because I was on a non-personal Mac. A quick search turned up the ‘dd’ command. This simple command on unix which has been around forever to copy data from/to block devices in theory should be able to write over my data multiple times and erase the contents.

dd if=/dev/urandom of=/Volume/NO\ NAME/id_rsa conv=notrunc count=1024 bs=1024

That command writes out 1 MiB of random data to the specified id_rsa file. You can alternate the above command with

dd if=/dev/zero of=/Volume/NO\ NAME/id_rsa conv=notrunc count=1024 bs=1024

to overwrite with zeros and then with random data again.

Now, that in theory should overwrite the contents of the file and a simple unlink or rm should delete the file entry. If anyone reading this sees a flaw in my logic/implementation, or has improvements please leave me a comment.

I saw a great deal recently on a 64GB Kingston SSD drive and I purchased one to install as a second HDD on my older (Early 2008) Macbook Pro.

The installation was fine, I removed the optical drive and got a tray which allowed me to install the SSD as a second HDD drive.

OS X installation went fine, but after booting, I had problems when closing the lid. After closing the lid, the computer would not go to sleep. Opening the lid again would not wake the display.

After taking it to the Genius Bar in Palo Alto, he (Chris?) took one look and checked the system profiler’s Serial-ATA bus. The SSD apparently was not on the SATA bus. It was under the ATA bus. This makes sense because the Optical drive was still ATA back then.

I’m going to go home tonight and swap the SSD to the main bay. This may not solve my issue though, because the main HDD is SATA as well. If that’s the case, I may end up having to use a remotely mounted NAS drive. I got the SSD mainly for the quicker boot up, but I may either have to give up the higher local storage capacity, or get a hybrid drive.

*sigh* Upgrades are never simple.

Update: Looks like having the boot drive in the main bay allows the Macbook Pro to sleep properly. I think it has to do with the way the ATA bus shuts down. When I switched the HDD positions, on sleep, the spindle shut off rather abruptly. I couldn’t notice it before on the SSD because there are no moving parts. After I moved the boot drive to the main bay using StartupDisk, the machines goes to sleep and wakes up just fine. Finally.

I don’t know why, but I get conscripted every now and then to put up random easter eggs in our internal website. Recently our execs served the rank and file breakfast and someone took a picture and asked me to put it up. I decided to put in some rotating quotes that change at random.

Since I could not (did not want) to figure out how the bugzilla template system worked, I did the rotator in JS/HTML. I wanted it to allow easy updates of any extra quotes and for it to rotate from the selection randomly. The code is below:

<script type="text/javascript">
var quotes = [ 'What would you like on your sandwich?', 'Regular eggs or extra cheesy eggs?', 'How about some honey lawyer juice?' ];
var i = 0;
i = ((i + Math.ceil(Math.random() * (quotes.length - 1))) % quotes.length);
setInterval(function() { i = ((i + Math.ceil(Math.random() * (quotes.length - 1))) % quotes.length); document.getElementById('sandwich_quote').innerHTML = quotes[i]; }, 4500 );
document.getElementById('sandwich_quote').innerHTML = quotes[i];
</script>

A simple Math.random would not guarantee that each quote would be different during rotation, so by adding a number equal to the length of the quotes array (less 1 for zero indexing), and then modulo the quotes.length, gives us a guaranteed different quote each time the interval fires.

Having played with my new iPad for over a week, I have come to the conclusion that while it may not yet replace the laptop, it creates a new category of tech devices.

The large format screen and familiar iPhone OS were easy to get acquainted with. The touch interface and keyboard is much easier to thumb type with. The A4 CPU feels much faster and scrolling is quite smooth. I am still trying out different apps to find what works well for my needs but so far the redesigned mail application is truly an experience.

Netflix has a free application for the iPad and iPhone that allows subscribers to watch their instant watch library via the app. It is a great way to watch movies on the go or without turning on a computer. The built in Youtube app is also great for those who like independent content.

Drawing programs are another breed of fun applications. There are many to choose from, but a good price to feature app is ArtStudio. The $0.99 price belies the advanced features found on this app. With layer support (up to 3 layers), brushes and image import/export, you can save to your photos or email them to others.

News readers are another really excellent group of apps. Many newspapers have free apps allowing easy access to their content. I haven’t gotten a chance to check out most of them, but the WSJ app is pretty nice. The interface takes a little getting used to, but once you get the hang of it, it is far superior to searching thru the printed version. SkyGrid is another news aggregator and allows searching multiple sources for recent news.

Back to the post topic. WordPress is a popular blogging software (which powers this blog), and this post is being written on their iPad app. The app is open source as well, so if you are interested in developing iPhone/iPad apps, you can start by checking out the code. My complaint about this app is the save feature is a little broken. This is my third attempt at writing this post. When you click the home button, it seems to recover your changes, but when you hit save, it reverts to the older version. So hit Save before you go play a tune.

-Huey

I was recently looking at different opportunities and saw a quite a few great companies doing wonderful things. Among them is Cooliris, previously known as PicLens. Their flagship product is a browser plugin which allows a very enticing scrolling view of media files. Images, videos, and music scroll by on the screen in an endless wall. Clicking on an image will zoom in to a higher resolution photo and a video file will zoom in and start playing. Needless to say this is a pretty cool little tool, but it’s a plugin which means the download stops a lot of potential users. But wait, they have a flash embed file which allows any website to embed the same experience on any web page! Let’s see how we can use this to show off our photos. continue reading…

I’m not sure how everyone else is using Zend_Layout, but I’m doing the following to render my navigation and footer links. It’s not the most DRY code, but works until I learn more about the framework.

In my Action file, I add actions to the stack for nav, footer, continue reading…

Someone asked how I get a db connection in my models using ZF1.5.1

Basically I have a ConfigDB singleton pattern that gets one db connection, then sets the default adapter so when I extend the Zend_DB_Table_Abstract class, the default connection gets carried around.

class ConfigDB {
static private $instance;
private function __construct() {
}
public static function getInstance() {
if (!ConfigDB::$instance) {
$params = array(
/* redacted */
);
ConfigDB::$instance = Zend_Db::factory('Mysqli', $params);
Zend_Db_Table_Abstract::setDefaultAdapter(ConfigDB::$instance);
}
return ConfigDB::$instance;
}
public static function selectDb($db) {
return ConfigDB::$instance->getConnection()->select_db($db);
}
}
ConfigDB::getInstance();

That grabs the connection and sets the default adapter. So in my model class I can do:
class Country extends Zend_Db_Table_Abstract {
protected $_name = 'countries';
protected $_primary = 'country_id';
function __construct($country = 1, $abbr = '')
{
parent::__construct();
}
}

That’s it