<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-428821977922102947</id><updated>2012-02-16T12:10:31.538-06:00</updated><category term='nmh'/><category term='dojo'/><category term='TLS'/><category term='SMTP'/><category term='ajax'/><category term='json'/><category term='errors'/><title type='text'>Rants from the home office</title><subtitle type='html'>General comments about software development, web technologies, XML, email, electronic publishing, and anything else that comes to mind.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-428821977922102947.post-7109276488035612703</id><published>2011-08-11T00:47:00.002-05:00</published><updated>2011-08-11T01:05:26.073-05:00</updated><title type='text'>IzPack standalone compiler: Custom langpacks</title><content type='html'>See my &lt;a href="http://earlhood.blogspot.com/2011/08/izpack-standalone-compiler-registering.html"&gt;first post&lt;/a&gt; for a general introduction.&lt;br /&gt;&lt;br /&gt;In this post, I discuss how to include custom langpacks in the installer when using the standalone-compiler.jar.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;NOTE:&lt;/b&gt; The IzPack documentation talks about custom langpacks and how to reference them in your installation file.  &lt;b&gt;However&lt;/b&gt;, these langpacks are limited, and do not provide the ability to customize all the text strings used by an IzPack-based installer and uninstaller.&lt;br /&gt;&lt;br /&gt;If you use the normal IzPack installation to create your installer, to customize the text strings for a given language, you edit/replace the appropriate XML file under &lt;tt&gt;bin/langpacks/installer&lt;/tt&gt; of the IzPack installation.  When creating an installer with IzPack, IzPack copies the files in that location into the the installer jar created, and if an uninstaller is created, they will be included in it also.  Which files are copied is based upon the langpack setting(s) in your installation file.&lt;br /&gt;&lt;br /&gt;For standalone-compiler.jar usage, all that is required is create the sub-tree &lt;tt&gt;bin/langpacks/installer&lt;/tt&gt; in some directory, and place your customized language files in it.&lt;br /&gt;&lt;br /&gt;If you are using the izpack ant task, just include the directory that contains the sub-tree in the classpath when defining the task, and you are good to go.  For example:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;span style="font-family: courier new;"&gt;    &amp;lt;taskdef name="izpack"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;             classname="com.izforge.izpack.ant.IzPackTask"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      &amp;lt;classpath&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        &lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;pathelement location="${project.build.rc-install}"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        &lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;pathelement location="${contrib.izpack.dir}/standalone-compiler.jar"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;      &lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;/classpath&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    &lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;/taskdef&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In the above, &lt;span style="font-family: courier new;"&gt;${project.build.rc-install}&lt;/span&gt; represents the pathname to the directory containing the &lt;tt&gt;bin/langpacks/installer&lt;/tt&gt; sub-tree.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/428821977922102947-7109276488035612703?l=earlhood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/7109276488035612703/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://earlhood.blogspot.com/2011/08/izpack-standalone-compiler-custom.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/7109276488035612703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/7109276488035612703'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/2011/08/izpack-standalone-compiler-custom.html' title='IzPack standalone compiler: Custom langpacks'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-428821977922102947.post-7755979855007179112</id><published>2011-08-11T00:17:00.004-05:00</published><updated>2011-08-11T00:45:35.742-05:00</updated><title type='text'>IzPack standalone compiler: Registering custom listeners</title><content type='html'>&lt;a href="http://izpack.org/"&gt;IzPack&lt;/a&gt; is an open source Java-based software installer.  In a project I work on, I use it to create the installer for the project by using the standalone-compiler.jar, and things works pretty good.&lt;br /&gt;&lt;br /&gt;One problem though is that for certain customizations tasks, the IzPack documentation is oriented in using an IzPack installation and its tree structure vs standalone-compiler.jar usage.  This, post is the start of ways I have found to leverage the customization features of IzPack, but sticking with the standalone-compiler.jar.&lt;br /&gt;&lt;br /&gt;Note, I'm working with IzPack 4.3.0, so no guarantees if the methods I describe are applicable to other versions.&lt;br /&gt;&lt;br /&gt;In this first post, I figured out how to register a custom listener.  In my case, I needed an uninstaller listener.  The &lt;a href="http://izpack.org/documentation/custom-actions.html"&gt;IzPack documentation for custom action&lt;/a&gt; discusses how to implement a listener, but the instructions, and previously noted, is based on working with a regular IzPack installation vs standalone-compiler.jar.&lt;br /&gt;&lt;br /&gt;For standalone-compiler.jar, you still need create your listener class, and it must implement the appropriate interface.  Since I needed an uninstall listener, I extended &lt;tt&gt;com.izforge.izpack.event.SimpleUninstallerListener&lt;/tt&gt;.  For sake of this blog post, my listener class is &lt;tt&gt;com.earlhood.izpack.MyUninstallListener&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;I compile the class and jar it up in a file called &lt;tt&gt;MyInstallListener.jar&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;In my IzPack installation file, I add the following tag within the&lt;br /&gt;&lt;tt&gt;&amp;lt;listeners&amp;gt;&lt;/tt&gt; element:&lt;br /&gt;&lt;pre&gt;&amp;lt;listener uninstaller="MyUninstallListener"&lt;br /&gt;   jar="${path.to.dir.containing.my.jar}/MyUninstallListener.jar"/&amp;gt;&lt;/pre&gt;&lt;br /&gt;where &lt;tt&gt;${path.to.dir.containing.my.jar}&lt;/tt&gt; is the pathname to where the jar file is located.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;IMPORTANT:&lt;/b&gt; The &lt;tt&gt;uninstaller&lt;/tt&gt; attribute value must be the basename of the class.  IzPack scans the jar file to find any .class entry whose basename matches this value.  The package name is irrelevant for purposes of IzPack finding the .class file representing the listener.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;NOTE:&lt;/b&gt; The &lt;tt&gt;jar&lt;/tt&gt; attribute is undocumented.  I discovered it when examining the IzPack source.&lt;br /&gt;&lt;br /&gt;That is basically it.  Of course, I have Ant build scripts to automate the entire build process and use the izpack ant task to create the project installer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/428821977922102947-7755979855007179112?l=earlhood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/7755979855007179112/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://earlhood.blogspot.com/2011/08/izpack-standalone-compiler-registering.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/7755979855007179112'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/7755979855007179112'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/2011/08/izpack-standalone-compiler-registering.html' title='IzPack standalone compiler: Registering custom listeners'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-428821977922102947.post-7427685244956078199</id><published>2011-04-18T20:30:00.004-05:00</published><updated>2011-04-18T21:02:43.296-05:00</updated><title type='text'>Dynamically changing log4j levels in web application</title><content type='html'>&lt;a href="http://logging.apache.org/log4j/1.2/"&gt;Log4j&lt;/a&gt; is a popular logging library for Java, and I've been using it for many years.&lt;br /&gt;&lt;br /&gt;One thing I have found handy, especially with web applications, is the ability to dynamically change the logging level (like to DEBUG)  of any category (aka logger) in a running application.  I can selectively choose which components I want to change w/o affecting the logging level of other components.&lt;br /&gt;&lt;br /&gt;A long time ago, I wrote a servlet to provide this capability, but it requires registering in &lt;tt&gt;web.xml&lt;/tt&gt; and it depends on some utility classes.  Although this is generally sufficient, I'm recently working on a project where adding my own custom servlets to the application is awkward, but dropping in a JSP can be done easily.  Plus, since servlet engines (e.g. Tomcat) generally support dropping in a JSP at any time, having a JSP allows setting of logging levels w/o having to modify an application's web descriptor.&lt;br /&gt;&lt;br /&gt;As a quick hack, I created a JSP version of the servlet, one that is self-contained.  The JSP may not be a good example of good JSP coding style since I wanted to spend minimal time in getting things to work.  The JSP is self-contained, requiring no external dependencies except log4j.&lt;br /&gt;&lt;br /&gt;The JSP can be downloaded from the following location:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.earlhood.com/blogspot/files/log4j.jsp"&gt;http://www.earlhood.com/blogspot/files/log4j.jsp&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The interface is simple, but it does the job.  When started, it will list out all the logging categories that are currently defined, with each a link to an edit form to change its logging level.&lt;br /&gt;&lt;br /&gt;If you need to set the logging level for a category not yet loaded, you can select any other category and then edit the Category field to the category name you desire before submitting the form.&lt;br /&gt;&lt;br /&gt;Categories that have their level explicitly set will have the level rendered in bold.  Categories that have an inherited value will have the applicable level rendered in italics.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/428821977922102947-7427685244956078199?l=earlhood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/7427685244956078199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://earlhood.blogspot.com/2011/04/dynamically-changing-log4j-levels-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/7427685244956078199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/7427685244956078199'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/2011/04/dynamically-changing-log4j-levels-in.html' title='Dynamically changing log4j levels in web application'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-428821977922102947.post-1047210695209303802</id><published>2011-03-22T20:14:00.006-05:00</published><updated>2011-03-22T20:37:28.890-05:00</updated><title type='text'>Detecting when DOM node comes into view with Dojo</title><content type='html'>Working on a project that uses dojo, the need arose to have the ability to automatically be notified when a DOM node comes into view in the browser window.  For example, the node may below the fold, and when the page is scrolled, and the node comes into view, the application is notified.&lt;br /&gt;&lt;br /&gt;Searching around, I came across this useful post:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dustindiaz.com/element-scroll-into-view/"&gt;http://www.dustindiaz.com/element-scroll-into-view/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;However, the code uses YUI, while I needed something that works with dojo (v1.4).  Also, what Mr. Diaz provides does not deal with resize events that can cause a node to become visible, or the case when the node is already visible (before any scroll or resize occurs).&lt;br /&gt;&lt;br /&gt;So I wrote up a mini-library to provide something that works with dojo.  A couple of the utility functions can probably be replaced if using a later version of dojo, but since I needed something to work with dojo 1.4, I could not use newer convenience functions to access window dimensions (like dojo.window.getBox).&lt;br /&gt;&lt;br /&gt;Basic usage:&lt;pre&gt;dojo.require('ewh.nodeview');&lt;br /&gt;ewh.nodeview.connect(domNode, func, cdata);&lt;/pre&gt;&lt;br /&gt;&lt;tt&gt;domNode&lt;/tt&gt; is the DOM node that you want monitored.&lt;br /&gt;&lt;tt&gt;func&lt;/tt&gt; is the function that is called when &lt;tt&gt;domNode&lt;/tt&gt; comes into view.&lt;br /&gt;&lt;tt&gt;cdata&lt;/tt&gt; is an arbitrary object to pass into &lt;tt&gt;func&lt;/tt&gt; when it is called.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Note:&lt;/b&gt; Some may say that call-data can be attached to &lt;tt&gt;func&lt;/tt&gt; itself and/or use dojo.hitch(), but I wanted to provide an interface that was friendly to those who may not be familiar with such techniques.&lt;br /&gt;&lt;br /&gt;When &lt;tt&gt;func&lt;/tt&gt; is called, it is passed an object.  The object contains the following properties:&lt;ul&gt;&lt;li&gt;&lt;tt&gt;node&lt;/tt&gt;: The DOM node.&lt;br /&gt;&lt;li&gt;&lt;tt&gt;cdata&lt;/tt&gt;: Callback object.&lt;br /&gt;&lt;li&gt;&lt;tt&gt;event&lt;/tt&gt;: Associated event object, which can be undefined.&lt;br /&gt;&lt;/ul&gt;The function is only ever called once.  Once called, the internal event hooks are disconnected.  If for whatever reason the caller needs to be notified again for the node, they can call the connect method again for it.&lt;br /&gt;&lt;br /&gt;Source code:&lt;br /&gt;&lt;a href="http://www.earlhood.com/blogspot/files/nodeview.js"&gt;http://www.earlhood.com/blogspot/files/nodeview.js&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/428821977922102947-1047210695209303802?l=earlhood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/1047210695209303802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://earlhood.blogspot.com/2011/03/detecting-when-dom-node-comes-into-view.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/1047210695209303802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/1047210695209303802'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/2011/03/detecting-when-dom-node-comes-into-view.html' title='Detecting when DOM node comes into view with Dojo'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-428821977922102947.post-6647314077273575321</id><published>2010-11-13T12:37:00.009-06:00</published><updated>2010-11-13T13:13:25.411-06:00</updated><title type='text'>Avoiding URL length limits when loading pages with Javascript</title><content type='html'>Working on a web application that must work with IE, I encountered problems with opening windows (via window.open), or loading content in iframes, that required a large set of parameters to the URL provided.  IE has a hard-coded limit on the size of URL strings, so parameter data could get clipped.&lt;br /&gt;&lt;br /&gt;Also, it is not pretty to have a large URL string showing in the address bar.&lt;br /&gt;&lt;br /&gt;Therefore, the solution was to use an HTTP POST based method.&lt;br /&gt;&lt;br /&gt;My first attempt was to use AJAX with a POST request to retrieve the desired page, and then do a document.write() into a blank window.  However, I discovered that IE does not process data in a serial manner via document.write().  For example, if the page content contains &amp;lt;script&amp;gt; elements referencing external resources to load, IE will not process those in sequential order, so if you have Javascript code that calls a function that is defined by a previous &amp;lt;script&amp;gt;, you can get a runtime error. IE will load the external javascript resources, but they are done asynchronously, with IE not waiting to execute subsequent Javascript in the page that comes after the &amp;lt;script&amp;gt;.&lt;br /&gt;&lt;br /&gt;The solution I came up with is to create a transient page that performs a form post.  I.e. In the blank window, I create dynamic HTML page that contains an HTML form with the set of parameter data defined as hidden fields. The HTML page created has an onLoad action to submit the form.&lt;br /&gt;&lt;br /&gt;With this approach, the browser is directly fetching the resource, so the document.write() problem described earlier (for IE) is no longer a factor.&lt;br /&gt;&lt;br /&gt;What follows is a function for loading a document using a POST-based method:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;loadDocument = function(&lt;br /&gt;    /*Object*/args&lt;br /&gt;)&lt;br /&gt;{&lt;br /&gt;  // summary:&lt;br /&gt;  //      Load a document for a given document node.&lt;br /&gt;  // description:&lt;br /&gt;  //      This function uses a POST-style method for loading the&lt;br /&gt;  //      contents of a document node, where the document requested&lt;br /&gt;  //      takes an arbitrary number of request parameters.  This&lt;br /&gt;  //      function works-around limitations of some browsers where&lt;br /&gt;  //      there is a limit to the length of query-string parameters&lt;br /&gt;  //      for GET-based requests.&lt;br /&gt;  //&lt;br /&gt;  // args: Object&lt;br /&gt;  //      Object contain the following properties:&lt;br /&gt;  //&lt;br /&gt;  //      doc: Node&lt;br /&gt;  //            Document node to load content for.&lt;br /&gt;  //      url: String&lt;br /&gt;  //            URL to fetch content from.&lt;br /&gt;  //      params: Object?&lt;br /&gt;  //            Properties of string values representing parameters&lt;br /&gt;  //            for the request denoted by url.&lt;br /&gt;  //      message: String?&lt;br /&gt;  //            Message text (HTML) to display while content is&lt;br /&gt;  //            loading.&lt;br /&gt;&lt;br /&gt;  var doc = args.doc;&lt;br /&gt;  doc.open();&lt;br /&gt;  doc.write('&amp;lt;html&amp;gt;');&lt;br /&gt;  doc.write('&amp;lt;script type="text/javascript"&amp;gt;');&lt;br /&gt;  doc.write('function submitForm(){document.forms[0].submit();}');&lt;br /&gt;  doc.write('&amp;lt;/script&amp;gt;');&lt;br /&gt;  doc.write('&amp;lt;body style="background-color:#FFF;" onLoad="submitForm()"&amp;gt;');&lt;br /&gt;  if (args.message) {&lt;br /&gt;    doc.write(args.message);&lt;br /&gt;  }&lt;br /&gt;  doc.write('&amp;lt;form method="post" action="');&lt;br /&gt;  doc.write(args.url);&lt;br /&gt;  doc.write('"&amp;gt;');&lt;br /&gt;  if (args.params) {&lt;br /&gt;    for (var p in args.params) {&lt;br /&gt;      var v = args.params[p];&lt;br /&gt;      if (v instanceof Array || typeof v == "array") {&lt;br /&gt;        for (var i=0; i &amp;lt; v.length; ++i) {&lt;br /&gt;          doc.write('&amp;lt;input type="hidden" name="');&lt;br /&gt;          doc.write(p);&lt;br /&gt;          doc.write('" value=\'');&lt;br /&gt;          doc.write(escapeHTML(v[i]));&lt;br /&gt;          doc.write('\'&amp;gt;&amp;lt;/input&amp;gt;');&lt;br /&gt;        }&lt;br /&gt;      } else {&lt;br /&gt;        doc.write('&amp;lt;input type="hidden" name="');&lt;br /&gt;        doc.write(p);&lt;br /&gt;        doc.write('" value=\'');&lt;br /&gt;        doc.write(escapeHTML(args.params[p]));&lt;br /&gt;        doc.write('\'&amp;gt;&amp;lt;/input&amp;gt;');&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  doc.write('&amp;lt;/form&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;');&lt;br /&gt;  doc.close();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Helper function to escape HTML specials for use above.&lt;br /&gt;escapeHTML = function(/*String*/s) {&lt;br /&gt;  // summary: Convert HTML special characters to entity references.&lt;br /&gt;  // s: String to escape.&lt;br /&gt;  if (!(typeof s == "string" || s instanceof String)) {&lt;br /&gt;    s = s + ""; // force it to a string&lt;br /&gt;  }&lt;br /&gt;  return s.replace(/&amp;amp;/g, "&amp;amp;amp;")&lt;br /&gt;          .replace(/&amp;lt;/g, "&amp;amp;lt;")&lt;br /&gt;          .replace(/&amp;gt;/g, "&amp;amp;gt;")&lt;br /&gt;          .replace(/"/g, "&amp;amp;quot;")&lt;br /&gt;          .replace(/'/g, "&amp;amp;#39;");&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The primary function works on a Document object, allowing it to not just be used for new windows, but for any object that contains a Document object, like frames and iframes.&lt;br /&gt;&lt;br /&gt;Simple example using the above:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;var w = window.open("");&lt;br /&gt;loadDocument({&lt;br /&gt;  doc: w.document,&lt;br /&gt;  url: "http://example.com/some/resource/",&lt;br /&gt;  params: {&lt;br /&gt;    p1: "Hello",&lt;br /&gt;    p2: "World!"&lt;br /&gt;  }&lt;br /&gt;  message: 'Loading..."&lt;br /&gt;});&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/428821977922102947-6647314077273575321?l=earlhood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/6647314077273575321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://earlhood.blogspot.com/2010/11/avoiding-url-length-limits-when-loading.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/6647314077273575321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/6647314077273575321'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/2010/11/avoiding-url-length-limits-when-loading.html' title='Avoiding URL length limits when loading pages with Javascript'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-428821977922102947.post-675806027557465295</id><published>2010-01-31T16:06:00.008-06:00</published><updated>2010-02-12T21:15:50.542-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TLS'/><category scheme='http://www.blogger.com/atom/ns#' term='SMTP'/><category scheme='http://www.blogger.com/atom/ns#' term='nmh'/><title type='text'>HOW-TO: Posting to Gmail servers with non-SSL/TLS-aware MUAs</title><content type='html'>I'm a long-time user of the nmh mail user agent (MUA), &amp;lt;&lt;a href="http://www.nongnu.org/nmh/"&gt;http://www.nongnu.org/nmh/&lt;/a&gt;&amp;gt;, and its predecessor MH before that.&lt;br /&gt;&lt;br /&gt;It's an old MUA.  It currently does not support submitting emails to mail servers that require SSL/TLS connections.  Other venerable MUAs have the same problem.   Fortunately, there is an OSS program that provides proxy capabilities that can negotiate the SSL/TLS part, and if necessary, the SMTP AUTH part if the MUA does not support it: DeleGate, &amp;lt;&lt;a href="http://www.delegate.org/delegate/" target="_blank"&gt;http://www.delegate.org/&lt;/a&gt;&amp;gt;.&lt;br /&gt;&lt;br /&gt;DeleGate provides proxy capabilities for various Internet protocols (e.g. http, ftp), but for this article, all we care about is its SMTP capabilities.&lt;br /&gt;&lt;br /&gt;Nice thing about DeleGate is you do not need root priviledges to run it.  You can have it listen to local client requests on any port you choose and forward the request to remote server (which will be smtp.gmail.com in this article).&lt;br /&gt;&lt;br /&gt;Best way to show how to use it is with an example:&lt;br /&gt;&lt;br /&gt;The following starts delegated on the local system on port 25 (the standard SMTP port):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;delegated -Plocalhost:20025 +=$HOME/delegate/conf/gmail.conf&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This says to listen for client requests on port 20025 and to read additional configuration parameters from &lt;span style="font-family:courier new;"&gt;gmail.conf&lt;/span&gt; located under &lt;span style="font-family:courier new;"&gt;delagate/conf&lt;/span&gt; of your home directory (you can specify all parameters on command-line, but that gets kind of ugly).  In my gmail.conf file, I have something like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;SERVER=smtp://smtp.gmail.com:587&lt;br /&gt;STLS=fsv&lt;br /&gt;AUTHORIZER=-list{localuser:MD5:964ba203464913531aa73b9f774b58f7}&lt;br /&gt;MYAUTH=username@gmail.com:pass:smtp&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;SERVER specifies what remote server the proxy should connect to.  In this case, we specify that is the SMTP server smtp.gmail.com on port 587 (TLS port).&lt;br /&gt;&lt;br /&gt;STLS setting specifies that SSL/TLS should be used when connecting to remote server (smtp.gmail.com).&lt;br /&gt;&lt;br /&gt;The AUTHORIZER parameter is not required, but if specified, client must (SASL) authenticate to the proxy.  The username is "localuser" (change to whatever your want).  This may be handy so other users on the local system cannot hijack your proxy server and post email thru your Gmail account.  If you are the sole user of your system, client authentication may not be needed.  Also, if your MUA does not support SASL, you should not set AUTHORIZER.&lt;br /&gt;&lt;br /&gt;To determine if your MUA supports SASL, if your MUA provides the ability to specify an username and password when posting a message to a mail server, it probably supports SASL.  If no such capability is provided, it probably does not.&lt;br /&gt;&lt;br /&gt;The password listed for AUTHORIZER can be provided in plaintext, but DeleGate will show in its log the MD5 hash of it, which you can then insert into the configuration file.  A plaintext version of AUTHORIZER is as follows:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;AUTHORIZER=-list{localuser:password}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The MYAUTH specifies the username/password to use for authenticating to the remote server (smtp.gmail.com).  This should be set to your gmail address and gmail password.  Unfortunately, the password cannot be encrypted since DeleGate needs to send the password to the remote server.  Therefore, make sure the configuration file is only readable by you and no one else. For Unix-based users, the chmod command can be used:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;chmod 600 gmail.conf&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For Windows users, right click on the file and select Properties.  Then select the Security tab.  Make sure you are the only user that has read access to the file.&lt;br /&gt;&lt;br /&gt;With DeleGate running, just configure your MUA to post messages to localhost:2005 and you should be good to go.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;NOTES&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;If you cannot specify an alternate port number for posting messages, you will need to run DeleGate on port 25.  If this is the case, you will need to have admin priviledges to start DeleGate.  DeleGate does provide an option for it to drop priviledges to a separate user.  See documentation for more details.&lt;br /&gt;&lt;br /&gt;DeleGate supports multi-user access, but configuration becomes more complex.  If you want to support multi-user access, see the documentation.&lt;br /&gt;&lt;br /&gt;For nmh user, SASL is supported, so client-based connections can be restricted, especially if running DeleGate as a personal proxy.  However, for nmh, if DeleGate is not running on port 25, the &lt;span style="font-family:courier new;"&gt;whom&lt;/span&gt; command at the "What Now?" will not work.  The command will also not work if you enable SASL for client connections.  For &lt;span style="font-family:courier new;"&gt;whom&lt;/span&gt; to work, nmh code modifications are required.  I've committed changes into the nmh project so SASL support is available for the &lt;tt&gt;whom&lt;/tt&gt; command.  You'll need to check out the latest source and build if you need the feature.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/428821977922102947-675806027557465295?l=earlhood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/675806027557465295/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://earlhood.blogspot.com/2010/01/how-to-posting-to-gmail-servers-with.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/675806027557465295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/675806027557465295'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/2010/01/how-to-posting-to-gmail-servers-with.html' title='HOW-TO: Posting to Gmail servers with non-SSL/TLS-aware MUAs'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-428821977922102947.post-9002413422613693246</id><published>2009-10-28T11:43:00.002-05:00</published><updated>2009-10-28T11:59:31.006-05:00</updated><title type='text'>Converting XML Catalogs to TR9401 Catalogs</title><content type='html'>Having worked with SGML/XML for some time now, I still encounter software that does not support XML Catalogs (including software I wrote), but do support TR9401 Catalogs.&lt;br /&gt;&lt;br /&gt;Instead of trying to update/modify older software, I found it easy to write an XSLT to convert an XML Catalog into a TR9401 catalog.  The XSLT is viewable/downloadable from the following link:&lt;a href="http://www.earlhood.com/blogspot/files/xmlcat-to-opencat.xsl"&gt; xmlcat-to-opencat.xsl&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For features supported in XML Catalogs but not in TR9401, the XSLT will print out warnings, but continue processing.&lt;br /&gt;&lt;br /&gt;Unsure if anyone else may find the transform useful, but it comes in handy when I need to use my old DTD parsing tools.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/428821977922102947-9002413422613693246?l=earlhood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/9002413422613693246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://earlhood.blogspot.com/2009/10/converting-xml-catalogs-to-tr9401.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/9002413422613693246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/9002413422613693246'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/2009/10/converting-xml-catalogs-to-tr9401.html' title='Converting XML Catalogs to TR9401 Catalogs'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-428821977922102947.post-6375293068965778044</id><published>2009-08-17T14:28:00.006-05:00</published><updated>2009-08-17T15:08:24.954-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='json'/><category scheme='http://www.blogger.com/atom/ns#' term='errors'/><category scheme='http://www.blogger.com/atom/ns#' term='dojo'/><title type='text'>Providing meaningful errors in dojo.xhr calls</title><content type='html'>I've been working with &lt;a href="http://www.dojotoolkit.org/"&gt;Dojo&lt;/a&gt; lately, and one problem is the useless error messages one gets back from the server, especially when using dojo.xhr.  The problem is that the response body from the server is generally some large HTML message that may not be useful for display purposes in an AJAX-based calling environment.&lt;br /&gt;&lt;br /&gt;To remedy this, I made some modifications to the server-side (implemented in Java servlets) to capture exceptions and return a JSON structure if the request is an AJAX request.  This makes it easier for the Javascript code to process error text more easily.&lt;br /&gt;&lt;br /&gt;On the client-side, I have some basic utility functions to facilitate capturing/reporting errors from dojo.xhr calls.&lt;br /&gt;&lt;br /&gt;First, the server-side:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Before I Start&lt;/b&gt;:&lt;br /&gt;&lt;br /&gt;Before providing detail, I should note that I've created a base servlet&lt;br /&gt;class that all my servlets sub-class.  This allows me to centralize&lt;br /&gt;operations and services for all my servlets.  In the context of this post,&lt;br /&gt;this becomes useful for the purposes of exception handling.  The base&lt;br /&gt;class checks all exceptions from sub-classes allowing centralization&lt;br /&gt;of error handling based upon the type of exception that occurred.&lt;br /&gt;&lt;br /&gt;I also have a custom request object to encapsulate the HttpServletRequest&lt;br /&gt;and HttpServletResponse objects.  This encapsulation allows me to add&lt;br /&gt;support for additional capabilities beyond the standard servlet API&lt;br /&gt;related to request/response.  For example, I provide file-upload support&lt;br /&gt;and still provide a single consistent interface for servlets to access&lt;br /&gt;request parameters.&lt;br /&gt;&lt;br /&gt;Some of the code provided here may contain references to custom classes I&lt;br /&gt;use, but I believe they are self-explanatory.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How to detect an AJAX request&lt;/b&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public boolean isAjaxRequest() {&lt;br /&gt;    String reqwith = req.getHeader("x-requested-with");&lt;br /&gt;    if (StringUtil.isBlank(reqwith)) return false;&lt;br /&gt;    if (reqwith.toLowerCase().equals("xmlhttprequest")) return true;&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;/pre&gt;&lt;br /&gt;The above works for most cases, and wrt Dojo, definitely works&lt;br /&gt;since Dojo sets the proper request headers.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Capturing Servlet Exceptions&lt;/b&gt;:&lt;br /&gt;&lt;br /&gt;In my base servlet class, I catch all exceptions:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    } catch (Exception e) {&lt;br /&gt;      if (r.isAjaxRequest()) {&lt;br /&gt;        log.error("Exception caught for AJAX request: "+e, e);&lt;br /&gt;        sendJSONError(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,&lt;br /&gt;                      e.getMessage());&lt;br /&gt;      } else {&lt;br /&gt;        if (e instanceof ServletException) {&lt;br /&gt;          throw (ServletException)e;&lt;br /&gt;      }&lt;br /&gt;       throw new ServletException(e.getMessage(), e);&lt;br /&gt;      }&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;I check if the request in an AJAX request, and if so, utilize the sendJSONError() method to do what I want.  sendJSONError() looks like the following:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  private void sendJSONError(&lt;br /&gt;      HttpServletResponse resp,&lt;br /&gt;      int status,&lt;br /&gt;      String message&lt;br /&gt;  ) throws IOException {&lt;br /&gt;    Writer w = resp.getWriter();&lt;br /&gt;    resp.setStatus(status);&lt;br /&gt;    resp.setContentType("application/json");&lt;br /&gt;    w.write("{");&lt;br /&gt;    w.write("\"status\":");&lt;br /&gt;    w.write(Integer.toString(status));&lt;br /&gt;    w.write(",");&lt;br /&gt;    w.write("\"message\":");&lt;br /&gt;    w.write(JSONObject.quote(message));&lt;br /&gt;    w.write("}");&lt;br /&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Capturing/display Errors in Dojo&lt;/b&gt;:&lt;br /&gt;&lt;br /&gt;On the client-side, I have two utility functions.  One is a generic error handling function for dojo.xhr that will popup an alert displaying the error message received from the server.  The other is a function to extract the error message from the servlet response, mainly for use by custom error functions that need to do more than display an alert dialog:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;mylib.xhrErrorAlert = function(&lt;br /&gt;    /*Object*/response,&lt;br /&gt;    /*Object*/ioArgs&lt;br /&gt;)&lt;br /&gt;{&lt;br /&gt;  var prefix = "Error: ";&lt;br /&gt;  if (ioArgs.args.myAlertPrefix) {&lt;br /&gt;    prefix = ioArgs.args.myAlertPrefix;&lt;br /&gt;  }&lt;br /&gt;  alert(prefix + mylib.getXhrResponseMessage(response));&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;mylib.getXhrResponseMessage = function(&lt;br /&gt;    /*Object*/response&lt;br /&gt;)&lt;br /&gt;{&lt;br /&gt;  var msg = response.message;&lt;br /&gt;  if (response.responseText != undefined &amp;&amp;&lt;br /&gt;      response.responseText.charAt(0) == '{') {&lt;br /&gt;    try {&lt;br /&gt;      var o = dojo.fromJson(response.responseText);&lt;br /&gt;      if (o.message != undefined) {&lt;br /&gt;        msg = o.message;&lt;br /&gt;      }&lt;br /&gt;    } catch (err) {&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  return msg;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The following is an example of how to use the alert function:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;dojo.xhrPost({&lt;br /&gt;  url: url,&lt;br /&gt;  handleAs: 'json',&lt;br /&gt;  load: function(response, ioArgs) {&lt;br /&gt;    ...&lt;br /&gt;  },&lt;br /&gt;  myAlertPrefix: 'Error doing something: ',&lt;br /&gt;  error: mylib.xhrErrorAlert&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;Note, there is a reliance that the message text is meaningful in the exception thrown on the server-side.  Regardless, this provides a better error message than what is normally available in &lt;tt&gt;response.message&lt;/tt&gt;, which normally contains the canned message the server defines for the given HTTP response code versus the message text from the underlying exception.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/428821977922102947-6375293068965778044?l=earlhood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/6375293068965778044/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://earlhood.blogspot.com/2009/08/providing-meaningful-errors-in-dojoxhr.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/6375293068965778044'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/6375293068965778044'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/2009/08/providing-meaningful-errors-in-dojoxhr.html' title='Providing meaningful errors in dojo.xhr calls'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-428821977922102947.post-4464973227668052731</id><published>2009-08-16T17:32:00.002-05:00</published><updated>2009-08-16T17:38:30.693-05:00</updated><title type='text'>Getting fixed-width font for Gmail messages</title><content type='html'>Gmail labs has a feature to display a message in a fixed-width font, but you have to manual select it from a menu each time you want.&lt;br /&gt;&lt;br /&gt;The following is a quick CSS userContent.css hack for Firefox that will cause message content to always display in a fixed-width font:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@-moz-document domain(google.com) {&lt;br /&gt;.ii {&lt;br /&gt;  font-family: monospace;&lt;br /&gt;  font-size: 75%;&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;I use "monospace" since it will use what I have specified in my font preferences in FF.  The key item is the ".ii" class.&lt;br /&gt;&lt;br /&gt;The only negative side-effect is that non-text messages, like HTML, will have the default font be monospace.  However, I'm currently willing to live with that limitation.&lt;br /&gt;&lt;br /&gt;I posted a suggestion on the Gmail labs group for Google to define CSS classes based upon content media-types, so CSS settings can be constrained for a given media-type.  Who knows if they will ever do such a thing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/428821977922102947-4464973227668052731?l=earlhood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/4464973227668052731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://earlhood.blogspot.com/2009/08/getting-fixed-width-font-for-gmail.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/4464973227668052731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/4464973227668052731'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/2009/08/getting-fixed-width-font-for-gmail.html' title='Getting fixed-width font for Gmail messages'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-428821977922102947.post-7108772862805760737</id><published>2009-08-16T16:36:00.003-05:00</published><updated>2009-08-16T16:46:02.585-05:00</updated><title type='text'>Disabling ads in Gmail</title><content type='html'>For those that do not know, Firefox supports the ability for a user to define their own custom CSS settings, allow the user to customize how pages appear in FF.  The file is called userContent.css and is located under the chrome/ directory of your profile.&lt;br /&gt;&lt;br /&gt;As an exercise, I tried to see if it is possible to suppress the Google ads displayed in the Gmail web interface.  Well, with a little help from Firebug to examine the HTML/CSS structure of Gmail pages, I came up with the following:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; .vb {&lt;br /&gt;   display: none;&lt;br /&gt; }&lt;br /&gt; .u5 {&lt;br /&gt;   display: none;&lt;br /&gt; }&lt;br /&gt; table[class~="Bs"] &gt; tr &gt; td:nth-of-type(+3) &gt; div:nth-of-type(+2) {&lt;br /&gt;   width: auto !important;&lt;br /&gt; }&lt;br /&gt; table[class~="Bs"] &gt; tr &gt; td:nth-of-type(+3) &gt; div:nth-of-type(+2) &gt;&lt;br /&gt;                      div &gt; div:last-child&lt;br /&gt; {&lt;br /&gt;   display: none;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above works best in FF 3.5, especially since the last items utilize CSS3 selectors.&lt;br /&gt;&lt;br /&gt;FF supports the ability to limit the settings for a given domain.  I Include the above in the following block so it only applies to google.com sites:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@-moz-document domain(google.com) {&lt;br /&gt;...&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/428821977922102947-7108772862805760737?l=earlhood.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://earlhood.blogspot.com/feeds/7108772862805760737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://earlhood.blogspot.com/2009/08/disabling-ads-in-gmail.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/7108772862805760737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/428821977922102947/posts/default/7108772862805760737'/><link rel='alternate' type='text/html' href='http://earlhood.blogspot.com/2009/08/disabling-ads-in-gmail.html' title='Disabling ads in Gmail'/><author><name>E Hood</name><uri>http://www.blogger.com/profile/17985891579499891276</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
