Wednesday, November 23, 2011

Cool things to do with chrome

Apart from being an excellent browser for web developers, Google Chrome is also a pretty awesome browser for everyone else. I've collected a few of the cool things you can do with Chrome.



1. Incognito Window
If you ever need to log in to the same service with two different accounts (say, if you're on your wife's computer and both want to check your gmail), open a 'New Incognito Window' (Shift+⌘+N/Ctrll+Shift+N). Cookies and history entries will not affect other windows.




2. Undo a closed tab
Yes, that's right, simply press Shift+⌘+T / Ctrl+Shift+T and the tab you just closed is opened again! AND - you can press it several times!




3. Pinned tabs
Using the same web sites all the time? Wouldn't it be nice if they where always on the same tab so you could use keyboard shortcuts to access them  with ⌘+n / Ctrl+n (n is the tab number you wish to jump to)?
Right click on the tab and select "Pin tab" and you have it! In addition, the tab size get's shrunk to just displaying the webpage's icon, and it's automatically moved as the first tab. Next time you (re)start Chrome, it's still there!



4. Synced chrome
Using chrome on several computers? Setup syncing through your Google account, and your bookmarks and settings is automatically synced across machines. Go to chrome://settings/personal (or preferences > personal) to set it up.




5. Which tab is making the sound
Ever had several tabs opened and suddenly one (or more) of them started playing audio? And you couldn't find which one? Then MuteTab might be just the thing for you!




6. Customized search engines - with shortcuts
If you use a custom search engine/dictionary/encyclopedia often, you might want to consider adding it as a custom search engine with a shortcut.
Go to chrome://settings/searchEngines and fill in the three inputs.
Use %s for the query part of the URL:
Anything you put in the Keyword input will become the shortcut, so in this example, if you type g+ in the location bar you'll be able to search directly (the shortcut for the location bar is -L or Ctrl-L.




7. Developer omnibox
If you're a developer, you certainly don't want to miss the Developer Omniboxes. They allow you to search through API reference documentation for a variety of languages and libraries.




8. Birds on the bleeding edge
If you want to try out the absolutely latest possible Chrome, go for the Canary release. This is the the daily build, but there are other channels as well if you want to try.


9. Tab overview
Got many tabs open and can't find the one you're looking for?
Go to chrome://flags/ and enable Tab Overview. You can now use the three-finger-down-swipe or Ctrl+⌘+T shortcut to have a nice thumbnail view of all open tabs.
Make sure to check out the other stuff there as well, but read the warning first.







10. Isolated chrome 
If you want to have an isolated chrome environment of the same release, you can do this by issuing a different --user-data-dir on startup. This article also explains how to neatly make a convinent shortcut to the different directories you want to create.



Feel free to share YOUR favorite chrome feature below!

Monday, November 21, 2011

Shell gems

I found a really good thread via +Patrick Aljord today called Give me that one command you wish you knew years ago on reddit.

It had a few really cool commands that I honestly didn't know about:

disown

Ever been in a situation where you'd like to turn off your laptop, but you just started a long lasting process and forgot to use screen? disown to the rescue:
$> long-lasting-command-that-you-dont-want-to-wait-for.sh
^Z
[1]+  Stopped        long-lasting-command-that-you-dont-want-to-wait-for.sh
$> bg
$> disown
^D
# Process still lives, although terminal is disconnected

fc

How about those simple one-liners that somehow always turn out to
be so long that they really should be done as a script on file instead?
$> ls | perl -nle 'started-out-short-and-neat-but-now-long-and-complex-oneliner'
$> fc
# Opens your $EDITOR and pastes the last command used, ready to be edited and saved!

cd -

cd - is a small little gem that basically changes your current path to
you previous directory (see also pushd and popd):
$/very/long/path/to/somewhere > cd /another/very/long/path/to/somewhere
$/another/very/long/path/to/somewhere > cd -
$/very/long/path/to/somewhere >
You can also use it to copy something from your previous directory:
$/very/long/path/to/somewhere > cp `cd -`/file.txt .

units

This one speaks for it self:
$> units "100 kg" stones
    * 15.747304
    / 0.063502932

OSX Bonus

For OSX users I tend to find pbcopy and pbpaste really usefull for copying and pasting to the clipboard:
$> ls *.jpg | pbcopy
# Copy file-list to clipboard

I also discovered that my soon-to-be-collegaue +Adam Ohren made a cool tool
called pbfcopy that does the same as pbcopy only for files. Nice!

Monday, October 3, 2011

Automating webcam time lapse


Ever wanted to see how stuff changes over time? With a webcam this can be done quite easily.
Set up cron/windows scheduled tasks  to go fetch a new image every minute/hour/day and compile the images to a video.
I've made a really simple script for making a sliding window view of the past 24 hours that can be used on any image feed.

Getting the images and making the video

I wanted to use ffmpeg since it has a solid command line interface and it's available on most platforms. ffmpeg wants the image files in a sequential order, so we need to rename the images after adding the newest image.

I'm not a bash expert (I usually solve stuff like this in Perl - when you have a hammer etc.), so it's probably other ways to make this work, but at least I think my code is quite easy to read and understand:

# Make sure we are in the right directory and that it has an images directory
cd /path/to/where/our/timelapse/stuff/will/be
mkdir -p images

# Delete files older than 1 day
find images/ -name '*.jpg' -mtime +0 -delete

# Download the latest image
curl 'http://www.yourdomain.com/webcam.jpg' > images/newest.jpg

# Create a prefix so files won't get overwritten in the rename process
prefix="images/$(date +%s)_"

# Rename files, oldest to newest from 0 .. xxx
for oldname in `ls -tr images/*.jpg`
do
  count=$(( $count + 1 ))
  newname=$prefix$(printf "%.4d.jpg" $count);
  mv $oldname $newname
done

# Make a video of the images, not overwriting the existing
ffmpeg -r 60 -b 4096k -i "$prefix%04d.jpg" -s 580x384 "$prefix.flv"
mv "$prefix.flv" timelapse.flv

Here I've set the framerate to 60 and the bitrare to 4096 kbit/s. (The less variation in the images the higher the frame rate). With a size of 580 x 384, this gives a file of roughly 11 mb (this will vary with the type of images of course).

Scheduling the process

Depending on your platform, there are several ways of adding scheduled tasks, but on Mac and *nix it's easiest just to add a cron job and silence the script's output so it won't fill your mailbox.

* * * * * bash /path/to/where/our/timelapse/stuff/will/be/scriptname.sh > /dev/null 2>&1

Adding the player

One would think that finding a decent free player capable of streaming video would be easy. I've looked at a lot of players and the only free and really good player I've found is Flowplayer (please leave a comment if you have other good alternatives). It offers lots of configuration options, but what I really like is how easy it is to implement:

<!doctype html> 
<html>
  <head> 
    <script type="text/javascript" src="./flowplayer-3.2.6.min.js"></script> 
  </head> 
  <body> 
    <a href="./timelapse.flv"
      style="display:block;width:580px;height:384px;" id="player"></a> 
    <script language="JavaScript"> 
      flowplayer("player", "./flowplayer-3.2.7.swf", {
          clip: { autoPlay: false, autoBuffering: true },
        });
    </script>              
  </body> 
</html>

Just download the player and you're ready to go.

The results

I made the video below for a local ski resort.  In order to get a smooth time lapse we need to fetch the images (atleast) every minute, but  rendering the video is quite CPU intensive so this is done once every hour. The result is a "sliding window" from the last 24 hours:



Feel free to copy, although it's nice if you leave a comment and a link back to this article if you find it useful!

Thursday, September 29, 2011

Automating Facebook (and a warning)

After receiving some 140+ posts on my wall for my birthday, I wanted to give some form of recognition to the greetings. Not wanting to spend the next hour or so pressing "Like", I thought I'd just use the javascript console directly from Chrome.

After some inspecting and tinkering, I decided to give it a try and just construct a mouse click-event and dispatch it on all of the like-buttons.

Having heard rumors about FB blocking abuse, I figured I'd just set up an interval timer with a 1 second delay so I didn't hand of too many simultaneous request to the FB servers.

This is what my code looked like:

var mouseClick = document.createEvent('MouseEvent');
mouseClick.initMouseEvent('click', true, true, window,
                          1, 0, 0, 0, 0,
                          false, false, false, false, 0, null);

var likeButtons = document.getElementsByName('like');

var numLikes = 0;
var intervalId = setInterval(function () {
  likeButtons[ numLikes++ ].dispatchEvent( mouseClick );
  console.log("Liked "+numLikes);
  if ( numLikes >= likeButtons.length ) clearInterval( intervalId );
}, 1000);

So, off I went, running the code:


Everything seemed fine, and the console just kept on counting..
Until this warning popped up:


The moral of the story is; Yes you can use your console to manipulate FB, but be cautious on the number of requests your script is performing.

PS! There are many ways to manipulate FB. The obvious would be through the FB APIs (maybe through their console?). There's a lot of Grease Monkey scripts around as well.

Sunday, August 28, 2011

Bitten By Bugs - the Asynchronous Way

Can you tell why the following code produces this output?

Source:
function getHighScores () {
  var highScoresDb = openDatabase('highScores', '1.0', 'My High Score list', 25500);
  var highScores = [];
  highScoresDb.transaction(
    function ( tx ) {
      tx.executeSql("select * from hiscores order by score desc", [],
                    function ( tx, results ) {
                      for ( var i = 0; i < results.rows.length; i++ ) {
                        highScores.push( results.rows.item( i ) );
                      }
                      console.log( "Num scores accumulated: ", highScores.length - 1 );
                    });
    });
    return highScores;
  }
var highScores = getHighScores();
console.log( "Num high scores returned: ", highScores.length - 1 );


Output:

Given the title of this post it might not be very hard to spot what's going on - but if you got your mind dialed in on procedural programming, it's not always easy to catch bugs like these.

Dealing with multi-paradigmatic programming languages like Javascript offers the possibilities of altering between and combining different programming paradigms. It's not uncommon to write procedural programs in Javascript while still using it's object-oriented features as well.

Javascript, like Perl, supports callbacks and closures quite elegantly. This is very useful when writing event-driven systems such as asynchronous I/O. Basically it let's you call a function and instead of hanging around waiting for the function to complete, you rather give the function a reference to a callback that will be invoked whenever the results are ready.

So now it might be clearer what's going on in the example;
  • 'highScores' is initialized as an empty array.
  • Both the call to the database object's transaction-method and the transaction object's (tx) executeSql-method are asynchronous methods that takes callbacks to be executed.
  • The execution of getHighScores is finished before the results are back from the database, thus it will return the empty array, and the log will show -1 since we haven't received any high scores - yet.
Bugs like these can be hard to find, especially if the callback was executed just fast enough on your computer but slower on other computers. You'd then have the dreaded non reproducable bugs.
(Actually - on my MBP with SSD the database returns the results before console.log is called)

How to fix it?

The most obvious and natural solution is to refactor our program to be callback driven itself.
This can be achieved by rewriting the getHighScores method to take a reference to a function that will be called once the results are ready:

function getHighScores ( callback ) {
  var highScoresDb = openDatabase('highScores', '1.0', 'My High Score list', 25500);
  highScoresDb.transaction(
    function ( tx ) {
      tx.executeSql("select * from hiscores order by score desc", [],
                    function ( tx, results ) {
                      var highScores = [];
                      for ( var i = 0; i < results.rows.length; i++ ) {
                        highScores.push( results.rows.item( i ) );
                      }
                      callback( highScores );
                    });
    });
    return highScores;
  }
getHighScores( function ( highScores ) {
  console.log( "Num high scores returned: ", highScores.length - 1 );
});

Thursday, May 12, 2011

It gets better



What is the It Gets Better Project?

In September 2010, syndicated columnist and author Dan Savage created a YouTube video with his partner Terry to inspire hope for young people facing harassment. In response to a number of students taking their own lives after being bullied in school, they wanted to create a personal way for supporters everywhere to tell LGBT youth that, yes, it does indeed get better.

Help spread the word http://www.itgetsbetter.org/

Tuesday, April 5, 2011

Google's driverless car

TED brings us this really cool video where Sebastian Thrun talks about Google's amazing driverless car project. Just plain awesome!