Tuesday, December 21, 2010

An HTML select that allows user created options

I was thinking the other day that it would be useful to have a select option that people could also put their own options into on the fly.  Obviously you wouldn't do this if you wanted completely normalization, but many times I have made selects with an "other" option, and then below put a text field "If you have selected "other" please tell us what your preference is.

This is meant to address that.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

A simple way to have a dropdown that also allows user input.  If the user choses "other" from the dropdown, he/she will
be shown a text field into which he/she can put a new option.  When the user clicks save, the option will be added to
the select and made as the selected item.  There is a place in the code where you can call the onchange after a new value is added, or comment out that if desired.

// Daniel Fishman
// 2010-12-21
// Released to the public domain.

<style type="text/css">


<script type="text/javascript">
    function localOnchange(lid,allowOther){
        var mySelect=document.getElementById(lid);
        var postKey=mySelect.name;
        var postData=mySelect.options[mySelect.selectedIndex].value;
        if(postData == "other" && allowOther == "true"){
            document.getElementById(lid+'_select_div').className = "hidden";
            document.getElementById(lid+'_input_div').className = "show";
            alert('perform regular onchange with '+postData)

    function updateSelect(lid){
        var newVal=document.getElementById(lid+"_text").value;
        if(newVal == "")return;
        var mySelect=document.getElementById(lid);
        //insert the new value in alphgabetical order.  If this select is not in alphabetical order, tough
        for (var x = 0;x <mySelect.length; x++) {
          var postData=mySelect.options[x].value;
          if (newVal < postData || mySelect.options[x].value == 'other') {
              var elOptNew = document.createElement('option');
              elOptNew.text = newVal;
              elOptNew.value = newVal;
              try {
                mySelect.add(elOptNew, mySelect.options[x]); // standards compliant; doesn't work in IE
              catch(ex) {
                mySelect.add(elOptNew, x); // IE only
              //uncomment below line for onchange behavior
              alert('perform regular onchange with '+newVal);
              document.getElementById(lid+'_select_div').className = "show";
              document.getElementById(lid+'_input_div').className = "hidden";
              //reset the div color


    function cancel(lid){
        document.getElementById(lid+'_select_div').className = "show";
        document.getElementById(lid+'_input_div').className = "hidden";
<div class="show" id="sid_select_div">

<!--you could call localOnchange with('sid','false'), and then it will do the normal onchange behavior-->

    <select onchange="localOnchange('sid','true')" id="sid" name="objectName">
        <option value="Dog">Dog</option>
        <option value="Cat">Cat</option>
        <option value="Bird">Bird</option>
        <option value="Person">Person</option>
        <option value="Snake">Snake</option>
        <option value="Bear">Bear</option>
        <option value="other">other</option>


<div class="hidden" id="sid_input_div">

    Enter the new value:&nbsp;<input type="text" value="" id="sid_text">
<a href="javascript:updateSelect('sid')">save</a>
<a href="javascript:cancel('sid')">cancel</a>


Monday, December 13, 2010

A modification of Lifehacker's Invisibility Cloak

Need to curtail your surfing during certain time periods?  I've tweaked Gina Trapiani's original code to make it a little more tolerant. 

Put a few numbers into the "surfHours" array and you'll be able to access your "blocked" sites for one hour after each hour listed.  As an example, if surfHours = [9,13,17] you can access facebook (or any other site) from 9-10am, 1-2pm and 5-6pm.

You can install the script directly from userScript and the source code is below.  If you don't know how to install a grease monkey script, check out the instructions at http://userscripts.org/scripts/show/92640

// Invisibility Cloak
// version 0.1
// Gina Trapani
// 2006-01-03
// Released to the public domain.
// ==UserScript==
// @name          Modified Invisibility Cloak
// @description   Turns time-wasting web pages invisible until a specified time of day.
// @include       http://flickr.com/*
// @include       http://*.flickr.com/*
// @include       http://metafilter.com/*
// @include       http://*.metafilter.com/*
// @include   http://*.facebook.com/*
// @include   http://*.twitter.com/*

// ==/UserScript==
// ==RevisionHistory==
// Version 0.1:
// Released: 2006-01-03.
// Initial release.
// Version 0.2
// Released 2010-12-13
// by Dan Fishman
// allows surfing on "invisible" sights for one hour after each number in the 
// surfHours array 
// ==/RevisionHistory==

(function () {
     var surfHours=[9,13,17];
     var tstamp = new Date();
     var hours=tstamp.getHours();
     var okToView=false;
     for(var x=0;x<surfHours.length;x++){
        //alert("hours=="+hours+" sh="+surfHours[x]);
     if (!okToView){
 var b = (document.getElementsByTagName("body")[0]);
 b.setAttribute('style', 'display:none!important');
 //The alert gets irritating on sites that link back to facebook 5 times.
        //alert("You can surf from 9-10, 1-2 and after 5");


Friday, December 03, 2010

Making your facebook group safe for the enter key

I've been very frustrated recently with the fact that in facebook groups, if you press enter while typing a post, it submits the post.  If you just want to make a line break you have to hit shift-enter.

Fortunately we don't have to live that way any more.  I've made a greasemonkey script for people who use firefox.  You can either install it directly or install it from the UserScripts.org site

To be perfectly clear:

You must be running firefox http://www.getfirefox.com 


You must have GreaseMonkey installed:  https://addons.mozilla.org/en-US/firefox/addon/748/

BEFORE you can install my script.

After you have installed my script when you are on a group page, press the alt-z to turn on safe typing. Now you will be able to press the enter key all you want to make line breaks. Then when you are ready to save, you can press the alt-q to turn OFF safe typing and THEN press enter (sequentially, not simultaneously), and your post will save.  You'll need to press the alt-z AGAIN to re-enable safe typing.

Comments welcome.

Sunday, November 28, 2010

Time for a smaller government

I just read this intriguing piece in the Times:  http://www.nytimes.com/2010/11/28/opinion/28rich.html?_r=3&hp

What's great about this article is that I think the means that it describes and ends we would all find desirable: a government that votes it's conscience. We differ greatly as to the means. I've been thinking recently that the problem is lack of accountability. First a little history:

Under the Articles of Confederation, Congress was a unicameral body in which each state held one vote. The ineffectiveness of the federal government under the Articles led Congress to summon a Constitutional Convention in 1787. The issue of how Congress was to be structured was one of the most divisive among the founders during the Convention. James Madison's Virginia Plan called for a bicameral Congress: the lower house would be "of the people," elected directly by the people of the United States and representing public opinion, and a more deliberative upper house that would represent the individual states, and would be less susceptible to variations of mass sentiment, would be elected by the lower house.

The Virginia Plan drew the support of delegates from large states such as Virginia, Massachusetts, and Pennsylvania, as it called for representation based on population. The smaller states, however, favored the New Jersey Plan, which called for a unicameral Congress with equal representation for the states.

Eventually, the Convention reached the "Connecticut Compromise" under which one house of Congress would provide representation proportional to each state's population, whereas the other would provide equal representation amongst the states. The Constitution was ratified by the requisite number of states and the House began work on April 1, 1789, when it achieved a quorum for the first time.

During the first half of the 19th Century, the House was frequently in conflict with the Senate over regionally divisive issues, including slavery. The North was much more populous than the South, and therefore dominated the House of Representatives. However, the North held no such advantage in the Senate, where the equal representation of states prevailed. Conflict over slavery and other issues persisted until the Civil War.

The war culminated in the South's defeat and in the abolition of slavery. Because all southern senators except Andrew Johnson ( who would become the 17th President) resigned their seats at the beginning of the war, the Senate did not have the balance of power between North and South during the war. In reality, if the southern senators had not resigned their seats, it is unlikely the 13th and 14th ammendments could have passed.

The only constitutional rule relating to the size of the House says: "The Number of Representatives shall not exceed one for every thirty Thousand." Congress regularly increased the size of the House to account for population growth until it fixed the number of voting House members at 435 in 1911. The number was temporarily increased to 437 in 1959 upon the admission of Alaska and Hawaii (seating one representative from each of those states without changing existing apportionment), and returned to 435 four years later, after the reapportionment consequent to the 1960 census.

Which leads us to the present day, where each congressional district has more than 700000 people in it. The House, which was meant to directly responsible to the people, has become more and more abstracted. When there were only 33k people in a district, 10 activists could easily have a snowball affect and cause an avalanche in an election. With 700000 people in a district, 10 activists have a snowball's chance in hell of affecting an election.

We cannot have a free market without a free populance, and we cannot have a free populance without each person's voice being heard. And that comes down to scale. If we were to form a government among our members here, we'd make a pretty liberal government indeed based on the fact that there are many more liberals in this group -- but even though I am not a typical conservative, my opinions and thoughts would have some influence because I was heard by the other 55 members of our group. At 700000 people per district, one voice is lost in the din.

When I say that the Federal Government is too large and too powerful I am complaining about just this. 300000000 people cannot be fairly represented by 437, nor justly governed. The system by which the Red States impose their will on the Blue States and the Blue States dictate terms tot he Red States based on the votes of Ohio and Florida has got to end. And the only way it CAN end is for the states to reassert the rigths granted to them in the constitution.

Monday, October 25, 2010

We're through Adobe

I've been an anti-flash guy for a pretty long time now but I've been "ok" with running flash on machines when I had flashblock installed.  Today however I ceded to Adobe's nag and installed the latest upgrade to Flash -- bringing me to Flash Player 10.1  It ran mostly in the background, and I had to agree to what read like a EULA.  My oh my what bullshit they pulled.

Turns out they installed McAfee anti-virus/antispyware, which I've always thought was terrible.  Don't just take my word for it though.  You need no further proof as to how seriously McAfee takes spyware than to see that they don't mind that their program IS INSTALLED AS SPYWARE.  If you have McAfee I would be worried that for $$$ McAfee will decide some other programs aren't spyware, and allow them to be installed on your PC.  Nothing is more dangerous than a false sense of security, and it's clear McAfee has little interest in your PC's security.

As for Adobe.  I'm done with Flash.  Bring on HTML5

I'm not the only one either.

Wednesday, October 13, 2010

Encyclopedia Brown and the Case of the Mysterious Sweater

I wrote this in summer of 2008.  My gang of friends had all come down to Woods Hole, and Mark Z. had brought a sweater he had found in his apartment.  All the girls we knew were assembled, yet no  one claimed the sweater.  After the weekend, emails flew among the group trying to decide who owned the "mysterious sweater."  The phrase reminded me of my childhood, and I sat down and wrote the following:

Encyclopedia Brown
and the
Case of the Mysterious Sweater

It was a warm Memorial Day on Cape Cod.  Encyclopedia Brown was driving down to visiting his friend Dan in Woods Hole from Idaville.  He had picked up his old friend Sally Kimball from Smith, where she was doing a double major in physical education and flannel shirts.   They were looking forward to a pleasant day of vacation.  But when they got to Woods Hole they found a mystery awaiting them.

Encyclopedia Brown pulled into the hidden driveway, and saw Dan standing out in the driveway directing him to park at the front end of the driveway.  "Boy Leroy, I'm glad to see you -- we've got quite a mystery on our hands!" said Dan.  Encyclopedia grimaced -- usually only his parents or teachers called him by his actual name.   Everyone else just called him Encyclopedia. 

"Please -- don't call me that." Encyclopedia whispered

"Dude!  You're 30 years old!  I can't still call you 'Encyclopedia'" said Dan, putting out his hand for a shake.  Encyclopedia  shook hands briefly, and then decided what the hell -- Dan was his best friend, and pulled him in for the hug.

"Hey Sally -- looking foxy!"  Dan said.  Sally had recently lost a 5 round exhibition match to Tatiana Ali by a split decision, and had the black eye to show for it, but that didn't change the fact that she knew that she was Encyclopedia's bodyguard.  She was still the same girl who had knocked out Bugs Meany in the 5th grade, and made sure that Encyclopedia's back didn't sprout any knives when he was sleuthing.

"Please Dan -- we just got here!" Sally said.  "How about we have some lunch first and mysteries second?"

After a great lunch of BLT sandwiches and kickass left over spinach dip, Encyclopedia said "so tell me about this mystery."

"Ok.  My buddy Mark found this sweater in his apartment the day after St. Patrick's Day." said Dan

"So March 18th?" asked Sally.

"Wow...  It's amazing EB solves anything without your help Sally" Dan said.   "Yes, on March 18th, Mark found this sweater in his apartment.  The day before, Mark had hosted his annual St. Paddy's day breakfast, which was well attended as per usual.  He claims that in between St. Patrick's day and today he has not had any girls in his apartment, so he was baffled who the swetaer belonged to -- but he figured if he brought it down here, one of the girls would know whose it was."

"Who exactly was at the St. Patrick's day party?" asked Encyclopedia?

"Well, the usual suspects, me, Ellie, Mark, Kim...Monte...Jessica, Stephanie, Lori, Evil Dan, Christine.  I think that's it" said (Good) Dan, counting off people on his fingers.

"And they were all here this weekend to deny ownership?"

"Well actually no, Lori didn't make it, but emails have been flying around this morning, and it's not her sweater."

EB closed his eyes, and he did when he wanted to concentrate.  Suddenly they sprang open and he said :"Do you have any pictures of the day?"  

"Actually I do!  I don't know why I didn't think of that earlier!!!"  Dan yelled, as he ran inside to get his digital camera.  5 minutes later, everyone was peering into a 2 inch digital screen looking at pictures from the St. Paddy's day party.

"There seems to be quite a bit of drinking going on" observed Encyclopedia.  "How sure are you that you're not leaving out someone who was there?"

"I don't see Mark's sister -- could it be her sweater?" asked Sally?

"Nope -- she definitely wasn't there."  Dan said.  "And I trust Mark on the discovery date -- if he says that he found the sweater on the 18th, then it wasn't there on the 16th.  We may have been drinking, but not that much."

"Does Mark have a girlfriend?" Encyclopedia asked, flipping through the photos again on the camera.

"Not then.  And trust me, if an unknown girl had shown up at the party and claimed to be a friend of Mark's, we would all remember."

"Do you have any pictures of the sweater?" asked Sally.

Dan flipped the camera to photos from the previous day.  "Yep -- Here's Jessica styling the sweater.  The Vodka sauce stain is new as of this weekend by the way."

"And none of the girls in these photos claims the sweater?"  sniffed Sally as she flipped through the camera.  "I can see why not -- it's a bit girly."

"Nope -- everyone denied having even SEEN the sweater before."

"I've got it!" yelled Sally.  "The sweater must belong to this guy!" she said, pointing to Monte on one of the pictures.  "It's a perfect fit, but he denied ownership because it was too feminine."

"I don't think so" said Encyclopedia.  "If you look at everything else Monte is wearing, you can tell he's a guy who doesn't put a lot of thought it what he's wearing, but certainly would not wear a girl's sweater.  Did you guys see anyone else that day?"

"Well, there was a giant parade,with 86 bagpipers" Dan laughed.  "We saw Mark's neighbors, though we didn't really talk with them.  We also saw Matt McLaughlin, who's a close friend to everyone.  He lives right across the street, and everyone comes down to the street in Southie for the parade"

"Do you have any pictures of him?"  Encyclopedia asked.  "I know you didn't list him in the people who were there, but I'm just curious."

"Umm, no direct ones, but lemme see..." Dan flipped through the photos.  "Yep, here's Matt gaping at the Star Wars procession."

Sally looked at the photo and said "Why is there a Star Wars float in the St. Patrick's Day parade?"

"Well, that mystery will have to be solved on another day, but I know who the sweater belongs to..." said Encyclopedia.

Do you know who the sweater belongs to?  What evidence did Encyclopedia see in the photos that led him to his deduction!  Scroll down to read the answer!

"See this girl next to Matt.  Who's that?" asked Encyclopedia. 

"SON OF A BITCH!  It's Amanda!" Dan roared.  "But wait -- she's wearing a coat, not a sweater."

"The way she's bundled up though, I bet she's got a sweater under that coat.  And you look at her -- she's the right size for that sweater."  Encyclopedia chuckled.  "I know you Dan.  After the parade, you probably skedadled almost immediately.  That's why you don't remember Matt and Amanda coming over later in the evening -- but it's St. Patrick's Day.  How could a guy named Matt Mclaughlin NOT raise a cup of cheer with his good friend at some point later on in the evening.  Likewise, Matt's such a good friend, that his coming over doesn't count as an unusual event for Mark, which is why he didn't remember it either.  But I bet if you ask Amanda, she'll be missing a sweater.

"Goddam I bet you're right!  Dude--Amazing!"  Dan jumped to his feet,  "Ladies and Gentlemen!  The one and only ENCYCLOPEDIA BROWN!!!"

Author's Footnote:  

When I started writing, I did not actually know how the story would end, but as Encyclopedia began asking questions, I realized exactly as EB knew, Matt and Amanda would have certainly come over -- so EB really did solve the case.

Monday, October 11, 2010

Javascript , YUI, Dates and Datatable

I've had some issues with pushing strings in JSON to a browser and having the browser parse them correctly.  Some browsers will take strings as argument, some want numbers -- it's a bit confusing.  To avoid all confusion, I recommend making a new date and then setting the values, rather than using the ambiguous constructors, which are implemented differently on different browsers.

As an example

new Date("2010, 12, 25");


new Date("12 25,2010");

both yield a date in Firefox, but not in IE.

Better is to do this:

Date d = new Date();
d.setFullYear(int year,int month,int day);  

Note that month is 0 based, so 0 is January, 11 is December.

Wednesday, September 29, 2010

A simple versioning implementation of Voldemort

I've been playing around with Voldemort recently for a robust enormous datastore at Esped.com.  One of the frustrating things I found in getting into it was the lack of complete existing code samples, so I thought I'd contribute one to the community.

This is a bit more than simple put/get because I need versioning associated with my objects.  This code assumes you've got a Voldemort server up and running.  Make the object you want to save implement Storeable, and then you can call VoldemortValet.process(yourObject) and it will save it.

It would be easy enough to take the versioning OUT of this code if you needed to.

import org.jdom.Element;

public interface Storeable {
    public String getIidString();
    public Element rawXML();
    public String getUserId();
    public String getDataType();

 * A simple versioning datastore.  In this example we want to keep track of every iteration of every object
 * as well as every change made by every user.  In a relationalDB we'd have a userid in the versions of the objects, but
 * noSQL doesn't work that way.  We use the ID of the object as a storage point in the store for the current version of
 * the object we're storing.  When we store a new version of an object, we increment the version in Voldermort, and the
 * store the object with <id>_<version> as the key.
 * <p/>
 * Thus if you want to retrieve all the entries for an object with id='3141529' you'd first query Voldemort to see how many
 * versions there were, and then get every version by specific key
public class VoldemortValet {

    public static SimpleDateFormat datetime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    static StoreClientFactory factory;
    static String bootstrapUrl = "tcp://";
    static String storeName = "myStore";

    static {
        ClientConfig cc = new ClientConfig();
        factory = new SocketStoreClientFactory(cc);

    public static void main(String argv[]) {
        DefaultStoreClient<Object, Object> client = null;
        try {
            client = (DefaultStoreClient<Object, Object>) factory.getStoreClient(storeName);
        } catch (Exception e) {
            System.out.println("Could not connect to server: " + e.getMessage());
        client.put("hello", "new world:" + new Date().toString());

     * When saving a Storeable, we first find out the version of the we will be saving, and then save takt with a key
     * of IID_V where IID is the id of the object and V is the version number we want to save with.
     * @param
    public static boolean process(Storeable so) {
        DefaultStoreClient<Object, Object> client = null;
        //create the XML we'll be saving and add the time and updating user id to it
        Element element = so.rawXML();
        element.setAttribute("CALLED_BY", so.getUserId());
        element.setAttribute("IVDATE", datetime.format(new Date()));
        //convert the JDOM element to a string
        String uxml = new XMLOutputter().outputString(element);
        try {
            //connect to the client
            client = (DefaultStoreClient<Object, Object>) factory.getStoreClient(storeName);
        } catch (Exception e) {
            System.out.println("Could not connect to server: " + e.getMessage());
            return false;
        //get the version number counter, defaulting to 0 if there is nothing in Voldemort
        String versionCounter = (String) client.getValue(so.getIidString(), "0");
        //get the update number counter this user has done, by querying with the userid
        String updateCounter = (String) client.getValue(so.getUserId(), "0");
        //iterate the counters
        versionCounter = Integer.toString(Integer.parseInt(versionCounter) + 1);
        updateCounter = Integer.toString(Integer.parseInt(updateCounter) + 1);
        //store the updated counters
        client.put(so.getIidString(), versionCounter);
        client.put(so.getUserId(), updateCounter);
        //store the newest version of the Storeable
        client.put(so.getIidString() + "_" + versionCounter, uxml);
        //store the transaction with the user's ID, so we could find all the updates he/she did if we wanted to
        client.put(so.getUserId() + "_" + updateCounter, so.getDataType() + "_" + so.getIidString() + "_" + versionCounter);
        return true;

     * This gets back a vector of all the last N version of an object
     * @param key
     * @param numberOfVersions
     * @return
    public static Vector get(String key, int numberOfVersions) {
        DefaultStoreClient<Object, Object> client = null;
        Vector v = new Vector();
        try {
            client = (DefaultStoreClient<Object, Object>) factory.getStoreClient(storeName);
            //client = (DefaultStoreClient<Object, Object>) factory.getStoreClient(String.valueOf(eo.getOrganizationID()));
        } catch (Exception e) {
            System.out.println("Could not connect to server: " + e.getMessage());
            return null;
        //how many versions of this object are there?
        String version = (String) client.getValue(key, "0");
        int versionNumbers = Integer.parseInt(version);
        //prepare to make a JDOM element out of the stored XML
        SAXBuilder builder = new SAXBuilder();
        Document xdoc = null;
        //get the specific versions
        for (int x = 0; versionNumbers - x > 0 && x < numberOfVersions; x++) {
            String rxml = (String) client.getValue(key + "_" + Integer.toString(versionNumbers - x));
            try {
                //note that this makes a document and puts the stored element in as the root element.
                xdoc = builder.build(new StringReader(rxml));
            } catch (JDOMException e) {
            } catch (IOException e) {
        return v;


/* code syntax highlights courtesy of http://www.manoli.net/csharpformat/ I used the C# option, and it worked well for java. */