Selling Out the Movies

I love going to the movie theater. Or, at least, I used to.

When I was growing up, my family did not have a lot of money, and so it was a rare treat to go to the theater to see a movie. As a young college student, I got hired as a projectionist at a small movie theater in New Hampshire, and I absolutely loved it. There were many late nights, after splicing all the movie reels of a newly-delivered film together, that I would sit with my brother and my closest friends to sneak preview the movie until the small hours of the morning.

To me, the experience of a larger-than-life movie on a larger-than-life screen is thrilling. I love the smell of popcorn and the auditory onslaught of music and explosions from the sound system. I love seeing all the movie posters for upcoming films.

I especially love the movie trailers. It seems to me that lots of other people do too; of some 10-billion videos watched annually on the internet, movie trailers rank third, after news and user-created video. To me, the experience of watching the trailers is an important part of the theater experience. It's like the appetizer before a great meal, or if the meal turns out to be bad, it can save the memories of the evening. The same can be said about movie trailers; how many times have you heard that the trailers were the best part of the movie?

I took my sons to the theater today to see "Despicable Me". This was only the second time my children have been to the theater, and I was probably more excited for them than they were about seeing the movie. However, I was dismayed to find out that my movie experience has been sold out. Before the trailers (but after the trivia and random bits of information), a number of commercials were run for everyday products, such as deodorant, and other health and beauty aids. I was horrified, even though my children didn't know any different.

To me, the practice of running product advertisements before the movies is like going to a nice restaurant and being served airline peanuts before the appetizers and meal. It cheapens the rest of the meal. What's worse is that in the movies, you're a captive audience so to speak. You can't change the channel, and most people aren't likely to get up and stand in the hallway while the ads are running. I can practically see the advertising executives greedily rubbing their hands together and laughing wickedly.

Sadly, I know this is just the start. I wouldn't be surprised if at some point in the next decade, films will take regular commercial breaks, or display ads in a running ticker along the bottom of the screen.

I sincerely hope I'm wrong about that.

Trackback URL for this post:

http://beyrent.net/trackback/244

Apache Solr: Conditionally Display Facet Blocks

In my last post, I showed a method for conditionally displaying facet blocks with Search Lucene, depending on the type of query being performed.  This can also be adapted to work for Apache Solr, albeit with a different mechanism. The easiest way to do this with Apache Solr is to use the Context module to control which facet blocks are displayed, along with when and where they are displayed.  In this example, I set up a context based on path, where that path was search/apachesolr/*.  I then added all of my Apache Solr facet blocks in the context. With the context configured, I now have the ability to alter that context on the fly, based on whatever conditions I choose. 

<?php 

/**
 * Implementation of hook_context_active_contexts_alter().
 *
 * <a href="http://twitter.com/param">@param</a> mixed $contexts
 *   Associative array of context objects
 */
function MYMODULE_context_active_contexts_alter(&$contexts) {
  
// If one of the active contexts is the apachesolr_search context, remove 
  // some unneccessary blocks
  
if(in_array('search-apachesolr-search'array_keys($contexts))) {
    
/**
     * Look at the type of query that has been performed, and set a flag regarding whether or 
     * not to show the biblio facets if the type:biblio filter is in effect
     */
    
$show_biblio_facets false;
    
$query apachesolr_current_query();
    if(
$query) {
      if(
$query->has_filter('type''biblio')) {
        
$show_biblio_facets true;
      }
    }
    
// Loop through the apachesolr-search blocks and remove the Biblio facet blocks if needed
    
foreach($contexts['search-apachesolr-search']->block as $bid => $block) {
      if(
preg_match('/^apachesolr_biblio_/'$bid)) {
        if(!
$show_biblio_facets) {
          unset(
$contexts['search-apachesolr-search']->block[$bid]);
        }
      }
    }
  }
}

?>
 In this example, I get all of the active contexts, and if my apachesolr-search context is in effect, I look at the current Apache  Solr query to see what filters have been applied.  In the example, a flag is set to show the biblio facets if the current search is filtering by the biblio content type. There may be other methods for displaying facets conditionally in Apache Solr; however, I find this method to be fairly straightforward, and if you're not currently using Context for controlling block placement in Drupal, you should definitely reconsider that decision.

Trackback URL for this post:

http://beyrent.net/trackback/243

Search Lucene API: Conditionally Display Facet Blocks

I am working on a Drupal project that implements Search Lucene API, along with the Biblio module.  The client did not like the fact that when a generic search was executed, all enabled facet blocks were being displayed without context.  For example, a search for the generic term "data" with no filters showed Biblio-specific facet blocks, which didn't make any sense to the client.  He only wanted to display Biblio facet blocks if the current query was being filtered by content type where the content type was biblio.

After protesting mildly to the client, I realized that this request wasn't very difficult to achieve by implementing hook_luceneapi_facet_postrender_alter() in a custom module.  This implementation of the hook first checks to see if a search was executed, and if so, we retrieve the Zend query object in order to get the terms.  If the query is filtering by type where type is biblio, a flag is set to true to indicate that the Biblio facet blocks should be displayed.  If this flag is not set, the code loops through all the facet blocks ($items) passed into the hook, and removes the Biblio facets.

<?php 
function MYMODULE_luceneapi_facet_postrender_alter(&$items$realm$module$type NULL) {
  
// The example is only valid for "node" content.
  
if ($type != 'node') {
    return;
  }
  
  if (
$realm == 'block') {
    
/**
     * Look at the type of query that has been performed, and set a flag regarding whether 
     * or not to show the biblio facets if the type:biblio filter is in effect
     */
    
$show_biblio_facets false;
    if(
$module luceneapi_search_executed()) {
      
$query Zend_Search_Lucene_Search_QueryParser::parse(search_get_keys());
      if(
$query) {
        
module_invoke_all('luceneapi_query_alter'$query$module'node');
        
$terms $query->getQueryTerms();
        if(!empty(
$terms)) {
          foreach(
$terms as $term) {
            if(
$term instanceof Zend_Search_Lucene_Index_Term) {
              if(
$term->field == 'type' && $term->text == 'biblio') {
                
$show_biblio_facets true;
                break;
              }
            }
          }
        }
      }
    }
    
    if(!
$show_biblio_facets) {
      
// Loop through the items and remove the Biblio facet blocks if needed
      
if(!empty($items)) {
        foreach(
$items as $name => $item) {
          if(
preg_match('/^biblio_/'$name)) {
            unset(
$items[$name]);
          }
        }
      }
    }
  }
}

?>

Trackback URL for this post:

http://beyrent.net/trackback/227

Tracking JW Player Events with SiteCatalyst

I recently had a client with a Drupal site who wanted to be able to track whether or not his site members were watching videos on his site completely, and also wanted to know at what point site members were leaving the videos. The client currently uses SiteCatalyst for analytics, and is using the JW Media Player. After a lot of research, I came across this blog post, which gave some terrific insight regarding how to connect events in the JW Media Player to Omniture. However, the code samples did not apply to SiteCatalyst. The author of the blog post suggested using the s.tl() function in the SiteCatalyst code to track events. After a lot more research, I finally came up with a solution that tracks when users play a video, pause a video, watch a video until the end, and if the user navigates away from the video before it has completed. The current time of the video is also tracked for each of these events. Using this methodology, one could easily extend the tracking to include other events such as seek and playlist events. My code is below.

// Detect if the user navigates away from the video
window.onbeforeunload = confirmExit;
var currentPosition = 0;
var currentVolume = 0;
var currentMute = false;
var currentState = "NONE";
var defaultState = "NONE";
var clipduration = 0;
var player = null;
var s = null;
 
function playerReady() {
  player = document.getElementById('swfobject-1');
  addListeners(player);
} 
 
function addListeners(player) {
  if (player) {
    addAllModelListeners(player);
  }
  else {
    setTimeout("addListeners("+player+")",100);
  }
}
 
function addAllModelListeners(player) {
  if (typeof player.addModelListener == "function") {
    player.addModelListener("BUFFER", "doNothing");
    player.addModelListener("ERROR", "doNothing");
    player.addModelListener("LOADED", "doNothing");
    player.addModelListener("META", "doNothing");
    player.addModelListener("STATE", "stateListener");
    player.addModelListener("TIME", "positionListener");
  }
}
 
function doNothing(obj) { 
  //nothing
}
 
function positionListener(obj) {
  currentPosition = obj.position;
  clipduration = obj.duration;
}
 
function stateListener(obj) {
  s = s_gi('sitecatalyst_id');
  currentState = obj.newstate;
  switch(obj.newstate) {
    case 'PLAYING':
      s.linkTrackVars="prop1,eVar1,events";
      s.linkTrackEvents="video_play";
      s.prop1=secondsToMinutes(currentPosition);
      s.eVar1=secondsToMinutes(currentPosition);
      s.events="video_play";
      s.tl(this,'o','Play Video');
      break;
    case 'PAUSED':         
      s.linkTrackVars="prop1,eVar1,events";
      s.linkTrackEvents="video_pause";
      s.prop1=secondsToMinutes(currentPosition);
      s.eVar1=secondsToMinutes(currentPosition);
      s.events="video_pause";
      s.tl(this,'o','Pause Video');
      break;
    case 'COMPLETED':
      s.linkTrackVars="prop1,eVar1,events";
      s.linkTrackEvents="video_complete";
      s.events="video_complete";
      s.tl(this,'o','Video Complete');
      break;
  }
}
 
function confirmExit() {
  if(currentState != 'COMPLETED') {
    s.linkTrackVars="prop1,eVar1,events";
    s.linkTrackEvents="video_leave";
    s.prop1=secondsToMinutes(currentPosition);
    s.eVar1=secondsToMinutes(currentPosition);
    s.events="video_leave";
    s.tl(this,'o','Leave Video');
    currentState = '';
  }
}
 
// Helper function to convert seconds to mm:ss format
function secondsToMinutes(seconds) {
  // Parse the minutes
  minVar = parseInt(Math.floor(seconds/60));
  minVar = minVar <10 ? '0' + minVar : minVar;
  // Parse the seconds
  secVar = parseInt(seconds % 60);              
  // The balance of seconds
  secVar = secVar <10 ? '0' + secVar : secVar;
  return minVar + ':' + secVar;
}

Resources:

Channeling Steve Wilson

I have been a big fan of Candian musician Devin Townsend for a long time. If you're not familiar with his music, it's somewhat difficult to describe. First of all, it's definitely metal and mostly heavy. However, what makes Devin Townsend's music different is that he layers track upon track and ends up with a solid thick sonic wall that is so rich, you feel like you can reach out and grab it.

This morning, I went to check out his website and saw that a new video and song has been posted on the front page. My first thought was that Devin Townsend was channeling his inner Steve Wilson (Porcupine Tree, Blackfield). It certainly feels that way for most of the track, called "Coast". However, towards the end, the music turns decidedly in the direction of Townsend's previous DevLab work; strangely ambient, white noise, feedback, and general audio chaos. What makes this track different though is that the audio chaos is neatly and almost gently rendered on top of the more steady musical background. It's really quite something to listen to.

Even better than the song though is the accompanying video. It's simply incredible; aliens, monoliths, all shot in grainy black and white to mimic hand-held VHS camcorders. It's very reminiscent of parts of the X-Files, or something from the mind of M. Night Shyamalan.

Check out the video, or visit the Devin Townsend website.

Crayon Physics

Crayon Physics Deluxe trailer 2 from Petri Purho on Vimeo.This has got to be one of the coolest games I have ever seen.

I've always been a fan of puzzle games, but in this particular game, the puzzle of how to connect a ball to a star separated by distances and objects, is as dynamic as your imagination.

Players are presented with more than 70 different puzzles and its brilliance is found in the way it challenges you to use your imagination to envision and then implement your own unique solutions to each one.

In the PC version, players use the mouse to draw shapes and objects that react to the laws of physics. For example, if you draw a box in the air, it will fall because of gravity.

What's particularly clever about this game (as you'll see in the video below) is that you can be as creative as you want. Simple levers and inclined planes work, but then again, so will rockets, dragons, and trebuchets.

Watch the video to see what I'm talking about... Other really interesting demonstrations can be seen here and here.

[tags]crayon, game, petri+purho, physics[/tags]

New Drupal Module Released

Back in October, I released my first module for Drupal, the open-source content management system. These days, I seem to be developing exclusively for Drupal, and with a robust API and thriving community, I can only say how much fun it is to work with.

However, like any platforms, there are pieces missing. Fortunately, Drupal is one of those platforms that is very easily extended through modules. I came across one of those missing pieces while working on a project. I do all of my development in a sandbox, and when the work is complete, I QA the product in a staging environment before pushing the code and database changes to a production environment. I found that there was no way to manage user/role permissions in code; all management was a manual process via the web interface.

Having to repeat manual tasks like this across different environments increases the odds of errors. Steps can be omitted or performed improperly. In the case of permissions, I decided to correct that by writing a module called Permissions API. What this module allows you to do is to grant and revoke permissions to roles in code.

This is probably most useful in the context of programmatically creating CCK content types. The ability to import CCK content types through code is great until you decide that you want members of specific roles to be able to do something with this content type. Currently, the only way to grant the permissions is to navigate through the access control page in the admin interface, which is completely unusable if you have a lot of roles and a lot of modules. This module addresses that problem by providing two functions:

permissions_grant_permissions()
permissions_revoke_permissions()

Each function accepts a role id and an array of permissions. Sample usage would be:


<?php
function mymodule_update_1(){
  
// Handle roles and permissions
  
$rid db_result(db_query('SELECT r.rid FROM {role} r WHERE r.name = \'some custom role\''));
  if(
$rid 0){
    
$permissions = array(
      
'create some_content_type content',
      
'edit some_content_type content',
      
'edit own some_content_type content',
    );
    
permissions_grant_permissions($rid$permissions);  
  }
}
?>

This module also provides functions for granting all permissions defined by a given module to a given role, as well as granting all defined permissions to a given role, which is useful for creating admin-type roles. Sample usage would be:

<?php
function mymodule_update_2(){
  
// Create a "super-admin" role by granting all permissions
  
$rid db_result(db_query('SELECT r.rid FROM {role} r WHERE r.name = \'some custom role\''));
  if(
$rid 0){
    
permissions_grant_all_permissions($rid);
  }
}
?>

The next example shows how to grant all permissions defined by a specific module to a specific role:

<?php
function mymodule_update_3(){
  
// Grant all permissions defined by a module's hook_perm implementation
  
$rid db_result(db_query('SELECT r.rid FROM {role} r WHERE r.name = \'some custom role\''));
  if(
$rid 0){
    
permissions_grant_all_permissions_by_module($rid'some module')
  }
}
?>

[tags]api, code, drupal, module, permissions[/tags]

Drupal and Taxonomy Weights

I recently worked on a project in Drupal that called for a large number of taxonomy terms. I needed to put the terms in a specific order, but unfortunately, I had more terms than Drupal's weight field supports, which is a range from -10 to +10.

I did a quick search on Drupal, and was horrified to see how many people are hacking core to add a greater range. This is pretty easy to do without hacking core. All you need to do is create your own module that implements hook_form_alter().

my_module.module

<?php

function my_module_form_alter($form_id, &$form) {
  switch(
$form_id) {
    case 
'taxonomy_form_term':
    
$form['weight']['#delta'] = 100;
    break;
  }
}
?>

And that's it!

[tags]alter, drupal, form, hook, module, taxonomy, term, weight[/tags]

Get Firefox Ad

This is a pretty cool ad for Firefox that just makes me laugh...

Firefox, IE, Opera, Netscape, browsers, funny, ad

Tradition vs. Technology

I've lived in New England my entire life, and if there's one thing that Yankees treasure, it's tradition. I'm no different, and yet today, I grudgingly decided that one tradition is not worth keeping.

Ever since I was a child, my family engaged in one of the most time-honored New England traditions of the autumn: raking leaves. Raking leaves is a noble chore. You get exercise and fresh air, your lawn benefits from being dethatched by the tines of the rake, and it instills a solid work ethic in the young.

It's a chore that I have always cherished. This year, however, I was rather dreading it. I just purchased a new home in September, and it has a substantially larger yard than my previous home. I knew that it would take me weeks to rake the entire property, and with a full time job, young kids, a wife, and everything else that keeps a family busy, I was trying to figure out how I could squeeze an extra 12 hours into each day.

Mostly out of curiosity, I decided to try a leaf blower. I'll categorically state that I find this to be cheating, but in the face of weeks of raking, I saw little reason to not give it a try. I'll have to admit, I was highly skeptical of the tool. As I mentioned before, one of the benefits of raking by hand is that the lawn gets a good dethatching; that is, all the dead grass and other material that forms a carpet right at the level of the soil and blocks nutrients from reaching the roots of the grass gets pulled up by the tines of the rake. I didn't see how a leaf blower would help with this.

At this point, I have to concede that the idea for the leaf blower was not mine. The leaf blower was a gift to me from my father, who is much wiser than I am. When he first gave it to me, I had no intention of using the thing for the reasons I had mentioned above. I have the unfortunate tendency to forget about things that I dismiss as useless, even if my determination regarding the usefulness of a thing is based on little or no prior experience. I don't know what it was about today that made me rethink my position on the leaf blower, but I was pleasantly surprised by its effectiveness.

As I mentioned, I have a large yard. Nearly two acres of level lawn, ringed by a thick woods of maple, oak, birch, and sumac. I was able to completely clear my backyard of fallen leaves in under an hour, a chore that would have easily taken me six hours had I resorted to my traditional techniques. The leaf blower was powerful enough to scrub the lawn and underlying soil clean. However excited I was about my progress and the ease of clearing the leaves, I could not help but feel sadness.

You see, I'm addicted to technology. I work with it every day, and run my life with it. The use of technology, even simple technology like a leaf blower, has implications. Using a leaf blower is a one-man job, and the tool is so loud, there's no chance for discussion and conversation while working. Furthermore, when you use a tool that cuts your work time down to next to nothing, the issue of work ethic is not even worth mentioning.

I was left wondering how I will teach all of these things to my sons. How will I teach them the value of sweat equity, the importance of physical labor and the satisfaction of putting your body to work with fantastic results? How can they learn the fine art of Yankee conversation, which occurs in short bursts, layered on top of physical work? The great New Hampshire author Noel Perrin described this very thing in one of his essays.

Sure, I can choose to abandon the leaf blower and go back to traditional methods. But as much as I have this choice, my Yankee sense of frugality forbids me from doing something that takes so much time when I have at my disposal the tools to get the job done faster leaving room for other things. Would I rather rake or spend the extra time with my sons?

As my father always reminds me, there's no such thing as setting aside quality time with your kids. He points out that any time you spend with your kids is quality. Perhaps I'll take this to heart and take my kids for a walk in the woods instead of raking up the woods.

[tags]autumn, chores, leaf+blower, leaves, new+england, new+hampshire, raking, work, yankee[/tags]

About Erich

Erich is a web developer and a native New Englander who is passionate about life, the universe, and everything.

He is currently a senior Drupal developer at Harvard University, working on the IQSS OpenScholar project.  Prior to joining the team at Harvard, he was the engineering manager at CommonPlaces e-Solutions, in Hampstead, NH, contributing as the lead engineer on the Greenopolis.com and Twolia.com.

Erich is active in the Drupal community, having contributed modules and patches to the community. He presented at DrupalCon in Szeged Hungary, and co-presented at DrupalCon 2009 in Washington, DC.

Erich lives in New Hampshire with his wife, two sons, and two weimaraners.  When not writing code, Erich enjoys landscaping and woodworking.

Faceted search

Categories

Content type

Project types

Artwork Type

Artwork Tags

Recent comments

Activity Stream

May 28, 2010

  • Twitter ebeyrent tweeted "@j_macdonald Thanks for the heads-up. It's fixed now..." 6:25am #

May 27, 2010

May 26, 2010

  • Twitter ebeyrent tweeted "#selinux prevented #drupal from contacting my #solr server. The fix? setsebool -P httpd_can_network_connect 1" 11:10am #

May 25, 2010

  • Twitter ebeyrent tweeted "RT @Dries: RT @acquia: Hear @bjaspan participate in a @gluster webinar tomorrow - Deploying Open Source Storage Clouds http://bit.ly/cE0j7n" 7:59pm #
  • Twitter ebeyrent tweeted "First swim in the pool tonight, a refreshing 64 degrees! Now to watch the #Lost finale that I recorded! #turningintoagreatnight" 7:58pm #
  • Twitter ebeyrent tweeted "@DamienMcKenna Ever hear Lewis Black talk about MN winters? You'll make up for the heat this winter..." 8:09am #
  • Twitter ebeyrent tweeted "Dear #asshole on the train, your music sucks, turn down your goddamn #ipod. Thank you." 8:07am #
  • Twitter ebeyrent tweeted "1 accident effs up traffic for the whole morning on 93" 6:39am #

May 22, 2010

  • Twitter ebeyrent tweeted "About to start the Carter Mtn brass band concert" 7:21pm #

May 21, 2010

  • Twitter ebeyrent tweeted "beyrent.net relaunched on #drupal, replacing a #wordpress blog" 8:29pm #
  • Twitter ebeyrent tweeted "#android update to 2.1 was smooth with no problems. Sweet!" 8:26pm #

May 20, 2010

  • Twitter ebeyrent tweeted "@cpliakas It sounds like Zend Lucene as a PECL extension or running under #HipHop would be very fast, because the hash tables are cached" 1:20pm #