<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D08DQXg7eyp7ImA9WhBUFkw.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302</id><updated>2013-05-03T17:17:50.603-04:00</updated><category term="mvc" /><category term="The Romantics" /><category term="Gaming" /><category term="Rick James" /><category term="jeditable" /><category term="javascript" /><category term="Application Context" /><category term="Killing a joke" /><category term="spring" /><category term="html" /><category term="euphemism" /><category term="knockout.js" /><category term="java config" /><category term="j'accuse" /><category term="language" /><category term="GMail Syncer" /><category term="code" /><category term="Enable" /><category term="Facebook" /><category term="etymology" /><category term="Meta" /><category term="letter" /><category term="knockout" /><category term="Photoshop" /><title>Fresh Notes</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://blog.fawnanddoug.com/" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/FreshNotes" /><feedburner:info uri="freshnotes" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;C0QAQno_fip7ImA9WhJVFE8.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-2447328465920689765</id><published>2012-08-28T08:47:00.000-04:00</published><updated>2012-08-31T09:55:43.446-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-08-31T09:55:43.446-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="spring" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="Enable" /><category scheme="http://www.blogger.com/atom/ns#" term="Application Context" /><category scheme="http://www.blogger.com/atom/ns#" term="java config" /><title>How those Spring @Enable* Annotations work</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;img border="0" src="http://3.bp.blogspot.com/-2DfLcLj2fHs/UDw4lf0SQbI/AAAAAAAAMMI/BEdq6o-DTH4/s1600/300px-Dark_roasted_espresso_blend_coffee_beans_1.jpg" /&gt;&lt;/div&gt;
Spring's Java Config is a great way to configure your application without writing a lot of configuration code. &amp;nbsp;One reason is those awesome @Enable* annotations that let you magically set up things like Transactions (@EnableTransactionManagement), Spring MVC (@EnableWebMvc) or timed jobs (@EnableScheduling) with a simple class level annotation on your configuration class. These simple statements provide a lot of functionality but their machinations are fairly obscure. &amp;nbsp;On the one hand, it's great to get so much functionality for so little work, but on the other hand, if you don't understand how something works it makes debugging and problem solving much harder.&amp;nbsp; I couldn't find any posts or documents that covered how those annotations work so I figured I would write up one based on the research I did while debugging.&amp;nbsp; I don't work for Spring and I didn't write any of this code so please post any corrections or improvements in the comments and I'll update the post.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Design Goals&lt;/h3&gt;
From what I can tell, the design goal of those @Enable* annotations is to allow the user set up complex functionality with a minimal amount of code. &amp;nbsp;In addition, it seems clear that users must be able to use either a &amp;nbsp;simple default or be allowed to manually configure that code. &amp;nbsp;Finally, the complexities of the code are intended to be hidden from the user. &amp;nbsp;In short, let the user set up a lot of beans and optionally configure them without having to know the details of those beans (or really what's being set up). &amp;nbsp;I think there are a lot of pros (and some cons) to this approach but I'll discuss that at the end.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Case #1: @EnableScheduling (importing an @Configuration class)&lt;/h3&gt;
The first thing to note is that the @Enable* annotations are not magic.&amp;nbsp; Nothing in the Bean Factory knows anything about them specifically and there are no dependencies in the Bean Factory classes between the core functionality and specific annotations (like @EnableWebMvc) or the jars they're stored in (like spring-web). &amp;nbsp;Let's take a look at @EnableScheduling and see how it works. &amp;nbsp;You might have a MainConfig class that looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;@Configuration
@EnableScheduling
public class MainConfig {
// some beans go in here
}
&lt;/pre&gt;
&lt;br /&gt;
There's nothing special in the above.  Just a standard Java Config that's annotated with @EnableScheduling.  @EnableScheduling lets you execute certain methods at a set frequency. For example, you can run BankService.sendMoneyToDoug() every 20 minutes. &amp;nbsp; The @EnableScheduling annotation itself looks like this:
&lt;br /&gt;
&lt;pre class="brush:java"&gt;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {

}
&lt;/pre&gt;
&lt;br /&gt;
If we look at the annotation above, we can see that it is just a standard Class level annotation (@Target/@Retention) that should be included in JavaDocs (@Documented), but it has one Spring-specific annotation: @Import. &amp;nbsp;@Import is the key that ties everything together. &amp;nbsp;In this case, since our MainConfig is annotated as @EnableScheduling, when the Bean Factory is parsing the file (technically the ConfigurationClassPostProcessor is parsing it) it will also find the @Import(SchedulingConfiguration.class) annotation and it will import the class defined in the value. &amp;nbsp;In this case&amp;nbsp;SchedulingConfiguration. &amp;nbsp;What does it mean to import? &amp;nbsp;Well, in this case it's just treated as another Spring bean. &amp;nbsp;SchedulingConfiguration is actually annotated as @Configuration, so the Bean Factory will see it as another configuration class and all of the beans defined in that class will get pulled into your Application Context just as if you had defined another @Configuration class yourself. &amp;nbsp;If we inspect&amp;nbsp;SchedulingConfiguration we can see that it only defines one bean (a Post Processor) which does the scheduling we described above.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;@Configuration
public class SchedulingConfiguration {

 @Bean(name=AnnotationConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
 public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
  return new ScheduledAnnotationBeanPostProcessor();
 }

}
&lt;/pre&gt;
&lt;br /&gt;
OK, but what if I want to configure the beans defined in SchedulingConfiguration? &amp;nbsp;Well, at this point we're just dealing with regular beans. &amp;nbsp;So the same mechanisms that you would use for any other beans apply here. &amp;nbsp;In this case, the&amp;nbsp;ScheduledAnnotationBeanPostProcessor uses a standard Spring Application Event to find out when the Application Context is refreshed. &amp;nbsp;When this happens it checks to see if any beans implement SchedulingConfigurer and if so, uses those beans to configure itself. &amp;nbsp;This is not at all intuitive (or easy to find with an IDE) but it is completely separated from the Bean Factory and is a fairly common pattern for a bean to be used to configure another bean. &amp;nbsp;And now that we can connect all of the dots it is (somewhat) easy to find (or you could google the documentation or read the JavaDocs).&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Case #2: @EnableTransactionManagement (importing an ImportSelector)&lt;/h3&gt;
&lt;div&gt;
In the previous case we discussed how an annotation like @EnableScheduling can use @Import to pull in another @Configuration Class and make all of its beans available (and configurable) to your application. But what happens if you want to load a different set of beans based on some configuration? &amp;nbsp;@EnableTransactionManaged is a good example of this. &amp;nbsp;You might have a MainConfig class that looks like this:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class="brush:java"&gt;@Configuration
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
public class MainConfig {
// some beans
} 
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Once again, there's &amp;nbsp;nothing special in the above. Just a standard Java Config that's annotated with @EnableTransactionManagement. The only thing that's a little different from the previous example is that the user specified a parameter to the annotation (mode=AdviceMode.ASPECTJ). &amp;nbsp;The @EnableTransactionManagement annotation itself looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
 boolean proxyTargetClass() default false;
 AdviceMode mode() default AdviceMode.PROXY;
 int order() default Ordered.LOWEST_PRECEDENCE;
}
&lt;/pre&gt;
&lt;br /&gt;
As before, a fairly standard annotation, although this time it has some parameters. &amp;nbsp;However, I mentioned previously that the @Import annotation was the key that ties everything together and that is true once again. &amp;nbsp;The distinction though, is that this time we are importing&amp;nbsp;TransactionManagementConfigurationSelector.class which is not a class that is annotated with @Configuration. &amp;nbsp;TransactionManagementConfigurationSelector is a class that implements&amp;nbsp;ImportSelector. &amp;nbsp;The purpose of ImportSelector is to allow your code to choose which configuration classes to load at runtime. &amp;nbsp;It has one method that takes some metadata about an annotation and returns an array of class names. &amp;nbsp;In this case, the&amp;nbsp;TransactionManagementConfigurationSelector looks at the mode and returns some classes based on the mode:&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt; protected String[] selectImports(AdviceMode adviceMode) {
  switch (adviceMode) {
   case PROXY:
    return new String[] { AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName() };
   case ASPECTJ:
    return new String[] { TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME };
   default:
    return null;
  }
 }
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Most of these classes are @Configuration classes (e.g.&amp;nbsp;ProxyTransactionManagementConfiguration) so we know that they'll work like before, but some of them are not (let's ignore those for now). &amp;nbsp;For the @Configuration classes they get loaded and configured in the exact same way that we previously saw. &amp;nbsp;So in short, we can use @Import with an @Configuration class to load a standard set of beans or we can use @Import with an ImportSelector to load a set of beans that are decided at run time. &amp;nbsp;Sweet! But what about those classes we ignored?&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Case #3: @EnableAspectJAutoProxy (importing at the Bean Definition Level)&lt;/h3&gt;
@Import supports one last case which is when you want to deal with a Bean Registry (Factory) directly. If you need to manipulate the Bean Factory or work with beans at the Bean Definition level then this case is for you and it's very similar to the ones above. &amp;nbsp;Your MainConfig might look like:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;@Configuration
@EnableAspectJAutoProxy 
public class MainConfig {
// some beans
}
&lt;/pre&gt;
&lt;br /&gt;
Once again, there's nothing special in the above. Just a standard Java Config that's annotated with @EnableAspectJAutoProxy.&amp;nbsp; Here's the source for @EnableAspectJAutoProxy:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush:java"&gt;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
 boolean proxyTargetClass() default false;

}
&lt;/pre&gt;
&lt;br /&gt;
As before, the @Import is the key, but this time it's pointing to&amp;nbsp;AspectJAutoProxyRegistrar which is neither an @Configuration class nor implements ImportSelector. &amp;nbsp;The trick this time is that it implements&amp;nbsp;ImportBeanDefinitionRegistrar. &amp;nbsp;This interface gives access to the Bean Registry and Annotation Metadata so that we can manipulate the registry at runtime based off of the parameters in the annotation. &amp;nbsp;If you look at the previous case you can see that the classes we ignored were also ImportBeanDefinitionRegistrars. &amp;nbsp;These classes directly manipulate the Bean &amp;nbsp;Factory for those times when @Configuration classes aren't enough. &lt;br /&gt;
&lt;br /&gt;
So now we've covered all of the different ways the @Enable* annotations use @Import to pull various beans into your Application Context. &amp;nbsp;They either pull in a set of @Configuration classes directly and all of the beans from those classes get imported into your Application Context. &amp;nbsp;Or they pull in an ImportSelector which chooses a set of @Configuration classes at runtime and imports those beans into your Application Context. &amp;nbsp;Or finally, they pull in an&amp;nbsp;ImportBeanDefinitionRegistrars which can directly work with the Bean Factory at the Bean Definition level.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Conclusion&lt;/h3&gt;
In general I think this approach to importing beans into an Application Context is great because it makes set up very easy for the developer. &amp;nbsp;Unfortunately it obscures how to find the available options and how to configure them. &amp;nbsp;In addition, it doesn't directly take advantage of the IDE so it's hard to tell which beans are being created (and why). &amp;nbsp;However, now that we know about the @Import annotation we can&amp;nbsp;use our IDE to dig a little into each Annotation and its related configuration classes and understand which beans are being created, how they're being added to your Application Context and how to configure them. &amp;nbsp;I hope this helps! Please leave comments to let me know what you think and what I've missed / messed up.&lt;br /&gt;
&lt;div style="display: none;"&gt;
&lt;pre class="brush:java"&gt;&lt;/pre&gt;
&lt;pre class="brush:xml"&gt;&lt;/pre&gt;
&lt;pre class="brush:js"&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;script type="text/javascript"&gt;
 function loadScript(url, callback){
  var script = document.createElement("script")
  script.type = "text/javascript";
  if (script.readyState){  //IE
   script.onreadystatechange = function(){
    if (script.readyState == "loaded" ||
      script.readyState == "complete"){
     script.onreadystatechange = null;
     callback();
    }
   };
  } else {  //Others
   script.onload = function(){
    callback();
   };
  }
  script.src = url;
  document.getElementsByTagName("head")[0].appendChild(script);
 }
 loadScript("http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js", 
  function(){
   loadScript("http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js", 
    function(){
     SyntaxHighlighter.config.bloggerMode = true;
     SyntaxHighlighter.autoloader(
       'js jscript javascript http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushJScript.js',
       'css http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushCss.js',
       'java http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushJava.js',
       'xml xhtml xslt html http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushXml.js'      
     );     
     SyntaxHighlighter.all();
    }  
   );
  }
 );
&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/JvsCAyMfnGc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/2447328465920689765/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/08/how-those-spring-enable-annotations-work.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/2447328465920689765?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/2447328465920689765?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/JvsCAyMfnGc/how-those-spring-enable-annotations-work.html" title="How those Spring @Enable* Annotations work" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-2DfLcLj2fHs/UDw4lf0SQbI/AAAAAAAAMMI/BEdq6o-DTH4/s72-c/300px-Dark_roasted_espresso_blend_coffee_beans_1.jpg" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/08/how-those-spring-enable-annotations-work.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkAAQ3ozfSp7ImA9WhJaFks.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-5472259531997127982</id><published>2012-05-23T09:30:00.000-04:00</published><updated>2012-10-07T21:45:42.485-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-10-07T21:45:42.485-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="knockout.js" /><category scheme="http://www.blogger.com/atom/ns#" term="knockout" /><category scheme="http://www.blogger.com/atom/ns#" term="html" /><category scheme="http://www.blogger.com/atom/ns#" term="jeditable" /><title>In Place Editor Custom Binding for Knockout.js</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-912KxA_poFQ/T7v7f3bkmUI/AAAAAAAAAi0/N7_KQ9S7Z4U/s1600/Mike-tyson-punch-out-001.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-912KxA_poFQ/T7v7f3bkmUI/AAAAAAAAAi0/N7_KQ9S7Z4U/s320/Mike-tyson-punch-out-001.png" width="132" /&gt;&lt;/a&gt;&lt;/div&gt;
I recently discovered &lt;a href="http://knockoutjs.com/" target="_blank"&gt;knockout.js&lt;/a&gt;&amp;nbsp;and was totally blown away. It does a great job of removing the need for (most) DOM manipulations which lets you focus on your data model and get complex UIs running with a minimal amount of code. &amp;nbsp;That said, those complex UIs are by default made up of simple widgets (input boxes, buttons, etc) and if you want more complex widgets (&lt;a href="http://www.knockmeout.net/2011/07/another-look-at-custom-bindings-for.html" target="_blank"&gt;date pickers&lt;/a&gt;, inline editors, etc) you need to either find them elsewhere or roll your own. &amp;nbsp;&lt;a href="http://www.knockmeout.net/2011/07/another-look-at-custom-bindings-for.html" target="_blank"&gt;Ryan Niemeyer&lt;/a&gt;&amp;nbsp;gives a great explanation of how to create a date picker (or any custom binding) and I quickly incorporated it into my own site. &amp;nbsp;Since I also needed an inline editor I figured I would post my results so others could reuse and improve upon them. &amp;nbsp;The following code is very much based on the &lt;a href="http://www.knockmeout.net/2011/07/another-look-at-custom-bindings-for.html" target="_blank"&gt;Custom Bindings article&lt;/a&gt; referenced above and the &lt;a href="http://www.appelsiini.net/projects/jeditable" target="_blank"&gt;Jeditable &lt;/a&gt;inline editor.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;h2&gt;












The Goal:&lt;/h2&gt;
&lt;div&gt;
The goal is to create something that looks like text but when you click it becomes editable. &amp;nbsp;I also wanted when you click off or hit enter for the text to be saved to the model. &amp;nbsp;Finally, I want hitting "Esc" to undo the latest change. &amp;nbsp;Here is a live example you can play with:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;table&gt;
 &lt;tbody&gt;
&lt;tr&gt;
  &lt;td style="text-align: right;"&gt;Click this:&lt;/td&gt;
  &lt;td&gt;&lt;span data-bind="jeditable: name, jeditableOptions: {}" style="background-color: yellow;"&gt;&lt;/span&gt;&lt;/td&gt;
 &lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;Current value:&lt;/td&gt;
  &lt;td&gt;&lt;span data-bind="text: name"&gt;&lt;/span&gt;&lt;/td&gt;
 &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;h2&gt;








The Prerequisites:&lt;/h2&gt;
&lt;div&gt;
The following code is based on:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://knockoutjs.com/documentation/installation.html" target="_blank"&gt;Knockout.js 2.1.0&lt;/a&gt;&amp;nbsp;(obviously)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.jquery.com/Downloading_jQuery#CDN_Hosted_jQuery" target="_blank"&gt;JQuery 1.7.x&lt;/a&gt;&amp;nbsp;(parent of Jeditable)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.appelsiini.net/projects/jeditable" target="_blank"&gt;Jeditable&lt;/a&gt;&amp;nbsp;(inline edit control that does most of the work)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2&gt;










The HTML:&lt;/h2&gt;
The HTML is pretty simple:&lt;br /&gt;
&lt;pre class="brush:html "&gt;Click this: &amp;lt;span data-bind="jeditable: name, jeditableOptions: {}"&amp;gt;&amp;lt;/span&amp;gt;
Current value: &amp;lt;span data-bind="text: name"&amp;gt;&amp;lt;/span&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
If you're comfortable with Knockout.js this should look pretty familiar. &amp;nbsp;The first line uses a custom binding called "jeditable" to tie a model property called "name" to a span tag. &amp;nbsp;Knockout.js will be responsible for keeping the model and DOM in sync. &amp;nbsp;As a developer I just tell it to use the "jeditable" binding for this element and the "name" property. &amp;nbsp;There is also an optional "jeditableOptions" property which I can use to pass options to the jeditable binding.&lt;br /&gt;
&lt;br /&gt;
The second line uses the standard text binding to display the current value of the "name" property in the span. Once again, as a developer, I don't have to think at all about what to update when the model changes. It all happens automatically.&lt;br /&gt;
&lt;h2&gt;







The Model&lt;/h2&gt;
&lt;div&gt;
The model can also be super simple: &lt;br /&gt;
&lt;pre class="brush: js"&gt;     function myViewModel() {
      this.name = ko.observable("Innocent looking text");
     };
  
     ko.applyBindings(new myViewModel());  
&lt;/pre&gt;
In this case I just need a single property called "name" that I default to "innocent looking text". &amp;nbsp;I pass an instance of my model to Knockout as is the KO way and it handles all of the heavy lifting. &amp;nbsp;All that leaves is...&lt;/div&gt;
&lt;h2&gt;





The Custom Binding&lt;/h2&gt;
The Custom Binding is the reusable code that knows how to update the DOM when the model changes and update the model when the DOM (or control) changes:
&lt;br /&gt;
&lt;pre class="brush: js"&gt;ko.bindingHandlers.jeditable = {
     init: function(element, valueAccessor, allBindingsAccessor) {
         // get the options that were passed in
         var options = allBindingsAccessor().jeditableOptions || {};
         
         // "submit" should be the default onblur action like regular ko controls
         if (!options.onblur) {
          options.onblur = 'submit';
         }
         
         // set the value on submit and pass the editable the options
         $(element).editable(function(value, params) {
          valueAccessor()(value);
          return value;
         }, options);

         //handle disposal (if KO removes by the template binding)
         ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
             $(element).editable("destroy");
         });

     },
     
     //update the control when the view model changes
     update: function(element, valueAccessor) {
         var value = ko.utils.unwrapObservable(valueAccessor());
         $(element).html(value);
     }
 };
&lt;/pre&gt;
&lt;br /&gt;
This is a little more complicated and requires some explanation. &amp;nbsp;The binding consists of two functions "init" and "update". &amp;nbsp;"init" is called only once, when the binding is initially evaluated. &amp;nbsp;Here we can create our control and pass it any options that the user specified. &amp;nbsp;We also listen for any changes so we can notify the model. &amp;nbsp;"update" is called every time the model changes and gives us a chance to alter the control to match the state of the model.&lt;br /&gt;
&lt;br /&gt;
The work begins at line 4. &amp;nbsp;Here we check to see if the user passed in any options. &amp;nbsp;This gives the user the ability to customize the Jeditable control using any of the &lt;a href="http://www.appelsiini.net/projects/jeditable" target="_blank"&gt;options allowed&lt;/a&gt; by the plugin. &amp;nbsp;One option allowed is "onblur". &amp;nbsp;This tells the control what to do when the user clicks outside of the control. &amp;nbsp;By default Jeditable will cancel any edits onblur but since the default Knockout.js controls will save onblur we follow this convention and set the default onblur value to be "submit" (that is, save) on lines 7-9.&lt;br /&gt;
&lt;br /&gt;
Lines 12-15 are where we create the control with the specified options and tie it to the appropriate DOM node. &amp;nbsp;The function that we pass in is what gets called when the user saves a new value. &amp;nbsp;In this function we simply update the model with the new value and return that value so that Jeditable thinks everything is ok.&lt;br /&gt;
&lt;br /&gt;
Lines 18-20 are just housekeeping. &amp;nbsp;That's where we clean up our control if Knockout.js tells us that the DOM node should be cleaned up.&lt;br /&gt;
&lt;br /&gt;
Finally, it's time to update at lines 25-28. &amp;nbsp;Here we simply get a reference to the new value in the model and update the Jeditable control to display that new value. &amp;nbsp;And that's it! &amp;nbsp;Now we have a custom binding that can be reused many times throughout the site.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;




The Conclusion&lt;/h2&gt;
Knockout.js bindings may seem a little scary at first but they're not that complicated and can be very powerful. &amp;nbsp;Even someone like me who is new to Knockout.js (and JQuery) can easily whip one up and reuse it throughout a site. &amp;nbsp;My only wish is that it was easier to distribute custom bindings so that some nice libraries could be written and shared across the 'net. &amp;nbsp;Please give me any feedback or improvements you have in the comments!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="display: none;"&gt;
&lt;pre class="brush:java"&gt;&lt;/pre&gt;
&lt;pre class="brush: js"&gt;&lt;/pre&gt;
&lt;pre class="brush: xml"&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;script type="text/javascript"&gt;
 function loadScript(url, callback){
  var script = document.createElement("script")
  script.type = "text/javascript";
  if (script.readyState){  //IE
   script.onreadystatechange = function(){
    if (script.readyState == "loaded" ||
      script.readyState == "complete"){
     script.onreadystatechange = null;
     callback();
    }
   };
  } else {  //Others
   script.onload = function(){
    callback();
   };
  }
  script.src = url;
  document.getElementsByTagName("head")[0].appendChild(script);
 }
// we get jquery from blogger
 loadScript("http://github.com/downloads/SteveSanderson/knockout/knockout-2.1.0.js", 
  function() {
   loadScript("http://www.appelsiini.net/download/jquery.jeditable.mini.js",
    function() {
     ko.bindingHandlers.jeditable = {
     init: function(element, valueAccessor, allBindingsAccessor) {
         // get the options that were passed in
         var options = allBindingsAccessor().jeditableOptions || {};
         
         // "submit" should be the default onblur action like regular ko controls
         if (!options.onblur) {
          options.onblur = 'submit';
         }
         
         // set the value on submit and pass the editable the options
         $(element).editable(function(value, params) {
          valueAccessor()(value);
          return value;
         }, options);

         //handle disposal (if KO removes by the template binding)
         ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
             $(element).editable("destroy");
         });

     },
     
     //update the control when the view model changes
     update: function(element, valueAccessor) {
         var value = ko.utils.unwrapObservable(valueAccessor());
         $(element).editable().html(value);
     }
 };

     function myViewModel() {
      var self = this;
      self.name = ko.observable("Innocent looking text");
     };
  
     ko.applyBindings(new myViewModel());  
    }
   );
  }
 );

 loadScript("http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js", 
  function(){
   loadScript("http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js", 
    function(){
     SyntaxHighlighter.config.bloggerMode = true;
     SyntaxHighlighter.autoloader(
       'js jscript javascript http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushJScript.js',
       'css http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushCss.js',
       'java http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushJava.js',
       'xml xhtml xslt html http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushXml.js'      
     );     
     SyntaxHighlighter.all();
    }  
   );
  }
 );
&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/M1zBIbB-OLw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/5472259531997127982/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/05/inline-editor-custom-binding-for.html#comment-form" title="10 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/5472259531997127982?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/5472259531997127982?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/M1zBIbB-OLw/inline-editor-custom-binding-for.html" title="In Place Editor Custom Binding for Knockout.js" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-912KxA_poFQ/T7v7f3bkmUI/AAAAAAAAAi0/N7_KQ9S7Z4U/s72-c/Mike-tyson-punch-out-001.png" height="72" width="72" /><thr:total>10</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/05/inline-editor-custom-binding-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUINSXo4eip7ImA9WhVUEEQ.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-206097347176663598</id><published>2012-05-15T10:53:00.000-04:00</published><updated>2012-05-15T10:53:18.432-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-15T10:53:18.432-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="euphemism" /><category scheme="http://www.blogger.com/atom/ns#" term="language" /><category scheme="http://www.blogger.com/atom/ns#" term="etymology" /><title>Euphemisms: When Good Words Go Bad</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-_qOJYFrKHBo/T7JsdXD2LsI/AAAAAAAAAfU/rwFGEiBpY6M/s1600/euphemism-misc1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="301" src="http://3.bp.blogspot.com/-_qOJYFrKHBo/T7JsdXD2LsI/AAAAAAAAAfU/rwFGEiBpY6M/s400/euphemism-misc1.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
A euphemism is a nice way of saying something not so nice. &amp;nbsp;The problem with euphemisms is that the more successful they are, the more likely they are to take on the not so nice meaning of the thing they're trying to be nice about. &amp;nbsp;Once this reversal happens, they&amp;nbsp;transition&amp;nbsp;from a euphemism to a synonym and a new euphemism must be created. &amp;nbsp;It's an interesting quirk of language that a word or phrase can be intended to mean one thing and then become so popular that it comes to mean something entirely different.&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
One example is the phrase "making love". &amp;nbsp;The original meaning of the phrase was exactly what it sounds like, creating love. &amp;nbsp;In other words, flirting. &amp;nbsp;If you were wooing someone you might send them love letters, make them fancy meals and generally put in lots of effort to create love. &amp;nbsp;This is a beautiful and somewhat innocent idea. &amp;nbsp;Which is exactly why it makes such a great euphemism. &amp;nbsp;Back in olden tymes one could have said "Ebeneezer&amp;nbsp;and I were 'making love'", implying that you were in the process of forming a relationship when really the only thing you were forming was the beast with two backs.&lt;br /&gt;
&lt;br /&gt;
The problem with this euphemism is that it's too good. &amp;nbsp;Everyone started using it and that was its downfall. &amp;nbsp;By becoming so successful the phrase grew more popular and consequently more people started to catch on. &amp;nbsp;It got to the point where today "making love" only means "having sex" and has completely lost its original meaning.&lt;br /&gt;
&lt;br /&gt;
This isn't specific to this one phrase. &amp;nbsp;Almost every successful euphemism faces this burden because by becoming successful it means that people use it and if people use it then they know what it means and consequently its meaning changes to what people are actually using it for (as opposed to its original meaning). &amp;nbsp;There's even a a phrase to describe this phenomenon: &lt;a href="http://en.wikipedia.org/wiki/Euphemism#Euphemism_treadmill" target="_blank"&gt;The Euphemism Treadmill&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Another great example is the word "retarded". &amp;nbsp;The verb retard means to make slow or to delay. &amp;nbsp;It was, at one point, a gentle way of describing a mental deficiency. &amp;nbsp;In fact it's very elegant. &amp;nbsp;It didn't mean that a person was incapable of anything, merely that they could arrive at the same place as everyone else, it just took them a little longer because they were slowed. &amp;nbsp;In&amp;nbsp;essence, something was delaying their progress not impeding their completion. &amp;nbsp;I think this is a lovely way of describing a phenomenon, but alas so did a lot of people. &amp;nbsp;And once again, that was the problem. &amp;nbsp;When everyone started to use "retarded" in this way it took on a negative connotation. &amp;nbsp;As with other euphemisms, it's gotten to the point today where most people think of the insulting definition first and the slowed definition second (if at all).&lt;br /&gt;
&lt;br /&gt;
I think there are a lot of people who see language as static; that a word means something which can never change; that there is a correct usage which cannot grow or evolve. &amp;nbsp;Euphemisms are one example that clearly show how languages are affected by the way that they are used. I think it is this feature of language, that they alter and self-correct over time to better reflect the people that use them to communicate, that makes language and&amp;nbsp;etymology&amp;nbsp;so interesting.&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/E7gmaXUUvcc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/206097347176663598/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/05/euphemisms-when-good-words-go-bad.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/206097347176663598?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/206097347176663598?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/E7gmaXUUvcc/euphemisms-when-good-words-go-bad.html" title="Euphemisms: When Good Words Go Bad" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-_qOJYFrKHBo/T7JsdXD2LsI/AAAAAAAAAfU/rwFGEiBpY6M/s72-c/euphemism-misc1.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/05/euphemisms-when-good-words-go-bad.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04CR3w8eCp7ImA9WhVUF00.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-6239202715358229548</id><published>2012-05-08T10:16:00.000-04:00</published><updated>2012-05-22T14:06:06.270-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-22T14:06:06.270-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="mvc" /><category scheme="http://www.blogger.com/atom/ns#" term="spring" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="java config" /><title>Pagination with Spring MVC, Spring Data and Java Config</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-70xPL4lDHW0/T6dKS7-VZbI/AAAAAAAAAb0/7lXBCmxie60/s1600/book-pages.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://1.bp.blogspot.com/-70xPL4lDHW0/T6dKS7-VZbI/AAAAAAAAAb0/7lXBCmxie60/s400/book-pages.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
Spring 3.1 has a lot of features for limiting the boiler-plate code you have to write for common functionality. &amp;nbsp;One great example is pagination. &amp;nbsp;Getting paged data from a database and presenting it to the user is one of those tasks that everyone seems to reinvent even though it's common functionality that is never specific to your business. &amp;nbsp;Spring Data provides some facilities to add pagination to your application with a minimal amount of code. &amp;nbsp;The &lt;a href="http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/" target="_blank"&gt;documentation &lt;/a&gt;on this is pretty good and it includes some steps on how to set up&amp;nbsp;both in the data tier and the &lt;a href="http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/#web-pagination" target="_blank"&gt;web tier&lt;/a&gt;. &amp;nbsp;Unfortunately, the documentation is unclear in a few places (see below) and doesn't explain at all how to use a Java Config. &amp;nbsp;This post tries to fill those gaps.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style="font-size: x-large;"&gt;&lt;b&gt;Data Tier&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
The first thing we need is a data tier that can return paged data from a database. &amp;nbsp;&amp;nbsp;Spring Data provides a way to access the database without writing any code (almost). Instead of having to define and implement common CRUD methods you simply define an interface. You don't have to write the implementation because Spring will create a proxy that automagically fulfills your interface. &amp;nbsp;You just wire the interface and Spring does the rest. &amp;nbsp;I'm using JPA and here's a real example:&lt;/div&gt;
&lt;br /&gt;
&lt;pre class="brush: java"&gt;package com.fawnanddoug.gmailsyncer.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import com.fawnanddoug.gmailsyncer.domain.SyncJobDetail;

public interface SyncJobDetailRepository extends JpaRepository&amp;lt;SyncJobDetail, Long&amp;gt; {
 
 public Page&amp;lt;SyncJobDetail&amp;gt; findBySyncJobIdOrderByLastUpdateDesc(long syncJobId, Pageable p);
  
}
&lt;/pre&gt;
Most of the work occurs on line 9 where I extend the JpaRepository interface. &amp;nbsp;Simply by extending that interface I get common CRUD methods like save(), findAll(), delete(), etc. &amp;nbsp;I also give my Entity Type (SyncJobDetail) and the key (Long) so that I get a strongly typed interface. &amp;nbsp;Now I have a repository that can create and modify Objects in my domain and all I did was extend an Interface.&lt;br /&gt;
&lt;br /&gt;
I get some additional help on line 11. &amp;nbsp;There I define a method to grab the SyncJobDetails by their parent's Id and I sort them by the last updated time. &amp;nbsp;Spring can automatically infer what the implementation should look like based on the method name (which is admittedly ugly) and once again I don't have to write any implementation. &amp;nbsp;The first parameter will map to the SyncJobId in the query and the best part is it automatically adds support for Paging just by adding the Pageable parameter. &amp;nbsp;Pageable has methods like "getPageNumber" and "getPageSize" so I can easily specify that I want pages with 20 items per page and give me page number 7. &lt;b&gt;The only trick here is the configuration which I'll describe below.&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style="font-size: x-large;"&gt;&lt;b&gt;








Web Tier&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Now that we can pull the data from the database we need some way to serve it over the web. &amp;nbsp;This also requires a minimal amount of code. &amp;nbsp;Here's an example:&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class="brush: java"&gt;@Controller
public class HomeController {

 private final SyncJobDetailRepository repo;

 @Inject
 public HomeController(SyncJobDetailRepository repo) {
  this.repo = repo;
 }

 @RequestMapping(value = "/history/detail/{id}", method = RequestMethod.GET)
 public String historyDetail(Model model, @PathVariable long id, Pageable p) {
  Page&amp;lt;SyncJobDetail&amp;gt; page = this.repo.findBySyncJobIdOrderByLastUpdateDesc(id, p);
  model.addAttribute("page", page);

  return "historyDetail";
 }
&lt;/pre&gt;
&lt;br /&gt;
Injecting the repository (line 6) and using the request mapping (line 11) are pretty basic Spring MVC concepts. &amp;nbsp;In short, if the user requests a page like /history/detail/123 then the historyDetail() method will get automatically invoked. &amp;nbsp;The real magic is on line 12 where the Pageable parameter is automatically inferred from the parameters that are passed into the request. &lt;b&gt;This also requires some configuration magic which is described below.&lt;/b&gt;&amp;nbsp; Once we have the Pageable we can just pass it on to our repository to get the appropriate data. &amp;nbsp;The returned Page is then exposed to the View so that it can be displayed to the user. &amp;nbsp;The page has useful information like which page we're looking at, how many total items exist and which items were returned in this page. &amp;nbsp;Once again we have barely any code written and we get Paging essentially for free.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;span style="font-size: x-large;"&gt;&lt;b&gt;






The View&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
Now that the Page Object is exposed to the view we can use that Page to display useful information to the user. &amp;nbsp;Here's an example JSP:&lt;/div&gt;
&lt;div&gt;
&lt;script class="brush: xml" type="syntaxhighlighter"&gt;
&lt;![CDATA[
  &lt;util:pagination maxPages="${page.totalPages}" maxElements="${page.totalElements}" page="${page.number}"
   size="${page.size }" /&gt;
  &lt;table&gt;
   &lt;thead&gt;
&lt;tr&gt;
     &lt;td width="2%"&gt;&lt;/td&gt;
     &lt;td width="30%"&gt;GMail Name&lt;/td&gt;
     &lt;td width="10%"&gt;Status&lt;/td&gt;
     &lt;td width="58%"&gt;Message&lt;/td&gt;
    &lt;/TR&gt;
&lt;/THEAD&gt;
   &lt;tbody&gt;
    &lt;c:set var="first" value="${page.size * page.number}"/&gt;
    &lt;c:forEach items="${page.content}" var="row" varStatus="status"&gt;
&lt;tr class="${status.count % 2 == 0 ? 'even' : 'odd'}"&gt;
      &lt;td&gt;${first + status.count}&lt;/td&gt;
      &lt;td&gt;${row.googleName}&lt;/td&gt;
      &lt;td&gt;${row.status}&lt;/td&gt;
      &lt;td&gt;${row.message}&lt;/td&gt;
     &lt;/tr&gt;
&lt;/c:forEach&gt;
   &lt;/tbody&gt;
  &lt;/table&gt;
]]&gt;
&lt;/script&gt;
&lt;/div&gt;
There's nothing particularly special here. &amp;nbsp;I created a pagination util tag lib since I reuse pagination in a few places. &amp;nbsp;It shows things like the total number of pages, the current page and how many elements are on the page. &amp;nbsp;As you can see all of this information comes from the Page object on lines 1 and 2. &amp;nbsp;The only other interesting item is that the content is exposed from the Page object at line 14. &amp;nbsp;Pretty straight forward and I didn't have to manually calculate or even query any of this information.&lt;br /&gt;
&lt;br /&gt;
The only thing left is to post back to the controller when we want a new page. &amp;nbsp;In this case we just have to specify the right parameters for the page size and the requested page and we're done. &amp;nbsp;Here's an example of how I generate the URL for my "Next" button:&lt;br /&gt;
&lt;script class="brush: xml" type="syntaxhighlighter"&gt;
&lt;![CDATA[
&lt;spring:url value="" var="next"&gt;
   &lt;spring:param name="page.page" value="${page.number + 1}" /&gt;
   &lt;spring:param name="page.size" value="${page.size}" /&gt;
&lt;/spring:url&gt;
]]&gt;
&lt;/script&gt;
In line 1 I use "" as the url value so that we post back to the same page.  I then add the "page.page" parameter for the next page (current page plus one) and use the same size that we're currently using.  Nothing particularly special here and all of the values come from the Page object that was returned from the data tier.
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: x-large;"&gt;&lt;b&gt;



The Gotchas&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
The code, as you can see above, is pretty minimal and can apply generically to any domain. &amp;nbsp;There are, however, a number of gotchas. &amp;nbsp;Let's explore these gotchas by working backwards from the View to the Web Tier to the Data Tier.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;b&gt;&lt;span style="font-size: large;"&gt;



View Gotchas&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
The first one is related to the &lt;a href="http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/#web-pagination" target="_blank"&gt;documentation&lt;/a&gt;. &amp;nbsp;In the above example I specify the next page parameter with the key "page.page". &amp;nbsp;The gotcha is that the docs say the parameter name is just "page" so it took me a little while to catch. &amp;nbsp;Technically you can specify any prefix you want (so it could be "foo.page"), but the important bit is that you must specify a prefix and then the parameter name. &amp;nbsp;The prefix can be configured on the PageableArgumentResolver which is described below.&lt;br /&gt;
&lt;br /&gt;
The next gotcha is that the Java Doc for PageRequest (the Pageable implementation) says that it is 0-based but the Java Doc for Page says that it is 1-based. &amp;nbsp;In other words, when you request data the first page is 0 but when it returns data the first page is 1. &amp;nbsp;This can be pretty confusing and may lead you to try to compensate in your code for potential one-off issues. &amp;nbsp;In fact, I think it's intentional and the goal is that when you display data it uses numbers that a User wants to see (e.g. page 1 is "1") but still plays nice with databases that think of the first page as 0. &amp;nbsp;The PageableArgumentResolver (described below) will automatically handle the conversion which means you won't need code to compensate for this, but it can still be confusing. &amp;nbsp;In short, it does the right thing but may be hard to wrap your head around.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;


Web Tier Gotchas&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
I mentioned above that to get the Pageable parameter to work in your controller you need some configuration magic. &amp;nbsp;In order for Spring to know how to convert the parameter to a Pageable object you need to configure a HandlerMethodArgumentResolver. &amp;nbsp;Spring Data provides a PageableArgumentResolver but it uses the old ArgumentResolver interface instead of the new (Spring 3.1) HandlerMethodArgumentResolver interface. &amp;nbsp;The XML config can handle this discrepancy for us, but since we're using Java Config we have to do it a little more manually. Luckily this can be easily resolved if you know the right magic incantation:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: java"&gt;@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
        
        @Override
        public void addArgumentResolvers(
                        List&amp;lt;HandlerMethodArgumentResolver&amp;gt; argumentResolvers) {
                
                PageableArgumentResolver resolver = new PageableArgumentResolver();
                resolver.setFallbackPagable(new PageRequest(1, 10));
                
                argumentResolvers.add(new ServletWebArgumentResolverAdapter(resolver));
        }
&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
The above is a standard Spring MVC Java Config. &amp;nbsp;It extends WebMvcConfigurerAdapter so that it can override some common methods and add functionality. &amp;nbsp;In this case we are overriding addArgumentResolvers so that we can add our PageableArgumentResolver. &amp;nbsp;The key here is that on line 12 we wrap the PageableArgumentResolver in a ServletWebArgumentResolverAdapater. &amp;nbsp;This lets us reuse the PageableArgumentResolver and still wrap it in the new Interface. &amp;nbsp;Now we get the Pageable object injected into our methods for free. &lt;br /&gt;
&lt;br /&gt;
One other note is that I set the FallBackPageable to use Page 1 and a Page Size of 10. &amp;nbsp;This means that if there is no Page parameters set it will use Page 1 and a Page Size of 10. &amp;nbsp;However, if you were paying attention above you would note that Pageable is supposed to be 0-based. &amp;nbsp;The magic here is that the PageableArgumentResolver tries to automatically compensate for 0-based and 1-based issues so it will treat both "0" and "1" as the first page. &amp;nbsp;"2" is always the second page. &amp;nbsp;This can be a little disconcerting at first, but as long as your view is passing in the values that the user wants (e.g. page "1" is "1") then you'll be fine.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;&lt;b&gt;
Data Tier Gotchas&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
I said above that this was about using Java Config but the sad news is that you can't use the JPA Data Repository scanning without XML. &amp;nbsp;A typical approach is to import the XML using something like this:&lt;br /&gt;
&lt;pre class="brush: java"&gt;@Configuration
@ImportResource("classpath:com/fawnanddoug/gmailsyncer/config/jpa.xml")
public class MainConfig {

// beans go here

} 
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Then you can have a simple xml config that looks something like this:&lt;/div&gt;
&lt;div&gt;
&lt;script class="brush: xml" type="syntaxhighlighter"&gt;
&lt;![CDATA[
&lt;?xml version="1.0" encoding="UTF-8" standalone="no"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:jpa="http://www.springframework.org/schema/data/jpa"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/data/jpa 
http://www.springframework.org/schema/data/jpa/spring-jpa-1.1.xsd"&gt;
 
 &lt;!-- find repos because there's no java config equivalent --&gt;
 &lt;jpa:repositories base-package="com.fawnanddoug.gmailsyncer.repository" /&gt;
&lt;/beans&gt;
]]&gt;
&lt;/script&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
In the above, line 11 searches the specified package to find our repository interfaces. &amp;nbsp;It then generates the appropriate implementations. Now we can wire our repository into the Java Config and use the cool new features. &amp;nbsp;In our case the SyncJobDetailRepository will get autowired into the HomeController so we don't have to add any additional configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: x-large;"&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
And that's it. &amp;nbsp;With a minimal amount of code you can add paging to your application and still use strongly typed methods and services. &amp;nbsp;Just make sure to configure the appropriate parts and look out for 0-based / 1-based issues.&amp;nbsp;&lt;/div&gt;
&lt;div style="display: none;"&gt;
&lt;pre class="brush:java"&gt;&lt;/pre&gt;
&lt;pre class="brush:xml"&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;script type="text/javascript"&gt;
 function loadScript(url, callback){
  var script = document.createElement("script")
  script.type = "text/javascript";
  if (script.readyState){  //IE
   script.onreadystatechange = function(){
    if (script.readyState == "loaded" ||
      script.readyState == "complete"){
     script.onreadystatechange = null;
     callback();
    }
   };
  } else {  //Others
   script.onload = function(){
    callback();
   };
  }
  script.src = url;
  document.getElementsByTagName("head")[0].appendChild(script);
 }
 loadScript("http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js", 
  function(){
   loadScript("http://alexgorbatchev.com/pub/sh/current/scripts/shAutoloader.js", 
    function(){
     SyntaxHighlighter.config.bloggerMode = true;
     SyntaxHighlighter.autoloader(
       'js jscript javascript http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushJScript.js',
       'css http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushCss.js',
       'java http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushJava.js',
       'xml xhtml xslt html http://alexgorbatchev.com/pub/sh/3.0.83/scripts/shBrushXml.js'      
     );     
     SyntaxHighlighter.all();
    }  
   );
  }
 );
&lt;/script&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/zouaR_oFqdY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/6239202715358229548/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/05/pagination-with-spring-mvc-spring-data.html#comment-form" title="10 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/6239202715358229548?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/6239202715358229548?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/zouaR_oFqdY/pagination-with-spring-mvc-spring-data.html" title="Pagination with Spring MVC, Spring Data and Java Config" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-70xPL4lDHW0/T6dKS7-VZbI/AAAAAAAAAb0/7lXBCmxie60/s72-c/book-pages.jpg" height="72" width="72" /><thr:total>10</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/05/pagination-with-spring-mvc-spring-data.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cEQXY-eip7ImA9WhVWGEo.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-7756422650267028881</id><published>2012-05-01T09:30:00.000-04:00</published><updated>2012-05-01T09:30:00.852-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-05-01T09:30:00.852-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Facebook" /><category scheme="http://www.blogger.com/atom/ns#" term="GMail Syncer" /><title>I wrote A Facebook To GMail Syncing App</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-BiejjUSgysc/T59AgOfY6_I/AAAAAAAAAZo/sQ_NdfGJNS0/s400/map.png" target="_blank"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-BiejjUSgysc/T59AgOfY6_I/AAAAAAAAAZo/sQ_NdfGJNS0/s1600/map.png" /&gt;&lt;/a&gt;&lt;/div&gt;
I wrote an app that syncs your Facebook Friends and GMail Contacts! &amp;nbsp;Actually, I rewrote an app that syncs your Facebook Friends and GMail Contacts. &amp;nbsp;The first version had some &lt;a href="http://blog.fawnanddoug.com/2012/04/i-convinced-100s-of-people-to-give-me.html" target="_blank"&gt;flaws&lt;/a&gt;. &amp;nbsp;But this version is new and improved. &amp;nbsp;Let me count the ways:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Brand New User Interface:&lt;/b&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;img border="0" height="513" src="http://2.bp.blogspot.com/-m8AurOmm_fk/T5894GCkl7I/AAAAAAAAAZc/Ot8FT7yWyuw/s640/UI.png" width="640" /&gt;&lt;/div&gt;
&lt;br /&gt;
I tried to redesign the UI with an eye towards a few things:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Clearly convey information with large text and bold icons&lt;/li&gt;
&lt;li&gt;Feel consistent within Facebook's style while adding a touch of whimsy&lt;/li&gt;
&lt;li&gt;Provide simple calls to action (errors are big and red with simple buttons that indicate the next step)&lt;/li&gt;
&lt;li&gt;Limited options that respond immediately (e.g. you can change the Sync Frequency without reloading the page or clicking submit)&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
I'm really interested in your feedback! &amp;nbsp;What do you think? Please post a comment!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;World Wide Appeal:&lt;/b&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-BiejjUSgysc/T59AgOfY6_I/AAAAAAAAAZo/sQ_NdfGJNS0/s1600/map.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="393" src="http://1.bp.blogspot.com/-BiejjUSgysc/T59AgOfY6_I/AAAAAAAAAZo/sQ_NdfGJNS0/s640/map.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
I'm not sure how this is a new feature but the all new GMail Contact Syncer has been used in 47 countries in the first month. &amp;nbsp;Above is a world map from Google Analytics (I'm big in India).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Cloud Based Development Platform&lt;/b&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://www.cloudfoundry.com/" target="_blank"&gt;&lt;img border="0" height="60" src="http://2.bp.blogspot.com/--MhpTiqH-ww/T59Bf9JMF1I/AAAAAAAAAZw/cko40_E3KhM/s320/logo_header_cloudfoundry.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
I moved the server out of my basement and now have a full data center with redundancy and and horizontal scaling. &amp;nbsp;There's lots of other buzz words like "Platform as a Service", "Open Stack" and "Virtual Jabberwockies" (I made up some of those). &amp;nbsp;Not that I really need it but it's cool (and free). &amp;nbsp;Thanks &lt;a href="http://cloudfoundry.com/"&gt;CloudFoundry.com&lt;/a&gt;!&amp;nbsp;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Completely Rewritten Syncing Infrastructure:&lt;/b&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://www.springsource.org/" target="_blank"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-lH9ECoPY4U4/T59EzaKtzpI/AAAAAAAAAZ8/Ehx25qf0Ivo/s1600/placeholder_video_spring_projects.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
The original syncing infrastructure was written by hand. &amp;nbsp;It put each Sync Job in a single transaction, was single threaded and periodically brought my Athlon 3200+ to its knees. &amp;nbsp;The new infrastructure was rewritten using Spring Integration for Enterprise Integration and Spring Social for Social Networking Integration. &amp;nbsp;It's fast enough that I actually had to&amp;nbsp;artificially&amp;nbsp;limit its speed so that Facebook would stop rejecting my requests for being too fast. &amp;nbsp;Also it partitions each job into logical steps to make failover more convenient (e.g. when Facebook randomly fails requests).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Totally doesn't steal your passwords:&lt;/b&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;img border="0" height="198" src="http://3.bp.blogspot.com/-KJ4SfUUfZmY/T59GhSjA1hI/AAAAAAAAAaE/ETOkEzLNf3Q/s200/OAuth-Shine-300x298.png" width="200" /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
The original version of the GMail Syncer required you to enter your GMail password and it stored it in the database. &amp;nbsp;This is a &lt;a href="http://www.blogger.com/"&gt;&lt;span id="goog_1536151232"&gt;&lt;/span&gt;bad&lt;span id="goog_1536151233"&gt;&lt;/span&gt;&lt;/a&gt; idea&lt;span style="font-family: Verdana, sans-serif; font-size: 12px; line-height: 16px;"&gt;™&lt;/span&gt;. &amp;nbsp;The new version never knows your passwords. &amp;nbsp;Using a technology called OAuth your passwords stay with your services (Facebook &amp;amp; Google) and the GMail Syncer stays completely ignorant. &amp;nbsp;You give access using the providers that you're comfortable with (Facebook &amp;amp; Google) and can revoke it at any time.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Set it and forget it:&lt;/b&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-iqdxnZuoiio/T59J009s3dI/AAAAAAAAAaQ/4EljIt5MPug/s1600/491595737_31ee926a9a.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="218" src="http://4.bp.blogspot.com/-iqdxnZuoiio/T59J009s3dI/AAAAAAAAAaQ/4EljIt5MPug/s320/491595737_31ee926a9a.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
As of May 1st, 2012 the GMail Syncer has processed over 1000 jobs, but you don't have to care. &amp;nbsp;Just set it up once, pick your sync frequency and forget about it. &amp;nbsp;It'll sync forever (or until you revoke access).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;It's Free:&lt;/b&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-iOeyRYWKeCo/T588VAEdEMI/AAAAAAAAAZU/Lpo3boxEm1w/s1600/thats+gold+jerry.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="233" src="http://4.bp.blogspot.com/-iOeyRYWKeCo/T588VAEdEMI/AAAAAAAAAZU/Lpo3boxEm1w/s320/thats+gold+jerry.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
And it's free. &amp;nbsp;I aught to figure out a way to monetize this bad boy, but I'm not sure how to do that yet. &amp;nbsp;So take advantage of my bad business sense and get in while the getting's good.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Please give it a try and give me any feedback you have in the comments or at doug [at] fawn and doug [dot] com.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Thanks!&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/pS7BQN52AGQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/7756422650267028881/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/05/i-wrote-facebook-to-gmail-syncing-app.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/7756422650267028881?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/7756422650267028881?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/pS7BQN52AGQ/i-wrote-facebook-to-gmail-syncing-app.html" title="I wrote A Facebook To GMail Syncing App" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-BiejjUSgysc/T59AgOfY6_I/AAAAAAAAAZo/sQ_NdfGJNS0/s72-c/map.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/05/i-wrote-facebook-to-gmail-syncing-app.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EERHs4cSp7ImA9WhVWE0w.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-4647449129694225687</id><published>2012-04-24T09:24:00.000-04:00</published><updated>2012-04-24T21:00:05.539-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-24T21:00:05.539-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="j'accuse" /><category scheme="http://www.blogger.com/atom/ns#" term="Rick James" /><category scheme="http://www.blogger.com/atom/ns#" term="The Romantics" /><title>In which I accuse New Wave rockers "The Romantics" of defiling Rick James' Grave</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-GNRUhjOQ7fE/T5Ha6g8k42I/AAAAAAAAAV0/zeVQOA_h5jg/s1600/The_romantics-talking_in_your_sleep_s.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-GNRUhjOQ7fE/T5Ha6g8k42I/AAAAAAAAAV0/zeVQOA_h5jg/s320/The_romantics-talking_in_your_sleep_s.jpg" width="317" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;i&gt;Update: The below is officially facts because it is cited in &lt;a href="http://en.wikipedia.org/wiki/Talking_in_Your_Sleep_(The_Romantics_song)#cite_note-1" target="_blank"&gt;Wikipedia&lt;/a&gt;.&lt;/i&gt;&lt;/div&gt;
&lt;br /&gt;
In the low stakes world of accusing 80s rock bands of ripping off Rick James, few have the gumption to publicly post their assertions on the Internet. &amp;nbsp;What with the rabid&amp;nbsp;fanaticism&amp;nbsp;of "The Romantics" die-hards and the Internet's strict requirements for rock solid proof, no one is willing to touch this red hot topic with a serial mouse. &amp;nbsp;But people of the Internet, live in fear no more - for I shall lead you out of the dark as I raise my keyboard and shout for all to hear that The Romantics totally ripped off "Super Freak" in their modest 1983 hit "Talking in your sleep".&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;"What?" you say in exasperated disbelief. &amp;nbsp;"Why would a hard rocking New Wave band whose fourth album totally went to number 14, stoop so low as to jack Rick James, the paragon of demure sensibilities, the very image of 80s sobriety? Well, the dastardly "The Romantics" might as well have been twirling their riff-stealing mustaches while they tied&amp;nbsp;genteel&amp;nbsp;Rick to the train tracks of financial oblivion. And gentle reader I'm getting all up in there because they totes did. &amp;nbsp;Poor damsel Rick could only wait for a super hero to appear out of nowhere and save the day. &amp;nbsp;And that's what I've done. &amp;nbsp;All Rick had to do was wait 21 years and then die and then wait 8 more years and here I am with my &lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=MrGaoSB0Eus#t=128s" target="_blank"&gt;Jones-like&lt;/a&gt; ability to show up just in time and save the day.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The Facts:&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Fact: "Super Freak" was released in &lt;a href="http://en.wikipedia.org/wiki/Super_Freak" target="_blank"&gt;1981&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fact: "Talking in your sleep" was released in &lt;a href="http://en.wikipedia.org/wiki/Talking_in_Your_Sleep_(The_Romantics_song)" target="_blank"&gt;1983&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Fact: Wikipedia is &lt;a href="http://www.nytimes.com/2007/02/21/education/21wikipedia.html?_r=1&amp;amp;em&amp;amp;ex=1172466000&amp;amp;en=d1211c2d017e16b6&amp;amp;ei=5087%0A" target="_blank"&gt;indisputable&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;b&gt;The&amp;nbsp;Damning Evidence:&lt;/b&gt;&lt;br /&gt;
Everyone knows the famous "Super Freak" riff. &amp;nbsp;Listen closely to seconds&amp;nbsp;&lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=QYHxGBH6o4M#t=2s" target="_blank"&gt;2-6&lt;/a&gt;&amp;nbsp;or the whole thing because it &lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=QYHxGBH6o4M#" target="_blank"&gt;repeats&lt;/a&gt; like a 1000 times. &amp;nbsp; Now listen to the exact same thing as&amp;nbsp;perpetrated&amp;nbsp;by&amp;nbsp;&lt;a href="http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=HwT9ltDBG14#t=5s" target="_blank"&gt;The Romantics&lt;/a&gt;. &amp;nbsp;Bam! &amp;nbsp;They don't call it "Gotcha Journalism" for nothing. &amp;nbsp;Ok, no one would call this Journalism but still. Bam?&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The Superfluous&amp;nbsp;Conclusion:&lt;/b&gt;&lt;br /&gt;
There's not much more to say. The Romantics are evil thieves what&amp;nbsp;profited&amp;nbsp;from an innocent man's&amp;nbsp;paean&amp;nbsp;to his love of skanks. &amp;nbsp;It's time we brought these heartless bastards down and finally give a little praise to a humble man who quietly lived the bard's life, writhing and suffering for his art.&lt;br /&gt;
&lt;br /&gt;
p.s. If your spell checker doesn't recognize "skanks", don't try to check your spelling by Googling it. &amp;nbsp;The results are disgusting.&lt;br /&gt;
&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/48pA5ucP828" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/4647449129694225687/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/04/in-which-i-accuse-new-wave-rockers.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/4647449129694225687?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/4647449129694225687?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/48pA5ucP828/in-which-i-accuse-new-wave-rockers.html" title="In which I accuse New Wave rockers &quot;The Romantics&quot; of defiling Rick James' Grave" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-GNRUhjOQ7fE/T5Ha6g8k42I/AAAAAAAAAV0/zeVQOA_h5jg/s72-c/The_romantics-talking_in_your_sleep_s.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/04/in-which-i-accuse-new-wave-rockers.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQFRH4-eSp7ImA9WhVXF0s.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-4393268750012166789</id><published>2012-04-18T12:36:00.000-04:00</published><updated>2012-04-18T12:41:55.051-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-18T12:41:55.051-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Meta" /><title>I find interesting things interesting</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-vENURmn2VFU/T47uR9Ym-qI/AAAAAAAAAVg/y0AJwQl7nlo/s1600/Screen-Shot-2011-12-16-at-2.23.19-PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="225" src="http://4.bp.blogspot.com/-vENURmn2VFU/T47uR9Ym-qI/AAAAAAAAAVg/y0AJwQl7nlo/s320/Screen-Shot-2011-12-16-at-2.23.19-PM.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I'm fascinated by design in general and web design in particular. &amp;nbsp;The domain of Design always seemed complex and inaccessible to me even though as a professional programmer I do a particular kind of design on a regular basis. &amp;nbsp;Capital "D" Design has seemed to me like a far away land with it's own language, culture and secret societies that were all unapproachable to the lay person. &amp;nbsp;However, as I started to read and learn more about the process of Design it seems in many ways to be just like&amp;nbsp;programming&amp;nbsp;(a wild land I am&amp;nbsp;nevertheless&amp;nbsp;at home in). &lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
In &amp;nbsp;programming we often talk about "elegant design" meaning a simple solution to a complex problem. &amp;nbsp;"Elegant Design" is a lofty goal that is often difficult to achieve. &amp;nbsp;Programmers &amp;nbsp;try to increase our odds of success by carefully limiting the scope of the issue we're trying to solve and then focusing on a smaller and thus more&amp;nbsp;manageable&amp;nbsp;problem. &lt;br /&gt;
&lt;br /&gt;
As one might expect, this is a guiding principal in creative pursuits of all kinds, from &lt;a href="http://www.dailyblogtips.com/procrastinating-to-write-that-huge-article-break-it-down-in-small-parts/" target="_blank"&gt;Writing&lt;/a&gt; to &lt;a href="http://www.dummies.com/how-to/content/einsteins-general-relativity-theory-gravity-as-geo.html" target="_blank"&gt;General Relativity&lt;/a&gt; to &lt;a href="http://www.geek.com/articles/geek-cetera/a-brilliant-explanation-of-how-a-cars-differential-works-20111218/" target="_blank"&gt;Axle Differential&lt;/a&gt;. &amp;nbsp;Thus, the overwhelming topic of Design started to become approachable to me when I realized that I didn't need to understand everything at once and could just focus on the particular bite size portion I wanted to address that day like intro to Typography or beginning Color. &amp;nbsp;As I expand my vocabulary and get introduced to the world of Design, I hope to further my education by posting about the various items that I learn about. Thus reinforcing my new knowledge and hopefully sharing it as well.&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/YoyaBqWo3x8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/4393268750012166789/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/04/i-find-interesting-things-interesting.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/4393268750012166789?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/4393268750012166789?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/YoyaBqWo3x8/i-find-interesting-things-interesting.html" title="I find interesting things interesting" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-vENURmn2VFU/T47uR9Ym-qI/AAAAAAAAAVg/y0AJwQl7nlo/s72-c/Screen-Shot-2011-12-16-at-2.23.19-PM.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/04/i-find-interesting-things-interesting.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUIGSH8-eip7ImA9WhVXEUk.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-7914454630714957569</id><published>2012-04-10T21:51:00.001-04:00</published><updated>2012-04-11T08:32:09.152-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-11T08:32:09.152-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Killing a joke" /><title>Killing a Joke: Cannibal Joe's</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-NmsCe_Ppwd4/T4Ti7n0eQsI/AAAAAAAAAVI/JjRNZTTgDcw/s1600/CannibalCauldren.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="360" src="http://4.bp.blogspot.com/-NmsCe_Ppwd4/T4Ti7n0eQsI/AAAAAAAAAVI/JjRNZTTgDcw/s400/CannibalCauldren.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I have no idea how professional comedy writers work, but for some reason I'm convinced that one of their favorite things to do is come up with a simple set up and then write 200 punchlines for it. &amp;nbsp;This isn't based on any facts or&amp;nbsp;empirical&amp;nbsp;research, other than sometimes in sitcoms you'll see a set up that every character in the room gets to riff on. &amp;nbsp;Also, it's something I like to do. &amp;nbsp;I think it's a fun mind exercise to see how many punchlines I can come up, especially when I'm bored. &amp;nbsp;Here's an example from a recent Facebook post that none of my friends seemed to care about. I like the last one the best. &amp;nbsp;Post your own slogans below!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-pAeHmb1gRsw/T4Ti8Hks7tI/AAAAAAAAAVQ/jnFrTbCHq6U/s1600/jim.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="640" src="http://4.bp.blogspot.com/-pAeHmb1gRsw/T4Ti8Hks7tI/AAAAAAAAAVQ/jnFrTbCHq6U/s640/jim.png" width="616" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/kzAri7qgnCE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/7914454630714957569/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/04/killing-joke-cannibals-joes.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/7914454630714957569?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/7914454630714957569?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/kzAri7qgnCE/killing-joke-cannibals-joes.html" title="Killing a Joke: Cannibal Joe's" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-NmsCe_Ppwd4/T4Ti7n0eQsI/AAAAAAAAAVI/JjRNZTTgDcw/s72-c/CannibalCauldren.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/04/killing-joke-cannibals-joes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUAAR3k_eCp7ImA9WhVXEEQ.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-2830670610492123557</id><published>2012-04-03T09:11:00.000-04:00</published><updated>2012-04-10T17:35:46.740-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-10T17:35:46.740-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Facebook" /><category scheme="http://www.blogger.com/atom/ns#" term="GMail Syncer" /><title>I convinced 100s of people to give me their GMail passwords</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-tDbBiEG9XJ4/T4SngTHuQCI/AAAAAAAAAVA/BOvV6O5gJko/s1600/Gmail_logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="288" src="http://4.bp.blogspot.com/-tDbBiEG9XJ4/T4SngTHuQCI/AAAAAAAAAVA/BOvV6O5gJko/s640/Gmail_logo.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
Honestly, it wasn't intentional. &amp;nbsp;My goal was just to sync my Facebook Friends with my GMail Contacts. &amp;nbsp;I tried searching for an app that could do it, but I couldn't find one and so I figured this might be a good opportunity to learn a little about developing with Facebook &amp;amp; Google. &amp;nbsp;My only intention was to scratch an itch that had been bothering me for a little while, but then it got &lt;a href="https://gmailsyncer.cloudfoundry.com/about" target="_blank"&gt;popular&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;My first pass at the app was just for myself so I hard coded my Facebook username &amp;amp; password and my Google username &amp;amp; password. &amp;nbsp;I figured it would just be for me and running on my machine at home so why bothering making it generic. &amp;nbsp;Really I just wanted to play with the APIs and get something that worked. &amp;nbsp;But then the Missus saw it, thought it was cool and asked if I could hook her up too. &amp;nbsp;I could have continued with the hard coded approach, but now that I had multiple users, it seemed like a good excuse to make it a full fledged Facebook app.&lt;br /&gt;
&lt;br /&gt;
Rather than just have it run on my server at home I could make it an official apps.facebook.com app with a User Interface and everything. &amp;nbsp;I could use the Facebook login mechanism so I didn't have to hard code my username &amp;amp; password and I could play with all of the cool Facebook APIs. &amp;nbsp;I was particularly excited about posting a message to my wall every time it synced. &amp;nbsp;Wouldn't everyone want to see how cool my app was? Every day? Surely they would.&lt;br /&gt;
&lt;br /&gt;
So I whipped it all up. &amp;nbsp;Whipped is maybe overstating it. &amp;nbsp;I had a young son and another on the way and a full time job. &amp;nbsp;I worked on it when I could. &amp;nbsp;Eventually, though, it was working. &amp;nbsp;Anyone could sign up as long as they had a Facebook account. &amp;nbsp;I didn't need to know your Facebook username &amp;amp; password , but the catch was that I did need your GMail username &amp;amp; password. &amp;nbsp;The site had a nice clean interface (if I say so myself) with the slightest touch of whimsy and a great big text box for your GMail username &amp;amp; password.&lt;br /&gt;
&lt;br /&gt;
I filled it out. &amp;nbsp;My wife filled it out. &amp;nbsp;And I thought that would be the end of it. &amp;nbsp;But a weird thing happened. &amp;nbsp;Every day the app posted a message to my wall that said that I had just synced my Facebook &amp;amp; GMail contacts with a link to the app. &amp;nbsp;That's when the questions started. &amp;nbsp;My friends started asking me: "What is this thing?" "Does it really work?" "Can I try it?" &amp;nbsp;Pretty soon a bunch of my friends had signed. up. &amp;nbsp;People who never in a million years would have given me their GMail password if I had asked, were all too happy to type it into a website. &amp;nbsp;Even though it was a website they knew I made. Then it got even weirder.&lt;br /&gt;
&lt;br /&gt;
I rarely ever checked the logs on my app. &amp;nbsp;It was working fine for me so I didn't have much reason to care. &amp;nbsp;Nevertheless, out of&amp;nbsp;curiosity&amp;nbsp;one day I checked the logs and noticed that I had over twenty users. &amp;nbsp;Wow! Twenty of my friends checked this thing out? &amp;nbsp;Wow, that's pretty cool. &amp;nbsp;Then I noticed one of the users was someone I had never met. &amp;nbsp;Apparently some friend of a friend had seen the app and signed up. &amp;nbsp;That's pretty cool I thought. &lt;br /&gt;
&lt;br /&gt;
A few weeks later I checked again and this time I had over 100 users.80% of which I didn't know and all of which had given me their GMail username &amp;amp; password. &amp;nbsp;"This is getting out of hand" I would have thought if I had time to think but my kids were yelling and the bills needed to get paid. &lt;br /&gt;
&lt;br /&gt;
By November of 2011 I had over 500 users all of whom gave me their GMail username &amp;amp; password, the vast majority of whom had absolutely no reason to trust me. &amp;nbsp;It turns out that I'm not interested in exploiting these fine people but they didn't know that. &amp;nbsp;They blindly entered their GMail username &amp;amp; password into a website and just like that could have given up tons of personal information and potentially financial information too.&lt;br /&gt;
&lt;br /&gt;
In November 2011, Facebook instituted a new security requirement that all Facebook apps support HTTPS. &amp;nbsp;This does add some amount of security to your transactions but doesn't really help when you're giving a website your GMail password. &amp;nbsp;Anyway, I was doing this as a hobby and wasn't really paying attention to new Facebook requirements. &amp;nbsp;And even if I was, I wasn't about to shell out $100+ for an SSL certificate so that I could be HTTPS compliant. &amp;nbsp;Especially for a service that I wasn't making money on. &amp;nbsp;In fact, you could argue that I was losing money on it if you count the time/effort I put into it plus the cost of running my server. &amp;nbsp;In fact, I wouldn't have even noticed that Facebook had stopped access to the service if people hadn't started complaining to me that the Syncer wasn't working any more. &amp;nbsp;These were people I never met. &amp;nbsp;People who had started relying on this service. &amp;nbsp;It was crazy!&lt;br /&gt;
&lt;br /&gt;
I didn't have time to fix the service so I just let it languish. &amp;nbsp;I started getting angry service complaints from people who wanted their Syncer but I didn't have the free time to figure out any solutions. &amp;nbsp;I figured I would let it run so that people who already signed up could continue to sync and not get pissed off at me.&lt;br /&gt;
&lt;br /&gt;
Finally in March 2012 I decided to rewrite the application. &amp;nbsp;This time my first priority was to avoid having anyone's username or password. &amp;nbsp;There are actually standards for this and it wasn't terribly difficult to implement but I never thought the app would reach the kind of audience it did. &amp;nbsp;And that was with all of the odds against it. &amp;nbsp;The new version of the app doesn't require any usernames or passwords. &amp;nbsp;It uses the Facebook / Google APIs to let you authenticate with those services directly and my app never sees your personal information. &amp;nbsp;I also signed up with a service to provide HTTPS so that Facebook will play nice as well. &amp;nbsp;You can find the new app at&amp;nbsp;&lt;a href="https://apps.facebook.com/gmailsyncer" target="_blank"&gt;https://apps.facebook.com/gmailsyncer&lt;/a&gt;. &amp;nbsp;However, the moral of this story is &lt;b&gt;NEVER GIVE YOUR GMAIL PASSWORD TO ANYONE OTHER THAN GMAIL!&lt;/b&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/c0SwMMRVQMk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/2830670610492123557/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/04/i-convinced-100s-of-people-to-give-me.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/2830670610492123557?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/2830670610492123557?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/c0SwMMRVQMk/i-convinced-100s-of-people-to-give-me.html" title="I convinced 100s of people to give me their GMail passwords" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-tDbBiEG9XJ4/T4SngTHuQCI/AAAAAAAAAVA/BOvV6O5gJko/s72-c/Gmail_logo.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/04/i-convinced-100s-of-people-to-give-me.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ADRHk-eCp7ImA9WhVXEEQ.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-8135968729161142412</id><published>2012-02-24T21:08:00.002-05:00</published><updated>2012-04-10T18:09:35.750-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-10T18:09:35.750-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="letter" /><title>A Letter to Ari's kids about Ametropes</title><content type="html">&lt;i&gt;This letter was requested by my friend Ari in response to my &lt;a href="http://blog.fawnanddoug.com/2012/02/letter-to-my-toddlers-about-women.html" target="_blank"&gt;previous letter&lt;/a&gt;.&lt;/i&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-T91dDqANPWg/T4Sj8dL5QVI/AAAAAAAAAUI/yLANHaLGaT4/s1600/large+image+of+red+glasses.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-T91dDqANPWg/T4Sj8dL5QVI/AAAAAAAAAUI/yLANHaLGaT4/s320/large+image+of+red+glasses.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Dear Jacob &amp;amp; Abby,&lt;br /&gt;
&lt;br /&gt;
There are some things in this world that can be seen. &amp;nbsp;There are also some things that cannot be seen. &amp;nbsp;Unfortuntately for you, your parents' compromised gene pools have likely condemned you to a life of stumbling around grasping for the later. &amp;nbsp;But despair not! &amp;nbsp;There is a solution. &amp;nbsp;In 1784 God bestowed upon Man the means with which to focus the unseen and render it knowable. &amp;nbsp;He called them Glasses and were it not for them you may never have been born in the first place. &amp;nbsp;Glasses will undoubtedly become a fixture in your life just as they were the fixture that made your life. &amp;nbsp;You need to know and love glasses. &amp;nbsp;Fear and respect glasses. &amp;nbsp;Or at a bare minimum, don't pull them off your father's God damn face. &amp;nbsp;The man needs to see and you need to live. &amp;nbsp;You can accomplish those two goals by the simple act of not impairing your father's sight. &amp;nbsp;Also, don't stab him with them once you've got them. &amp;nbsp;That's just cruel. &amp;nbsp;Plus he can't find you to stop you so he's got to yell until Mommy comes. &amp;nbsp;And she's got better things to do than defend her husband from a toddler. &amp;nbsp;So be a sport and leave the damn glasses alone.&lt;br /&gt;
&lt;br /&gt;
Love,&lt;br /&gt;
Uncle Doug&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/n4O93rUNw8c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/8135968729161142412/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/02/letter-to-aris-kids-about-ametropes.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/8135968729161142412?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/8135968729161142412?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/n4O93rUNw8c/letter-to-aris-kids-about-ametropes.html" title="A Letter to Ari's kids about Ametropes" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-T91dDqANPWg/T4Sj8dL5QVI/AAAAAAAAAUI/yLANHaLGaT4/s72-c/large+image+of+red+glasses.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/02/letter-to-aris-kids-about-ametropes.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUUDQnY8eip7ImA9WhVXEEQ.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-750847112891910161</id><published>2012-02-23T20:34:00.002-05:00</published><updated>2012-04-10T17:27:53.872-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-10T17:27:53.872-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="letter" /><title>A letter to my toddlers about women</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-rCpUUrTbcGA/T4Sly0d6XnI/AAAAAAAAAUo/SEj-4I2FOqI/s1600/frau.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-rCpUUrTbcGA/T4Sly0d6XnI/AAAAAAAAAUo/SEj-4I2FOqI/s320/frau.png" width="157" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Dear Tyler &amp;amp; Aidan,&lt;br /&gt;
&lt;br /&gt;
There are some things in this world that can be known. &amp;nbsp;There are also some things that are unknowable. &amp;nbsp;Part of life is learning to accept that some things cannot be known. &amp;nbsp;You will find and rebel and eventually accept that much about women is simply unknowable. &amp;nbsp;It is frustrating and difficult and ultimately insurmountable. &amp;nbsp;Accepting it will be one of the great triumphs in your life. &amp;nbsp;But there is at least one thing about women that is knowable. &amp;nbsp;And that, is that you do not fuck with their hair. &amp;nbsp;If there is a woman that you like/respect/would enjoy ever seeing again, you are to compliment them on their hair and then shut the fuck up. &amp;nbsp;It is simple, but it is critical to your future happiness. &amp;nbsp;Women are not impenetrable magical sphinxes with mysterious vails and complex machinations. &amp;nbsp;They are human, with everything that entails. &amp;nbsp;So do yourself a favor, respect all women and show them that by at a bare minimum praising their hair and being quiet. &amp;nbsp;It is hard fought wisdom that is as true today as it will be when you care to remember it. &amp;nbsp;But for now, please stop pulling your mother's hair every time she gives you a hug. &amp;nbsp;I'm sick of hearing her complain about it. &amp;nbsp;Just give her a kiss and go away.&lt;br /&gt;
&lt;br /&gt;
Love,&lt;br /&gt;
Dad&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/rnzuxo43ncE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/750847112891910161/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/02/letter-to-my-toddlers-about-women.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/750847112891910161?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/750847112891910161?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/rnzuxo43ncE/letter-to-my-toddlers-about-women.html" title="A letter to my toddlers about women" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-rCpUUrTbcGA/T4Sly0d6XnI/AAAAAAAAAUo/SEj-4I2FOqI/s72-c/frau.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/02/letter-to-my-toddlers-about-women.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EGQ3g5cCp7ImA9WhRVGUU.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-8012447754904289311</id><published>2012-01-18T09:30:00.000-05:00</published><updated>2012-01-19T09:00:22.628-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-19T09:00:22.628-05:00</app:edited><title>I hate Children's Music, but are my kids ready for Hip Hop?</title><content type="html">&lt;div&gt;
&lt;i&gt;A little while ago my &lt;a href="https://twitter.com/#!/urbanrhetoric" target="_blank"&gt;friends &lt;/a&gt;at &lt;a href="http://urbanrhetoricblog.blogspot.com/" target="_blank"&gt;Urban Rhetoric&lt;/a&gt;, progenitors of all things cool, asked me to write a piece on being a parent and a fan of Hip Hop. &amp;nbsp;Below is a reprint of the &lt;a href="http://urbanrhetoricblog.blogspot.com/2012/01/i-hate-childrens-music-but-are-my-kids.html" target="_blank"&gt;original article&lt;/a&gt;.&lt;/i&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-vPwWOBUCYTo/TweWQDLhGnI/AAAAAAAAAmA/EYEwy1jPDWc/s320/dj_lance.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-vPwWOBUCYTo/TweWQDLhGnI/AAAAAAAAAmA/EYEwy1jPDWc/s320/dj_lance.png" /&gt;&lt;/a&gt;&lt;/div&gt;
Children's music is universally atrocious.&amp;nbsp;&amp;nbsp; It is trite and tedious.&amp;nbsp; An endless sea of monotony that crushes ones humanity with unrelenting waves of banal tedium. &amp;nbsp;At first it laps gently at the shores of your sanity. &amp;nbsp;A barely felt current, swathing your new baby in passivity and lulling him to sleep. &amp;nbsp;Slowly it seeps into diaper changes and car rides, please touch museums and toy stores. &amp;nbsp;It's suddenly everywhere and you are caught in the swell of its undertow. &amp;nbsp;You gasp for Nas, Mos Def, Kanye, but it's too late, your lungs are already saturated with Three Blind Mice, Itsy Bitsy Spider and something called "Raffi". Children's music is devious. &amp;nbsp;It's born of &amp;nbsp;platitudes and gentle hell fire. &amp;nbsp;It's boring and insidious. &amp;nbsp;It is the incarnate soul of the devil.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
Perhaps I've tipped my toe into hyperbole but while some hazards of parenthood are often discussed: the lack of sleep, the constant worrying, the lack of free time - no one ever talks about the terrible and omnipresent music.&amp;nbsp;Car rides, play time, diaper changes, bath time, museums, stores - all come with the regular and insistent jack hammering of fairy tales and nursery rhymes and dead eyed automatons and all manner of sonic daemons numbing your humanity and sapping your will to fight back. But not entirely.&lt;br /&gt;
&lt;br /&gt;
Any music lover thusly assaulted, will, after some time, come to rebel against this aural malaise and ultimately arrive at the same cure: &amp;nbsp;Either find children's music by artists you can tolerate (in my case nearly impossible) or introduce your children to the music you love. &amp;nbsp;I wanted my kids to know Hip Hop (and all the music I love) but, for me, there were two key drivers. &amp;nbsp;On the one hand, Hip Hop is such a looming and significant part of my life that it is important to me to introduce my kids to the culture and the music that I immerse myself in daily (or at least I used to). &amp;nbsp;On the other hand, I can't listen to "Wheels on the bus" another damn time. &amp;nbsp;So I made up my mind, but that's where the trouble started.&lt;br /&gt;
&lt;br /&gt;
My first thought was: "Just turn on the radio, dummy! The radio has good music and it's censored. It's a win-win". Actually, it's a lose-lose as I was wrong on both accounts. &amp;nbsp;Here are the top five most played songs on Hot 97 (the local Hip-Hop &amp;amp; R&amp;amp;B station) for the week of December 27th 2011:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;i&gt;Dance (Ass)&lt;/i&gt;&lt;b style="font-style: italic;"&gt;&amp;nbsp;&lt;/b&gt;- Big Sean featuring Nicki Minaj&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;This track must have the record for the most times "Ass" is said in a single song. &amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;/ol&gt;
&lt;li&gt;&lt;i&gt;Ni**as in Paris&lt;/i&gt;&amp;nbsp;- Jay-Z &amp;amp; Kanye West&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;This song is awesome but it seems like they're actively trying to do the worst censoring job they can.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;/ol&gt;
&lt;li&gt;&lt;i&gt;She Will&lt;/i&gt;&amp;nbsp;- Lil Wayne featuring Drake&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;There is nothing redeeming about this song.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;/ol&gt;
&lt;li&gt;&lt;i&gt;Work Out&lt;/i&gt;&amp;nbsp;- J. Cole&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Same old "shake that ass girl" garbage that reminded me why I don't listen to the radio any more.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;/ol&gt;
&lt;li&gt;&lt;i&gt;Make me proud &lt;/i&gt;&amp;nbsp;- Drake featuring Nicki Minaj&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;This passes for positive. *sigh*&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;div&gt;
One good song in the top 5? &amp;nbsp;And none I want my kids to hear? &amp;nbsp;Radio is not the move. &amp;nbsp;For the record, the Pop and Rock stations are just as unacceptable. &amp;nbsp;That said, I don't want to begrudge any adult from listening to whatever they want. &amp;nbsp;Even on the radio. &amp;nbsp;I don't even care if they play uncensored screaming on the radio. &amp;nbsp;Just have a way to warn me and let me shield my kids from it. &amp;nbsp;And you can make&amp;nbsp;judgments&amp;nbsp;about what's appropriate for your kids. That said, I still want to listen to *my* songs and while I want to expose my kids to the music that I love, I'm wary of them getting over-exposed. &amp;nbsp;So it occurred to me that maybe I should think through exactly what my criteria are for songs I want my kids to hear. &amp;nbsp;I came up with what I thought were two reasonable rules:&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;No words I didn't want to hear repeated at Grandma's house&lt;/li&gt;
&lt;li&gt;No phrases or concepts I didn't want to explain&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
At first blush these seem reasonable and should leave me with a huge selection. &amp;nbsp;I think of myself as a *real* Hip Hop fan. &amp;nbsp;I love the golden age, backpack, underground, modern classics etc. &amp;nbsp;I hate "Bitches &amp;amp; Bling", "Da Club" and all the crap that goes with that (with some exceptions). &amp;nbsp;Surely it should be easy to find some tracks that meet my criteria. &amp;nbsp;In truth, it's possible but it requires some serious leg work. &amp;nbsp;Here are some classics I thought would obviously work until I re-listened to them with an ear to the above rules. &amp;nbsp;Note that my kids are 2.5 and 6 months so my criteria might ease up in a few years:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;i&gt;Don't Curse&lt;/i&gt;&amp;nbsp;- Various Artists&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;How could this possibly offend? Kool G Rap: "Even made a record on how I'm doing on my B-I-T-C-H-es"&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;I can&amp;nbsp;&lt;/i&gt;- Nas&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Great message but lots of drug and other references&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;Definition&lt;/i&gt;&amp;nbsp;- Black Star&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;"Mos Def &amp;amp; Kweli just, make a pussy freeze up, thinking of it, ease up"&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;They Reminisce Over You&lt;/i&gt;&amp;nbsp;- Pete Rock &amp;amp; C.L. Smooth&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;"We laughed all night about the hookers at the party"&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;Me, Myself &amp;amp; I&lt;/i&gt;&amp;nbsp;- De La Soul&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Cool message until problems are resolved with violence: "I'll calmly punch them in the 4th day of July"&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;Jesus Walks&lt;/i&gt;&amp;nbsp;- Kanye West&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Hell no&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;My Philosophy -&amp;nbsp;&lt;/i&gt;Boogie Down Productions&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Great until: "How many MCs must get dissed, before somebody says 'Don't fuck with Kris'"&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;Woo-Ha!! I got you all in check&lt;/i&gt;&amp;nbsp;- Busta Rhymes&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;The chorus is: "I got that head nod shit to make you break your neck"&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;Cha Cha Cha&lt;/i&gt;&amp;nbsp;- MC Lyte&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;"Well Well Well, I'll be damned"&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;It Takes Two -&amp;nbsp;&lt;/i&gt;Rob Base &amp;amp; DJ Easy Rock&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;"I like the whopper, fuck the big mac"&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;Public Enemy #1&lt;/i&gt;&amp;nbsp;- Public Enemy&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;"I'll show you my gun; my Uzi weighs a ton"&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;&lt;i&gt;Case of the P.T.A.&lt;/i&gt;&amp;nbsp;- Leaders of the New School&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;"What the Hell's going on"&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;div&gt;
Even a song called "Don't Curse" fails the criteria? Wow. &amp;nbsp;In all honesty though, some of these are not really that bad. &amp;nbsp;The censoring in "It Takes Two" is pretty blatant but I don't think that's really a deal breaker and "Case of the P.T.A." and "Cha Cha Cha" are really kind of a stretch. &amp;nbsp;That kind of stuff I think I can probably let slide. &amp;nbsp;What hurts more is songs like "I can" which I think have a good message but too much other content that I'm not ready for my kids to start grappling with.&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I think what it comes down to is that I was hoping for an easy solution. &amp;nbsp;Unfortunately, like everything else with kids, &amp;nbsp;I needed to step up and be a parent first. &amp;nbsp;It's not easy to vet a ton of songs from my library but if I want to listen to them with my kids then it's something I've got to do. &amp;nbsp;Of course, once I put in that initial work it's not so bad. &amp;nbsp;I ended up making a playlist of songs that I thought were appropriate. &amp;nbsp;It started out small (mostly instrumentals) and when I found time I added a song here and a song there. &amp;nbsp;At this point its well over 2000 songs of both children's music and songs I like. &amp;nbsp;It fits on my phone, so I can bring the list on car rides or play it during dinner time and I don't have to worry about what might come up next or hearing the same awful tune over and over. &amp;nbsp;Much like the children it's intended for, the process was a huge pain in the ass but ultimately I think it's worth it.&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/28NoiAzC33c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/8012447754904289311/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/01/i-hate-childrens-music-but-are-my-kids.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/8012447754904289311?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/8012447754904289311?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/28NoiAzC33c/i-hate-childrens-music-but-are-my-kids.html" title="I hate Children's Music, but are my kids ready for Hip Hop?" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-vPwWOBUCYTo/TweWQDLhGnI/AAAAAAAAAmA/EYEwy1jPDWc/s72-c/dj_lance.png" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/01/i-hate-childrens-music-but-are-my-kids.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMMSHk6fyp7ImA9WhRVE00.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-7086518644556846975</id><published>2012-01-11T11:00:00.000-05:00</published><updated>2012-01-11T12:54:49.717-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-11T12:54:49.717-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Photoshop" /><title>Simple Photoshop Star Burst Effect</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://lh3.ggpht.com/-3_uS5OFzafs/Tvt_VUn6GLI/AAAAAAAAAPk/9axmPxq4EvQ/s1600-h/star%25255B2%25255D.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="star" border="0" height="312" src="http://lh5.ggpht.com/-8OI2ELx06Wk/Tvt_Vm77gII/AAAAAAAAAPs/vk6KkFhJ_FA/star_thumb.png?imgmax=800" style="background-image: none; border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="star" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
One effect that I really like, especially for a splashy or retro type feel, is the star burst effect.&amp;nbsp; I think the spinning color adds a lot of energy and can be a fun way to add a little pep.&amp;nbsp; There are many tutorials on the &lt;a href="https://www.google.com/search?sourceid=chrome&amp;amp;ie=UTF-8&amp;amp;q=photoshop+star+burst+effect" target="_blank"&gt;web&lt;/a&gt; but they seem to either be &lt;a href="http://www.youtube.com/watch?v=rJ9l9zDXTgE" target="_blank"&gt;complicated&lt;/a&gt; or &lt;a href="http://www.photoshopessentials.com/photo-effects/starburst-background/" target="_blank"&gt;time consuming&lt;/a&gt;.&amp;nbsp; That said, the two linked above do provide additional flexibility.&amp;nbsp; The only advantage to this technique is that it is simple and fast.&amp;nbsp; So let’s start:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="font-size: large;"&gt;1. Create a new file&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
Here’s an example:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://lh5.ggpht.com/-Mh1Df_qUzV8/Tvt_Vk23aZI/AAAAAAAAAP0/hQJYPr5xDwM/s1600-h/image%25255B3%25255D.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="image" border="0" height="245" src="http://lh5.ggpht.com/-6CJKCFTC65s/Tvt_V9x2eTI/AAAAAAAAAP8/nkmR5lGcBAU/image_thumb%25255B1%25255D.png?imgmax=800" style="background-image: none; border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;2. Fill the background layer with a color&lt;/span&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://lh6.ggpht.com/-M-PmYdg77qo/Tvt_WPdCTwI/AAAAAAAAAQE/JSMK8MaXmgY/s1600-h/image%25255B27%25255D.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="image" border="0" height="303" src="http://lh5.ggpht.com/-lYAv7czC2TA/Tvt_Wcfg5MI/AAAAAAAAAQM/8FE9ANVZfOE/image_thumb%25255B9%25255D.png?imgmax=800" style="background-image: none; border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I chose this color:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://lh3.ggpht.com/-AnGCbRjXxqs/Tvt_WikhMXI/AAAAAAAAAQU/5F-6kKw0QQg/s1600-h/image%25255B30%25255D.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="image" border="0" height="270" src="http://lh5.ggpht.com/-M5AgLV240ug/Tvt_W_Y-TRI/AAAAAAAAAQc/MwF9yHOMNrY/image_thumb%25255B10%25255D.png?imgmax=800" style="background-image: none; border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;3. Get our magic shape&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
3a. Create a new layer&lt;br /&gt;
3b. Set the foreground color to White&lt;br /&gt;
3c. Select the custom shape tool&lt;br /&gt;
&lt;a href="http://lh4.ggpht.com/-fgrXW91mBRQ/Tvt_XGCMrmI/AAAAAAAAAQk/O2GvfbiZDXM/s1600-h/image%25255B41%25255D.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img alt="image" border="0" height="400" src="http://lh4.ggpht.com/-c7MTvBGRqJ8/Tvt_XfzHaAI/AAAAAAAAAQs/PuEKei8bEbc/image_thumb%25255B19%25255D.png?imgmax=800" style="background-image: none; border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="150" /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3d. Select these options:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://lh5.ggpht.com/-6USWgYEewKc/Tvt_XbHoQSI/AAAAAAAAAQ0/gLYVUUrouNk/s1600-h/image%25255B46%25255D.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="image" border="0" height="53" src="http://lh6.ggpht.com/-3yGEPPTLJG4/Tvt_Xky8C5I/AAAAAAAAAQ8/8HBNGO4fXDY/image_thumb%25255B26%25255D.png?imgmax=800" style="background-image: none; border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="420" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
The key option is the shape.&amp;nbsp; You want the “Symbols” shape list and the “Registration Target 2” shape.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://lh3.ggpht.com/-Wb22sHft6nY/Tvt_XzlYUkI/AAAAAAAAARE/SL_P3t7ZI6k/s1600-h/image%25255B51%25255D.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="image" border="0" height="337" src="http://lh5.ggpht.com/-MrXCB2jKPV4/Tvt_YAZFRQI/AAAAAAAAARM/NlI-N8Y4J3M/image_thumb%25255B32%25255D.png?imgmax=800" style="background-image: none; border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;4. Drag the shape over the layer so the Star Burst covers the whole image&lt;/span&gt;&lt;br /&gt;
I hold “Shift” so it’s an evenly distributed burst.&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://lh3.ggpht.com/-eEAbUHs7Jiw/Tvt_YV0y1jI/AAAAAAAAARU/L40p2GU4RSc/s1600-h/image%25255B58%25255D.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="image" border="0" height="304" src="http://lh3.ggpht.com/-hR_9ZOMB9Lk/Tvt_YteNQMI/AAAAAAAAARc/7vYupK0Z4ok/image_thumb%25255B38%25255D.png?imgmax=800" style="background-image: none; border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;5.&amp;nbsp; Set the layer Blending Mode to “Overlay” and the Opacity to taste&lt;/span&gt;&lt;br /&gt;
I like ~75% Opacity in this case&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://lh4.ggpht.com/-qpBMbh35abw/Tvt_YxZVRJI/AAAAAAAAARk/tlz56R7kqy8/s1600-h/image%25255B59%25255D.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="image" border="0" height="304" src="http://lh3.ggpht.com/-W5cbU0u1fiQ/Tvt_ZCj7E7I/AAAAAAAAARs/rzc4pEUhAAg/image_thumb%25255B42%25255D.png?imgmax=800" style="background-image: none; border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;6. Slap an image over the center&lt;/span&gt;&lt;br /&gt;
Like this one:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-mfGXeX0EO4g/TvuBUalO7-I/AAAAAAAAASc/kJkCeyISHak/s1600/star+alone.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="155" src="http://2.bp.blogspot.com/-mfGXeX0EO4g/TvuBUalO7-I/AAAAAAAAASc/kJkCeyISHak/s200/star+alone.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
And you’re done!&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://lh5.ggpht.com/-MULNH-X1iRM/Tvt_ZdOcY1I/AAAAAAAAAR0/2l8XJ3GGs-4/s1600-h/image%25255B62%25255D.png" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="image" border="0" height="303" src="http://lh6.ggpht.com/-IlG-0MzIxTI/Tvt_ZqFkHbI/AAAAAAAAAR8/BjjNN5AgsBo/image_thumb%25255B43%25255D.png?imgmax=800" style="background-image: none; border-bottom-color: initial; border-bottom-style: initial; border-bottom-width: 0px; border-left-color: initial; border-left-style: initial; border-left-width: 0px; border-right-color: initial; border-right-style: initial; border-right-width: 0px; border-top-color: initial; border-top-style: initial; border-top-width: 0px; display: inline; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/5QhN7QO1Qqo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/7086518644556846975/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2012/01/simple-photoshop-star-burst-effect.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/7086518644556846975?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/7086518644556846975?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/5QhN7QO1Qqo/simple-photoshop-star-burst-effect.html" title="Simple Photoshop Star Burst Effect" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-8OI2ELx06Wk/Tvt_Vm77gII/AAAAAAAAAPs/vk6KkFhJ_FA/s72-c/star_thumb.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2012/01/simple-photoshop-star-burst-effect.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08HQ3k5cCp7ImA9WhVXEEQ.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-2357932995484824841</id><published>2011-12-28T10:54:00.000-05:00</published><updated>2012-04-10T18:10:32.728-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-10T18:10:32.728-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Gaming" /><title>Greatest Game Ever Still Pretty Great</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-Q3AyZ0woRQQ/T4SmtR8UbpI/AAAAAAAAAU4/mNPnvrr86Z4/s1600/meet_the_christmas.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="180" src="http://3.bp.blogspot.com/-Q3AyZ0woRQQ/T4SmtR8UbpI/AAAAAAAAAU4/mNPnvrr86Z4/s320/meet_the_christmas.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
There are a number of criteria that reviewers use to mistakenly calculate the greatness of a game. &amp;nbsp;By "game", of course, I mean Video Game since I am writing this after 1982. &amp;nbsp;Some of these mistaken criteria are "Graphics Quality", "Story", or "Fun". &amp;nbsp;All of these are &lt;a href="http://www.youtube.com/watch?v=d3nzlJD2rC8"&gt;crocker&lt;/a&gt;. &amp;nbsp;There is only one criterion by which you can judge any game's true Greatness: hours played.&lt;br /&gt;
&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;At first blush, "Hours played" seems awful as it doesn't take into account for the factors that reviewers routinely write about like "Maximum Resolution" and "Frames Per Second" and other similarly quantifiable values. &amp;nbsp;And to make it even worse Reviewers always gussy up the statistics with wobbly gushy feelings like "playability" and "character exposition". &amp;nbsp;But all of these are bunk because they muddle up the only thing that truly identifies greatness. &amp;nbsp;How long are you willing to put up with it? &amp;nbsp;You might have had a hot girlfriend or a sweet girlfriend but the one you're willing to spend your life with is by your own actions the one you think is greatest. &amp;nbsp;Even if her graphics appeal and audio fidelity average lower than girl A or girl B, the one that's actually great is the one that you want to spend your time with, not the one with the cool effects that gets boring after a while.&lt;br /&gt;
&lt;br /&gt;
This is why the greatest game ever is &lt;a href="http://www.teamfortress.com/"&gt;Team Fortress 2&lt;/a&gt;. &amp;nbsp;I've logged over &lt;a href="http://steamcommunity.com/profiles/76561197963683883/stats/TF2/?tab=stats"&gt;500 hours&lt;/a&gt; in this bad boy and it's still bringing me joy. &amp;nbsp;Valve has made a huge effort to continually add additional content (&lt;a href="http://www.teamfortress.com/119/"&gt;for free&lt;/a&gt;) and this has gone a long way toward keeping the community attuned and vibrant. &amp;nbsp;They've even recently started adding content from the community into the game and this has reinvigorated the cycle with more to do and more people&amp;nbsp;involved&amp;nbsp;who make more to do and so on and so forth.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://www.teamfortress.com/screamfortress/images/bg_top.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://www.teamfortress.com/screamfortress/images/bg_top.jpg" width="265" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
One of my favorite annual updates is &lt;a href="http://www.teamfortress.com/screamfortress/"&gt;Scream Fortress&lt;/a&gt;, which is a limited time Halloween themed update with events and achievements intended to embrace the holiday. &amp;nbsp;It's silly and gratuitous but every time I think I'm out, they give me a new reason to stick around and try out the new stuff and revisit my old TF2 friends. &amp;nbsp;Congratulations Team Fortress you're still the Greatest Game Ever.&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/pBsVoRe6v9E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/2357932995484824841/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2011/12/greatest-game-ever-still-pretty-great.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/2357932995484824841?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/2357932995484824841?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/pBsVoRe6v9E/greatest-game-ever-still-pretty-great.html" title="Greatest Game Ever Still Pretty Great" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-Q3AyZ0woRQQ/T4SmtR8UbpI/AAAAAAAAAU4/mNPnvrr86Z4/s72-c/meet_the_christmas.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2011/12/greatest-game-ever-still-pretty-great.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQCSXozfSp7ImA9WhVXEEQ.&quot;"><id>tag:blogger.com,1999:blog-7790006377311932302.post-4009950423939830339</id><published>2011-12-21T11:00:00.000-05:00</published><updated>2012-04-10T17:29:28.485-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-04-10T17:29:28.485-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Meta" /><title>Resurfacing: It's not just for parking lots and Joan Rivers' face</title><content type="html">&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-gn9GMzWQoB4/T4SmKnUb74I/AAAAAAAAAUw/aoQ3_ZmeEBU/s1600/joan-rivers.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="297" src="http://3.bp.blogspot.com/-gn9GMzWQoB4/T4SmKnUb74I/AAAAAAAAAUw/aoQ3_ZmeEBU/s320/joan-rivers.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; color: #333333; font-family: 'trebuchet ms', verdana, arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; color: #333333; font-family: 'trebuchet ms', verdana, arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;Many years ago in a land &lt;a href="https://home.fawnanddoug.com/mambo/" target="_blank"&gt;far away&lt;/a&gt; I had a super long commute and a pressing need for the constant adulation that can only be provided by strangers commenting on my thoughts. &amp;nbsp;So, I started a blog. As it turns out, the pressing need persisted but the strangers' comments did not. &amp;nbsp;Actually, the strangers' comments never materialized (unless you count &lt;a href="https://home.fawnanddoug.com/mambo/index.php?set_albumName=garden&amp;amp;id=P1010014&amp;amp;option=com_gallery&amp;amp;Itemid=&amp;amp;include=view_photo.php" target="_blank"&gt;comment spam&lt;/a&gt;) and as you might expect the flow of unread posts dried up while the ads for fake Canadian Cialis kept popping up.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; color: #333333; font-family: 'trebuchet ms', verdana, arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', verdana, arial, sans-serif; font-size: small;"&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; font-size: 13px; line-height: 18px;"&gt;Nevertheless, a pressing need will need pressing and so I'm back again to blog at the internetz until you respond in the way that sates my hunger for attention. &amp;nbsp;This time however, I'm armed with a better spam filter and some significantly more modest goals. &amp;nbsp;Specifically, I want to try out&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; color: #333333; font-family: 'trebuchet ms', verdana, arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;different writing styles like &lt;a href="http://www.avclub.com/"&gt;those&lt;/a&gt; &lt;a href="http://www.lifehacker.com/"&gt;in&lt;/a&gt; &lt;a href="http://kotaku.com/"&gt;the&lt;/a&gt; &lt;a href="http://gizmodo.com/"&gt;blogs&lt;/a&gt;&amp;nbsp;&lt;a href="http://www.pcgamer.com/"&gt;I&lt;/a&gt; &lt;a href="http://www.engadget.com/"&gt;read&lt;/a&gt; and more importantly I'm not going to&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; color: #333333; font-family: 'trebuchet ms', verdana, arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;commit to posting a lot (and thus fail and stop posting at all). &amp;nbsp;The blog is resurfacing, let's see how it goes. And by "let's" I probably mean "I'll". And by "see how it goes" I mean "delete a bunch of spam and then give up".&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; color: #333333; font-family: 'trebuchet ms', verdana, arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', verdana, arial, sans-serif; font-size: small;"&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; font-size: 13px; line-height: 18px;"&gt;For&amp;nbsp;posterity's&amp;nbsp;sake, here's the original post from the original blog:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', verdana, arial, sans-serif; font-size: small;"&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; font-size: 13px; line-height: 18px;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;
&amp;nbsp;&amp;nbsp;Hey all! Well, I got a Treo from the 'rents for my bday - and what with its keyboard and my two hour daily commute it seems inevitable that &lt;a href="http://fawnanddoug.com/"&gt;&lt;span class="Apple-style-span" style="color: black;"&gt;fawnAndDoug.com&lt;/span&gt;&lt;/a&gt; will soon be overrun with trite (and yet verbose) missives on my various musings, opinions and incindiary votives.&amp;nbsp; So let's begin. For starters the keyboard on this badboy is kinda tight so my usual explitive laced comments may be slightly censored since my thumbs aren't nearly as quick with the curses as my ten fingered assault. Damn! I dont really have much else to say today - so I'll just suggest you check out sahara hotnights (specifically a jam called kicks) and I'm out! Wow - we're already at my stop - I guess i'll continue offending you tomorrow . &amp;nbsp;&lt;/blockquote&gt;&lt;img src="http://feeds.feedburner.com/~r/FreshNotes/~4/1IRb6OyeWu4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://blog.fawnanddoug.com/feeds/4009950423939830339/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://blog.fawnanddoug.com/2010/10/resurfacing-its-not-just-for-parking.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/4009950423939830339?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7790006377311932302/posts/default/4009950423939830339?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FreshNotes/~3/1IRb6OyeWu4/resurfacing-its-not-just-for-parking.html" title="Resurfacing: It's not just for parking lots and Joan Rivers' face" /><author><name>Doug Haber</name><uri>https://plus.google.com/107713549455752626164</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="//lh3.googleusercontent.com/-fer2LHoO9vk/AAAAAAAAAAI/AAAAAAAANZ0/P82oCt4rnp8/s512-c/photo.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-gn9GMzWQoB4/T4SmKnUb74I/AAAAAAAAAUw/aoQ3_ZmeEBU/s72-c/joan-rivers.jpg" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://blog.fawnanddoug.com/2010/10/resurfacing-its-not-just-for-parking.html</feedburner:origLink></entry></feed>
