The Twitter web interface polls for new tweets and displays a notification when any are found. Clicking on that notification will show all of the new tweets. I've found there is a point with a relatively small number of new tweets – between 30 and 200 – where I want to skim them all, but it's a hassle to return to the position where I left off reading.

New Tweets Notification
The visual indicator for the newest tweet is very subtle and virtually unnoticeable while scrolling fast.

Newest Tweet Indicator - A slightly darker line
Solution
It's a fairly simple problem to solve with a bookmarklet – a tiny bit of javascript that is manually executed by opening a bookmark.
Right-click and bookmark the following link, or drag it to your bookmarks toolbar or menu: First New Tweet
This may not work in a feed reader. If that's the case, manually add the bookmarklet or view the original post. Internet Explorer may prompt you about adding a Favorite that is not safe; ignore that, or get a better browser.
There is a known bug (#86643) affecting some versions of Chrome that results in a bookmark that does not contain a name. Right click and Edit the bookmark to fix that.
To use the bookmarklet, open it the way you would a normal bookmark. If there are new tweets, the browser will automatically scroll to the oldest new tweet – which will be right above the last tweet visible prior to loading the newest tweets.
Read more about bookmarklets at Wikipedia.
Source Code
Unminified code, complete with a modified version of Dustin Diaz's getElementsByClass to accommodate Internet Explorer. I briefly tested this on Google Chrome 13, Firefox 4 and IE 8. This isn't meant to be pretty.
javascript:(function(){
if( document.getElementsByClassName ) {
var t=document.getElementsByClassName("last-new-tweet")[0];
if(t) {
window.scrollTo(0, t.offsetTop + t.offsetParent.offsetTop );
}
} else {
var els = document.getElementsByTagName("div"), elsLen = els.length, pattern = new RegExp("(^|\\s)last-new-tweet(\\s|$)");
for (var i = 0; i < elsLen; i++) {
if ( pattern.test(els[i].className) ) {
window.scrollTo(0, els[i].offsetTop + els[i].offsetParent.offsetTop );
break;
}
}
}
})();
Minified code, in case you'd like to manually create your own bookmarklet.
javascript:(function(){if(document.getElementsByClassName){var t=document.getElementsByClassName("last-new-tweet")[0];if(t){window.scrollTo(0,t.offsetTop+t.offsetParent.offsetTop);}}else{var els=document.getElementsByTagName("div"),elsLen=els.length,pattern=new RegExp("(^|\\s)last-new-tweet(\\s|$)");for(var i=0;i<elsLen;i++){if(pattern.test(els[i].className)){window.scrollTo(0,els[i].offsetTop+els[i].offsetParent.offsetTop);break;}}}})();
I wanted to cleanly display tabular data from a PHP command line script, and I like how MySQL formats its output. This is quick, somewhat inefficient, hacky code, but it got the job done. You'll find nothing to be proud of in this code; I don't want to spend more time writing this post about it than I did writing it :)
/**
* Out a MySQL-style table of data
*
* @param array $data Associative array of data to output.
* @param array $header_keys Optional; Assoc array of display names to use for headers. Keys must match those of $data. Defaults to keys of $data.
* @param string $glue String to join lines with, defaults to newline.
* @return string
*
*/
function build_table($data, $header_keys=array(), $glue="\n") {
$table = '';
$data_fmt = array();
$divider_row = array();
$header_fmt = array();
$keys = array_keys($data[0]);
$col_lengths = array_flip($keys); // used to determine the max column width
if( empty($header_keys) ) {
$header_keys = array_combine($keys, $keys);
}
// set the base max length to the length of our header keys
foreach( $keys as $key ) {
$col_lengths[$key] = strlen($header_keys[$key]);
}
foreach( $data as $row ) {
foreach( $keys as $key ) {
$col_lengths[$key] = max($col_lengths[$key], strlen($row[$key]));
}
}
foreach( $keys as $key ) {
$data_fmt[] = '%-' . $col_lengths[$key] . 's';
$header_fmt[] = '%-' . $col_lengths[$key] . 's';
$divider_row[] = str_pad('', $col_lengths[$key]+2, '-'); // fill the spacing
}
$data_fmt = '| ' . implode(' | ', $data_fmt) . ' |';
$divider_row = '+' . implode('+', $divider_row) . '+';
$header_fmt = '| ' . implode(' | ', $header_fmt) . ' |';
// assemble the table
$table .= $divider_row . $glue;
$table .= vsprintf($header_fmt . $glue, $header_keys);
$table .= $divider_row . $glue;
foreach( $data as $row ) {
$table .= vsprintf($data_fmt . $glue, $row);
}
$table .= $divider_row . $glue;
return $table;
}
The output will be similar to:
+--------------------+--------------------+---------------+
| First | Second col | Random Column |
+--------------------+--------------------+---------------+
| 60386980488376 | 597655305189574649 | 51 |
| 959432 | 459191 | 396802 |
| 73874213 | 570702 | 771 |
| 144579584678722975 | 892300317939345 | 59180 |
| 293172 | 314 | 127725766727 |
+--------------------+--------------------+---------------+
It only works with associative arrays, but that's easy enough to fix. You can proudly test it out using this glorious snippet:
$data = array();
function get_rand() {
$max=rand(1,6);
$str='';
for( $i = 0; $i < $max; $i++ ) {
$str .= rand(10, 1000);
}
return $str;
}
for( $i = 0; $i < 5; $i++ ) {
$row = array(
'one' => get_rand(),
'two' => get_rand(),
'three' => get_rand(),
);
$data[] = $row;
}
$disp = array(
'one' => 'First',
'two' => 'Second col',
'three' => 'Random Column',
);
echo build_table($data, $disp);
This is basically a port of the WordPress paginate_links function from PHP to ColdFusion, with a few enhancements. The original function was written by Michael D Adams (trac ticket).
Changes include the ability to control page size via a query string parameter, the ability to restrict the maximum page size (overriding the value of page_size) and a threshold (show_all_threshold) for displaying all pages. show_all_threshold is useful in cases where you may have a small number of pages and would like to display links to each of them.
Sample Usage
<cfparam name="url.pagenum" default="12" />
<cfparam name="url.nrecords" default="20" />
<cfoutput>
paginate_links(link_format="?pagenum=%PAGE%", end_size=2, mid_size=3, current=#url.pagenum#, total=260, page_size=#url.nrecords#)
#paginate_links(link_format="?pagenum=%PAGE%", end_size=2, mid_size=3, current=url.pagenum, total=260, page_size=url.nrecords)#
paginate_links(link_format="?pagenum=%PAGE%", end_size=2, mid_size=3, show_all_threshold=15, current=#url.pagenum#, total=350, page_size=#url.nrecords#)
#paginate_links(link_format="?pagenum=%PAGE%", end_size=2, mid_size=3, show_all_threshold=15, current=url.pagenum, total=350, page_size=url.nrecords)#
paginate_links(link_format="?pagenum=%PAGE%", end_size=2, mid_size=3, current=#url.pagenum#, total=300, page_size=#url.nrecords#
#paginate_links(link_format="?pagenum=%PAGE%", end_size=2, mid_size=3, current=url.pagenum, total=300, page_size=url.nrecords)#
</cfoutput>
Output
paginate_links(link_format="?pagenum=%PAGE%", end_size=2, mid_size=3, current=12, total=260, page_size=20)
« Previous12345678910111213Next »
paginate_links(link_format="?pagenum=%PAGE%", end_size=2, mid_size=3, show_all_threshold=15, current=12, total=350, page_size=20)
« Previous12…9101112131415…1718Next »
paginate_links(link_format="?pagenum=%PAGE%", end_size=2, mid_size=3, current=12, total=300, page_size=20)
« Previous12…9101112131415Next »
Code
<cffunction name="paginate_links" access="public" output="false" returntype="any" hint="Return links to paginated results, heavily based on paginate_links() <http://trac.wordpress.org/ticket/3159> from WordPress <http://wordpress.org/> by Michael D Adams <http://blogwaffe.com/>">
<cfargument name="link_format" required="YES" type="string" default="" hint="Link format. Use %PAGE% for the page number placeholder (required), %SHOW% for the paging size (optional)" />
<cfargument name="prev_next" required="YES" type="boolean" default="true" hint="Show previous/next links" />
<cfargument name="prev_text" required="YES" type="string" default="« Previous" hint="Text for 'Previous Page' link" />
<cfargument name="next_text" required="YES" type="string" default="Next »" hint="Text for 'Next Page' link" />
<cfargument name="end_size" required="YES" type="numeric" default="1" hint="How many numbers on either end including the end" />
<cfargument name="mid_size" required="YES" type="numeric" default="2" hint="How many numbers to either side of current not including current" />
<cfargument name="current" required="YES" type="numeric" default="" hint="Currently active page" />
<cfargument name="total" required="YES" type="numeric" default="1" hint="Total number of results. Number of pages will be calculated by total/page_size" />
<cfargument name="page_size" required="YES" type="numeric" default="20" hint="Number of results to show per page" />
<cfargument name="max_page_size" required="YES" type="numeric" default="50" hint="Maximum number of results to show per page, to prevent abuse." />
<cfargument name="show_all" required="YES" type="boolean" default="false" hint="Show all page numbers (ignore end_size, mid_size)" />
<cfargument name="show_all_threshold" required="YES" type="numeric" default="0" hint="Show all page numbers ONLY if the total number of pages is <= this value. 0 to ignore." />
<cfargument name="prev_class" required="YES" type="string" default="page-numbers pn-prev" hint="Class(es) to use for Previous Page link" />
<cfargument name="next_class" required="YES" type="string" default="page-numbers pn-next" hint="Class(es) to use for Next Page link" />
<cfargument name="current_class" required="YES" type="string" default="page-numbers pn-current" hint="Class(es) to use for Next Page link" />
<cfargument name="dots_class" required="YES" type="string" default="page-numbers pn-dots" hint="Class(es) to use for dots span" />
<cfargument name="page_numbers_class" required="YES" type="string" default="page-numbers" hint="Class(es) to use for page numbers" />
<cfargument name="return_type" required="YES" type="string" default="text" hint="Valid types are array, text" />
<cfscript>
var page_links = ArrayNew(1);
var link = '';
var n = 0;
var dots = false;
var num_pages = Ceiling( arguments.total / arguments.page_size ); // Total number of pages
// Sanity checks
if( arguments.end_size LT 0 ) {
arguments.end_size = 1;
}
if( arguments.mid_size LTE 0 ) {
arguments.mid_size = 2;
}
if( arguments.max_page_size ) {
arguments.page_size = Min( arguments.page_size, arguments.max_page_size );
}
// If we are within our show all threshold, enable the display of all pages
if( arguments.show_all_threshold GTE num_pages ) {
arguments.show_all = true;
}
// Add Previous Page link if current page is 2+, and we want to show next/prev links
if( arguments.prev_next AND arguments.current AND arguments.current GT 1 ) {
link = ReplaceNoCase( arguments.link_format, '%PAGE%', arguments.current - 1 );
link = ReplaceNoCase( link, '%SHOW%', arguments.page_size );
ArrayAppend(page_links, '<a class="#arguments.prev_class#" href="#link#">#arguments.prev_text#</a>' );
}
// Build internal page number links
for( n = 1; n LTE num_pages; n=n+1 ) {
if( n EQ arguments.current ) {
ArrayAppend( page_links, '<span class="#arguments.current_class#">#n#</span>' );
dots = true;
} else {
if( arguments.show_all OR ( n LTE arguments.end_size OR ( arguments.current AND n GTE arguments.current - arguments.mid_size AND n LTE arguments.current + arguments.mid_size ) OR n GT num_pages - arguments.end_size ) ) {
link = ReplaceNoCase( arguments.link_format, '%PAGE%', n );
link = ReplaceNoCase( link, '%SHOW%', arguments.page_size );
ArrayAppend( page_links, '<a class="#arguments.page_numbers_class#" href="#link#">#n#</a>' );
dots = true;
} else if( dots AND NOT arguments.show_all ) {
ArrayAppend( page_links, '<span class="#arguments.dots_class#">...</span>' );
dots = false;
}
}
}
// Add Next Page link if current page LT total, and we want to show next/prev links
if( arguments.prev_next AND arguments.current AND arguments.current LT num_pages ) {
link = ReplaceNoCase( arguments.link_format, '%PAGE%', arguments.current + 1 );
link = ReplaceNoCase( link, '%SHOW%', arguments.page_size );
ArrayAppend(page_links, '<a class="#arguments.next_class#" href="#link#">#arguments.next_text#</a>' );
}
if( arguments.return_type EQ "array" ) {
return page_links;
} else {
return ArrayToList(page_links, "");
}
</cfscript>
</cffunction>
Another helper function for ColdFusion, this one to replicate PHP's array_merge which allows you to merge multiple arrays. In this case I'm only concerned with associative arrays, which ColdFusion calls structs.
CFMX provides StructAppend which will merge two (and only two) structures, optionally overwriting keys. I always want to overwrite keys, and I want to merge unlimited structures.
<cfscript>
function struct_merge() {
var base = {};
var i = 1;
for( i = 1; i LTE ArrayLen(arguments); i=i+1 ) {
if( IsStruct(arguments[i]) ) {
StructAppend(base, arguments[i], true);
}
}
return base;
}
</cfscript>
Usage
<cfscript>
one = {
a = "a",
b = "b",
c = "c",
d = "d",
e = "e"
};
two = {
1 = "one",
2 = "two",
3 = "three",
4 = "four",
a = "one_SetByTwo",
c = "three_SetByTwo"
};
three = {
a = "one_SetByThree",
2 = "b_SetByThree"
};
new = struct_merge(one, two, three);
</cfscript>
<cfdump var=#new#>
Result:
