Disable ESPN Autoplay

I wrote a Google Chrome extension that stops videos and ads from playing automatically on ESPN.com. This is another example of scratching my own itch; most people can enable this feature by clicking Autostart Off on any ESPN video, but I clear out my cookies every time I close Chrome, so that tool doesn’t work for me. Also, this is more important for me than other people because I’ll click to open three stories at once, and if the videos all begin playing at the same time, it gets extremely annoying.

Anyway, here’s the extension, all six lines of it in Javascript:

jQuery("#videoPlayer").ready(function(){
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.text = "function check_if_ready(){if (espn.video.player.adPlaying){espn.video.pause();} else{setTimeout(check_if_ready, 100);}}check_if_ready();"
    document.body.appendChild(script);
});

Unfortunately getting to that point took a while; I tried a few other things before I hit on that solution. It’s not perfect but it gets the job done. In the future it would be nice to skip the ads entirely, or auto-play only the video in the tab I’m currently watching. You can download the extension here or improve the source code here.

Auto-lightbox images in WordPress

I’m starting a new side project, where I’ll have to insert lots of screenshots for each blogpost. I’d like to allow users to enlarge images without having to leave the current page. The best way to do this is with a “lightbox,” which darkens the background and displays the image in the center of the screen.

What I would like is just to post an image to the blog and have the lightboxing and image resizing occur automatically. Unfortunately none of the WordPress plugins let you do this; most of them require you to add an extra link with a special tag. So I wrote this short bit of Javascript which extends a popular WordPress lightbox plugin, Lightbox 2. The script takes an image and wraps an “a” tag around it with the rel=”lightbox” attribute set, which triggers the Lightbox code. It also resizes the image to a maximum of 600 pixels wide or high. Here’s the code:

//get all images inside entry content
jQuery(document).ready(function(){
    jQuery(".entry-content img").each(function(){
//get the URL of the image
        var the_url = jQuery(this).attr('src');
//insert a href before image where rel=lightbox
        var a = jQuery("<a></a>").attr({"href": the_url, "rel": "lightbox"});
        jQuery(this).wrap(a);
        jQuery(this).load(function(){
            var the_width = jQuery(this).width();
            var the_height = jQuery(this).height();
            var max_dimension = 600;
            if (the_width && the_height){
                var ratio = the_width / the_height;
                if (ratio >= 1 && the_width > max_dimension){
                    jQuery(this).css('width', max_dimension);
                    jQuery(this).css('height', the_height * max_dimension / the_width);
                }
                else if (ratio > 1 && the_height > max_dimension){
                    jQuery(this).css('height', max_dimension);
                    jQuery(this).css('width', the_width * max_dimension / the_height);
                }
            }
        });
    });
});

You can also download the file here. To install, edit the header.php file of your WordPress directory and add the following lines above the

<?php wp_head(); ?>

line:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script>
<script src="/path/to/img.js file" type="text/javascript"></script>

Then you’re done!

The ACM ICPC: a supposedly fun thing I’ll never do again

Yesterday I was part of CMC’s first ever entry into the ACM ICPC, an international programming competition. Last year solving three problems would have been good enough for 5th place, but this year solving three problems was only good enough for 29th out of 75 or so.

The easiest three problems were easy to pick out and we started work on them. The first problem was, given an expected distribution of T-shirt sizes and a number of participants, write some code to determine how many T-shirts to order. The code for this problem was more or less written in the problem description and I was able to solve it in the first twenty minutes or so.

While I was doing that my teammates were working on a cipher problem – given a codeword, create a simple code alphabet and use it to decrypt a message.

While they were doing that going on I started working on the third problem, which was a map labeling algorithm. It was like a Rand McNally map where if you go off the top of the map you have to go to another page on the map. You were given a ‘map’ divided up into a series of blocks, and had to number each block, and then for each block label the block’s neighbors. I solved this one pretty quickly too, however I forgot to remove a print statement from my code, so it was printing an empty line before the output, which cost two incorrect submissions and 40 penalty minutes.

The cipher problem turned out to be fairly difficult. There was a problem with the program that took about an hour to solve, partly because we kept printing out code that we thought was showing one thing when in fact it was showing something else. Also, we had an array of characters that was supposed to hold all of the letters of the alphabet from A to Z, but in fact was missing W. Once we solved those we submitted the code and got the correct answer on the first submission, but by this point we had an hour and a half left.

I started working on the fifth problem, which I thought was the next easiest. The problem was, given a triangle and a thousand points inside that triangle, split the points into three even groups by finding another point inside the triangle.

triangle

I found the algorithm right away, which was to do a binary search and always move toward the region that contained the most points. However, this turned out to be tricky to implement in practice. Ultimately this problem was really difficult and only a few groups solved it correctly (the winning Harvey Mudd team solved seven of eight problems and this was the one problem they didn’t solve). Trying it was a tactical mistake on my part, and we might have been able to solve a fourth if we’d attempted a different problem.

Ultimately it was a long day and as my teammate Jacob noted, “the nerdiest thing I’ve ever done.” It was good I guess, considering I was the only person on our team who’d practiced before the contest and we were the first team ever from CMC to go to the competition. I’d wanted to join the competition because I show my resume to people and they say “Great you’re an economics major, so, marketing?” and I wanted to show that I could code a little bit. It would have been great to do better in the competition but them’s the breaks.

Among other things this shows how wide the differences between programmers can be; it’s estimated that the best programmers are 10 times as efficient as average programmers, and looking at the times to completion it’s easy to see how this is true. By the time I solved Problem 1 the Harvey Mudd team had already solved three problems, and there were some teams there that didn’t even solve a single problem. These are hard to measure, which is why it’s so important to actually look at someone’s code to see how they do things, or ask them to write sample code.

All of my practice code can be found here; unfortunately you can’t keep the code you wrote during the competition.

Google Finance killed my weekend project

One annoying thing about Google Finance is that there’s no way to see how your portfolio’s value has changed over time. You can see your cost basis and the current value but none of the intermediate values. Way back when I used to log into MSN Money and record the value in a spreadsheet every day. That didn’t last very long.

Over the weekend I built a tool that keeps track of how much your portfolio’s worth. Every night at midnight it would grab the current value of all your portfolios and store it in my database, and then when you visited my site again, it would display a chart with all of the daily values of your portfolios. I got the entire backend working, and got to the point where the app was displaying all of the daily values on the page in plain text. Here’s my cost basis and a week’s worth of daily values, with some numbers blurred.

This weekend I was going to turn those numbers into a pretty Annotated Time Line using the Google Chart API. Unfortunately (or fortunately), I checked Google Finance today and it turns out that they just built the portfolio value chart into their main product.

Google Finance portfolio view

It’s pretty cool that they put the chart in there; obviously it would have been nice to have visitors to my own site, and I built it so that anyone can log in and check the values, but also a little deflating, that my project won’t be useful for people. Guess I’ll have more time to work on my other projects. In the meantime though, I got better at XML parsing, learned a ton about OAuth, implemented an app with user-specific data for the first time, and got better at programming.

You can grab the code I was using here, or check your own portfolio here.

To learn how you can outperform the Dow by 10%, or to learn more about the app, you should email me here.

Escaping from your email

I only download my email once every four hours. Otherwise I check it too much. This works really well and my "need to check" email addiction has totally shut off.

For this to work on your own email, you want to set up a Gmail account with an address that no one knows, as well as access to a cron task scheduler. Cron is an application that runs tasks on a set schedule, so every minute or every year or every Monday at 5pm, etc. If you have Mac or Linux, and you're the type of person that keeps their computer on 24/7, you can run "cron jobs" from your local machine (you want to edit the /etc/crontab file - here are some instructions). I use my web hosting provider's cron service, because it will run even when my laptop is shut down.

Here's the script:

import imaplib
from datetime import datetime
import email
import smtplib
import sys
import os
import random
import base64
def main():
    #check user
    if os.isatty(sys.stdin.fileno()):
        #i'm trying to get my email by cheating, not a cron
        print "Are you sure you want to do this?"
        ans = raw_input()
        if ans != "yes":
            return
        no_of_mults = 3
        for i in range(no_of_mults):
            a = random.randint(1000,9999)
            b = random.randint(1000,9999)
            print "What is " + str(a) + " * " + str(b) + "?"
            ans = float(raw_input())
            if ans != a*b:
                print "Sorry, incorrect answer."
                return
    imap_domain = "imap.gmail.com"
    imap_port = 993
    imap_username =  base64.b64decode('my_gmail_username_encoded')
    imap_password = base64.b64decode('my_gmail_pass_encoded')
    #smtp settings
    smtp_domain = "my_smtp_host.com"
    smtp_port = 587
    smtp_username = "my_smtp_user"
    smtp_password = "my_smtp_pass"
    email_recipients = ['kburkeorg@gmail.com']
    imap_server = imaplib.IMAP4_SSL(imap_domain, imap_port)
    imap_server.login(imap_username, imap_password)
    server = smtplib.SMTP(smtp_domain, smtp_port)
    server.ehlo()
    server.starttls()
    server.ehlo()
    server.login(smtp_username, smtp_password)
    imap_server.select('INBOX')
    status, email_ids = imap_server.search(None, '(UNSEEN)')
    recipient = email_recipients
    count = 0
    for e in email_ids[0].split(' '):
        if e is not '':
            try:
                raw_msg = imap_server.fetch(e, '(RFC822)')
                msg = email.message_from_string(raw_msg[1][0][1])
                #modify reply-to so we preserve email address
                if not msg['Reply-To']:
                    msg['Reply-To'] = msg['From']
                result = server.sendmail(msg['From'], recipient, msg.as_string())
                count += 1
            except smtplib.SMTPRecipientsRefused, e:
                print "SMTPRecipientRefused" + str(e)
                continue
            except Exception, err:
                print err
                continue
    # so I can see how many messages were printed
    print "Sent " + str(count) + " messages."
    filename = "/home/kevinburke/webapps/b/sent.txt"
    with open(filename, 'w') as f:
        f.write(str(count))
    print datetime.now()
    server.quit()
if __name__ == "__main__":
    main()

Then in your cron file, you want to add the following line:

0 */4 * * * /usr/bin/python /path/to/email/file.py

where

/path/to/email/file
is the filepath to wherever you saved the script above. The 0 means run the script at the top of the hour, and the */4 means run it once every 4 hours.

Losing all your work

You’ve been typing away on an essay in Microsoft Word when the whole thing crashes, and you lose all your work. You wail, gnash your teeth, yell at the CMC tech staff and then commiserate with everyone you know.

Losing all your work is probably a positive development however, if you have some extra time. It forces you through a second iteration of your work, which should be clearer and sharper than your first because you are visiting the ideas for a second time. Losing all your work on paper though doesn’t mean you lose it in your head, and you also probably have an outline or some other reference document to go on.

The other option is to write all of your essays from the command line and use version control to save all of your drafts. It’s much less prone to crashes than Word.