<?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-6921426717100761060</id><updated>2011-11-04T15:45:41.307-04:00</updated><category term='Gravey'/><category term='ganttMagic'/><category term='reXume'/><category term='JavaScript'/><category term='faultExpectant'/><category term='Captain&apos;s Log'/><title type='text'>PolyGlot, Inc. News</title><subtitle type='html'>A series of professional and personal posts from PolyGlot Inc's principle consultant, Bruce Wallace.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>32</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-246419560245334345</id><published>2011-11-04T15:39:00.001-04:00</published><updated>2011-11-04T15:45:41.346-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>A rant about Front End Developers not knowing Modular Programming</title><content type='html'>&lt;span style="color: #0b5394; font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: small;"&gt;Here is a post of mine to an internal support forum at a client site, where I have to teach front end developers about basic software engineering (begging the question why people hiring them don't demand software engineers instead of self-taught programmers....rant, rant, rant....). I keep finding FEDs that think that any piece of DOM, bit of JavaScript, or chunk of CSS that they can see via Firebug is fair game to fiddle with...rant...rant...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why does my App break when I upgrade to the new version of the Framework?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This thread is a general purpose Q&amp;amp;A on the topic of code  breaking when a newer version of [GUI Framework] is used, and it is illustrated by a  particular real-world scenario...&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;&lt;u&gt;Example Question:&lt;/u&gt;  "The following code was provided to us by [GUI Framework] team for auto complete  in [widget] a long time ago when we were working on the [foo project]  with the [GUI Framework] team.&amp;nbsp; In there, you can see there are quite a few  references to the private attributes. ... ... ... functionality is not  working as before. Can you please provide pointers to resolve this."&lt;/div&gt;&lt;div style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;&lt;u&gt;Example Answer:&lt;/u&gt;  "... A quick look at the code in the attachment makes me believe that  it was a hack to replace the internal workings of the list filtering…you  SHOULD have been provided an above-board way to  subclass/decorate/configure [widget] (instead of that quick and dirty  method)."&lt;/div&gt;&lt;br /&gt;There are general software engineering principles of &lt;a href="http://c2.com/cgi/wiki?EncapsulationIsNotInformationHiding" target="_blank"&gt;"encapsulation" and "information hiding"&lt;/a&gt; which come from the Modular Programming era in the mid-1970s (just before Object Oriented expanded upon it).&amp;nbsp; To combat &lt;a href="http://en.wikipedia.org/wiki/Software_brittleness" target="_blank"&gt;"brittleness"&lt;/a&gt; of a system, Components hide their (private) implementation details inside a (public) interface so that changes in one part of a system don't break other far-flung parts of that system (aka &lt;a href="http://en.wikipedia.org/wiki/Loose_coupling" target="_blank"&gt;"loose coupling"&lt;/a&gt;).&amp;nbsp; The warranty provided by the component is that as long as you use it as designed, and via the stable interface, the insides are free to be changed/fixed/enhanced without affecting you.&lt;br /&gt;&lt;br /&gt;So, a component (&lt;i&gt;where "widget" is just another word for component&lt;/i&gt;) is not just a collection of functionality like the collection of bits and wires below...&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.chrismcovell.com/segahacking/rgb_decodeboard.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://www.chrismcovell.com/segahacking/rgb_decodeboard.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&amp;nbsp;...but rather a collection of functionality that has had a stable interface published on the outside of a &lt;a href="http://en.wikipedia.org/wiki/Black_box" target="_blank"&gt;"black box"&lt;/a&gt; thus hiding the implementation inside that box, as shown below...&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://mixonline.com/gear/newproducts/Black_Box_Analog_Design.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://mixonline.com/gear/newproducts/Black_Box_Analog_Design.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b style="color: red;"&gt;This warranty is voided&lt;/b&gt;&lt;/span&gt; however if you break into the box and connect to its private implementation (aka &lt;a href="http://en.wikipedia.org/wiki/Hacker_%28hobbyist%29" target="_blank"&gt;"hacking"&lt;/a&gt;) as seen below...&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.chrismcovell.com/segahacking/gg_inside.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://www.chrismcovell.com/segahacking/gg_inside.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.chrismcovell.com/segahacking/rgb_inside.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="232" src="http://www.chrismcovell.com/segahacking/rgb_inside.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&amp;nbsp;In [GUI Framework], there are two major indicators as to whether a property or method of a widget is public interface versus private implementation:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;If the name of the property or method starts with an underscore ("_") then it is definitely private (or at best &lt;a href="http://stackoverflow.com/questions/1020749/what-are-public-private-and-protected-in-object-oriented-programming" target="_blank"&gt;"protected"&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;If the property or method is documented in the [GUI Framework] JsDoc API Docs then it is definitely public.&lt;/li&gt;&lt;/ol&gt;SO, IN CONCLUSION, if someone advises that non-documented or private parts of a widget be used by your app, you should get them to sign a document acknowledging that they are voiding their warranty, and they will pay the costs incurred when components are replaced or upgraded later (as they will be EVEN IF YOU REMAIN USING THE SAME VERSION OF [GUI Framework] because only the Interfaces are promised to be kept stable for a release, not the Implementations!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-246419560245334345?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/246419560245334345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=246419560245334345' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/246419560245334345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/246419560245334345'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2011/11/rant-about-front-end-developers-not.html' title='A rant about Front End Developers not knowing Modular Programming'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-8891699949906333392</id><published>2011-02-25T10:27:00.043-05:00</published><updated>2011-02-25T11:14:47.753-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Performance Tips of the RIA All-Stars</title><content type='html'>&lt;style type="text/css"&gt; div.TipsArticle p,div.TipsArticle ul,div.TipsArticle dl { font-family: "Franklin Gothic Medium", "Trebuchet MS", sans-serif;}div.TipsArticle p { text-align: justify;}div.TipsArticle h1,div.TipsArticle h2,div.TipsArticle h3 { font-family: Arial,Helvetica,sans-serif;    margin-top: 0px; margin-bottom: 0px;}div.TipsArticle h2 {    font-size: 2.0em;}div.TipsArticle h3 {    font-size: 1.0em;}div.TipsArticle cite { font-family: Arial,Helvetica,sans-serif;    font-size: 0.875em;    letter-spacing: -1px;    font-style: normal;    font-variant: small-caps;}div.TipsArticle q { font-family: "Times New Roman",Times,serif; color: navy;}div.TipsArticle q:before { content: '' }div.TipsArticle q:after  { content: '' } div.TipsArticle ul.quotes { color: maroon; margin-top: 0px; margin-bottom: 0px;}div.TipsArticle ul.quotes q { color: maroon; margin-top: 0px; margin-bottom: 0px;} div.TipsArticle abbr { font-family: monospace; font-size: 0.875em; font-weight: bold;}div.TipsArticle dl ul { margin-left: 0; padding-left: 0;}div.TipsArticle ul.biblist { list-style-type: none;}div.TipsArticle dl.tips dd { text-align: justify;}div.TipsArticle dl.tips dt { font-weight: bold; margin-top: 10px;}div.TipsArticle dl.tips dt:before { content: "\00BB TIP: "}div.TipsArticle var { font-family: monospace; font-style: normal;}div.TipsArticle code { font-family: monospace; font-weight: bold; color: green;}div.TipsArticle mark { text-decoration: underline;}div.TipsArticle mark.extra { text-decoration: none; color: purple;}&lt;/style&gt;&lt;br /&gt;&lt;article&gt;&lt;br /&gt;&lt;div class="TipsArticle"&gt;&lt;section&gt;&lt;br /&gt;&lt;h3&gt;CODING and LOADING&lt;/h3&gt;&lt;p&gt;This guide will summarize the performance-related DOs and DON'Ts of JavaScript and Web Site development as espoused by well-known pundits like Douglas Crockford. The publications listed below are surveyed, but since they overlap, this guide can act as both summary and cheat sheet for their catalog of techniques.  The tips fall into 2 major categories: CODING and LOADING. &lt;em&gt;i.e. making JavaScript and CSS performant, and minimizing the apparent time needed to load responsive user interfaces.&lt;/em&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul class="biblist"&gt;&lt;li&gt;&lt;abbr&gt;[HPW]&lt;/abbr&gt; High Performance Web Sites, Steve Souders, O'Reilly, 2007&lt;/li&gt;&lt;li&gt;&lt;abbr&gt;[JGP]&lt;/abbr&gt; JavaScript: The Good Parts, Douglas Crockford, O'Reilly, 2008&lt;/li&gt;&lt;li&gt;&lt;abbr&gt;[EFW]&lt;/abbr&gt; Even Faster Web Sites, Steve Souders, O'Reilly, 2009&lt;/li&gt;&lt;li&gt;&lt;abbr&gt;[HPJ]&lt;/abbr&gt; High Performance JavaScript, Nicholas Zakas, O'Reilly, 2010&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;As with any optimization effort, the number one rule is to only optimize the portions of a system that are bottlenecks as actually measured at run time.  Often, optimization techniques have serious downsides that require tradeoff judgments to be made. For example, Crockford &lt;cite&gt;[JGP, P.65]&lt;/cite&gt; says both that &lt;q&gt;"Regular expressions usually have a significant performance advantage over equivalent string operations in JavaScript"&lt;/q&gt; AND &lt;q&gt;"regular expressions can be very difficult to maintain and debug"&lt;/q&gt;. Souders &lt;cite&gt;[EFW, P.6]&lt;/cite&gt; says &lt;q&gt;"Everything is a trade-off. When optimizing for performance, do not waste time trying to speed up code that does not consume a significant amount of the time. Measure first. Back out of any optimization that does not provide an enjoyable benefit."&lt;/q&gt;  Galbraith &lt;cite&gt;[EFW, P.9]&lt;/cite&gt; says &lt;q&gt;"developers seeking to create responsive, high-performance web sites can't, and shouldn't, go about achieving that goal by optimizing every single piece of code as they write it. The opposite is true: a developer should optimize only what isn't fast enough."&lt;/q&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;On the other hand, there are basic practices (like not putting operations inside a loop that can be done once outside the loop) that can be followed right from the start. As Zakas &lt;cite&gt;[HPJ, P.XII]&lt;/cite&gt; says, &lt;q&gt;"JavaScript forces the developer to perform the optimizations that a compiler would normally handle in other languages"&lt;/q&gt;. This catalog will contain a bit of each category.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;And finally, in a very few cases, these authors contradict each other; for example, bitwise operators are either really fast, or really slow, depending on who is judging. Crockford &lt;cite&gt;[JGP, P.112]&lt;/cite&gt;, in Appendix B: Bad Parts, says bitwise operators are &lt;q&gt;"very slow"&lt;/q&gt;, whereas, Zakas &lt;cite&gt;[HPJ, P.156]&lt;/cite&gt;, in Use the Fast Parts, says bitwise operators are &lt;q&gt;"incredibly fast"&lt;/q&gt;!&lt;br /&gt;&lt;/p&gt;&lt;dl&gt;&lt;dt&gt;Caveats: &lt;/dt&gt;&lt;dd&gt; &lt;ul&gt;&lt;li&gt;This guide assumes that the reader is already familiar with basic but modern JavaScript/Web development, and leaves to another guide the task of bringing the reader up to that level.&lt;/li&gt;&lt;li&gt;While the books referenced above contain a wealth of development advice, this guide will only summarize those tips that are related to improved performance.&lt;/li&gt;&lt;li&gt;Each tip is a summary of a high level idea. Please refer to the book sections referenced for more implementation details as well as discussion of alternate techniques for more specialized situations.&lt;/li&gt;&lt;/ul&gt;&lt;/dd&gt; &lt;/dl&gt;&lt;/section&gt;&lt;br /&gt;&lt;section&gt;&lt;br /&gt;&lt;h2&gt;Section 1: Coding Tips&lt;/h2&gt;&lt;ul class="quotes"&gt;&lt;li&gt;&lt;q&gt;"JavaScript forces the developer to perform the optimizations that a compiler would normally handle" - N. Zakas&lt;/q&gt;&lt;/li&gt;&lt;/ul&gt;&lt;dl class="tips"&gt;&lt;dt&gt;Arrays are not Arrays...&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[JGP, P.58,105]&lt;/cite&gt; &lt;q&gt;"[Conventional] arrays can be very fast data structures. Unfortunately, JavaScript does not have anything like this kind of array. ... their performance can be considerably worse than real arrays"&lt;/q&gt;.  Arrays in JavaScript are basically objects (i.e. dynamic bags of properties) whose property names are merely the string version of the integer subscripts. &lt;/dd&gt;&lt;dt&gt;...but String Arrays are faster than String Concatenation&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[JGP, P.78]&lt;/cite&gt;&lt;cite&gt;[EFW, P.99]&lt;/cite&gt; &lt;q&gt;"If you are assembling a string from a large number of pieces, it is usually faster to put the pieces into an array and join them than it is to concatenate the pieces with the + operator."&lt;/q&gt;  The more pieces that are concatenated together (think very big loops here), the faster it is to use &lt;var&gt;Array.join&lt;/var&gt;. &lt;pre&gt;&lt;code&gt;    var a = []; &lt;br /&gt;    a.push('a');  a.push('b');  a.push('c');  a.push('d'); &lt;br /&gt;    var c = a.join('');   // c is 'abcd' and faster than c = 'a'+'b'+'c'+'d';&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;cite&gt;[EFW, P.99]&lt;/cite&gt; While modern browsers have improved string performance to the point that this advice may be out of date, never the less, &lt;q&gt;"The performance decrease of the array technique in other browsers is typically much less than the performance increase gained in [pre-v8] Internet Explorer"&lt;/q&gt;. &lt;/dd&gt;&lt;dt&gt;Fastest implementation of the missing String.trim function&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[EFW, P.101]&lt;/cite&gt; JavaScript is missing a string &lt;var&gt;trim&lt;/var&gt; function, and it is usually implemented by the application. After performing research on the fastest way to execute string trimming in JavaScript, the following function consistently performs better than other variations: &lt;pre&gt;&lt;code&gt;    function trim( text ){ &lt;br /&gt;        text = text.replace(/^\s+/, ""); &lt;br /&gt;        for (var i=text.length-1; i&amp;gt;=0; --i) { &lt;br /&gt;            if (/\S/.test(text.charAt(i))) { &lt;br /&gt;                text = text.substring( 0, i+1 ); &lt;br /&gt;                break; &lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return text; &lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;dt&gt;Faster to process an array of properties than sorting an enumeration&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[JGP, P.24]&lt;/cite&gt; &lt;q&gt;"The for in statement can loop over all of the property names in an object... [but] there is no guarantee on the order of the names."&lt;/q&gt; So, rather than having to sort them (not to mention filtering out all of the unwanted inherited properties), use a normal for loop against an array of property names in the desired order. E.G. &lt;pre&gt;&lt;code&gt;    var i, pn = [ 'first-name', 'middle-name', 'last-name' ]; &lt;br /&gt;    for (i=0; i &amp;lt; pn.length; ++i) { &lt;br /&gt;        document.writeln( pn[i] + ': ' +  personObject[ pn[i] ] ); &lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;dt&gt;Use &lt;em&gt;Simple&lt;/em&gt; Regular Expressions instead of string manipulation&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[JGP, P.65, 69]&lt;/cite&gt; &lt;q&gt;"Regular expressions usually have a significant performance advantage over equivalent string operations in JavaScript...[however] regular expressions can be very difficult to maintain and debug...[and] the part of the language that is least portable is the implementation of regular expressions. Regular expressions that are very complicated or convoluted are more likely to have portability problems. Nested regular expressions can also suffer horrible performance problems in some implementations. Simplicity is the best strategy."&lt;/q&gt; &lt;/dd&gt;&lt;dt&gt;Eval is Evil (and so are its aliases)&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[JGP, P.110]&lt;/cite&gt; Slow performance is just one reason to not use &lt;var&gt;eval()&lt;/var&gt; and its equivalents. Between the two lines below, line one &lt;q&gt;"will be significantly slower because it needs to run the compiler just to execute a trivial assignment statement...The Function constructor is another form of &lt;var&gt;eval&lt;/var&gt;, and should similarly be avoided. The browser provides &lt;var&gt;setTimeout&lt;/var&gt; and &lt;var&gt;setInterval&lt;/var&gt; functions that can take string arguments or function arguments. When given string arguments, &lt;var&gt;setTimeout&lt;/var&gt; and &lt;var&gt;setInterval&lt;/var&gt; also act as &lt;var&gt;eval&lt;/var&gt;. The string argument form also should be avoided."&lt;/q&gt; &lt;pre&gt;&lt;code&gt;    eval("myValue = myObject." + myKey + ";"); &lt;br /&gt;    myvalue = myObject[ myKey ];&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;dt&gt;Always store multi-accessed values in local variables&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[HPJ, P.20-33]&lt;/cite&gt; &lt;cite&gt;[EFW, P.79-88]&lt;/cite&gt;  &lt;q&gt;"Generally speaking, you can improve the performance of JavaScript code by storing frequently used object members, array items, and out-of-scope variables in local variables. You can then access the local variables faster than the originals. ... A good rule of thumb is to always store out-of-scope values in local variables if they are used more than once within a function. ... Literal values and local variables can be accessed very quickly, whereas array items and object members take longer. ... Local variables are faster to access than out-of-scope variables because they exist in the first variable object of the scope chain. The further into the scope chain a variable is, the longer it takes to access. Global variables are always the slowest to access because they are always last in the scope chain. ... Nested object members incur significant performance impact and should be minimized. ... The deeper into the prototype chain that a property or method exists, the slower it is to access."&lt;/q&gt; &lt;/dd&gt;&lt;dt&gt;Avoid the &lt;var&gt;with&lt;/var&gt; statement&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[HPJ, P.33]&lt;/cite&gt; &lt;q&gt;"Avoid the &lt;var&gt;with&lt;/var&gt; statement because it augments the execution context scope chain. ... Also, be careful with the &lt;var&gt;catch&lt;/var&gt; clause of a &lt;var&gt;try-catch&lt;/var&gt; statement because it has the same effect."&lt;/q&gt; The net effect of each is that it makes the previously local variables no longer local, and hence, slower. &lt;/dd&gt;&lt;dt&gt;Optimize your loops because JavaScript won't&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[EFW, P.93]&lt;/cite&gt;  &lt;q&gt;"loops are a frequent source of performance issues in JavaScript,  and the way you write loops drastically changes its execution time. Once again, JavaScript   developers don't get to rely on compiler optimizations that make loops faster"&lt;/q&gt; Beyond the normal    refactoring of code to be outside of a loop wherever possible, there are a couple of operations     of the loop itself that must be hand optimized. The first version of the loop below runs much      slower than the second because it is looking up the &lt;var&gt;length&lt;/var&gt; property of values over and over,       and the comparison of &lt;var&gt;i--&lt;/var&gt; to zero is much faster than comparing &lt;var&gt;i&lt;/var&gt; to &lt;var&gt;length&lt;/var&gt;. &lt;pre&gt;&lt;code&gt;    //traditional unoptimized for loop&lt;br /&gt;    var values = [1,2,3,4,5];&lt;br /&gt;    for (var i=0; i &amp;lt; values.length; ++i){ process(values[i]); }&lt;br /&gt; &lt;br /&gt;    //over 50% faster version&lt;br /&gt;    var length = values.length;&lt;br /&gt;    for (var i=length; i--;){ process(values[i]); } &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;dt&gt;Use Cooperative Multitasking for Long-Running Scripts&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[EFW, P.102]&lt;/cite&gt; &lt;q&gt;"One of the critical performance issues with JavaScript is that code  execution freezes a web page. Because JavaScript is a single-threaded language, only one script   can be run at a time per window or tab. This means that all user interaction is necessarily halted    while JavaScript code is being executed."&lt;/q&gt; In general, when attempting to simulate true simultaneous     execution of multiple processes (&lt;em&gt;like JavaScript and the user interface&lt;/em&gt;), each process must either      volunteer to regularly yield control temporarily to other processes (&lt;dfn&gt;cooperative multitasking&lt;/dfn&gt;),       or have control regularly taken from it (&lt;dfn&gt;preemptive multitasking&lt;/dfn&gt;). The only option with JavaScript        is voluntarily yielding control to the UI thread by splitting your logic into pieces and having         each piece schedule the next piece with a time delay in between. &lt;q&gt;"Generally speaking, no single          continuous script execution should take longer than 100 milliseconds; anything longer than that           and the web page will almost certainly appear to be running slowly to the user"&lt;/q&gt;.   The &lt;var&gt;setTimeout&lt;/var&gt; function takes a function and a delay amount as parameters. &lt;q&gt;"When the delay has passed,  the code to execute is placed into a queue. The JavaScript engine uses this queue to determine what   to do next. When a script finishes executing, the JavaScript engine yields to allow other browser tasks to catch up. The web page display is typically updated during this time in relation to changes     made via the script. Once the display has been updated, the JavaScript engine checks for more scripts to run on the queue. If another script is waiting, it is executed and the process repeats; if there are no more scripts to execute, the JavaScript engine remains idle until another script appears in the queue."&lt;/q&gt; &lt;/dd&gt;&lt;dt&gt;Use Memoization to cache intermediate calculations&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[JGP, P.44]&lt;/cite&gt; One of the benefits of doing true "functional programming" is that it is  easy to avoid performing calculations that have already been done.  True functional programming has the rule that the result of a function depends totally on its parameters; i.e. it will always give    the same result given the same parameters. This means that a cache object could be kept by a function to store the result for each set of parameters as they are encountered. When a function is called,  the first thing it does it try to look up a cached result for the parameters it is given, and return   it if found.  If the result is not found, then it is calculated and saved in the cache before returning    the result. &lt;p&gt;A simple example is the Fibonacci function.  The first version below is the traditional implementation  and the second uses a memoization helper to prevent recalculation.  Since Fibonacci calls itself   &lt;mark&gt;recursively&lt;/mark&gt;, the savings add up very quickly.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;// traditional implementation&lt;br /&gt;function &lt;mark&gt;fibonacci&lt;/mark&gt;(n){ return n&amp;lt;2 ? n : &lt;mark&gt;fibonacci&lt;/mark&gt;(n-1) + &lt;mark&gt;fibonacci&lt;/mark&gt;(n-2); }; &lt;br /&gt; &lt;br /&gt;// simple memoization helper for functions-with-a-single-numeric-parameter&lt;br /&gt;var memoizer = function( mementoArray, lambda )&lt;br /&gt;{ &lt;br /&gt;    var memoizedLambda = function( n ) { &lt;br /&gt;        var result = mementoArray[n]; &lt;br /&gt;        if (typeof result !== 'number')&lt;br /&gt;            mementoArray[n] = result = lambda( memoizedLambda, n );&lt;br /&gt;        return result;&lt;br /&gt;    };&lt;br /&gt; &lt;br /&gt;    return memoizedLambda; &lt;br /&gt;};&lt;br /&gt; &lt;br /&gt;// memoized version &lt;mark class="extra"&gt;[ with preloaded memos for f(0)=0 and f(1)=1 ]&lt;/mark&gt;&lt;br /&gt;var &lt;mark&gt;fibonacci&lt;/mark&gt; = memoizer( &lt;mark class="extra"&gt;[0,1]&lt;/mark&gt;, function(&lt;mark&gt;myself&lt;/mark&gt;,n){ return &lt;mark&gt;myself&lt;/mark&gt;(n-1) + &lt;mark&gt;myself&lt;/mark&gt;(n-2); } );&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;&lt;dt&gt;Avoid CSS expressions&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[HPW, P.51]&lt;/cite&gt;  &lt;q&gt;"CSS expressions are a powerful (and dangerous) way to set CSS properties  dynamically. They're supported in Internet Explorer version 5 and later... The expression method is   simply ignored by other browsers, so it is a useful tool for setting properties in Internet Explorer    to create a consistent experience across browsers. ... CSS expressions are re-evaluated when the page     changes, such as when it is resized... &lt;strong&gt;The problem with expressions is that they are evaluated more      frequently than most people expect&lt;/strong&gt;. Not only are they evaluated whenever the page is rendered and       resized, but also when the page is scrolled and even when the user moves the mouse over the page.        ... CSS expressions benefit from being automatically tied to events in the browser, but that's         also their downfall."&lt;/q&gt; &lt;p&gt;The major technique used to avoid CSS expressions is to have your own JavaScript function registered  as an event listener triggered by only the appropriate event(s).  It should set the dynamic CSS property   to the desired recalculated value.&lt;/p&gt;&lt;/dd&gt;&lt;dt&gt;CSS Selectors are Backwards&lt;/dt&gt;&lt;dd&gt;&lt;cite&gt;[EFW, P.194]&lt;/cite&gt;  &lt;q&gt;"The impact of CSS selectors on performance derives from the amount  of time it takes the browser to match the selectors against the elements in the document. ...    Consider the following rule:   &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;code&gt;#toc &amp;gt; LI { font-weight: bold; }&lt;/code&gt;  Most of us, especially those who read left to right, might assume that the browser matches this  rule by moving from left to right, and thus, this rule doesn't seem too expensive. In our minds,   we imagine the browser working like this: find the unique &lt;var&gt;toc&lt;/var&gt; element and apply this styling to    its immediate children who are &lt;var&gt;LI&lt;/var&gt; elements. We know that there is only one &lt;var&gt;toc&lt;/var&gt;     element, and it has only a few &lt;var&gt;LI&lt;/var&gt; children, so this CSS selector should be pretty efficient.   In reality, &lt;strong&gt;CSS selectors are matched by moving from right to left!&lt;/strong&gt; With this knowledge,  our rule that at first seemed efficient is revealed to be fairly expensive. The browser must iterate over   every &lt;var&gt;LI&lt;/var&gt; element in the page and determine whether its parent is &lt;var&gt;toc&lt;/var&gt;. This descendant   selector example is even worse:   &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;code&gt;#toc A { color: #444; }&lt;/code&gt;  Instead of just checking for anchor elements inside &lt;var&gt;toc&lt;/var&gt;, as would happen if it was read left  to right, the browser has to check every anchor in the entire document. And instead of just   checking each anchor's parent, the browser has to climb the document tree looking for an ancestor    with the ID &lt;var&gt;toc&lt;/var&gt;. If the anchor being evaluated isn't a descendant of &lt;var&gt;toc&lt;/var&gt;,     the browser has to walk the tree of ancestors until it reaches the document root."&lt;/q&gt; &lt;/dd&gt; &lt;/dl&gt;&lt;/section&gt;&lt;br /&gt;&lt;section&gt;&lt;br /&gt;&lt;h2&gt;Section 2: Loading Tips&lt;/h2&gt;&lt;ul class="quotes"&gt;&lt;li&gt;&lt;q&gt;"Nothing else can happen while JavaScript code is being executed" - N. Zakas&lt;/q&gt;&lt;/li&gt;&lt;li&gt;&lt;q&gt;"Rule 1: Make Fewer HTTP Requests" - Steve Souders&lt;/q&gt;&lt;/li&gt;&lt;li&gt;&lt;q&gt;"Only 10-20% of the end user response time is spent downloading the HTML document.&lt;br /&gt;The other 80-90% is spent downloading all the components in the page." - the Performance Golden Rule&lt;/q&gt;&lt;/li&gt;&lt;/ul&gt;&lt;dl class="tips"&gt;&lt;dt&gt;What is Fast Enough&lt;/dt&gt;&lt;dd&gt;  &lt;cite&gt;[EFW, P.9]&lt;/cite&gt; &lt;q&gt;"It's fine to say that code needs to execute ''as fast as possible'', but ... exactly   what is ''fast enough'' ... Jakob Nielsen is a well-known and well-regarded expert in the field of    web usability; the following quote addresses the issue of ''fast enough'': &lt;blockquote&gt;The response time guidelines for web-based applications are the same as for all other applications.  These guidelines have been the same for 37 years now, so they are also not likely to change wit  whatever implementation technology comes next.&lt;br/&gt;&lt;strong&gt;0.1 second:&lt;/strong&gt; Limit for users feeling that they are directly manipulating objects  in the UI. For example, this is the limit from the time the user selects a column in a table until   that column should highlight or otherwise give feedback that it's selected. Ideally, this would    also be the response time for sorting the column-if so, users would feel that they are sorting the table.&lt;br/&gt;&lt;strong&gt;1 second:&lt;/strong&gt; Limit for users feeling that they are freely navigating the command  space without having to unduly wait for the computer. A delay of 0.2-1.0 seconds does mean that users   notice the delay and thus feel the computer is ''working'' on the command, as opposed to having the    command be a direct effect of the users' actions. Example: If sorting a table according to the selected     column can't be done in 0.1 seconds, it certainly has to be done in 1 second, or users will feel      that the UI is sluggish and will lose the sense of ''flow'' in performing their task. For delays       of more than 1 second, indicate to the user that the computer is working on the problem, for        example by changing the shape of the cursor.&lt;br/&gt;&lt;strong&gt;10 seconds:&lt;/strong&gt; Limit for users keeping their attention on the task. Anything  slower than 10 seconds needs a percent-done indicator as well as a clearly signposted way for   the user to interrupt the operation. Assume that users will need to reorient themselves when    they return to the UI after a delay of more than 10 seconds. Delays of longer than 10 seconds     are only acceptable during natural breaks in the user's work, for example when switching tasks. &lt;/blockquote&gt;In other words, if your JavaScript code takes longer than 0.1 seconds to execute, your page  won't have that slick, snappy feel; if it takes longer than 1 second, the application feels   sluggish; longer than 10 seconds, and the user will be extremely frustrated. These are the    definitive guidelines to use for defining &lt;em&gt;''fast enough.''&lt;/em&gt;  "&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Put Stylesheets at the Top&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPW, P.44]&lt;/cite&gt; &lt;q&gt;"In their effort to improve one of the most visited pages on the Web,  the Yahoo portal team initially made it worse by moving the [CSS] stylesheet to the bottom of   the page. They found the optimal solution by following the HTML specification and leaving it    at the top. Neither of the alternatives, the blank white screen or flash of unstyled content,     are worth the risk. ... If you have a stylesheet that's not required to render the page,      with some extra effort you can load it dynamically after the document loads."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Put JavaScript at the Bottom&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPJ, P.3]&lt;/cite&gt; &lt;cite&gt;[HPW, P.45]&lt;/cite&gt; &lt;q&gt;"Put all &lt;var&gt;&amp;lt;script&amp;gt;&lt;/var&gt; tags  at the bottom of the page, just inside of the closing &lt;var&gt;&amp;lt;/body&amp;gt;&lt;/var&gt; tag. This   ensures that the page can be almost completely rendered before script execution begins."&lt;/q&gt;   &lt;q&gt;"[While modern browsers] allow parallel downloads of JavaScript files...JavaScript    downloads still block downloading of other resources, such as images. And even though     downloading a script doesn't block other scripts from downloading, the page must still      wait for the JavaScript code to be downloaded and executed before continuing."&lt;/q&gt;   &lt;q&gt;"Since each &lt;var&gt;&amp;lt;script&amp;gt;&lt;/var&gt; tag blocks the page from continuing to render    until it has fully downloaded and executed the JavaScript code, the perceived performance     of this page will suffer. Keep in mind that browsers don't start rendering anything on      the page until the opening &lt;var&gt;&amp;lt;body&amp;gt;&lt;/var&gt; tag is encountered. Putting scripts       at the top of the page typically leads to a noticeable delay, often in the form of a        blank white page"&lt;/q&gt; &lt;q&gt;"This is the Yahoo Exceptional Performance team's first rule         about JavaScript: put scripts at the bottom."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Use External Scripts but Group them Together...&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPJ, P.4]&lt;/cite&gt; &lt;cite&gt;[HPW, P.55]&lt;/cite&gt; &lt;q&gt;"In Raw Terms, Inline [scripts are] Faster...  [but] using external files in the real world generally produces faster pages. This is due to ...   the opportunity for JavaScript and CSS files to be cached by the browser."&lt;/q&gt;  &lt;q&gt;"Group scripts together. The fewer &lt;var&gt;&amp;lt;script&amp;gt;&lt;/var&gt; tags on the page, the faster   the page can be loaded and become interactive. ... when dealing with external JavaScript files,    each HTTP request brings with it additional performance overhead, so downloading one single     100 KB file will be faster than downloading four 25 KB files. It's helpful to limit the      number of external script files that your page references. ... Typically, a large website       or web application will have several required JavaScript files. You can minimize the        performance impact by concatenating these files together into a single file and then         calling that single file with a single &lt;var&gt;&amp;lt;script&amp;gt;&lt;/var&gt; tag. The catenation          can happen offline using a build tool or in real-time using a tool like the Yahoo combo           handler."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;...ON THE OTHER HAND, don't group them All together&lt;br /&gt;(aka: Download Most JavaScript in a Nonblocking Fashion)&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPJ, P.5-9]&lt;/cite&gt; &lt;cite&gt;[EFW, P.22, 51, 73]&lt;/cite&gt; &lt;q&gt;"It turns out that  Facebook executes only 9% of the downloaded JavaScript functions by the time the &lt;var&gt;onload&lt;/var&gt;   event is called."&lt;/q&gt; &lt;q&gt;"Limiting yourself to downloading a single large JavaScript file will    only result in locking the browser out for a long period of time, despite it being just one     HTTP request. To get around this situation, you need to incrementally add more JavaScript      to the page in a way that doesn't block the browser. The secret to nonblocking scripts is       to load the JavaScript source code after the page has finished loading...[i.e.] after        the window's load event has been fired." &lt;strong&gt;"Dynamic script loading is the most         frequently used pattern for nonblocking JavaScript downloads&lt;/strong&gt; due to its cross-browser          compatibility and ease of use." "A new &lt;var&gt;&amp;lt;script&amp;gt;&lt;/var&gt; element can           be created very easily using standard DOM methods:&lt;/q&gt; &lt;pre&gt;&lt;code&gt;    var script = document.createElement("script"); &lt;br /&gt;    script.type = "text/javascript"; &lt;br /&gt;    script.src = "file1.js"; &lt;br /&gt;    document.getElementsByTagName("head")[0].appendChild(script); &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;q&gt;... [file1.js] begins downloading as soon as the element is added to the page. The important  thing about this technique is that the file is downloaded and executed without blocking   other page processes... It's generally safer to add new &lt;var&gt;&amp;lt;script&amp;gt;&lt;/var&gt; nodes    to the &lt;var&gt;&amp;lt;head&amp;gt;&lt;/var&gt; element instead of the &lt;var&gt;&amp;lt;body&amp;gt;&lt;/var&gt;, especially     if this code is executing during page load. ... This works well when the script is      self-executing but can be problematic if the code contains only interfaces to be used       by other scripts on the page. In that case, you need to track when the code has been        fully downloaded and is ready for use. This is accomplished using events that are fired         by the dynamic &lt;var&gt;&amp;lt;script&amp;gt;&lt;/var&gt; node. ... You can dynamically load as many          JavaScript files as necessary on a page, but &lt;strong&gt;make sure you consider the order in which           files must be loaded&lt;/strong&gt;. ... [Many] browsers will download and execute the various code            files in the order in which they are returned from the server. You can guarantee the             order by [daisy] chaining the downloads ...[or] concatenate the files into a single              file where each part is in the correct order. That single file can then be downloaded               ... (since this is happening asynchronously, there's no penalty for having a larger file)."               &lt;strong&gt;"The challenge in splitting your JavaScript code is to avoid undefined symbols."               "Preserving the order of JavaScript is critical, and this is true for CSS as well."&lt;/strong&gt;&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Separate Bootstrap Code from the bulk of the JavaScript&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPJ, P.10]&lt;/cite&gt; &lt;cite&gt;[EFW, P.27]&lt;/cite&gt; &lt;q&gt;"The recommended approach to loading a significant  amount of JavaScript onto a page is a two-step process: first, include the code necessary to   dynamically load JavaScript, and then load the rest of the JavaScript code needed for page    initialization. Since the first part of the code is as small as possible, potentially containing     just the &lt;var&gt;loadScript()&lt;/var&gt; function, it downloads and executes quickly, and so shouldn't cause much      interference with the page. Once the initial code is in place, use it to load the remaining       JavaScript [in a nonblocking fashion with a callback invoked on load completion]. For example: &lt;/q&gt; &lt;pre&gt;&lt;code&gt;    &amp;lt;script type="text/javascript" src="myScriptLoader.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;    &amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;      myScriptLoader( "the-rest.js", function(){ MyApplication.init(); } );&lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;q&gt;Place the loading code just before the closing &lt;var&gt;&amp;lt;/body&amp;gt;&lt;/var&gt; tag [so that] when  the second JavaScript file has finished downloading, all of the DOM necessary for the application   has been created and is ready to be interacted with, avoiding the need to check for another event    (such as &lt;var&gt;window.onload&lt;/var&gt;) to know when the page is ready for initialization." "The concept of a     small initial amount of code on the page followed by downloading additional functionality      is at the core of the YUI 3 design."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Prevent redirects due to missing trailing URL slashes&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPW, P.76]&lt;/cite&gt; &lt;q&gt;"A redirect is used to reroute users from one URL to another.  ...the main thing to remember is that redirects make your pages slower. ... One of the  most wasteful redirects happens frequently and web developers are generally not aware   of it. It occurs when a trailing slash (/) is missing from a URL that should otherwise    have one.  For example, &lt;strong&gt;http://yahoo.com/astrology &lt;/strong&gt; results in a redirect     to &lt;strong&gt;http://yahoo.com/astrology/ &lt;/strong&gt; .     The only difference is the addition of a trailing slash. ... Note that a redirect      does not happen if the trailing slash is missing after the hostname. For example,       &lt;strong&gt;http://www.yahoo.com&lt;/strong&gt; does not generate a redirect."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Never put an inline script after a &lt;var&gt;&amp;lt;link&amp;gt;&lt;/var&gt; tag&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPJ, P.4]&lt;/cite&gt;&lt;cite&gt;[EFW, P.75]&lt;/cite&gt;  &lt;q&gt;"Steve Souders has found that an inline  script placed after a &lt;var&gt;&amp;lt;link&amp;gt;&lt;/var&gt; tag referencing an external stylesheet caused   the browser to block while waiting for the stylesheet to download. This is done to ensure    that the inline script will have the most correct style information with which to work.     Souders recommends never putting an inline script after a &lt;var&gt;&amp;lt;link&amp;gt;&lt;/var&gt; tag      for this reason."&lt;/q&gt;    &lt;/dd&gt;&lt;dt&gt;Minify JavaScript&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPW, P.69]&lt;/cite&gt;  &lt;q&gt;"&lt;dfn&gt;Minification&lt;/dfn&gt; is the practice of removing unnecessary characters  from code to reduce its size, thereby improving load times. When code is minified, all comments   are removed, as well as unneeded whitespace characters (space, newline, and tab). In the case    of JavaScript, this improves response time performance because the size of the downloaded file     is reduced. ... The most popular tool for minifying JavaScript code is JSMin      (&lt;em&gt;http://crockford.com/javascript/jsmin&lt;/em&gt;) ... &lt;strong&gt;Gzip compression has the biggest impact       [about 70%], but minification further reduces file sizes [by about 20%].&lt;/strong&gt;"        "The savings from minifying CSS are typically less than the savings from minifying        JavaScript because CSS generally has fewer comments and less whitespace than JavaScript.         The greatest potential for size savings comes from optimizing CSS; i.e. merging identical          classes, removing unused classes, etc."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Remove Duplicate Scripts&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPW, P.85]&lt;/cite&gt; &lt;q&gt;"It hurts performance to include the same JavaScript file twice  in one page. This mistake isn't as unusual as you might think. A review of the 10 top U.S.  web sites shows that two of them (CNN and YouTube) contain a duplicated script. ... The two   sites that have duplicate scripts also happen to have an above-average number of scripts    (CNN has 11; YouTube has 7). ... One way to avoid accidentally including the same script     twice is to implement a script management module in your templating system. ... While      tackling the duplicate script issue, add functionality to handle script dependencies       and versioning of scripts too."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Use a Content Delivery Network&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPW, P.18]&lt;/cite&gt; &lt;q&gt;"The average user's bandwidth increases every year, but a user's  proximity to your web server still has an impact on a page's response time. ... A content   delivery network (CDN) is a collection of web servers distributed across multiple locations    to deliver content to users more efficiently. ... CDNs are used to deliver static content,     such as images, scripts, stylesheets, and Flash. Static files are easy to host and have      few dependencies. That is why a CDN is easily leveraged to improve the response times for       a geographically dispersed user population."&lt;/q&gt; Keeping in mind the &lt;dfn&gt;Performance Golden Rule&lt;/dfn&gt;        that says &lt;q&gt;"Only 10-20% of the end user response time is spent downloading the HTML document.         The other 80-90% is spent downloading all the components in the page",         [Tests and Yahoo experience show that] components hosted on a CDN loaded 18-20% faster          than with all components hosted from a single web server."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Use Server Compression&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPW, P.39]&lt;/cite&gt; &lt;q&gt;"If an HTTP request results in a smaller response, the transfer time  decreases because fewer packets must travel from the server to the client. ...   [Using server-side preprocessing] to compress HTTP responses... is the easiest technique for   reducing page weight and it also has the biggest impact. Gzip is currently the most popular    and effective compression method. It is a free format (i.e., unencumbered by patents or     other restrictions). ... Servers choose what to gzip based on file type, but are typically      too limited in what they are configured to compress. Many web sites gzip their HTML documents,       but it's also worthwhile to gzip your scripts and stylesheets, and in fact, any text response        including XML and JSON. Image and PDF files should &lt;em&gt;not&lt;/em&gt; be gzipped because they are already         compressed. ... Generally, it's worth gzipping any file greater than 1 or 2K."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Add "Long Shelf Life" Headers&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPW, P.32]&lt;/cite&gt; &lt;q&gt;"Browsers (and proxies) use a cache to reduce the number of HTTP requests  and decrease the size of HTTP responses, thus making web pages load faster. A web server uses the   &lt;var&gt;Expires&lt;/var&gt; header to tell the web client that it can use the current copy of a component until the    specified time. ... The &lt;var&gt;Cache-Control&lt;/var&gt; header was introduced in HTTP/1.1 to overcome limitations     with the &lt;var&gt;Expires&lt;/var&gt; header. ... [it] uses the &lt;var&gt;max-age&lt;/var&gt; directive to specify      [in seconds] how long a component may be cached. ... If the browser has a copy of the component      in its cache, but isn't       sure whether it's still valid, a conditional GET request is made. ... The browser is essentially        saying, ''I have a version of this resource with the following last-modified date. May I just use it?''         ... If the component has not been modified since the specified date, the server ...          skips sending the body of the response, resulting in a smaller and faster response.          Conditional GET helps pages load faster, but they still require making a roundtrip between          the client and server to perform the validity check. ... Those conditional requests add up           [&lt;em&gt;easily adding over 50% to the response time for subsequent views of a typical web page.&lt;/em&gt;]"&lt;/q&gt;            Configuring your web servers to generate headers that specify the predicted lifespan of             each component will maximize cache effectiveness. Using versioning to make each component              "immutable" will allow &lt;dfn&gt;"far future Expires"&lt;/dfn&gt; (i.e. very long lifespans) to be specified               thus avoiding unnecessary Conditional GETs.   &lt;/dd&gt;&lt;dt&gt;Remove ETags&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPW, P.89]&lt;/cite&gt; &lt;q&gt;"&lt;dfn&gt;Entity tags &lt;abbr&gt;(ETags)&lt;/abbr&gt;&lt;/dfn&gt; are a mechanism that web servers  and browsers use to validate cached components.  Reducing the number of HTTP requests needed for a   page is the best way to accelerate the user experience. You can achieve this by maximizing the    browser's ability to cache your components, but the [default] ETag header thwarts caching when     a web site is hosted on more than one server. ... The problem with ETags is that they are typically      constructed using attributes that make them unique to a specific server hosting a site. ...       The end result is that ETags generated by Apache and IIS for the exact same component won't        match from one server to another. ... If you have components that have to be [version-stamped]         based on something other than the last-modified date, [customized] ETags are a powerful way          of doing that. If you don't have the need to customize ETags, it is best to simply remove them.           ... removing the ETag altogether would avoid these unnecessary and inefficient downloads            of data that's already in the browser's cache."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Use Iframes Sparingly&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[EFW, P.191]&lt;/cite&gt; &lt;q&gt;"Even blank iframes are expensive. They are one to two orders of magnitude  more expensive than other DOM elements. When used in the typical way (&lt;var&gt;&amp;lt;iframe src="url"&amp;gt;&amp;lt;/ifram&amp;gt;&lt;/var&gt;),   iframes block the &lt;var&gt;onload&lt;/var&gt; event. This prolongs the browser's busy indicators, resulting in a page    that is perceived to be slower. ... Although iframes don't directly block resource downloads in     the main page, there are ways that the main page can block the iframe's downloads. ...      The browser's limited connections per server are shared across the main page and iframes,       even though an iframe is an entirely independent document. ... With all of these costs,        it's often best to avoid the use of iframes, and yet a quick survey shows that they are         still used frequently. ... An alternative way to [use frames] with better performance          would be for the main page to create a &lt;var&gt;DIV&lt;/var&gt; to hold the contents of the [frame]. When           the main page requests the [frame's] external script asynchronously, the &lt;var&gt;ID&lt;/var&gt; of this            &lt;var&gt;DIV&lt;/var&gt; could be included in the script's URL. The [frame's] JavaScript would then insert             the [frame] in the page by setting the &lt;var&gt;innerHTML&lt;/var&gt; of the &lt;var&gt;DIV&lt;/var&gt;.              This approach is also              more compatible with [frames] that take over a large part of the window and thus               cannot be constrained by an iframe. The use of iframes is declining as these other                techniques for inserting."&lt;/q&gt; ON THE OTHER HAND, iframes have been retained and                 even enhanced in HTML5.   &lt;/dd&gt;&lt;dt&gt;Flush the Document Chunks Early&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[EFW, P.191]&lt;/cite&gt; While the backend server is generating its response to a web page request, the browser (and the user) must sit and wait. &lt;q&gt;"In most cases, the browser waits for the HTML document to arrive before it starts rendering the page and downloading the page's resources."&lt;/q&gt; In order for the user to get some immediate feedback, and for the browser to start downloading images and the like, the backend server logic should flush an initial chunk of HTML back to the browser before starting any "slow" logic needed on its end to marshall up the remainder of the HTML.  To do this, HTML 1.1 "chunked encoding" needs to be supported by both the browser and server, and the server logic needs to "flush" its output buffer back to the browser after an appropriate HTML split point has been reached. &lt;q&gt;"This is exactly what's needed to combat the two shortcomings of a slow HTML document: blocked rendering and blocked downloads."&lt;/q&gt; ON THE OTHER HAND, early flushing and chunked encoding has many gotchas which can make it problematic in the real-world.   &lt;/dd&gt;&lt;dt&gt;Reduce DNS Lookups...&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPW, P.73]&lt;/cite&gt; &lt;cite&gt;[EFW, P.171]&lt;/cite&gt; &lt;q&gt;"the &lt;dfn&gt;Domain Name System &lt;abbr&gt;(DNS)&lt;/abbr&gt;&lt;/dfn&gt; maps hostnames to IP addresses, just as phonebooks map people's names to their phone numbers. ... DNS has a cost. It typically takes 20-120 milliseconds for the browser to look up the IP address for a given hostname."&lt;/q&gt; Minimizing how many different domain names your page references reduces DNS lookup delays. &lt;q&gt;"Google is the preeminent example of this, with only one DNS lookup necessary for the entire page."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;...ON THE OTHER HAND, Shard your Domain&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[EFW, P.161-8]&lt;/cite&gt; Most browsers limit the number of resources that they will simultaneously  download from any particular domain name. &lt;q&gt;"Some web pages have all their HTTP requests served   from one domain. Other sites spread their resources across multiple domains. ... sometimes    increasing the number of domains is better for performance, even at the cost of adding more     DNS lookups."&lt;/q&gt; Splitting resource downloads between multiple domain names (e.g. foo.com      and www.foo.com) is known as &lt;dfn&gt;Domain Sharding&lt;/dfn&gt;.  Having a particular resource always associated       with a particular domain name is needed to maximize caching. &lt;q&gt;"Research published by Yahoo        shows that increasing the number of domains from one to two improves performance, but increasing         it above two has a negative effect on load times. The final answer depends on the number          and size of resources, but &lt;strong&gt;sharding across two domains is a good rule of thumb&lt;/strong&gt;."&lt;/q&gt;   &lt;/dd&gt;&lt;dt&gt;Make Fewer and Thinner Image Requests&lt;/dt&gt;&lt;dd&gt; &lt;cite&gt;[HPW, P.10]&lt;/cite&gt; &lt;cite&gt;[EFW, P.133]&lt;/cite&gt;  &lt;q&gt;"Images are an easy place to improve performance  without removing features. Often, we can make substantial improvements in the size and number   of images with little to no reduction in quality. &lt;strong&gt;(1)&lt;/strong&gt; If you use multiple hyperlinked images    (&lt;em&gt;say a row of buttons&lt;/em&gt;), [client-side] image maps may be a way to reduce the number of HTTP     requests without changing the page's look and feel. An &lt;dfn&gt;image map&lt;/dfn&gt; allows you to associate      multiple URLs with a single image. The destination URL is chosen based on where the user       clicks on the image. &lt;strong&gt;(2)&lt;/strong&gt; Like image maps, &lt;dfn&gt;CSS sprites&lt;/dfn&gt; allow you       to combine images [onto one large compound image such that each individual image can be cropped via CSS]        ...         One surprising benefit is reduced download size. Most people would expect the combined          image to be larger than the sum of the separate images because the combined image has           additional area used for spacing. In fact, the combined image tends to be smaller            than the sum of the separate images as a result of reducing the amount of image             overhead (color tables, formatting information, etc.).  &lt;strong&gt;(3)&lt;/strong&gt; Optimizing images              begins with creative decisions made by the designer about the minimum number               of colors, resolution, or accuracy required for a given image [availing the                use of &lt;dfn&gt;lossy optimizations&lt;/dfn&gt;.] ... Once the quality choice has been made, use                 [automated] &lt;dfn&gt;nonlossy compression&lt;/dfn&gt; to squeak the last bytes out of the image.                  ... fantastic open source tools exist for optimizing images. &amp;#9679; Start                   by choosing the appropriate format: JPEG for photos, GIF for animations,                    and PNG for everything else. Strive for PNG8 whenever possible.                     &amp;#9679; Crush PNGs, optimize GIF animations, and strip JPEG metadata                     from the images you own. Use progressive JPEG encoding for JPEGs more                      than 10 KB in file size. &amp;#9679; Avoid AlphaImageLoader.                       &amp;#9679; Optimize CSS sprites. &amp;#9679; Create modular sprites if your                        site has more than two to three pages. &amp;#9679; Don't scale images                         in HTML. &amp;#9679; Generated images should be crushed, too. Once                          generated, they should be cached for as long as possible. Convert                           images to PNG8 and determine whether 256 colors is acceptable."&lt;/q&gt; &lt;/dd&gt; &lt;/dl&gt;&lt;/section&gt;&lt;br /&gt;&lt;/div&gt;&lt;/article&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-8891699949906333392?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/8891699949906333392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=8891699949906333392' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/8891699949906333392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/8891699949906333392'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2011/02/performance-tips-of-ria-all-stars.html' title='Performance Tips of the RIA All-Stars'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-6293122602646879330</id><published>2011-01-31T23:15:00.000-05:00</published><updated>2011-01-31T23:15:26.478-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>JavaScript: The Surprising Parts</title><content type='html'>This post is a summary of the the things that surprised me as I've been reading several books to update my knowledge of JavaScript (and practices that have changed since 2004/2005). &amp;nbsp;While this info would have been big news to most and worth writing articles about back then, it begs the question as to why I should blog about it given that now there are several good books available on the subject. There are two self-canceling&amp;nbsp;reasons; (1) this blog will act as a cheat sheet for me, and (2) the very act of writing it will make me more likely not to need a cheat sheet. &amp;nbsp;While there are many small things that I didn't happen to know (&lt;i&gt;or remember knowing&lt;/i&gt;), I am writing here about the things that actually &lt;b&gt;surprised&lt;/b&gt; me, and they tended to be either big or small surprises, so I will organize them that way.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Small Surprises&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.6]&lt;/span&gt; &lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;undefined&lt;/b&gt;&lt;/span&gt; is not a reserved word!&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.107]&lt;/span&gt;&amp;nbsp;&lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;undefined&lt;/b&gt;&lt;/span&gt;&amp;nbsp;is not a constant; it is a global&amp;nbsp;variable&amp;nbsp;which can be redefined! (so is NaN).&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.103]&lt;/span&gt;&amp;nbsp;Reserved words &lt;i&gt;can&lt;/i&gt; be used as object property names (&lt;i&gt;unless&lt;/i&gt; accessed via dot notation)! Even stranger, an empty string&amp;nbsp;is a legal property name! (as in&amp;nbsp;&lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;obj[""]=123;&lt;/b&gt;&lt;/span&gt;)&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.7]&lt;/span&gt; &lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;integer&lt;/b&gt;&lt;/span&gt;&amp;nbsp;types are really&amp;nbsp;&lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;double&lt;/b&gt;&lt;/span&gt;&amp;nbsp;under the hood!&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.10, 102]&lt;/span&gt;&amp;nbsp;Nested block statements (i.e.&amp;nbsp;&lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;{&lt;/b&gt;&lt;/span&gt;...&lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;}&lt;/b&gt;&lt;/span&gt;) do not define a new variable scope!&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.29]&lt;/span&gt;&amp;nbsp;If a method is called as a simple function,&amp;nbsp;&lt;b&gt;&lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;this&lt;/span&gt;&lt;/b&gt;&amp;nbsp;is not undefined but rather defined as the global object!&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.36, 102]&lt;/span&gt;&amp;nbsp;Local variables exist before they are declared! (which is why they may as well all be declared at the beginning of a function)&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.105]&lt;/span&gt;&amp;nbsp;The &lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;arguments&lt;/b&gt;&lt;/span&gt; array is not an array! (For that matter, arrays are not arrays!)&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.109]&lt;/span&gt;&amp;nbsp;The &lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;==&lt;/b&gt;&lt;/span&gt; operator does type coercion and the&amp;nbsp;&lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;===&lt;/b&gt;&lt;/span&gt;&amp;nbsp;operator does not. But the type coercion is done so poorly that it is too dangerous to use&amp;nbsp;&lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;==&lt;/b&gt;&lt;/span&gt;&amp;nbsp;at all in general!&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.102]&lt;/span&gt;&amp;nbsp;The&amp;nbsp;&lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;statement will return&amp;nbsp;&lt;span class="Apple-style-span" style="color: #274e13; font-family: 'Courier New', Courier, monospace;"&gt;&lt;b&gt;undefined&lt;/b&gt;&lt;/span&gt;&amp;nbsp;if the return value expression does not start on the same line as the return keyword!&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[HPJ, p.2]&lt;/span&gt;&amp;nbsp;Browsers block loading anything else while the JavaScript inside a script tag executes!&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[HPJ, p.7]&lt;/span&gt;&amp;nbsp;Scripts can be dynamically loaded by creating script tags via DHTML, and those scripts &lt;i&gt;don't&lt;/i&gt; block loading other elements (like images, etc).&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[HPJ, p.20]&lt;/span&gt;&amp;nbsp;Global variables are not the fastest to access (compared to variables in other scopes), as would be the case in compiled languages, but are in fact the slowest since all the other scopes are searched first.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.112,&amp;nbsp;HPJ, p.156]&lt;/span&gt;&amp;nbsp;Bitwise operators are either really fast, or really slow, depending on who is judging. Crockford, in Appendix B: &lt;b&gt;Bad Parts&lt;/b&gt;, say bitwise operators are "very slow", whereas, Zakas, in &lt;b&gt;Use the Fast Parts&lt;/b&gt;,&amp;nbsp;say bitwise operators are "incredibly fast"!&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Large Surprises&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, p.37,&amp;nbsp;HPJ, pp.21-26]&lt;/span&gt;&amp;nbsp;&lt;b&gt;Closures imply Cactus Stacks&lt;/b&gt;. &amp;nbsp;I didn't really understand in a deep way what closures were, and &lt;b&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;JGP&lt;/span&gt;&lt;/b&gt;&lt;i&gt;&amp;nbsp;&lt;/i&gt;didn't help&lt;i&gt; (nor any other JavaScript articles/books for that matter).&lt;/i&gt;&amp;nbsp;After all, Pascal had nested function definitions where the inner procedures had access to the outer local variables, but that didn't make closures. &amp;nbsp;What really made me understand was realizing that JavaScript was like Scheme with regard to closures. (See &lt;i&gt;JavaScript is Scheme not Java&lt;/i&gt; below). As I wrote in a comment to someone else's blog attempting to explain JavaScript closures...&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;I think it would be more accurate to say right up front that our normal notion of a “stack” (as used to hold parameters and local variables) does not apply in languages like JavaScript (and Scheme, etc). Unlike Pascal, Ada, C, C++, Java, etc., JavaScript has only “heap with garbage collection"; all those “stack frames” to hold parameters and local variables are just more objects on the heap. When no more references to each exist, they individually get garbage collected. This means that &lt;/span&gt;&lt;span class="Apple-style-span" style="color: #660000;"&gt;there is no special “saving the stack frame” after the outer function has returned for closures to use&lt;/span&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;…they all just get garbage collected like anything else does when all references to it are deleted.&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;BTW, the only way I ever&amp;nbsp;grokked&amp;nbsp;this was after learning Scheme by watching the &lt;/span&gt;&lt;a href="http://itunes.apple.com/us/itunes-u/computer-science-61a-fall/id354818329"&gt;UC-Berkeley Comp Sci 61A class on iTunes U&lt;/a&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;. Except for the EARRRRLY Fortran&amp;nbsp;on CDC supercomputer&amp;nbsp;days, where recursion was not supported and the hardware instruction set did not implement stacks, I had not experienced a language that wasn’t fundamentally stack-oriented (well ok, there was that funny Lisp language in the exotic languages class). The 61A class video explained (with nice pictures) how the “stack frames” are instead “environments” that chain to each other (just like JavaScript objects chain via Prototypes). There is a global environment with the global vars, plus a new environment for each function (to hold params and local vars), and instead of a stack of frames on a hardware stack, it is a linked list of&amp;nbsp;environments&amp;nbsp;on the heap.&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;It probably also requires explaining right up front that unlike the Pascal, Ada, C, Java, etc languages (where functions are defined at COMPILE-TIME), JavaScript, Scheme, etc languages define functions at RUN-TIME. Because of this, there is always an "environment" that is active at the time of function creation/definition, namely, the call-stack that exists while the code creating a function is executed. [EXCEPT, of course that there is no stack... There is a great way to visualize how the stack is really a tree at&lt;/span&gt; &lt;a href="http://en.wikipedia.org/wiki/Spaghetti_stack"&gt;http://en.wikipedia.org/wiki/Spaghetti_stack&lt;/a&gt;].&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;A reference to this “current environment” chain is saved as a part of the function definition. In Java-like languages this makes no sense because there is no “current stack or environment” at compile time when the function was defined/compiled.&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;SO, when a function gets called, instead of “pushing” its params/local vars on top of THE stack, it “pushes” it on top of an environment chain that was saved with the function definition. And since it isn't a real (hardware) stack, but actually sitting in the heap, the function can refer to “local variables” of its “outer” function long after that outer function has returned.&lt;/span&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[JGP, pp.40-57]&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;b&gt;JavaScript is Scheme not Java&lt;/b&gt;. &amp;nbsp;Having accidentally watched the entire 61A course that teaches Scheme and functional programming (&lt;i&gt;mentioned above&lt;/i&gt;) before ever reading&amp;nbsp;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;JGP&lt;/span&gt;&lt;/b&gt;,&amp;nbsp;I&amp;nbsp;immediately&amp;nbsp;recognized the exotic techniques of&amp;nbsp;&lt;b&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;JGP&amp;nbsp;&lt;/span&gt;&lt;/b&gt;chapter 4 (&lt;i&gt;currying, etc&lt;/i&gt;) as paralleling the topics in 61A. &lt;span class="Apple-style-span" style="color: purple;"&gt;[BTW, I originally watched 61A because I wanted to learn about this &lt;i&gt;Hadoop&lt;/i&gt; buzzword I kept coming across in Job Ads. When I looked it up and saw that it had something to do with Map/Reduce (whatever that was), and that this iTunes class had a section on Map/Reduce, I tried to watch just those lessons. It soon became clear that I needed to start from the beginning of the course to learn Scheme itself.]&lt;/span&gt;&amp;nbsp;Learning the culture and toolkit of functional programming, which goes way beyond simply using function pointers or having functions be objects, I could see that the new style of programming JavaScript was not very strange Java, but fairly normal Scheme. &amp;nbsp;Back in 2005, I was aware of, but avoided, many of those alternate ways that JavaScript could be twisted to define classes, objects, functions, methods, inheritance, etc, BECAUSE, why would you want to make your &amp;nbsp;JavaScript code look so un-Java-like!?! If one embraces JavaScript as Scheme, it is not a weird syntax but simply a different programming paradigm: functional programming with lambdas and lexical scoping.&lt;br /&gt;&lt;br /&gt;One of the many differences between functional and non-functional programming is the&amp;nbsp;cognitive&amp;nbsp;"weight" of functions. &amp;nbsp;In Fortran thru Java (and JavaScript as I had been using it), methods and functions are fairly heavy weight things that get full blown API documentation (e.g. JavaDoc/jsDoc), and lots of whitespace around them, and are mostly not defined in a nested scope. &amp;nbsp;In functional programming, functions definitions are like water, and are created, used, and abandoned in as casual a fashion as Strings are in "normal" languages. Function definitions within function definitions in Scheme are as common as string concatenations in Basic. SO, one has to get over the feeling that it is expensive overkill to define a function just to wrap another function so that a one variable closure can be created.&lt;/li&gt;&lt;/ul&gt;[JGP] Crockford, Douglas. JavaScript: The Good Parts, O'Reilly, 2008&lt;br /&gt;[HPJ]&amp;nbsp;Zakas, Nicholas. High Performance JavaScript, O'Reilly, 2010&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-6293122602646879330?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/6293122602646879330/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=6293122602646879330' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/6293122602646879330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/6293122602646879330'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2011/01/javascript-surprising-parts.html' title='JavaScript: The Surprising Parts'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-858793998305885832</id><published>2011-01-08T17:01:00.001-05:00</published><updated>2011-02-25T11:22:44.746-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Gravey'/><title type='text'>Adding Cross-browser support to the Gravey Framework</title><content type='html'>In order to get back into the Web 2.0  development world, I have recently taken on the project of upgrading the  Gravey framework to run on browsers other than Internet Explorer. This post is a chronicle of what I encountered/learned getting its sample applications to also run on iPad 4.2, Safari 5.0, Chrome 8.0, Firefox 3.6, SeaMonkey 2.0, and IE 8.0 (while not breaking IE6 on Win2K). [&lt;i&gt;Note that the issues listed herein may have an IE-centric viewpoint, but it is only because the original code base naively used circa-2005 IE-only techniques, and therefore the news for Gravey is how everybody &lt;/i&gt;else &lt;i&gt;does it now.&lt;/i&gt;]&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;blockquote&gt;&lt;span style="color: #073763;"&gt;The Gravey framework (&lt;a href="http://gravey.org/"&gt;gravey.org&lt;/a&gt;) is a JavaScript-only set of code that supports building Rich-Internet-Apps (RIA) using AJAX where the logic completely resides in the browser. The server-side need only provide a REST-style API for data persistence (&lt;i&gt;which can be a simple as the file:: protocol accessing local xml files)&lt;/i&gt;. The framework includes GUI widgets, automated domain object persistence, in-browser XML/XSL processing, and &lt;/span&gt;&lt;b style="color: #073763;"&gt;complete undo/redo capability&lt;/b&gt;&lt;span style="color: #073763;"&gt;.&amp;nbsp; In short, it was intended to allow RIA development in the style of "fat GUI" development in Java without requiring any particular server side technology (e.g. J2EE, .Net, LAMP, whatever).&amp;nbsp; The new version 2.5 of Gravey now runs on several browsers (including Safari on the iPad) without requiring any particular client-side technology (e.g. jQuery, Prototype, whatever).&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;Because it was back in 2005, when I was learning DHTML/OO-JavaScript/AJAX/CSS/REST on the fly, while building Gravey for use in several internal applications for a top-5-in-the-USA bank, and because their requirements only mandated (and their schedule only allowed) Internet Explorer 5.5 as the target browser, Gravey v1.0/v2.0 required IE5+, and were only tested on IE5/IE6 in Win2K/WinXP.&lt;br /&gt;&lt;br /&gt;Since Gravey is built in &lt;a href="http://www.stevenblack.com/PTN-Layers.html"&gt; layers&lt;/a&gt;, I had originally intended to merely retrofit the bottom layer to use jQuery to make short work of cross-browser compatibility.&amp;nbsp; However, I immediately encountered enough problems with jQuery that I was required to really learn the issues anyway, and so I ultimately fixed all of the problems in Gravey directly, and as a result, it still has no dependence on any other frameworks.&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #20124d; text-align: center;"&gt;&lt;span style="font-size: large;"&gt;•&lt;/span&gt;&lt;span style="font-size: large;"&gt;•&lt;/span&gt;&lt;span style="font-size: large;"&gt;• AJAX / XML / XSL Issues &lt;/span&gt;&lt;span style="font-size: large;"&gt;•&lt;/span&gt;&lt;span style="font-size: large;"&gt;•&lt;/span&gt;&lt;span style="font-size: large;"&gt;•&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; jQuery doesn't cover in-browser XSL processing&lt;/b&gt;&lt;br /&gt;Gravey and its example apps use in-browser processing of the XML returned from AJAX calls via XSL (also loaded from the server).&amp;nbsp; It turns out that the XSL processing API is browser-specific, and because jQuery didn't handle it, I was going to have to learn how to fix it directly anyway...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; IE doesn't do XSL processing like everyone else&lt;/b&gt;&lt;br /&gt;In order to support older IE browsers, the existing Gravey code that uses ActiveX is required, but other browsers need to use the standard DOM APIs.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;IE really wants XSL files to be loaded via&amp;nbsp;&lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Msxml2.DOMDocument&lt;/span&gt;&lt;/b&gt; even though XML files can be loaded via&amp;nbsp;&lt;b style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Msxml2.XMLHTTP&lt;/b&gt;. So, once the XML DOM has been loaded via AJAX, the IE XSL processing looks like...&lt;/li&gt;&lt;/ul&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var xmlDom = &lt;/b&gt;&lt;b&gt;XHR.responseXML;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var xslDom = new ActiveXObject("Msxml2.DOMDocument");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; xslDom.async = false;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; xslDom.load( xslURL );&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (xslDom.parseError.errorCode != 0)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; alert("Error loading["+xslURL+"]:" + xmlDom.parseError.reason);&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; var resultStr = xmlDom.transformNode( xslDom );&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;The other browsers accomplish this via the standard API...&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var xmlDom&amp;nbsp; = &lt;/b&gt;&lt;b&gt;XHR1.responseXML;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var xslDom&amp;nbsp; = &lt;/b&gt;&lt;b&gt;XHR2.responseXML;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var xslProc = new XSLTProcessor();&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xslProc.importStylesheet( xslDOM );&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;var resultStr =&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;xslProc.transformToDocument( xmlDOM ).documentElement.textContent;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;BTW, when I used an XMLSerializer to generate the result string in the above code, it gave me quotes around the result, so using the &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; font-size: small;"&gt;.textContent&lt;/span&gt;&lt;/b&gt; was simpler and did not include extraneous quotes.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;IE also requires the XML file to be loaded via &lt;span style="font-size: small;"&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Msxml2.DOMDocument&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; when the files are local. In other words, when the .html page is loaded from local disk via the "file::" protocol instead of via "http::" from a web server, IE fails attempting to load the xml unless it is via &lt;b&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: small;"&gt;Msxml2.DOMDocument&lt;/span&gt;. &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;Otherwise, for local files, the AJAX callback will be given &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;readyState==4 &lt;/span&gt;&lt;/b&gt;and &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;status==0&lt;/span&gt;&lt;/b&gt;, instead of status==200. At this point in Firefox/others, the file has loaded ok, but in IE it will have failed.    &lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Issue:&amp;nbsp; Some browsers can't handle &amp;lt;xsl:import&amp;gt;&lt;/b&gt;&lt;br /&gt;While good ole IE6 can handle an XSL file including another one via the &lt;b&gt;&amp;lt;xsl:import&amp;gt;&lt;/b&gt; directive, new browsers like Safari and Chrome can't.&amp;nbsp; I never did find a reasonable fix, so I bit the bullet and just copied the imported XSL directly into the top level XSL file. Not pretty but it works.&amp;nbsp; If I had a larger system to worry about, I would preprocess, on the server side, the XSL file to include the imports before sending it back to the browser's AJAX request.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Firefox doesn't call your AJAX callback on synchronous requests&lt;/b&gt;&lt;br /&gt;Parts of Gravey performed AJAX requests with async=false with no problem until Firefox came along.&amp;nbsp; It turns out FF doesn't call your callback function like everyone else on synchronous requests. For a fix, I simply changed to async=true because I was already processing the responses via callback instead of inline code anyway! [ Back in 2005, I had thought that synchronous requests might be faster, or higher priority, than async requests, but experience has taught me otherwise.]&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size: large;"&gt;&lt;span style="color: #20124d;"&gt;••• DOM Issues •••&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;b&gt;Issue:&amp;nbsp; jQuery doesn't like funny characters in your element IDs.&lt;/b&gt;&lt;br /&gt;This  problem I ran into immediately because Gravey uses all sorts of special  characters (e.g. ".", "#", "_", ":", etc), and it took a while to track  down a fix.&amp;nbsp; By that time, I had taken to fixing Gravey directly.&amp;nbsp; But  there is a work-around...&lt;br /&gt;Given that ID="tar.foo.bar", replace the following...&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: small;"&gt;$(ID).&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: small;"&gt;whatever...&lt;/span&gt;&lt;br /&gt;with...&lt;br /&gt;&lt;span style="color: #274e13; font-size: x-small;"&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: small;"&gt;$( jq(ID) ).&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: small;"&gt;whatever...&lt;/span&gt;&lt;br /&gt;where...&lt;br /&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;b&gt;&lt;span style="font-size: x-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-size: small;"&gt;function jq(ID){ return '#' + ID.replace(/(:|\.)/g,'\\$1'); }&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;b&gt;Issue:&amp;nbsp; Only IE looks up Names as well as IDs in getElementById()&lt;/b&gt;&lt;br /&gt;Gravey originally created HMTL elements identified by the "name" attribute because it worked just fine in IE when doing &lt;span style="font-size: small;"&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;document.getElementById("foo")&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;.&amp;nbsp; Other browsers don't, SO, I changed all those .name references to .id references.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; innerHTML doesn't equal what it was just set to&lt;/b&gt;&lt;br /&gt;Early on, I came across speculation that browser security might strip away inline JavaScript when setting the .innerHTML of some element. Being paranoid, I put in code to check if the .innerHTML I just set, was different than what I just set it to. To my surprise, it was quite often literally different, but not functionally different. In other words, the before and after strings did not match because the quotes might have been changed, the attributes might be in different orders, and the upper/lowercase of the tags might have been switched.&amp;nbsp; I never caught browser security stripping off anything, but the .toString() of the innerHTML could be completely reworked compared to my original HTML string.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Saving data between page loads in window or navigator properties is no longer reliable&lt;/b&gt;&lt;br /&gt;In the olden days of IE6 on Win2K, one could create properties on the navigator object that would allow communications between page loads.&amp;nbsp; With modern browsers this isn't reliable.&amp;nbsp; Gravey used this ability to save a reference to data between the time an AJAX request was made and when the callback was later invoked on the reply event. Luckily, I was only doing this because I didn't understand JavaScript "closures" enough to use one instead.&amp;nbsp; The Gravey 2.5 code uses a closure to save data in the callback function to be accessed when that function is later invoked on the reply event.&lt;br /&gt;&lt;br /&gt;If I really needed client-side storage of data in between page loads or between pages, I would hope to wait until the near future when HTML5 is supposed to have local storage to share fat data between pages. There is an &lt;a href="http://www.javaworld.com/community/?q=node/6768"&gt;article here&lt;/a&gt; that tests this new feature out on a the usual suspect browsers.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Some browsers change the placement of span and legend tags&lt;/b&gt;&lt;br /&gt;In tracking down all the event handling problems, I came across a bug in some browsers (e.g. Firefox/Safari/SeaMonkey, but not Chrome/IE) where I created a &amp;lt;legend&amp;gt; tag inside of a &amp;lt;span&amp;gt; tag (via setting innerHTML), but in Firefox (via Firebug) I could see that it put the legend outside and after the span!&amp;nbsp; Luckily, I could live with the &amp;lt;span&amp;gt; being &lt;i&gt;inside&lt;/i&gt; of the &amp;lt;legend&amp;gt;, and all the browsers seem to handle that ok.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; IE8 changes behavior depending on where a page is served up from&lt;/b&gt;&lt;br /&gt;I was trying to use a simple trick to determine if the browser is IE (and which version of IE) via conditional compilation as shown &lt;a href="http://www.quirksmode.org/css/condcom.html"&gt;here at quirksmode.org&lt;/a&gt;. Unfortunately, IE8 on WinXP would compile the comments and define the flags when the page was loaded from my test server on my LAN.&amp;nbsp; The exact same code would NOT compile when served up from my Internet web site.&amp;nbsp; Go figure. I tried adding a DOCTYPE to invoke quirks mode (which I had not specified before), but that made no difference. I wound up using the code below to distinguish between the cases that I needed to determine: pre-IE7, IE-in-general, IE-style-AJAX, Firefox-style-AJAX.&lt;br /&gt;In the home web page...&lt;br /&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;!--[if lte IE 6]&amp;gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;script type="text/javascript"&amp;gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //NOTE: THIS LOOKS COMMENTED OUT BUT IT IS ACTIVE IN IE !!!&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var Pre7IE = true;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/script&amp;gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;![endif]--&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;In the javascript...&lt;br /&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; function IE_Pre7()&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;{ return &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;(typeof(Pre7IE)=="undefined") ? false : Pre7IE;&lt;/span&gt; }&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; function FF_AJAX()&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;{ return &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;document.implementation&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; &lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt; &amp;amp;&amp;amp; &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;document.implementation.createDocument&lt;/span&gt;; }&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; function IE_AJAX()&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;{ return IE_Pre7() || !FF_AJAX(); }&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; function Is_IE&amp;nbsp;     ()&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;{ return '\v'=='v'; }&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #20124d; text-align: center;"&gt;&lt;span style="font-size: large;"&gt;••• Display and Styling Issues &lt;/span&gt;&lt;span style="font-size: large;"&gt;•••&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Handling of partial escape sequences is browser-specific &lt;/b&gt;&lt;br /&gt;A bug in Gravey went undetected because IE quietly ignored partial escape sequences like "&amp;amp;nb". The bug generated partial escape sequences in element text (e.g. &lt;span style="color: #274e13; font-size: small;"&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;lt;div&amp;gt;foo&amp;amp;nb&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;) and browsers like Safari and IE quietly display "foo".&amp;nbsp; Other browsers like Firefox and Chrome display "foo&amp;amp;nb". I fixed the bug so that only full sequences like "&amp;amp;nbsp;" would be generated.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Special character escape sequences are browser and OS-specific &lt;/b&gt;&lt;br /&gt;Originally, Gravey used special characters via the Microsoft "symbol" font, so I had a goal to replace them with standard HTML characters. &lt;span style="font-size: small;"&gt;E.G. replace...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;span style="font-size: small;"&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; '&amp;lt;font face="Symbol"&amp;gt;&amp;amp;#101;&amp;lt;/font&amp;gt;'&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;with...&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; "&amp;amp;epsilon;"&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The set of graphic characters like arrows, and bullets, and greek letters, etc can not be all rendered by all browsers.&amp;nbsp; Unfortunately, the intuitive idea that if an older browser can render a character, its newer brethren would also, is alas not true.&amp;nbsp; Most browsers, including IE6 on Win2000, can render the black star (&lt;b&gt;&amp;amp;#9734;&lt;/b&gt;) and white star (&lt;b&gt;&amp;amp;#9733;&lt;/b&gt;) characters, but IE8 on WinXP can't!&amp;nbsp; Some characters can be displayed when given the hex charcode, but not the name (e.g. &lt;b&gt;&amp;amp;rArr;&lt;/b&gt;). And some characters that you would think are part of a set are not all implemented together. E.G. Of the up/down/right/left arrow set (see &lt;a href="http://www.alanwood.net/unicode/geometric_shapes.html"&gt;shapes&lt;/a&gt;), IE6 can render the right arrow but not the down arrow.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Fieldset Legend rendering is browser-specific &lt;/b&gt;&lt;br /&gt;Given the same style settings, the Legends of Fieldsets render differently on different browsers. Gravey had used the attribute "text-align:center" which didn't do anything on IE, but it shifts the entire legend display to the center (instead of the left that I want) on non-IE browsers. I removed the attribute. Unfortunately, the "vertical-align: middle" attribute DOES do something I want in IE but not the other browsers.&amp;nbsp; It was needed to get the gif images (being used for expanded/collapsed icons) to line up with the title text inside the legend box.&amp;nbsp; After a lot of fiddling with transparent pixels around the icons and legend padding attributes, I gave up and switched to graphic arrow characters (ala Google results).&amp;nbsp; Unfortunately, I ran into all of the special character problems listed earlier, and still had to specify a different set of characters (&lt;a href="http://www.alanwood.net/demos/wingdings.html"&gt;wingdings&lt;/a&gt;) for IE6 than specified for the other browsers.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; CSS doesn't easily replace all HTML presentational attributes &lt;/b&gt;&lt;br /&gt;While the original Gravey used some external CSS, there was still a lot  of inline style specs, and old-time HTML presentational markup and  "spacer" gifs. I set out to replace them all with CSS, but since I was using IE specific attributes like cellspacing, cellpadding, bordercolordark and bordercolorlight it was not trivial. Sadly, some IE attributes like table "cellspacing" can't be replaced with CSS. Others like cellpadding, bordercolordark and bordercolorlight can but with great effort. Luckily, Gravey used a cellspacing and cellpadding of zero, some of which can be specified with "border-collapse:collapse". Also, the bordercolorlight/dark colors being used created an effect similar to { border-style: outset }.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Background color gradients are browser-specific &lt;/b&gt;&lt;br /&gt;The gradient coloring Gravey used was IE specific.  Other browser specific style settings had to be added. E.G. the following...&lt;br /&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;body {&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;filter:progid:DXImageTransform.Microsoft.Gradient &lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;     &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;(GradientType=0,StartColorStr='#f8f8f8',EndColorStr='#802222');&lt;/span&gt; &lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;gets replaced with...&lt;b style="color: #274e13;"&gt;&lt;span style="font-size: x-small;"&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;body {&lt;/span&gt;&lt;/span&gt;&lt;br style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;  background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#802222));&lt;/span&gt;&lt;/span&gt;&lt;br style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;background: -moz-linear-gradient(top, #f8f8f8, #802222) no-repeat;&lt;/span&gt;&lt;/span&gt;&lt;br style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;   &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;filter:progid:DXImageTransform.Microsoft.Gradient &lt;/span&gt;&lt;/span&gt;&lt;br style="color: #274e13; font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;" /&gt;&lt;span style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;    &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;(GradientType=0,StartColorStr='#f8f8f8',EndColorStr='#802222');&lt;/span&gt; &lt;/span&gt;&lt;br style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Tooltip rendering is browser-specific &lt;/b&gt;&lt;br /&gt;Tooltips are used extensively by Gravey, and for images it used the .alt text. It turns out that non-IE browsers don't render image &lt;b&gt;.alt&lt;/b&gt; text, only &lt;b&gt;.title&lt;/b&gt; text, so I changed all the alts to titles.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;There is also a known bug in Firefox where tooltips are not displayed on disabled buttons. As a workaround, the "readOnly" attribute can be used, however, when setting the readonly attribute rather than the disabled attribute, I could never get the CSS styling to kick in, even though I tried the selectors ".fooClass[readonly]" and "input[readonly]" and "input:read-only". So, I wound up dynamically setting (via JavaScript) the style for both readonly/not-readonly &lt;b&gt;&lt;i&gt;explicitly&lt;/i&gt;&lt;/b&gt; via classnames (ala .foo and .fooRO).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Cursor styles are browser-specific &lt;/b&gt;&lt;br /&gt;Gravey extensively used the "hand" and "not-allowed" cursor shapes which turn out to be IE-specific.&amp;nbsp; The "hand" cursor can be changed to the standard "pointer" to get the same effect. But while many browsers implement the non-standard "not-allowed", Firefox on the Mac does not and has no real equivalent. Because there is a visual difference between the default cursor and the "pointer" on Firefox, I live with it as is.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Disabled button styles are browser-specific &lt;/b&gt;&lt;br /&gt;Gravey expects the rendering of GUI widgets to reflect their enabled/disabled status. Some browsers stop showing disabled buttons differently if their foreground color is set to black (as Gravey was doing and IE not caring).&amp;nbsp; I was able to simply stop setting the foreground color since black was the default color anyway).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Chrome displays popup menu items in a strange order &lt;/b&gt;&lt;br /&gt;There is a strange (but known?) bug in Chrome where it displays items in a pop-up menu in a weird order that is different than the order shown in all the other browsers. I give up and document it as a known Chrome bug.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Cross-browser manipulation of element visibility is complicated &lt;/b&gt;&lt;br /&gt;Gravey originally got away with making chunks of HTML visible or not via...&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; e.style.visibility = visibleFlag ? "visible"&amp;nbsp; : "hidden";&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;e.style.position&amp;nbsp;&amp;nbsp; = visibleFlag ? "relative" : "absolute";&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;e.style.display&amp;nbsp;&amp;nbsp;&amp;nbsp; = visibleFlag ? "inline"&amp;nbsp;&amp;nbsp; : "none";&lt;/b&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;However, to do this with other browsers the original visible state needs to be saved and reused later when restoring visibility.&amp;nbsp; Code like the following is needed...&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (visibleFlag) showElem(e); else hideElem(e);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;function hideElem( e )&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; if ( e.style.display === "none" ) return;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; e.oldDisplay = e.style.display;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; e.style.display = "none";&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; e.style.visibility = "hidden";&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;function showElem( e )&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; e.style.visibility = "visible";&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; if ( e.oldDisplay ) e.style.display = e.oldDisplay;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; else if ( e.style.display==="none") e.style.display = "";&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;Also, some browsers have a problem unless the HTML is rendered visible before making it hidden.&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Pop-up windows are no longer reliable &lt;/b&gt;&lt;br /&gt;In the early IE5 days, the cursor would not reliably change to the "please wait" icon when told to, so as a workaround, Gravey used a little "please wait" popup window that was launched and later killed.&amp;nbsp; Unfortunately, modern browsers suppress popup windows, so, that code won't reliably work anymore. If the cursor STILL can not be reliably set in this modern age, then a replacement "please wait" popup window would have to be done via fancy CSS floating DIVs as I've seen elsewhere.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span style="color: #20124d; font-size: large;"&gt;••• Event Handling Issues &lt;/span&gt;&lt;span style="color: #20124d; font-size: large;"&gt;•••&lt;/span&gt;&lt;b&gt; &lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Issue:&amp;nbsp; Event object location is&lt;/b&gt;&lt;b&gt; browser-specific &lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;In IE, the event object may be accessed in event handler functions by the global variable "event". Most other browsers pass the event object as a parameter to the event handler function and it is not available as a global variable.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;ul&gt;&lt;li&gt;Thus, code like the following...&lt;b&gt;&lt;br /&gt;&lt;span style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;lt;body onKeyPress="onKey()"&amp;gt;&lt;br /&gt;...&lt;br /&gt;function onKey(){ alert(event...); }&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/b&gt;must be changed to...&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/b&gt;&lt;b&gt;script&amp;gt;&lt;/b&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; document.onkeypress = onKey;&lt;/b&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/b&gt;&lt;b&gt;function onKey(e){ e = e || window.event; alert(e...); }&lt;/b&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp; &amp;lt;/script&amp;gt;&lt;/b&gt;&amp;nbsp;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;ul&gt;&lt;li&gt; Another consequence of event handlers being passed the event as a parameter is that the calling signature has to be changed when passing your own parameters to the event handler. Even if you don't care about the event arg itself, the other parameters need to be shifted down otherwise the formal parameter list won't match the actual parameter list. For example, Gravey generates new HTML elements by building a string and setting the innerHTML.&lt;br /&gt;So, change code like this...&lt;br /&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; e.innerHTML = "&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;&amp;lt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;select onchange='return foo("+myArg+")'&lt;/b&gt;&lt;b style="color: #274e13; font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;&amp;gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;"&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;function foo( myArg ){ alert(myArg); }&lt;/b&gt;&lt;br /&gt;to this...&lt;br /&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; e.innerHTML = "&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;&amp;lt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;select onchange='return foo(event,"+myArg+")'&lt;/b&gt;&lt;b style="color: #274e13; font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;&amp;gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;"&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;...&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;function foo( e, myArg )&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;{ alert(myArg); }&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Issue:  Not all body tag event handlers are attached to the "window" object&lt;/b&gt;&lt;/div&gt;&lt;b&gt; &lt;/b&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;div style="text-align: left;"&gt;When moving the specification of event handlers from inline in the &amp;lt;body&amp;gt; tag to being set in JavaScript, one might think that they all go on the window event, but not so.&amp;nbsp; Thus, this tag...&lt;/div&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;&amp;lt;body onKeyPress="onKey()" onBeforeUnload="onBUL()" onLoad="onLoad()"&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;gets replaced with...&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;script&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; document.onkeypress&amp;nbsp;&amp;nbsp; = onKey;&lt;/b&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; window.onbeforeunload = onBUL;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; window.onload&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; = onLoad;&lt;/b&gt;&lt;/div&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;/script&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;/b&gt; &lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Issue:&amp;nbsp; Keyboard event objects are browser-specific&lt;/b&gt;&lt;b&gt; &lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;In keyboard-related events, some browsers supply the key pressed via the event's "keyCode" attribute, whereas others via the "which" attribute.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;ul&gt;&lt;li&gt;Thus code that reads keys...&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;function onKeyPress(){ alert( event.keyCode ); }&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;must be changed to...&lt;br /&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;function onKeyPress( e )&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;{&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; e = e || window.event;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var code = e.keyCode || e.which;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;alert( code );&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&amp;nbsp; }&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&amp;nbsp;     &lt;/b&gt;&lt;/li&gt;&lt;li&gt;Thus code that sets keys (like keystroke filtering)...&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; event.keyCode = char;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;must be changed to...&lt;br /&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; &lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;e = e || window.event;&lt;/b&gt;&lt;br /&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; if (e.keyCode) e.keyCode = char; else e.which = char;&lt;br /&gt;&amp;nbsp;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;Secondarily, some browsers supply a code that directly reflects the use of control keys, etc, whereas others supply a code for the basic key and require also looking at other attributes that flag the use of any modifier keys.&amp;nbsp; Thus, to detect a &lt;b&gt;control-z&lt;/b&gt; key, the following...&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&amp;nbsp; function onKeyPress(){ if ( event.keyCode==26 ) ... }&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;must be changed to...&lt;br /&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; &lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;function onKeyPress( e )&lt;/b&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;{&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp; e = e || window.event;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var code = e.keyCode || e.which;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ( code==26 || code==122 &amp;amp;&amp;amp; e.ctrlKey ) ...&lt;/span&gt;&lt;/b&gt;&lt;b style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&amp;nbsp; } &lt;/b&gt;&lt;span style="font-family: Times,&amp;quot;Times New Roman&amp;quot;,serif;"&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;Even then, &lt;b&gt;Chrome on the Mac will not generate an event at all when control-y is pressed&lt;/b&gt;, even though control-z works fine.&amp;nbsp; So, after not finding any info about this Chrome quirk, I gave up and documented the use of &lt;i&gt;shift&lt;/i&gt;-control-y as a workaround.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Modifier keys on mouse click are browser-specific &lt;/b&gt;&lt;br /&gt;Gravey and its example apps use "control-clicks" (ie. holding down the control key while clicking) in several places. Unfortunately, on the Mac, control-click activates the context menu (ala back-click). So, for it, allow the "command" key to be used as an alternate. Unfortunately, the DOM3 standard indicator for this key is the &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;event.metaKey&lt;/span&gt;&lt;/b&gt; flag and Internet Exploder does not even implement that attribute, so references to it will be &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;undefined&lt;/span&gt;&lt;/b&gt;. So, this code...&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; function onClick(){&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;var specialFlag = event.ctrlKey;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; }&lt;/span&gt;&lt;/b&gt; &lt;/div&gt;&lt;div style="text-align: left;"&gt;has to be changed to...&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b style="color: #274e13;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; function onClick(e){&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;   &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; e = e || window.event;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;   &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var cmdKey = (typeof e.metaKey=="undefined") ? false : e.metaKey;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;   &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var specialFlag = e.ctrlKey || cmdKey;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;   &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; }&lt;/span&gt;&lt;/b&gt; &lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;b&gt;Issue:&amp;nbsp; Some "are you sure you want to leave?" techniques are browser-specific &lt;/b&gt;&lt;br /&gt;In order to ask if the user really wants to leave the web page, only some browsers recognize setting the event object's "returnValue" attribute to the desired message.&amp;nbsp; However all browsers tested (except for a known bug on the iPad) will recognize returning the string message from the onbeforeunload event handler.&amp;nbsp; Thus, code like this...&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; function onBeforeUnLoad(){&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; if (unsavedData) event.returnValue = "Are you sure?";&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;gets replaced with code like this...&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; function onBeforeUnLoad(){&lt;/b&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; if (unsavedData)&lt;/b&gt;&lt;b&gt; return "Are you sure?";&lt;/b&gt;&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;b&gt;Issue: Getting a reference to the event's target element is browser-specific&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;For example, to blur the element that is the target of a keyboard event, the original code...&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; event.srcElement.blur();&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;has to be changed to (according to &lt;a href="http://www.quirksmode.org/js/events_properties.html"&gt;here in quirksmode.org&lt;/a&gt;)...&lt;/div&gt;&lt;div style="color: #274e13; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace; text-align: left;"&gt;&lt;b&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; var targ = e.target || e.srcElement;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (targ.nodeType == 3) // defeat Safari bug&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; targ = targ.parentNode;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; targ.blur();&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;b&gt;Issue:&amp;nbsp; Focus and Blur and Change events are browser-specific&lt;/b&gt;&lt;br /&gt;There is a &lt;a href="http://www.quirksmode.org/dom/events/blurfocus.html"&gt;known problem&lt;/a&gt;: "Safari and Chrome do not fire focus/blur events when the user uses the mouse to access checkboxes, radios or buttons. Text fields, textareas and select boxes work correctly."&lt;br /&gt;Hmmm...this is difficult because the entire architecture of Gravey is based on blur events triggering datamodel updates. Lets see if I can fake it for the offending browsers with the change event (but only the offending ones since onchange is apparently buggy on IE).&amp;nbsp; Actually because of what I am doing on blur is idempotent, I can just make both onchange and onblur invoke the same event handler (and also because of idempotency I dont have to worry about the unpredictable ordering of blur and change events in different browsers).&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-858793998305885832?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://gravey.org/' title='Adding Cross-browser support to the Gravey Framework'/><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/858793998305885832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=858793998305885832' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/858793998305885832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/858793998305885832'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2011/01/adding-cross-browser-support-to-gravey.html' title='Adding Cross-browser support to the Gravey Framework'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-8992434934617002750</id><published>2010-08-28T16:52:00.004-04:00</published><updated>2011-05-01T13:27:47.808-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Neural Nets, Vagueness, and Mob Behavior</title><content type='html'>&lt;i&gt;In response to the following question on a philosophy discussion board, I replied with the short essay below and reproduce it here. &lt;/i&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: #990000;"&gt;"It was then that it became apparent to me that these dilemmas – and indeed, many others – are manifestations of a more general problem that affects certain kinds of decision-making. They are all instances of the so-called ‘Sorites’ problem, or ‘the problem of the heap’. The problem is this: if you have a heap of pebbles, and you start removing pebbles one at a time, exactly at what point does the heap cease to be a heap?"&lt;/span&gt;&lt;/blockquote&gt;VAGUE CONCEPTS&lt;br /&gt;This leads to the entire philosophy of "vagueness". i.e. are there yes/no questions that don't have a yes/no answer? Are some things like baldness vague in essence, or, is our knowledge merely incomplete? e.g. we don't know the exact number of hairs on your head, and/or, we don't know/agree on the exact number of hairs that constitutes the "bald" / "not bald" boundary?&lt;br /&gt;&lt;br /&gt;NEURAL NETS&lt;br /&gt;My personal conclusion is that there ARE many vague concepts that we have created that are tied to the way our brains learn patterns (and, as a side effect, how we put things into categories). In contrast to rational thought (i.e. being able to demonstrate logically step by step our conclusions), we "perceive" (ala Locke/Hume/Kant) many things without being able to really explain how we did it.&lt;br /&gt;&lt;br /&gt;In Artificial Intelligence, there are "neural network" computer programs that simulate this brain-neuron style of learning. They are the programs that learn how to recognize all different variations of a hand-written letter "A" for example. They do not accumulate a list of shapes that are definitely (or are definitely not) an "A", but rather develop a "feel" for "A"-ness with very vague boundaries. They (like our brains) grade a letter as being more or less A-like. It turns out that this technique works much better than attempting to make rational true/false rules to decide. This is the situation that motivates "fuzzy logic" where instead of just true or false answers (encoded as 1 or 0), one can have any number in-between, e.g. 0.38742 (i.e. 38.7% likely to be true).&lt;br /&gt;&lt;br /&gt;WISDOM OF THE CROWD?&lt;br /&gt;Because each person has their own individually-trained "neural net" for a particular perception (e.g. baldness, redness, how many beans are in that jar?), we each come up with a different answer when asked about it. However, the answers do cluster (in a bell-curve-like fashion) around the correct answer for things like "how many beans".&amp;nbsp; This is &lt;a href="http://en.wikipedia.org/wiki/The_Wisdom_of_Crowds"&gt;what led Galton to originally think that there was "wisdom in the crowd"&lt;/a&gt;.&amp;nbsp; This idea has been hailed as one of the inspirations for the new World Wide Web (aka Web 2.0). The old idea was that McDonalds should ask you if "you want fries with that?" to spur sales. The new Web 2.0 idea is that Amazon should ask you if you want this OTHER book based on what other people bought when they bought the book you are about to buy. I.E. the crowd of Amazon customers know what to ask you better than Amazon itself.&lt;br /&gt;&lt;br /&gt;The problem is that there are many failures of "crowd wisdom" (as mentioned in that Wikipedia page in the link above). My conclusion is that most people advocating crowd wisdom have not realized that it is limited to "perceptions". Many Web 2.0 sites are asking the crowd instead about rational judgments, expecting them to come up with a better answer than individuals. The idea of democracy (i.e. giving you the right to vote) has been confused with voting guaranteeing the best answer, no matter the question. In fact, Kierkegaard wrote "&lt;a href="http://oregonstate.edu/instruct/phl201/modules/Philosophers/Kierkegaard/kierkegaard_the_crowd_is_untruth.html"&gt;Against The Crowd&lt;/a&gt;" almost 200 years ago where he recognized that individuals act like witnesses to an event, whereas people speaking to (or as a part of) a crowd, speak what we would now call "&lt;a href="http://en.wikipedia.org/wiki/Bullshit#Distinguished_from_lying"&gt;bullshit&lt;/a&gt;" because they are self-consciously part of a crowd. We can see this in the different results of an election primary (a collection of individuals in private voting booths) versus Caucuses where people vote in front of each other.&amp;nbsp; So, Web 2.0 sites (Facebook, MySpace, blog Tag Clouds, etc) that allow people to see the effect on other people of what they are saying, are chronicling mob mentality rather than collecting reliable witness reports.&lt;br /&gt;&lt;br /&gt;BTW, I have written several blog posts related to vagueness, for example:&lt;br /&gt;&lt;a href="http://existentialprogramming.blogspot.com/2010/03/model-entities-not-just-their-parts.html"&gt;http://existentialprogramming.blogspot.com/2010/03/model-entities-not-just-their-parts.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-8992434934617002750?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/8992434934617002750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=8992434934617002750' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/8992434934617002750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/8992434934617002750'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2010/08/in-response-to-comment-on-my-philosophy.html' title='Neural Nets, Vagueness, and Mob Behavior'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-6971611326858482970</id><published>2010-06-09T15:41:00.000-04:00</published><updated>2010-12-28T18:54:46.316-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Fuzzy Unit Testing, Performance Unit Testing</title><content type='html'>In reading Philosophy 101, about Truth with a capital "T", and the  non-traditional logics that use new notions of truth, we of course  arrive at Fuzzy Logic with its departure from simple binary true/false  values, and embrace of an arbitrarily wide range of values in between.&lt;br /&gt;&lt;br /&gt;Contemplating  this gave me a small AHA moment: Unit Testing is an area where there is  an implicit assumption that "Test Passes" has either a true or false  value.&amp;nbsp; How about Fuzzy Unit Testing where there is some numeric value  in the 0...1 range which reports a degree of pass/fail-ness? i.e. a &lt;i&gt;percentage  pass/fail&lt;/i&gt; for each test.&amp;nbsp; For example, testing algorithms that  predict something could be given a percentage pass/fail based on how  well the prediction matched the actual value.&amp;nbsp; Stock market predictions,  bank customer credit default prediction, etc come to mind.&amp;nbsp; This sort  of testing of predictions about future defaults (&lt;i&gt;i.e. credit grades&lt;/i&gt;)  is just the sort of thing that the BASEL II accords are forcing banks  to start doing.&lt;br /&gt;&lt;br /&gt;Another great idea (&lt;i&gt;if I do say so  myself&lt;/i&gt;) that I had a few years ago was the notion that there is  extra meta-data that could/should be gathered as a part of running unit  test suites; specifically, the performance characteristics of each test  run.&amp;nbsp; &lt;b&gt;The fact that a test still passes, but is 10 times slower than  the previous test run, is a very important piece of information that we  don't usually get.&lt;/b&gt;&amp;nbsp; Archiving and reporting on this meta-data about  each test run can give very interesting metrics on how the code changes  are improving/degrading performance on various application  features/behavior over time.&amp;nbsp; I can now see that this comparative  performance data would be a form of fuzzy testing.&lt;br /&gt;&lt;br /&gt;&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=existenprogra-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=1584885262&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=existenprogra-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=B00186Z0L4&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=existenprogra-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=1932394850&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=existenprogra-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=1933988274&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&lt;/iframe&gt;&lt;iframe align="left" frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://rcm.amazon.com/e/cm?t=existenprogra-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=0974514012&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr" style="height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;"&gt;&amp;lt;br&amp;gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-6971611326858482970?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://existentialprogramming.blogspot.com/2007/08/fuzzy-unit-testing-performance-unit.html' title='Fuzzy Unit Testing, Performance Unit Testing'/><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/6971611326858482970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=6971611326858482970' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/6971611326858482970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/6971611326858482970'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2010/06/fuzzy-unit-testing-performance-unit.html' title='Fuzzy Unit Testing, Performance Unit Testing'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-1766671199977073424</id><published>2010-04-08T11:40:00.001-04:00</published><updated>2011-05-01T13:20:32.091-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Too cool for school (or, history anyway)</title><content type='html'>&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;There has been a flurry of articles and blog posts in reaction to Oracle's Jeet Kaul who, at EclipseCon 2010, said "We need to get the younger generation interested and excited [about  Java] just like I was" and "I would like to see people with piercings doing Java programming".&amp;nbsp; There have been some exchanges over "cool" languages and whether "cool" is a good thing.&amp;nbsp; I contributed the following 2-cents on a JavaWorld discussion...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;"Cool" led to most computer security problems in the world today&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I have been around long enough to have seen several generations of "cool" languages overtaking established ones.&amp;nbsp; Unfortunately, the new language was sometimes a big step backward.&lt;br /&gt;&lt;br /&gt;A case in point was when C swept the world, replacing the line of languages like &lt;a href="http://en.wikipedia.org/wiki/Pascal_%28programming_language%29"&gt;Pascal&lt;/a&gt; and the stillborn &lt;a href="http://en.wikipedia.org/wiki/Ada_%28programming_language%29"&gt;Ada&lt;/a&gt;.&amp;nbsp; Because Unix was starting to get out of the lab and into microcomputers, &lt;a href="http://en.wikipedia.org/wiki/C_%28programming_language%29"&gt;C&lt;/a&gt; gained visibility.&lt;br /&gt;&lt;br /&gt;BIG PROBLEM: Pascal (and others) could tell how big an array was, and hence could stop execution when someone attempted to write past the end.&amp;nbsp; C was unable to do this (and because of the language design there was no way to "fix it" in the compiler).&amp;nbsp; This is the &lt;a href="http://www.windowsecurity.com/articles/Analysis_of_Buffer_Overflow_Attacks.html"&gt;security hole&lt;/a&gt; that is at the root of all computer virus exploits.&lt;br /&gt;&lt;br /&gt;If developers chose new languages (or &lt;a href="http://www.youtube.com/watch?v=6TWhtCavxsQ"&gt;systems&lt;/a&gt;) based on technical merit rather than "cool", we would be decades ahead of where we are today.&lt;br /&gt;&lt;br /&gt;As a side note/rant: I have always thought that "cool" was effected by political zeitgeist.&amp;nbsp; It seems more than coincidence that European/Govt-regulated/strong-typing languages (e.g. Pascal/Ada) were replaced by get-the-compiler-regulation-off-the-programmers-back ethic of C at the same time Ronald Reagan was selling everyone on the same notion about government.&amp;nbsp; Let the programmer do dangerous things (like &lt;a href="http://en.wikipedia.org/wiki/C_%28programming_language%29#Array-pointer_interchangeability"&gt;convert an array into a pointer&lt;/a&gt;) because he knows better...(sounds like let the bankers do whatever they want because they know better than the regulators who after all only learn from past mistakes...wimps!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-1766671199977073424?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/1766671199977073424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=1766671199977073424' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/1766671199977073424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/1766671199977073424'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2010/04/too-cool-for-school-or-history-anyway.html' title='Too cool for school (or, history anyway)'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-7510795578782528688</id><published>2010-03-30T17:45:00.001-04:00</published><updated>2010-12-28T18:54:46.317-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Moore's Paradox. I'm just saying!</title><content type='html'>The popular phrase "I'm just saying" has been around long enough for most people to have heard it, but not long enough for it to be well-documented as to where it originated.&amp;nbsp; I heard a great stand up comic bit about it in the 1980's by Paul Reiser. There are several blog sites that muse over its origin and solicit theories:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://prestwickhouse.blogspot.com/2010/01/plain-english-im-just-sayin.html"&gt;http://prestwickhouse.blogspot.com/2010/01/plain-english-im-just-sayin.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://painintheenglish.com/?p=958"&gt;http://painintheenglish.com/?p=958&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.urbandictionary.com/define.php?term=i%27m%20just%20sayin%27"&gt;http://www.urbandictionary.com/define.php?term=i%27m%20just%20sayin%27&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;It turns out that the most common definition of the phrase exhibits a logical paradox from Philosophy.&amp;nbsp; The book "this sentence is false" is a collection of philosophical paradoxes, and it describes Moore's Paradox (as developed by &lt;a href="http://en.wikipedia.org/wiki/G._E._Moore"&gt;G.E. Moore&lt;/a&gt;).&amp;nbsp; I summarize it as follows: &lt;br /&gt;&lt;blockquote&gt;Normally, everything that can be said about the world can be said by anyone. I can say the moon is made of green cheese, and you can say it.&amp;nbsp; The state of the world described by me can equally be described by you with no logical paradox...EXCEPT... I can say that the moon is made of green cheese, and I can say that you do not believe that the moon is made of green cheese, but YOU can not say the same thing.&amp;nbsp; I.E. you can not say that X is true and at the same time say that you do not believe that X is true.&amp;nbsp; Note that you are not saying that you could be wrong in your belief, you are be saying that you believe both that X is, and is not, true at the same time. A logical contradiction.&lt;/blockquote&gt;However, whenever you use the phrase "I'm just saying!", you are in effect performing Moore's paradox.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-7510795578782528688?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/7510795578782528688/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=7510795578782528688' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/7510795578782528688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/7510795578782528688'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2010/03/moores-paradox-im-just-saying.html' title='Moore&apos;s Paradox. I&apos;m just saying!'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-147722766053274681</id><published>2008-12-18T14:21:00.009-05:00</published><updated>2010-12-28T18:54:46.318-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Where Am I?</title><content type='html'>&lt;span class="Apple-style-span"  style="font-size:small;"&gt;In &lt;/span&gt;&lt;a href="http://www.amazon.com/Am-Strange-Loop-Douglas-Hofstadter/dp/0465030785/"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;I am a Strange Loop&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[1]&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;, Doug Hofstadter ponders where one's "self" is located while being mentally absorbed by a situation that is located in a different place than one's body is currently residing. A simple example being that of reading Jane Austin while sitting in a chair. Another example being remote-controlling a robot on the moon. He asks the question "Where Am *I*" (where "I" is his shorthand for soul/self/consciousness).&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;It reminded me of my very first days exploring the World Wide Web in 1994.  I explained to my family, as I gave them a guided tour of my new toy "Netscape", that we could "visit" places all around the world!  Look, here we go to the South Pole&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[2]&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; or Australia&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;[3]&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;!  Because in those early days, the web server and the content were actually physically in those places, and because the browser was hardly more than a remote terminal program, it really was like remote logging in to computers around the world, which felt very much like being there. That made switching from one site to another feel like teleporting instantly from one continent to another.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;These days, the content about a place, versus the server serving the content, versus the location of the many cached copies (e.g. Akamai), and so forth have blurred "where am I" so much as to be meaningless and not even contemplated anymore.  But in the early days, there was a real sense of "I am in Antarctica now!".&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;[1] "I am a Strange Loop",2007, Hofstadter, Basic Books&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="  white-space: pre; "&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;http://www.kinderwijs.nl/artikelen.asp?postid=18&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;8&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="white-space: pre;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;[2] http://www.usap.gov/videoClipsAndMaps/spwebcam.cfm&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;[3] http://www.radioaustralia.net.au/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-147722766053274681?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/147722766053274681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=147722766053274681' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/147722766053274681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/147722766053274681'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2008/12/where-am-i.html' title='Where Am I?'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-2313698930945328388</id><published>2008-01-05T11:21:00.001-05:00</published><updated>2010-12-28T18:54:46.319-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Shakespeare is (not) Shakespeare</title><content type='html'>&lt;span style="color: rgb(0, 102, 0);font-size:100%;" &gt;&lt;span style="font-style: italic;"&gt;[Ed. Note. This is part two of a series found on "Existential Programming, the blog": "&lt;/span&gt;&lt;a href="http://existentialprogramming.blogspot.com/search/label/rose"&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-style: italic;"&gt;A Rose is a Rose is (not) a Rose&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-style: italic;"&gt;"]&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;br /&gt;In the early part of the book &lt;a href="http://www.amazon.com/Stuff-Thought-Language-Window-Nature/dp/0670063274"&gt;The Stuff of Thought&lt;/a&gt; by Steven Pinker, the problem of what-a-name-names, is explored with the example of Shakespeare. Pinker distinguishes between Shakespeare: the historical figure, and Shakespeare: the author of numerous plays like Hamlet &lt;/span&gt;&lt;span style="font-size:100%;"&gt;attributed to Shakespeare&lt;/span&gt;&lt;span style="font-size:100%;"&gt;.&lt;br /&gt;&lt;br /&gt;In my earlier post, it was somewhat easy to see that there were multiple aspects to Superman because each aspect already had its own name; Superman vs Clark Kent. With Shakespeare however, it is much more subtle because the different aspects have the same name: Shakespeare. Additionally, we are not used to thinking that they are different aspects that can be independent of each other, any more than we think of Cher-the-person and Cher-the-singer as being independent things. But, as discussed in the book, many people over the centuries have debated whether the author of Hamlet, et al was really Francis Bacon, Christopher Marlowe, Queen Elizabeth, etc.&lt;br /&gt;&lt;br /&gt;The interesting thing is that because Shakespeare is SO ingrained as the name of the playwright that even if Sir Francis were to be proven the author, the headline will be "Bacon is the REAL Shakespeare!" which is absurd because clearly, Shakespeare-the-historical-figure is the "real" Shakespeare. Changing the human associated with the author-of-Hamlet concept will not change the concept's name; it will remain "Shakespeare's Hamlet (written by Bacon)" and not "Bacon's Hamlet".&lt;br /&gt;&lt;br /&gt;So, when assigning ID#(s) to putatively single entities, flexibility should be built in to allow ad-hoc collections of attributes of any entity to be grouped and named and referenced separately. Otherwise, the system would not be able to represent the statement: &lt;span style="color: rgb(153, 0, 0);"&gt;Shakespeare is not Shakespeare, Bacon is.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-2313698930945328388?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://existentialprogramming.blogspot.com/2007/12/shakespeare-is-not-shakespeare.html' title='Shakespeare is (not) Shakespeare'/><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/2313698930945328388/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=2313698930945328388' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/2313698930945328388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/2313698930945328388'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2008/01/shakespeare-is-not-shakespeare.html' title='Shakespeare is (not) Shakespeare'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-4741136228569887297</id><published>2007-12-22T13:45:00.002-05:00</published><updated>2010-12-28T18:54:46.319-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Clark Kent is (not) Superman</title><content type='html'>&lt;span style="color: rgb(0, 102, 0);font-size:100%;" &gt;&lt;span style="font-style: italic;"&gt;[Ed. Note. This is part one of a series found on "Existential Programming, the blog": "&lt;/span&gt;&lt;a href="http://existentialprogramming.blogspot.com/search/label/rose"&gt;&lt;span style="text-decoration: underline;"&gt;&lt;span style="font-style: italic;"&gt;A Rose is a Rose is (not) a Rose&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-style: italic;"&gt;"]&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;It delights me to find out that what I thought had been a particular nugget of wisdom, specific to building &lt;/span&gt;&lt;a style="font-style: italic;" href="http://www.identitysystems.com/freebook.htm"&gt;Identity matching&lt;/a&gt;&lt;span style="font-style: italic;"&gt; computer systems, actually has a deep principle at work.  W&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-style: italic;"&gt;hile working on &lt;/span&gt;&lt;a style="font-style: italic;" href="http://www.choicepoint.com/products/identity_matching.html"&gt;one of these systems&lt;/a&gt;, &lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-style: italic;"&gt;I learned th&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-style: italic;"&gt;e strategy of NOT merging all variations of an individual identity's name/address/phone/etc into a single canonical version&lt;/span&gt;&lt;span style="font-style: italic;"&gt;. It turns out that the need to keep, and assign a unique key to, every variation of identity data (as opposed to only the "canonical" one) has deep roots in language itself...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;While reading the &lt;a href="http://www.amazon.com/exec/obidos/ASIN/1594865132/"&gt;Intellectual Devotional&lt;/a&gt; &lt;span style="font-style: italic;"&gt;(which I highly recommend)&lt;/span&gt;, I came across &lt;a href="http://1.bp.blogspot.com/_JWiCz7S_rac/R21L42BeHUI/AAAAAAAAABs/9UtTIxkDG8c/s1600-h/clark.jpg"&gt;its page about "Philosophy of Language"&lt;/a&gt;  and it had an immediate resonance with a project at my current client.  The page describes the "&lt;a href="http://en.wikipedia.org/wiki/Philosophy_of_language#References"&gt;problem of reference&lt;/a&gt;" where ideas about what a name "means" have been debated and changed over time.&lt;br /&gt;&lt;br /&gt;One theory says that "names" don't have any meaning, in and of themselves, they merely refer to some &lt;/span&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;thing &lt;/span&gt;&lt;span style="font-size:100%;"&gt;that has meaning.  Hence, Shakespeare's quote &lt;span style="color: rgb(153, 0, 0);"&gt;"A rose by any other name would smell as sweet"&lt;/span&gt; summarizes the position that the &lt;/span&gt;&lt;span style="font-style: italic;font-size:100%;" &gt;word &lt;/span&gt;&lt;span style="font-size:100%;"&gt;"rose" is not meaningful, and could be exchanged with any other word that refers to the &lt;span style="font-style: italic;"&gt;thing  &lt;/span&gt;"rose". That is why "gulaab" (the Urdu word for rose) can work just as well for speakers of Urdu.&lt;br /&gt;&lt;br /&gt;Another more modern theory though, says that names not only refer to some thing, they also carry the connotation of "in what sense" is the thing being referenced. The book illustrates the example of Superman and Clark Kent both being names for the same &lt;span style="font-style: italic;"&gt;thing &lt;/span&gt;(the being Superman), but they are not interchangeable. Clark Kent (mild mannered reporter) has a work address of the Daily Planet whereas Superman (superhero able to leap tall buildings) does not. It &lt;span style="font-weight: bold;"&gt;matters&lt;/span&gt; which name is used when talking about Superman.&lt;br /&gt;&lt;br /&gt;So, in the same way that Clark Kent and Superman both refer to different aspects of the same entity, and are thus not interchangeable, a computer system managing legal entity identity data can not translate name/address variations into a single entity ID# when those variations actually refer to different aspects of the entity. For example, if there is data that is specific to a particular store branch, that branch needs its own well-known ID# even though it is only a &lt;span style="font-style: italic;"&gt;portion &lt;/span&gt;of a single legal entity.  Further, since legal entity names are not unique &lt;span style="font-style: italic;"&gt;(I own two different corporations with the identical legal name)&lt;/span&gt;, the entire name/address/phone/etc combination needs managing rather than separate "alternate name" lists. It is also not sufficient to support alternate name/address records merely as search aids that still ultimately result in the ID# of the entity-as-a-whole. Otherwise one would loose track of the fact that we were talking about Clark Kent, not Superman. &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-4741136228569887297?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://existentialprogramming.blogspot.com/2007/12/clark-kent-is-not-superman.html' title='Clark Kent is (not) Superman'/><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/4741136228569887297/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=4741136228569887297' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4741136228569887297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4741136228569887297'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2007/12/clark-kent-is-not-superman.html' title='Clark Kent is (not) Superman'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-2462627207382594422</id><published>2007-11-30T19:44:00.000-05:00</published><updated>2010-12-28T18:54:46.320-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Odometer Game Redux</title><content type='html'>&lt;span style="font-size:100%;"&gt;Well, after 35 years of pondering what I thought was an abstract mathematical puzzle, my "&lt;a href="http://polyglotinc.blogspot.com/2007/10/odometer-game.html"&gt;odometer game&lt;/a&gt;" has found a real-world application!&lt;br /&gt;&lt;br /&gt;It turns out that my notion of "remarkable" numbers &lt;span style="color: rgb(51, 51, 51);"&gt;[i.e. numbers that are so &lt;/span&gt;&lt;span style="font-style: italic; color: rgb(51, 51, 51);"&gt;remarkable &lt;/span&gt;&lt;span style="color: rgb(51, 51, 51);"&gt;that if the driver saw his odometer sitting on that number he would either honk his horn or point it out to his passengers]&lt;/span&gt; are just the ticket for finding "fake" ID numbers.&lt;br /&gt;&lt;br /&gt;My current contract at a major bank found me looking for suspect ID numbers, Tax IDs, phone numbers, etc. in various customer databases.  The bank employees entering this information would often get around the fact that these fields were "required" via entry of syntactically legal digit strings that were none the less meaningless.  After viewing a few of these it quickly became obvious that they were related to my notion of &lt;span style="font-style: italic;"&gt;remarkableness&lt;/span&gt;.  Actual values found included: &lt;/span&gt;&lt;span style="font-family:sans-serif;font-size:85%;"&gt;0, 121212121, 000000000, 999999999(9), 111111111, 111111112, 222222221,  888888889, 188888888, 0999999999, 589999999, 255511555 (?)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;So, rather than an explicit list of IDs to put on a watch list (as I was asked to find), it became clear that a better answer would have been to use an evaluation function that reported the remarkableness score for each value. A cutoff point could then be established to filter out suspicious values. Alas, while I have casually pondered the mathematics involved in scoring the remarkableness of a number, I've never actually tried to program it.  But, now it has become more than an obscure puzzle, and shows signs of having "real world" value!&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-2462627207382594422?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/2462627207382594422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=2462627207382594422' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/2462627207382594422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/2462627207382594422'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2007/11/odometer-game-redux.html' title='Odometer Game Redux'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-3953293248450870137</id><published>2007-10-13T11:51:00.000-04:00</published><updated>2010-12-28T18:54:46.320-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>The Odometer Game</title><content type='html'>&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;span style="font-size:78%;"&gt;Dear Dr. Douglas Hofstadter,&lt;br /&gt;Having been a fan of yours since GEB (I had you sign my copy in '83 at UC Santa Cruz), I have always wanted to write to you about an "odometer game" I concocted about 1973 which touches upon several of your favorite themes: patterns, their recognition, and "human" vs "machine" intelligence. Following Hofstadter's law, it has taken longer to write you than I ever thought it would. ;-)&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:78%;"&gt;The thought-provoking part is imagining how a computer would ever "play" the game. It would involve mathematically defining "remarkable" odometer numbers, where "remarkable" is defined as any number that would intuitively cause the driver to remark to the other passengers: "Hey, look at the odometer!". The more likely a number is to cause a driver to say that, the higher its "remarkableness".&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:78%;"&gt;I've casually pondered the math for this for years. Let me know if you have already solved it.&lt;br /&gt;sincerely,&lt;br /&gt;Bruce Wallace&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p style="font-weight: bold;"&gt;The Odometer Game&lt;/p&gt; &lt;p&gt;As many people have done over the years, I honked my horn when my odometer rolled over to all zeros [000000] (back when that only took 100,000.0 miles to do so).  Later, when I put on another 11,111.1 miles [111111], I decided that an odometer reading of all ones was also worthy of a honk (a bit of a geek whimsy).&lt;/p&gt; &lt;p&gt;Since I had many long boring drives between college and parents, I came up with a little diversion which was to honk (or otherwise take note of) any "remarkable" odometer reading [where "remarkable" was any number that would make a driver point it out to the passengers].&lt;/p&gt; &lt;p&gt;I even accumulated imaginary points that mirrored the amount of "remarkableness" of the number. But, soon I realized I needed a reason to keep from simply taking note of EVERY number in my quest to build up my point total.  I thought that maybe some function balancing total-points vs average-points-per-honk was needed.  And to make things more sporting, I should lose points if I missed any numbers in a "pattern" once I had taken points for that pattern. In other words, if I took points for [000000] and [111111], I would lose points if I missed [222222]. (I.E., don't start a pattern if you aren't going to keep it up!)&lt;/p&gt; &lt;p&gt;So, [000000] was definitely remarkable, and so was [111111], [222222], [333333], etc. (Hmmm... [111111] seems less remarkable than [000000], and [222222] thru [888888] all seem less remarkable than either [000000] or [111111]...should they all get the same points?). Then came [123456]. And while less remarkable, [234567], [345678], etc. all seem pretty good.&lt;/p&gt; &lt;p&gt;Palindromes are very good, but [123321] seems more remarkable than [394493] or [825528]. And [121212] &amp;amp; [123123] are very good, but less so [838383] &amp;amp; [378378].  While [010101] and [999999] beat out [898989] &amp;amp; [888888] respectively, all seem good enough to take the points.&lt;/p&gt; &lt;p&gt;Round numbers like [010000], [020000], [030000], etc. seem nice because the pattern is anchored with [000000]. Actually, a number like [000000] meets lots of patterns at once: [aaaaaa], [ababab], [abccba], [abcabc], etc. (in addition to being the ultimate round number), so, it gets LOTS of points.&lt;/p&gt; &lt;p style="font-weight: bold;"&gt;The Puzzle&lt;/p&gt; &lt;p&gt;Why are some numbers (i.e. digit strings) instinctively more "remarkable" than others? How would one model this mathematically?  Patterns seem part of the answer, but a readily recognizable pattern is in [192837] even though it would seem very unlikely for a driver to make a passenger take note of that number/pattern.&lt;/p&gt; &lt;p&gt;And why are [000000], [111111], &amp;amp; [999999] all more "remarkable" than [222222] thru [888888]? Why is [123456] more than [012345], but [121212] and [010101] seem more of a toss up? Is the "simplicity" of the pattern the crux of "remarkableness"? How would one describe that "simplicity" mathematically (especially when 0 and 1 and 9 seem somehow more "simple" than 2 thru 8)? What grammar "parses" this string language?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-3953293248450870137?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/3953293248450870137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=3953293248450870137' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/3953293248450870137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/3953293248450870137'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2007/10/odometer-game.html' title='The Odometer Game'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-2373203112746030591</id><published>2007-05-21T13:10:00.000-04:00</published><updated>2010-12-28T18:54:46.321-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Language Plateaus in Evolution?</title><content type='html'>&lt;p&gt;&lt;span style="font-size:85%;"&gt;In reading[1] about the different levels of human language competency that plateau at various ages (6, puberty, etc), it made me wonder if those capabilities mirrored those of our ancestors at various stages of evolution. Just as a human embryo looks like amphibians, etc as it is developing (in a mirror of DNA development over the ages), maybe language skill levels that jump in quantum leaps mirror primate evolution?&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;span style="font-size:85%;"&gt;[1] Introducing Chomsky, John Maher, Judy Groves, Icon Books, 1996.&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-2373203112746030591?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/2373203112746030591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=2373203112746030591' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/2373203112746030591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/2373203112746030591'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2007/05/language-plateaus-in-evolution.html' title='Language Plateaus in Evolution?'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-3584109743850192653</id><published>2003-11-29T13:06:00.005-05:00</published><updated>2010-12-28T18:53:43.393-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='reXume'/><category scheme='http://www.blogger.com/atom/ns#' term='ganttMagic'/><title type='text'>The reXume/GanttMagic webapps can now be embedded...</title><content type='html'>The &lt;a href="http://polyglotinc.blogspot.com/search/label/reXume"&gt;reXume&lt;/a&gt; and &lt;a href="http://polyglotinc.blogspot.com/search/label/ganttMagic"&gt;GanttMagic&lt;/a&gt; web apps have been modified such that they can be configured to process a hardwired reXume file rather than only uploaded files.&lt;br /&gt;&lt;br /&gt;My hand coded Interactive Resume web site ( &lt;a href="http://rexume.dyndns.org/resume"&gt;http://rexume.dyndns.org/resume&lt;/a&gt; ) is being replaced with a new version based on the std. reXume and GanttMagic web apps ( &lt;a href="http://rexume.dyndns.org/reXume/RBWrexume.html"&gt;http://rexume.dyndns.org/reXume/RBWrexume.html&lt;/a&gt; ) that also acts as a demonstration of using reXume for personal resume sites.&lt;br /&gt;&lt;br /&gt;The WAR files are currently deployed on JRun 3.0 but have been tested on Tomcat 4.1 as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-3584109743850192653?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/3584109743850192653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=3584109743850192653' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/3584109743850192653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/3584109743850192653'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/11/rexumeganttmagic-webapps-can-now-be.html' title='The reXume/GanttMagic webapps can now be embedded...'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-7491729414460756584</id><published>2003-10-06T10:56:00.001-04:00</published><updated>2010-12-28T18:53:43.394-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ganttMagic'/><title type='text'>Announcing RDDL file for GanttMagic XML Namespace...</title><content type='html'>There is a first major stab at publishing an &lt;a href="http://www.rddl.org/"&gt;RDDL&lt;/a&gt; file documenting the XML namespace I've defined for the GanttMagic XML input data. It is at &lt;a href="http://www.polyglotinc.com/NS/GanttMagic/"&gt;http://www.polyglotinc.com/NS/GanttMagic/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Soon (hopefully) there will be a similar one for the reXume data XML namespace [ http://www.polyglotinc.com/NS/reXume ].&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-7491729414460756584?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/7491729414460756584/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=7491729414460756584' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/7491729414460756584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/7491729414460756584'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/10/announcing-rddl-file-for-ganttmagic-xml.html' title='Announcing RDDL file for GanttMagic XML Namespace...'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-5027672307042693421</id><published>2003-09-21T22:08:00.000-04:00</published><updated>2010-12-28T18:54:46.321-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>How to Pick a Science Fair Experiment</title><content type='html'>Presented is a set of intuitive classroom assignments that lead students&lt;br /&gt;to pick better quality science fair projects, and in the process, teaching&lt;br /&gt;them the "Scientific Process" and how it is something that they already&lt;br /&gt;intuitively know.&lt;br /&gt;&lt;br /&gt;Students are often impeded with the notion that "thinking like a scientist"&lt;br /&gt;is so different from the way they normally think that they don't know how&lt;br /&gt;to proceed. The given approach starts students with intuitive activities&lt;br /&gt;with which they are already familiar then shows them how to merely "fine tune"&lt;br /&gt;their thinking rather than viewing science as "speaking a foreign language".&lt;br /&gt;&lt;br /&gt;In a nutshell, I propose that choosing a topic for a science fair project&lt;br /&gt;and designing its experiment properly are the equivalent to the intuitive&lt;br /&gt;activities of making a list of “Whenever THIS then THAT” statements and then&lt;br /&gt;choosing the best “bar bet” that can be constructed from the list.&lt;br /&gt;&lt;br /&gt;One intuitively makes observations and constructs theories to explain them&lt;br /&gt;whenever a “Whenever THIS then THAT” statement is made.  One intuitively&lt;br /&gt;evaluates the quality of a science experiment whenever one evaluates the&lt;br /&gt;quality of a bet. I.E. the same things that make a good bet make good science.&lt;br /&gt;Namely:&lt;br /&gt;* - you think you know something about the world that the other guy&lt;br /&gt;   doesn’t know (otherwise he won’t take the bet if he knows it too)&lt;br /&gt;* - you think you understand it well enough to explain it (otherwise it is&lt;br /&gt;   not a safe bet)&lt;br /&gt;* - you think you can demonstrate a prediction about it (i.e. the bet itself)&lt;br /&gt;   in such a way that the outcome will be clear (otherwise there will be&lt;br /&gt;   an argument over who won the bet).&lt;br /&gt;* - you have controlled the conditions of the demonstration (otherwise it&lt;br /&gt;   makes the outcome of the bet be affected by things you can’t predict).&lt;br /&gt;* - someone else can perform the bet if need be (otherwise people will think&lt;br /&gt;   you’ve rigged the game).&lt;br /&gt;&lt;br /&gt;-------------------&lt;br /&gt;The Approach&lt;br /&gt;-------------------&lt;br /&gt;&lt;br /&gt;0) Preview the Scientific Process to students&lt;br /&gt;&lt;br /&gt;a) observations about the world are made&lt;br /&gt;b) theories are created that explain those observations&lt;br /&gt;c) predictions are made from those theories&lt;br /&gt;d) experiments to verify the predictions are made&lt;br /&gt;e) the results of the experiments either confirm the&lt;br /&gt;   predictions and therefore the theory, or they don't,&lt;br /&gt;   in which case one goes back to (b) taking into account&lt;br /&gt;   the new observations made by this experiment.&lt;br /&gt;&lt;br /&gt;0) Preview some factors that make “good science”&lt;br /&gt;&lt;br /&gt;*) observations are new&lt;br /&gt;*) observations are surprising&lt;br /&gt;*) theories make predictions that can be tested&lt;br /&gt;*) experiments produce results that are conclusive&lt;br /&gt;*) experiments are repeatable by others&lt;br /&gt;&lt;br /&gt;1) Observations and Theories&lt;br /&gt;&lt;br /&gt;[Use the intuition students exhibit, to both make observations&lt;br /&gt; and generate theories to explain them, whenever they use&lt;br /&gt; sentences like "Whenever THIS then THAT".]&lt;br /&gt;&lt;br /&gt;(a) Assignment 1: make a list of things you know/believe about the world&lt;br /&gt;&lt;br /&gt; “Everyone make a list of things that they have noticed (or been told&lt;br /&gt;  or read) about the world.&lt;br /&gt;  (At least 5 things and extra credit for each extra item up to 20 items).&lt;br /&gt; The items in the list should all be in one of the following forms:&lt;br /&gt; * - Whenever THIS happens (or not),&lt;br /&gt;     then THAT seems to always happen (or not).&lt;br /&gt; * - Whenever THIS situation exists (or not),&lt;br /&gt;     then THAT seems to always happen (or not).&lt;br /&gt;&lt;br /&gt; Examples of form:&lt;br /&gt; * - I've noticed that whenever I let go of something I'm holding,&lt;br /&gt;     it seems to always fall to the ground.&lt;br /&gt; * - I've noticed that whenever I drop a rock in water,&lt;br /&gt;     it never floats.&lt;br /&gt; * - I've noticed that whenever people are with their friends,&lt;br /&gt;     they are louder than when they are alone or with strangers.&lt;br /&gt; * - I've been told that whenever plants get too much water,&lt;br /&gt;     they die.”&lt;br /&gt;&lt;br /&gt;(b) follow up discussion to Assignment 1: review how students made both&lt;br /&gt;    observations *and* theories to explain them.&lt;br /&gt;    * - By putting beliefs (whether inspired by direct observation or&lt;br /&gt;    having been informed by others) into the form "when this then that",&lt;br /&gt;    it filtered out simple observations that had no theory attached.&lt;br /&gt;    E.G. "I noticed that the sky is usually blue" is an observation, but&lt;br /&gt;    there is no theory to explain it. In order to say "if A then B",&lt;br /&gt;    one had to already have enough of an idea about cause and effect to&lt;br /&gt;    make the statement, whether the statement itself was correct or not.&lt;br /&gt;    But people/students makes statements like this all the time and&lt;br /&gt;    therefore are producing theories whether they realized it or not.&lt;br /&gt;&lt;br /&gt;2) Experiment Selection and Design&lt;br /&gt;&lt;br /&gt;[Use the intuition students exhibit, to choose interesting science&lt;br /&gt; experiments and to design them to produce a clear result, whenever&lt;br /&gt; they use sentences like "I'll bet you!".]&lt;br /&gt;&lt;br /&gt;(a) Assignment 2: make bets out of the theories&lt;br /&gt;&lt;br /&gt; Part 1: Everyone take their list of observations, and for each one, make&lt;br /&gt;        a bet out of it.&lt;br /&gt;        Examples:&lt;br /&gt;         * - I'll bet you that if I let go of this ball,&lt;br /&gt;             it will fall to the floor.&lt;br /&gt;         * - I'll bet you that if I throw this rock in the water,&lt;br /&gt;             it won't float.&lt;br /&gt;         * - I'll bet you that if we measure the noise level of 3 friends&lt;br /&gt;             eating together in the lunchroom it will be louder than if we&lt;br /&gt;             measure 3 people eating together that don't know each other.&lt;br /&gt;         * - I'll bet you that if I give this houseplant way more water&lt;br /&gt;             than the gardening book says it should get, it will die.&lt;br /&gt;&lt;br /&gt; Part 2: Take your list of bets and rate each one for the factors below.&lt;br /&gt;         Add these factors together to get the quality score for each bet.&lt;br /&gt;         For safety, add the practicality factor 3 times instead of once.&lt;br /&gt;         The higher the score, the better the quality.&lt;br /&gt;         * - How non-obvious is this? (i.e. will anyone take this bet?)&lt;br /&gt;             Rank from 1 to 10 where 10 is "nobody knows this but me"&lt;br /&gt;             and 1 is "everyone on the planet knows this"&lt;br /&gt;         * - How well do you understand your theory (i.e. how sure of&lt;br /&gt;             the bet are you?).  Rank from 1 to 10 where 10 means "I'm&lt;br /&gt;             sure I'll win the bet" and 1 means "I'm just guessing&lt;br /&gt;             what will happen."&lt;br /&gt;         * - How practical is it? (i.e. is there a way to actually&lt;br /&gt;             make a bet out of this?) Rank from 1 to 10 where 10 means&lt;br /&gt;             "this is easy to perform" and 1 means "this will take&lt;br /&gt;             a UN resolution to actually do."&lt;br /&gt;         * - How obvious will the outcome be? (i.e. how obvious will&lt;br /&gt;             it be who won the bet?) Rank from 1 to 10 where 10 means&lt;br /&gt;             "obvious result" and 1 means "we'll be in an argument&lt;br /&gt;             all day over who won, was it fair, is it a do-over, etc."&lt;br /&gt;&lt;br /&gt; Part 3: Make any changes you can to the description/design of each&lt;br /&gt;         bet to improve its quality score before settling on the final&lt;br /&gt;         quality score for each bet.  Take the top 3 bets and rank&lt;br /&gt;         each for the following factors:&lt;br /&gt;         * - How well can I control things that might affect the result?&lt;br /&gt;             (i.e. will I lose the bet because of something I can't&lt;br /&gt;             predict or control?).  Rank from 1 to 10 where 10 means&lt;br /&gt;             "nothing should foul up the works if I specify when/where/&lt;br /&gt;             how/etc" and 1 means "every time the air conditioner&lt;br /&gt;             comes on it blows down my house of cards".&lt;br /&gt;             What conditions can be added that will make it more of a&lt;br /&gt;             sure bet?  After adding them, make a final rank for this&lt;br /&gt;             factor.&lt;br /&gt;         * - How well can I describe the procedure? (i.e. how easy will&lt;br /&gt;             it be for a 3rd party to perform the bet?) Rank from 1 to&lt;br /&gt;             10 where 10 means "even a trained monkey could do this&lt;br /&gt;             correctly" and 1 means "I'm the only one who can ever&lt;br /&gt;             make this work".&lt;br /&gt;             How can the procedure and description be simplified and&lt;br /&gt;             improved such that others can get the same results every&lt;br /&gt;             time?  After making the improvements, make a final rank for&lt;br /&gt;             this factor.&lt;br /&gt;&lt;br /&gt; Part 4: Add the factors from part 3 to those from part 2 for the top&lt;br /&gt;         3 bets and pick the one with the highest quality score as your&lt;br /&gt;         choice for an experiment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-5027672307042693421?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/5027672307042693421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=5027672307042693421' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/5027672307042693421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/5027672307042693421'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/09/how-to-pick-science-fair-experiment.html' title='How to Pick a Science Fair Experiment'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-8354976020913173551</id><published>2003-09-15T11:55:00.002-04:00</published><updated>2010-12-28T18:53:43.395-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ganttMagic'/><title type='text'>The GanttMagic webapp works separately from reXume now....</title><content type='html'>The multiple web app WAR files previously published for GanttMagic have been consolidated into a single &lt;a href="http://www.polyglotinc.com/GanttMagic/GanttMagic.war"&gt;GanttMagic.war&lt;/a&gt; which can be deployed on any web container and has been tested with Tomcat 4.1 (J2EE 1.3) and JRun3.0 (J2EE 1.2). For older J2EE web containers running on JDK 1.3, you may need&lt;br /&gt;to install the following &lt;a href="http://www.polyglotinc.com/GanttMagic/PolyGlotUtils.jar"&gt;library jar file&lt;/a&gt; into the shared library area (e.g. for JRun3.0 it is at [jrun_install]/lib/ext/ ).&lt;br /&gt;&lt;br /&gt;Also with this release, this GanttMagic webapp may be deployed and used separately from the &lt;a href="http://polyglotinc.blogspot.com/search/label/reXume"&gt;new release of the reXume webapp&lt;/a&gt;. Previously the two had to be deployed within a single webapp to work properly.&lt;br /&gt;&lt;br /&gt;This code is running and available online at http://rexume.dyndns.org/GanttMagic/&lt;br /&gt;where is runs on my old Pentium II system with RedHat6.x and JRun3 (so don't expect lightning speed).&lt;br /&gt;The demo installation is still found at this &lt;a href="http://rexume.dyndns.org/GanttMagic/testGanttMagic.html"&gt;test page&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-8354976020913173551?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/8354976020913173551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=8354976020913173551' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/8354976020913173551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/8354976020913173551'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/09/ganttmagic-webapp-works-separately-from.html' title='The GanttMagic webapp works separately from reXume now....'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-717101344513694877</id><published>2003-09-15T11:49:00.002-04:00</published><updated>2010-12-28T18:53:43.396-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='reXume'/><title type='text'>The reXume webapp works separately from GanttMagic now....</title><content type='html'>The multiple web app WAR files previously published for reXume have been consolidated into a single &lt;a href="http://www.polyglotinc.com/reXume/reXume.war"&gt;reXume.war&lt;/a&gt; which can be deployed on any web container and has been tested with Tomcat 4.1 (J2EE 1.3) and JRun3.0 (J2EE 1.2).&lt;br /&gt;&lt;br /&gt;Also with this release, this reXume webapp may be deployed and used separately from the &lt;a href="http://polyglotinc.blogspot.com/search/label/ganttMagic"&gt;new release of the GanttMagic webapp&lt;/a&gt;. Previously the two had to be deployed within a single webapp to work properly.&lt;br /&gt;&lt;br /&gt;This code is running and available online at http://polyglotinc.dyndns.org/reXume/ where is runs on my old Pentium II system with RedHat6.x and JRun3 (so don't expect lightning speed).&lt;br /&gt;The demo installation is found at this &lt;a href="http://rexume.dyndns.org/reXume/Interactive.html"&gt;interactive resume page&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-717101344513694877?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/717101344513694877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=717101344513694877' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/717101344513694877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/717101344513694877'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/09/rexume-webapp-works-separately-from.html' title='The reXume webapp works separately from GanttMagic now....'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-5325900125604717001</id><published>2003-09-08T19:03:00.000-04:00</published><updated>2010-12-28T18:54:46.322-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Things I learned today while fighting the MSBlaster worm...</title><content type='html'>(1) what looks like normal problems with Charter cable modem&lt;br /&gt;  service being flaky can actually be caused by MSBLASTER.&lt;br /&gt;&lt;br /&gt;(1.5) It is hard to diagnose anything over Charter these days&lt;br /&gt;  because they have disabled all ICMP (i.e. ping/traceroute)&lt;br /&gt;  messages in a vain attempt to fight viruses.  Earthlink&lt;br /&gt;  happily does not block ICMP so you can dial out to Mindspring&lt;br /&gt;  to ping Charter boxes.&lt;br /&gt;&lt;br /&gt;(2) I found that one of my Win2K systems was infected by seeing&lt;br /&gt;  "msblast.exe" in the Task Manager display.&lt;br /&gt;&lt;br /&gt;(3) searching Yahoo I found a &lt;a href="http://www.pchell.com/virus/msblast.shtml"&gt;good page about the blaster worm&lt;/a&gt;&lt;br /&gt;  which told me how to fix it and had a link to the patch&lt;br /&gt;  to prevent getting it in the future.&lt;br /&gt;&lt;br /&gt;(4) while I normally am immune to these problems because of&lt;br /&gt;  my firewall, it didnt take long for the worm to find and&lt;br /&gt;  infect me while I was dialed into Mindspring/Earthlink&lt;br /&gt;  which puts my computer directly on the Internet (only the&lt;br /&gt;  cable modem goes thru the router/firewall [Netgear RP614]).&lt;br /&gt;&lt;br /&gt;(4.5) I see that when I dial directly to the net via Earthlink,&lt;br /&gt;  I am constantly &lt;a href="http://www.wikipedia.org/wiki/Smurf_attack"&gt;SMURF attacked&lt;/a&gt; which doesn't happen when&lt;br /&gt;  behind the firewall when connecting via the cable modem.&lt;br /&gt;&lt;br /&gt;(4.6) Even though the Netgear router lets you set up a static&lt;br /&gt;  IP address but still set it to "ask for DNS server addresses",&lt;br /&gt;  it doesnt work (at least with Charter) which makes sense&lt;br /&gt;  since DHCP which gives you a dynamic IP address, also gives&lt;br /&gt;  you the DNS addresses and if you dont ask for one, you wont&lt;br /&gt;  get the other either.&lt;br /&gt;&lt;br /&gt;(5) searching my Linux box's various logs to see what all that&lt;br /&gt;  network activity was about, I saw in the Apache logs (which&lt;br /&gt;  I never look at) that there were lots of failed requests&lt;br /&gt;  via the web for "default.ida" which is the symptom of other boxes&lt;br /&gt;  with the Code Red virus trying to attack me. Good little&lt;br /&gt;  discussion of it &lt;a href="http://www.thesitewizard.com/news/coderediiworm.shtml"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;(6) Just because you see the Norton AntiVirus running its auto-&lt;br /&gt;  update feature every day or so to update its virus definitions,&lt;br /&gt;  that doesn't mean it is scanning for viruses too.  That is&lt;br /&gt;  scheduled separately (and it hadn't scanned my system since&lt;br /&gt;  the last time I did it manually about 8 months ago.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-5325900125604717001?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/5325900125604717001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=5325900125604717001' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/5325900125604717001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/5325900125604717001'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/09/things-i-learned-today-while-fighting.html' title='Things I learned today while fighting the MSBlaster worm...'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-4997300136309230473</id><published>2003-09-04T16:29:00.002-04:00</published><updated>2010-12-28T18:53:43.396-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ganttMagic'/><title type='text'>Announcing GanttMagic from PolyGlot, Inc....</title><content type='html'>I've finally gotten around to making my Gantt chart software available to others as either a product or an open-source-project (haven't decided which yet).&lt;br /&gt;&lt;br /&gt;As with the reXume project (which uses GanttMagic to produce the "experience charts"), there is lots of web-accessible documentation to still to produce and the code published today is a first baby step.&lt;br /&gt;&lt;br /&gt;GanttMagic produces a &lt;a href="http://www.ganttchart.com/"&gt;gantt chart&lt;/a&gt; (often misspelled as &lt;a href="http://www.maxwideman.com/issacons3/iac1302/sld005.htm"&gt;"gannt"&lt;/a&gt;) given data in the GanttMagic XML format. (&lt;a href="http://www.polyglotinc.com/GanttMagic/GanttMagicDemo.xml"&gt;Here&lt;/a&gt; is the small example data file that the test program mentioned below uses.)&lt;br /&gt;It currently can produce the chart image in &lt;a href="http://www.w3.org/Graphics/SVG/"&gt;SVG&lt;/a&gt;, JPG, and PNG formats.&lt;br /&gt;It is implemented in Java using the &lt;a href="http://xml.apache.org/batik/"&gt;Apache Batik SVG library&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I have broken out and cleaned up my GanttMagic code and packaged it into a JavaBean that includes all of the basic functionality, a standalone application to use the bean via a command line, and a J2EE web application to make the functionality available from any JSP/Servlet engine.&lt;br /&gt;&lt;br /&gt;I have produced the following three varieties of WAR file for loading into the appropriate J2EE servers. [Tested on &lt;a href="http://jakarta.apache.org/tomcat/"&gt;Tomcat&lt;/a&gt; and &lt;a href="http://www.macromedia.com/software/jrun/"&gt;JRun&lt;/a&gt;]&lt;br /&gt;1) &lt;a href="http://www.polyglotinc.com/GanttMagic/GanttMagic3.war"&gt;GanttMagic3.war&lt;/a&gt;   - tested on Tomcat3.3 and JRun3.0 (both J2EE 1.2 compliant)&lt;br /&gt;2) &lt;a href="http://www.polyglotinc.com/GanttMagic/GanttMagic40.war"&gt;GanttMagic40.war&lt;/a&gt;  - tested on Tomcat4.0 (J2EE 1.3 compliant)&lt;br /&gt;3) &lt;a href="http://www.polyglotinc.com/GanttMagic/GanttMagic41.war"&gt;GanttMagic41.war&lt;/a&gt;  - tested on Tomcat4.1 (J2EE 1.3 compliant)&lt;br /&gt;&lt;br /&gt;This code is running and available online at http://rexume.dyndns.org/GanttMagic/&lt;br /&gt;where is runs on my old Pentium II system with RedHat6.x and JRun3 (so don't expect lightning speed).&lt;br /&gt;&lt;br /&gt;I'll add documentation soon, but for now, try using the &lt;a href="http://rexume.dyndns.org/GanttMagic/testGanttMagic.html"&gt;test page&lt;/a&gt; to experiment with. Choose which type of image you want (SVG,JPG,PNG) and hit the "show me" button.  The other controls are not interesting for now.  JPG is the most universal format.  To see the SVG, you'll need either a standalone viewer or a browser plugin.  I've heard new IE browsers may already have an SVG plugin installed. Otherwise follow the links to install an SVG viewer browser plug-in to see the raw SVG rendered.  Without an SVG viewer, you can see the raw SVG source which is just an XML text file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-4997300136309230473?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/4997300136309230473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=4997300136309230473' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4997300136309230473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4997300136309230473'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/09/announcing-ganttmagic-from-polyglot-inc.html' title='Announcing GanttMagic from PolyGlot, Inc....'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-3837776306043616621</id><published>2003-08-29T20:33:00.002-04:00</published><updated>2010-12-28T18:53:43.397-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='reXume'/><title type='text'>announcing reXume from PolyGlot, Inc....</title><content type='html'>I've finally gotten around to making my interactive resume available to others and I grabbed a couple of domain names to lock in the product/open-source-project (haven't decided which yet) name: "reXume" (pronounced "resume" following a trend to replace 's' with 'x' in names and to be a reference to the XML nature of the product).&lt;br /&gt;&lt;br /&gt;So, peruse www.rexume.org or www.rexume.net and see the one and only page so far.  It lets one upload one's resume in my reXume XML format, and then it returns it back to you all pretty formatted and filtered a la my interactive resume.&lt;br /&gt;&lt;br /&gt;Somebody in Hong Kong already has rexume.com but they haven't even hooked up a "parked" web page for it.  I grabbed the name because a google search showed virtually zero hits for it which makes it a great brand name.&lt;br /&gt;&lt;br /&gt;I'll add documentation soon, but for now, try uploading &lt;a href="http://www.polyglotinc.com/resume/resume.xml"&gt;my rexume&lt;/a&gt; file to experiment with.&lt;br /&gt;&lt;br /&gt;BTW, I got the domain names including free forwarding from goDaddy for ~$8/yr per name.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-3837776306043616621?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/3837776306043616621/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=3837776306043616621' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/3837776306043616621'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/3837776306043616621'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/08/announcing-rexume-from-polyglot-inc.html' title='announcing reXume from PolyGlot, Inc....'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-4664266514705419469</id><published>2003-02-25T17:11:00.001-05:00</published><updated>2010-12-28T18:54:46.323-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Navigation missing from MVC paradigm?</title><content type='html'>After playing with Struts and seeing its notion of what Model-View-Controller means (versus traditional "fat client" MVC), I think that MVC needs to add an explicit model for &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Navigation&lt;/span&gt;. A so-called &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;NMVC&lt;/span&gt; design pattern.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;In traditional MVC, &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Views&lt;/span&gt; are individual pages/dialog-boxes/panes/etc. and &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Controllers&lt;/span&gt; are geared towards translating (mouse/keyboard/clock) events into transaction requests against some data &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Model&lt;/span&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The large item left out is the universal need to define Navigation between views using controllers that are geared towards "movement" i.e. transactions against a Navigation model. In other words, a data model specifically geared towards user interface control is needed that is separate from the data models managing "business/domain/application data".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since UI navigation (especially in a web site context) usually maps well onto a finite state machine, a navigation model geared towards FSMs (with the definition of the state-transition graph specified in an external config-file maybe?) would take out some of the grunt work of UIs.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-4664266514705419469?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/4664266514705419469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=4664266514705419469' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4664266514705419469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4664266514705419469'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/02/navigation-missing-from-mvc-paradigm.html' title='Navigation missing from MVC paradigm?'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-4341889351597288566</id><published>2003-02-25T14:21:00.004-05:00</published><updated>2010-12-28T18:54:46.324-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Can Psychology help Framework Designs?</title><content type='html'>&lt;div&gt;There is a continuum of component sets (i.e. frameworks) that range between "simple" sets containing fewer more universal components versus "complex" sets containing more specialized components.  For example, compare old school Lego pieces that were generic shapes that built anything, versus new style Legos that build only one particular type of Jedi Starfighter.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;These frameworks tend to not integrate very well with other frameworks. It is simpler to pick one as a standard, but how does it affect those that prefer the one not picked? What is the overall cost/benefit of picking one vs the other [vs not picking one at all, and doing the more complicated work of supporting both]?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It would be interesting to perform a series of psych experiments to determine whether people have clear preferences between simple vs complex component sets and how well they can adapt to their non-preferred choice.  Also, do the choices change based on time pressure, organization, documentation of the sets, appropriateness of the components to the overall goal?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For example...&lt;/div&gt;&lt;div&gt;*) - Ask people to build a "plane" from the provided components.&lt;/div&gt;&lt;div&gt;Let people pick between a simple vs complex set of components (e.g. specialized legos vs generic tinkertoys). Measure time taken, and "quality" of result (both self evaluation and objective third party evaluation), and "how well they liked it" i.e. "how fun was it" i.e. "would they like to do another one". Compare the success and quality rates overall for simple vs complex when used by those preferring each.&lt;/div&gt;&lt;div&gt;1) variation: mixed pile of components&lt;/div&gt;&lt;div&gt;2) variation: pile of mixed simple and separate pile of mixed complex&lt;/div&gt;&lt;div&gt;3) variation: organized piles&lt;/div&gt;&lt;div&gt;4) variation: various time limits&lt;/div&gt;&lt;div&gt;5) variation: make complex parts clearly "plane related"&lt;/div&gt;&lt;div&gt;6) variation: make complex parts clearly unrelated to overall goal&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;*) - Ask people to build another goal object, but require them to use the opposite of their preference in the first test. Compare measurements to those of when using their preferred components.  Use similar variations to above (especially for various time limits). Compare the success/quality rates of simple vs complex overall when used by those not preferring it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Overall goals: determine whether:&lt;/div&gt;&lt;div&gt;1) success rate is significantly different between simple vs complex&lt;/div&gt;&lt;div&gt;2) quality rate is significantly different between simple vs complex&lt;/div&gt;&lt;div&gt;3) time taken is significantly different between simple vs complex&lt;/div&gt;&lt;div&gt;4) do people have strong preferences vs weak (what is the distribution each)&lt;/div&gt;&lt;div&gt;5) are people more able to use either simple or complex better when it is not preferred&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;*) i.e. can one pick simple vs complex as a standard or must both be avail and integrated with each other??&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Another variation to try is having the simple and complex component sets be compatible with each other (as opposed to the previous example of special-legos/tinkertoys that can not be used together). E.G. generic legos vs specialized legos. Goal: see if the choices made between simple/complex are as strong and the effects of the choices as strong when there is less of a consequence to starting with one set or the other.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Also, add variations to previous experiments that vary the size of the "simple" set and the "complex" set and see what the size boundaries are to these categories. See what the performance curve is when graphed against set size for the various categories of people.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-4341889351597288566?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/4341889351597288566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=4341889351597288566' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4341889351597288566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4341889351597288566'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/02/can-psychology-help-framework-designs.html' title='Can Psychology help Framework Designs?'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-7147106001414006415</id><published>2003-02-23T15:03:00.002-05:00</published><updated>2010-12-28T18:54:46.324-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Abstract Unit Tests</title><content type='html'>&lt;div&gt;I WANT TO UNIT TEST Requirements, Specifications, Use Cases, etc, and not just fully coded Implementations!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I believe that there needs to be a language that allows sufficiently abstract logic to be specified/programmed such that tests can be written against use cases, high level specifications, etc that are very general. An example of a high level use case might be "customer can get account balance from the ATM".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;In other words, I'd like to write, compile, and lock away in a test suite, a test that verifies that if joeBlow has $10 in his account, the result he gets from requesting his balance is $10, even though no user interface, extra details like logging in first, etc have been decided.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;Then later refinements of the system details can be "plugged in" such that the test can still run without being rewritten. Traditionally, tests must be written at a level of detail that is very specific such that it can interact with the actual system being tested, user interface screens, UI testing tools, etc.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On the other hand, "high level tests" have traditionally been written as high level test plans in (possibly structured) English; just as the use case descriptions themselves were in English.  A language is needed that can capture this logic (in either spec or test-case form) that is precise enough to be "compilable", and have a robust enough notion of "interfaces" that future detailed implementations can be passed at test runtime as "implementors of those abstract interfaces".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;E.G. If test cases can take the system-being-tested itself as an explicit parameter &lt;span class="Apple-style-span" style="font-style: italic;"&gt;(even though the system is normally the ultimate of implicit parameters)&lt;/span&gt;, that explicit parameter's type is an abstract interface, and the system-being-tested is defined as implementing that interface. [Ed. note: the rest of the world will later get this idea and call it &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;dependency-injection&lt;/span&gt;!]&lt;/div&gt;&lt;div&gt;The abstract interfaces must be able to be associated with the more specific interfaces that make up the various levels of abstraction that are captured as the system design is fleshed out.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, at the very high level (described in the use case above), the interface provides a simple "get balance" request that returns a "number".  Eventually, the actual system has a whole sequence of interaction required to login, navigate to account, request balance, receive formatted display, logout which is encapsulated in a test case defined at that level of abstraction but which none the less can "implement" the getBalance() interface and return the dollar formatted amount as a "number".  So, the specific test case implementation "subclasses" the abstract test case implementation.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;QUESTION: when (i.e. at what level of abstraction) does the "interface" analogy get replaced by the "subclass" analogy?&lt;/div&gt;&lt;div&gt;ANSWER: silly rabbit, each level of abstraction is really a framework that defines interfaces for the more detailed level(s) to implement, and defines "subclasses" to implement the interfaces defined by the framework(s) of the higher level(s) of abstraction.  [Ed. note: don't confuse frameworks with implementation-via-subclassing.  They can use other mechanisms than subclassing to override generic default behavior with specific behavior.]&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-7147106001414006415?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/7147106001414006415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=7147106001414006415' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/7147106001414006415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/7147106001414006415'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/02/abstract-unit-tests.html' title='Abstract Unit Tests'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-2417589280766311584</id><published>2003-02-04T13:45:00.002-05:00</published><updated>2010-12-28T18:54:46.325-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Musing on Events</title><content type='html'>&lt;div&gt;"Events" are a subclass of "Data" where there is one required attribute, namely, a time-stamp.  Arbitrary amounts of other data may be included in an Event but they all have a time-stamp.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The canonical use of Events is for them to act as a trigger for some action to occur.  They secondarily may be logged for audit/replay/etc.  Many systems do not care what the actual time-stamps are, but only that they are sorted in chronological order.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Examples of events are; keystrokes, message receipt, mouseclick, etc.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since the only requirement for an event is that it has a time-stamp, the clock itself can generate events that consist of nothing more than the time-stamp.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"Actors" are generators of events.  Having a "thread of control" means "being able to generate events" rather than only being able to react to events.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since events only need time, people often overlook the fact that a "clock" can be an "actor" and therefore the source of events in a system.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Objects are usually described as containing both behavior and state. State is data. Behavior is a sequence of events.  Control flow is the proscription of how to decide which events are to be generated. So, if objects can be modelled as state change diagrams, the states represent the possible instances of the object data, and the events represent the arcs that trigger a change from one state to another.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Programs represent a planned source of events, and "external actors" represent an unplanned (i.e. unpredictable) source of events.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-2417589280766311584?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/2417589280766311584/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=2417589280766311584' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/2417589280766311584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/2417589280766311584'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2003/02/musing-on-events.html' title='Musing on Events'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-8792241128333351771</id><published>2002-12-24T14:40:00.006-05:00</published><updated>2008-12-16T15:01:58.560-05:00</updated><title type='text'>Add Performance Tests to the Unit Test Paradigm</title><content type='html'>Of the types of automated unit tests (such as are typically implemented in frameworks like JUnit), I think a worthy addition would be performance tests.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It is often the case that code changes affect the performance of the code.  While a bug fix might fix a bug, it might slow down performance in the process.  So called "optimizations" and refactorings may actually slow down performance rather than improve it.  Mostly, it is not typically tested, and therefore not recognized when each chunk of code is checked in, whether it had any effect on performance whether good or bad!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, one could extend the JUnit framework to track the performance history of each test.&lt;/div&gt;&lt;div&gt;This could be simple and lightweight, storing performance numbers in local text files, or it could support a database driven framework with lots of fancy historical analysis.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;It could track the min/max/weighted-average/weight of the real-time and cpu seconds to execute each test. It could flag any test whose execution performance has changed dramatically from the norm. Refactorings that did not affect functionality (but did affect performance) can be noted this way.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Something like...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;import java.io.*;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;import java.util.*;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;import java.text.*;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;import junit.framework.*;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; * A custom JUnit fixture (following JBuilder practice)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; * that times each test run and accumulates the data in&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; * a flat comma-separated-value file (to be easily analysed&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; * via a spreadsheet).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; * @author Bruce Wallace&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; * @see "JBuilder 7 Building Applications pg 9-6"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt; */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;public class TimerFixture&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  final static String kPrefix = "TestData_";&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  final static String kSuffix = ".csv";&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  final static String kSep    = ",";&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  long     fTime;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  TestCase fTest;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  public TimerFixture(Object obj)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    fTest = (TestCase) obj;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  public void setUp()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    fTime = System.currentTimeMillis();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=" "&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  public void tearDown() throws Exception&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    // get data to log&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    long now     = System.currentTimeMillis(); // GET THIS FIRST!!&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    long elapsed = now - fTime;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    String date  = DateFormat.getDateTimeInstance&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;                 ( DateFormat.SHORT, DateFormat.SHORT )&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;                  .format( new Date(now) );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    String name  = fTest.getName();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    //System.out.println("\nTest: "+name+" elapsed time:"+elapsed );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    // append info to test data collection file&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    String fname    = kPrefix + name + kSuffix;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    PrintWriter out = new PrintWriter( new FileWriter(fname,true) );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    out.println( date +kSep+ name +kSep+ elapsed );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;    out.close();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-8792241128333351771?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/8792241128333351771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=8792241128333351771' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/8792241128333351771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/8792241128333351771'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2002/12/add-performance-tests-to-unit-test.html' title='Add Performance Tests to the Unit Test Paradigm'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-2696649767216054295</id><published>2002-12-18T16:18:00.002-05:00</published><updated>2010-12-28T18:54:46.325-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Add main() documentation to JavaDoc</title><content type='html'>&lt;div&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;Open Letter to JavaDoc group at Sun...&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There is a major aspect of Java programming that JavaDoc does not cover, and that is documenting standalone programs; i.e. main() methods.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The reason simply adding JavaDoc comments to main() is not sufficient, is that while the program may be implemented inside some internal package, running the program from the outside world's perspective is a public thing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There needs to be an "Applications" section up top in the overview page along with the packages summary.  In this section, all main() methods that are being "published" can document their calling sequence (aka command line parameters), the formats of any input and output files, the list of and meaning of the process exit codes, and generally anything that all programs need to document such that the outside world knows how to use them.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the Unix world, these things were in "man" pages.  Java needs a standard, platform invariant, way to publish the same info via the JavaDoc mechanism.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I would be interested in following up with you to develop specific proposals, but at this point I simply wanted to register the need with you and see if any efforts were already in the works.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-2696649767216054295?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/2696649767216054295/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=2696649767216054295' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/2696649767216054295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/2696649767216054295'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2002/12/add-main-documentation-to-javadoc.html' title='Add main() documentation to JavaDoc'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-1948705994252059518</id><published>2000-06-08T14:59:00.006-04:00</published><updated>2011-04-14T11:34:15.146-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>There is no such thing as a Component</title><content type='html'>I maintain and preach that there is no such thing as a Component in the same way that there is no such thing as a donut hole.  Just as the donut hole doesn't exist without a donut to define it, a Component doesn't exist without a Framework to define it.  Using a printed circuit board as a metaphor for a framework, it's the "sockets", into which IC chips are meant to be plugged, that define components.  So called universal or standalone components are meaningless (and certainly useless) without some framework that expects components of the same purpose and interface.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ok, so what's your point?  The point is that too many developers (and books on the subject) think about components as standalone chunks of functionality that can be "glued together" after the fact.  They don't realize that the framework has to come first and foremost in conception and design. Szyperski doesn't get around to talking about frameworks until chapter 21 of his Component Software book for heaven's sake.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Even physical components are like this. The prototypical component, the IC chip, always was designed within a family of chips that were meant to work together.  They all needed the same voltage levels for zeroes and ones and tri-states, the same amperage levels, the same clock rates, etc, etc.  Other families used other voltage levels.  The first reusable, interchangeable parts in history were for rifles.  They were meant to be easy and quick to replace (as opposed to the hand crafted muskets they were replacing) but they were meant specifically to make rifles!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can find all sorts of "widgets" and "gizmos" that you might guess are components to something, but unless you know what framework they were meant to be a part of, they are not good for anything but door stops or paperweights.  In other words, random components don't tend to fit together or work together.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Too many people are trying to make "universal" components without realizing that those components still work within some framework that allows them to be put together and communicate with each other.  The problem is that other people doing the same thing have defined other "generic" frameworks that are none the less incompatible.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For example, the toys that baby boomers played with when they were young abounded with generic frameworks of universal components: Tinker Toys, Lincoln Logs, Erector Sets, LEGOs.  They all had universal components within a generic framework that let you build anything.  BUT, you couldn't mix Tinker Toy parts with Erector Set parts (without glue or duct tape).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Ah, you say.  That's why I like duct tape, weakly typed, languages like Perl that lets me glue together parts.  Also, what about Play-doh?!  You could stick anything together with that!  Yes, but there was a reason you made bridges out of Erector Sets instead of Play-doh...and the same reasons apply to software systems....but Strong versus Weak typing is another discussion...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Objects versus Components&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Until I had this epiphany about components as donut holes, I didn't have a good answer to the question "what's the difference between an object and a component?".  I now understand that all objects ARE components, but not all components are objects.  The framework that defines a set of components does not have to be an object oriented framework.  But all object oriented languages define an object framework.  They are generic enough frameworks that any objects programmed in that language may interoperate with each other. Unfortunately though, as with Tinker Toys and Lincoln Logs, Java objects typically can't interact with Smalltalk objects.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In the Java language there are at least two levels of object framework.  There are plain old Java objects (POJOs) and there are so-called JavaBeans.  Whereas any property of a POJO can be accessed (assuming its not protected by the "private" keyword) via a &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;fooObject.barProperty&lt;/span&gt; syntax, only special properties may be accessed via the JavaBeans framework. JavaBeans are those objects that have defined special property accessor methods of the form: getBarProperty() and setBarProperty(). "JavaBean" is the name given to any component that works within that specialized framework. To make matters confusing however, it turns out that Javasoft called more than one framework "JavaBeans" (arrgh!).  There are even more specialized versions of JavaBeans that are made to work with fancy GUI toolkits. SO, WITHOUT CLEARLY FOCUSING ON FRAMEWORKS, EVEN JAVASOFT CONFUSES DIFFERENT COMPONENT TYPES WITH EACH OTHER!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The moral?  Don't fret that there is no such thing as a truly "universal" component. Don't spend energy trying to build them, or building "single universal" frameworks.  Focus on what is needed for your situation and design a well crafted framework first and foremost.  If it needs to work with other frameworks (like whatever Microsoft builds that won't integrate with anybody else), you will understand that the &lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;F&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;rameworks need bridges to each other&lt;/span&gt;&lt;/span&gt;, and not mistakenly think that mere component socket adapters are sufficient.&lt;/div&gt;&lt;aside&gt;&lt;br /&gt;&lt;div class="ppostscript"&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;POSTSCRIPT - Nov 6th, 2002&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;And of course, how could I forget the further confusion Javasoft caused by calling yet another (different) "widget", from yet another (different) framework, a JavaBean: The &lt;a href="http://www.javaworld.com/javaworld/jw-10-1998/jw-10-beans.html"&gt;Enterprise JavaBean&lt;/a&gt;!&lt;/td&gt; &lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/aside&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-1948705994252059518?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/1948705994252059518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=1948705994252059518' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/1948705994252059518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/1948705994252059518'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/2000/06/there-is-no-such-thing-as-component.html' title='There is no such thing as a Component'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-4948222826995074876</id><published>1999-07-17T17:20:00.000-04:00</published><updated>2010-12-28T18:54:46.326-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='faultExpectant'/><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Component Software book ideas</title><content type='html'>&lt;span class="Apple-style-span" style="font-size: small;"&gt;I see that there are some ideas in my Fault Expectant Programming framework that are similar to ideas in "&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial; "&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Component Software"&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; by &lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;a href="http://www.amazon.com/s/ref=rdr_ext_aut?_encoding=UTF8&amp;amp;index=books&amp;amp;field-author=Clemens%20Szyperski"&gt;Clemens Szyperski&lt;/a&gt;.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;On page 307, he talks about "atomic actions" that are invoked indirectly, and even queued up for execution.  This rhymes with my atomic transactions that are managed by a coordinator.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;On page 46, there is a section titled "Specifying Time and Space Requirements" which rhymes with my notion of &lt;span class="Apple-style-span" style="font-style: italic;"&gt;contracts&lt;/span&gt; having enough performance details that it enables bidding on &lt;span class="Apple-style-span" style="font-style: italic;"&gt;requests&lt;/span&gt; by would-be &lt;span class="Apple-style-span" style="font-style: italic;"&gt;workers&lt;/span&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-4948222826995074876?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/4948222826995074876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=4948222826995074876' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4948222826995074876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4948222826995074876'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/1999/07/component-software-book-ideas.html' title='Component Software book ideas'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-8390487600683182754</id><published>1999-07-07T16:29:00.003-04:00</published><updated>2010-12-28T18:54:46.327-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='faultExpectant'/><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>Catalog of Fault Mechanisms</title><content type='html'>&lt;span class="Apple-style-span" style="font-size: small;"&gt;In the previous blog entry, &lt;a href="http://polyglotinc.blogspot.com/1999/07/what-could-fault-expectant-programming.html"&gt;What Could Fault Expectant Programming Mean?&lt;/a&gt;, I outlined a framework abstracted out of recurring themes in a series of error detection, recovery, and avoidance mechanisms that I had compiled.  Here follows that list of mechanisms (in no particular order).&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Distributed Systems:&lt;/span&gt; remove single point of failure by using multiple components&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Loose Coupling:&lt;/span&gt; avoids failure from spreading via ripple effects or brittleness&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Ack/Nak:&lt;/span&gt; verify results and, on failure, repeat request (e.g. protocols)&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Fail Over:&lt;/span&gt; verify results and, on failure, repeat request but to different component&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Do Over:&lt;/span&gt; set aside failed requests or out-of-bound results and retry them later&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Auto Restart:&lt;/span&gt; on failure of a component, it should auto-reset/restart and continue&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Leases:&lt;/span&gt; dead-man switch on any allocated resource of a component (including the attention of its partners a la protocol timeout)&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Event Driven:&lt;/span&gt; handle non-deterministic order of returned results from components&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Fault Tolerance:&lt;/span&gt; ignore failed requests or out-of-bound results and continue rather than generating errors/exceptions&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Backtracking:&lt;/span&gt; processing that expects to hit dead-ends and so backtracks to try other approaches  (e.g. Prolog logic rules, parsers that employ backtracking algorithms)&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Redundant Components:&lt;/span&gt; issue parallel requests to multiple components and take a majority-rules vote on the result (but must know if results are deterministic or not; i.e. if more than one result can be valid then different components may return different, but still valid, results)&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Evolutionary Programming:&lt;/span&gt; issue parallel requests to multiple components and result is taken from the &lt;span class="Apple-style-span" style="font-style: italic;"&gt;most fit&lt;/span&gt; component i.e. chosen by the &lt;span class="Apple-style-span" style="font-style: italic;"&gt;quality&lt;/span&gt; of the result rather than the result itself&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Auctions:&lt;/span&gt; issue parallel requests to multiple components that compete on &lt;span class="Apple-style-span" style="font-style: italic;"&gt;cost of service&lt;/span&gt; as a definition of &lt;span class="Apple-style-span" style="font-style: italic;"&gt;most fit&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Neural Nets:&lt;/span&gt; issue parallel requests to multiple components and take a vote biased by each component's dynamically adjusted &lt;span class="Apple-style-span" style="font-style: italic;"&gt;success&lt;/span&gt; rating (i.e. each component votes its &lt;span class="Apple-style-span" style="font-style: italic;"&gt;stock&lt;/span&gt;).&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Fuzzy Logic:&lt;/span&gt; result returned by component is biased by a probability/quality rating&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Transactions:&lt;/span&gt; state transitions are confined to successful atomic steps&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Exceptions:&lt;/span&gt; asynchronous notification and response to problems where there is the ability to either continue or abort current operation.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Game Theory:&lt;/span&gt; multiple conflicting rule sets are projected via min-max trees to find a balanced result&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Blackboard Systems:&lt;/span&gt; multiple workers on problem process as much as each is able and share common result state i.e. individual workers are not expected to produce a complete result or even any result at all.  E.G. JavaSpaces &lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Workflow Models:&lt;/span&gt; combination of state-transition models and PERT dependency models to keep track of progress at a global level given multiple parallel workers and to reset to some given state(s) if results are not converging&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Belt &amp;amp; Suspenders:&lt;/span&gt; multiple independent methods of verifying results or progress&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Mobile Agents:&lt;/span&gt; workers dynamically move to more appropriate environments e.g. load balancing, fail-over, seek more reliable communications, etc.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Design by Contract:&lt;/span&gt; assertions to detect failure on the part of either the requestor or the worker e.g. Cleanroom techniques, Component Interfaces, Strong Types, policy driven security managers, etc.&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Pattern Matching:&lt;/span&gt; non-trivial matching of requestor interfaces with worker interfaces to allow more flexible and dynamic establishment of contracts e.g. &lt;a href="http://www.cs.umbc.edu/kqml/papers/kbks.pdf"&gt;KQML&lt;/a&gt; , &lt;a href="http://www-cdr.stanford.edu/ProcessLink/papers/jat/jat.html"&gt;JATLite&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-8390487600683182754?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/8390487600683182754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=8390487600683182754' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/8390487600683182754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/8390487600683182754'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/1999/07/catalog-of-fault-mechanisms.html' title='Catalog of Fault Mechanisms'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6921426717100761060.post-4796837358705102289</id><published>1999-07-07T13:41:00.015-04:00</published><updated>2010-12-28T18:54:46.327-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='faultExpectant'/><category scheme='http://www.blogger.com/atom/ns#' term='Captain&apos;s Log'/><title type='text'>What Could Fault-Expectant Programming Mean?</title><content type='html'>&lt;span class="Apple-style-span"  style="font-size:small;"&gt;"Fault-Expectant" is a new term I coined for an alternative to "fault tolerant". It was inspired by reading the transcript of the JAVA LANGUAGE FUTURES session at the 1999 JavaOne conference, where there was a discussion of building robust large scale systems by mimicking biological systems' strategy of actually expecting all their parts to fail.  I realized that fault tolerant (aka High Availability) systems still basically expect things to go right, but provide ways to recover from exceptional failures.  A completely different mind set is needed though to act as if failure is so normal that faults are &lt;/span&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;expected&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;, and expected everywhere.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;A part of the JavaOne discussion centered around the difficulty of building large systems because of the inability of programmers to generate perfect code above a certain size.  The heart of the problem seemed to be our general expectation to the contrary. Unlike biological systems that expect to deal with constant subsystem failure, we basically expect the operations that we invoke to work. We don't, as a rule, build in fine-grained mechanisms to carry on in the event of faults.  &lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;It reminded me of a networking company I worked with that had built error detection into their link layer protocol, but no higher layers.  When I asked why, they said that since there was guaranteed message delivery from machine-to-machine there was no need to recheck it at the end-to-end level.  When I asked, what if there was message loss &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt;inside&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 153);"&gt; a machine, they replied, "that would be a bug that we would have to fix".  It didn't occur to them that protocol stacks could be built to succeed in spite of "bugs" at many levels.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;So, what would "fault expectant" mean? After cataloging all the error detection, handling, &amp;amp; prevention techniques I could think of, and taking a step back, I saw that fault-expectant must mean some amount of non-determinism.  When I ask somebody to do something, I must expect that it will fail, and automatically ask again (whether the same somebody, or someone else). But this "try again" strategy can't be shallow.  It can't merely be like a protocol that re-requests a packet because it got a corrupted one.  It has to be more like a game playing program that looks ahead several promising moves, but backtracks multiple moves when it finds itself painted into a corner.  Like a database transaction that, not only rolls back changes if an error occurs before commit time, but actually tries a different algorithm on the re-attempt.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;Non-deterministic systems are basically trying to optimize a solution using some (hopefully) converging algorithm.  These systems have a long heritage in Artificial Intelligence literature.  There are many algorithms that attempt solutions using components (e.g. heuristic or logic rules) that may or may not succeed, and so rolling back and trying a different path is a normal and not exceptional mode of operation. Prolog is an example of a computer language having built-in goal-seeking behavior, and backtracking after "failures".  I put failures in quotes because they are more like SQL queries that return zero results; not really a failure, just didn't get the info we were looking for.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;A corollary to this approach is that "instructions" must be at such a high level of abstraction, that they are effectively declarative (again like SQL).  I.E. I need to specify &lt;/span&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;what&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; I want, and not &lt;/span&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;how&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt; to do it. Specify idealized instructions then expect &amp;amp; allow imperfect executions of those instructions. The instruction follower interprets the instructions in view of its own circumstances and its own bag of tricks. The book "Meme Machine" (pg x – xii) talks about successful memes having idealized instructions that avoid any details which may fail.  As the meme is perpetuated, each individual attempts to carry out those instructions and may do so imperfectly, but the essence of the idea carries on.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;A Conceptual Framework&lt;span class="Apple-style-span" style="font-weight: normal;font-size:13;" &gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:13;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;font-size:13;" &gt;After reviewing my catalog of error mechanisms (enumerated in a &lt;a href="http://polyglotinc.blogspot.com/1999/07/catalog-of-fault-mechanisms.html"&gt;separate blog entry&lt;/a&gt;), I came up with the following framework abstracted from a few recurring ideas. &lt;span class="Apple-style-span"  style="font-size:small;"&gt;Rather than using terms heavy with connotations (e.g. client, server, message), I have used the following more neutral terms:&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:16;"&gt; requestor, request, result, worker, contract, match, &amp;amp; goal.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;The Request:&lt;/span&gt; A &lt;span class="Apple-style-span" style="font-style: italic;"&gt;requestor&lt;/span&gt;, seeking a &lt;span class="Apple-style-span" style="font-style: italic;"&gt;goal&lt;/span&gt;, makes &lt;span class="Apple-style-span" style="font-style: italic;"&gt;requests&lt;/span&gt; to a set of &lt;span class="Apple-style-span" style="font-style: italic;"&gt;workers&lt;/span&gt; where zero or more workers may return &lt;span class="Apple-style-span" style="font-style: italic;"&gt;results&lt;/span&gt;.  There must be a decision as to which, if any, of the results are acceptable.  If the goal has not been met, there must be a decision as to how to proceed.  In the event of detection of worker failure (e.g. lease expiration, unacceptable result, etc.), a decision must be made as to how to proceed (e.g. Ack/Nak, Tolerance, Do-Over, Fail-Over, etc.).  If more than one result is acceptable, a decision must be made as to which to choose (e.g. majority-rules, most-&lt;span class="Apple-style-span"  style="font-size:small;"&gt;fit, voting-stock, etc.).  The most trivial case of this entire scenario is the statically compiled function call, followed by the increasingly less trivial scenarios: method calls, RPCs, ORB remote methods, web service requests, etc.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;The Negotiation:&lt;/span&gt; A &lt;span class="Apple-style-span" style="font-style: italic;"&gt;requestor&lt;/span&gt; and all responding &lt;span class="Apple-style-span" style="font-style: italic;"&gt;workers&lt;/span&gt; must have a common &lt;span class="Apple-style-span" style="font-style: italic;"&gt;contract&lt;/span&gt; between them that specifies the accepted protocol for each &lt;span class="Apple-style-span" style="font-style: italic;"&gt;request&lt;/span&gt;.  There must be a decision made as to which workers are a &lt;span class="Apple-style-span" style="font-style: italic;"&gt;match&lt;/span&gt; for the proffered contract (e.g. compatible interfaces, domain expertise, etc.).  There must be a decision made as to which compatible workers are actually chosen to be engaged (e.g. lowest cost).&lt;span class="Apple-style-span"  style="font-size:16;"&gt;&lt;span class="Apple-style-span"  style="font-size:13;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-size:16;"&gt;&lt;span class="Apple-style-span"  style="font-size:13;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;The Transaction:&lt;/span&gt; The act of &lt;span class="Apple-style-span" style="font-style: italic;"&gt;matching&lt;/span&gt; &lt;span class="Apple-style-span" style="font-style: italic;"&gt;requestor&lt;/span&gt; and &lt;span class="Apple-style-span" style="font-style: italic;"&gt;worker&lt;/span&gt;(s) for a particular &lt;span class="Apple-style-span" style="font-style: italic;"&gt;request&lt;/span&gt;, engaging the worker(s), judging the &lt;span class="Apple-style-span" style="font-style: italic;"&gt;result&lt;/span&gt;(s), and concluding or aborting the request. It is considered an atomic transaction that commits or rolls back system state.&lt;span class="Apple-style-span"  style="font-size:16;"&gt;&lt;span class="Apple-style-span"  style="font-size:13;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-size:16;"&gt;&lt;span class="Apple-style-span"  style="font-size:13;"&gt;&lt;span class="Apple-style-span"  style="font-size:16;"&gt;&lt;span class="Apple-style-span"  style="font-size:13;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;The Goal:&lt;/span&gt; The act of "engaging a set of &lt;span class="Apple-style-span" style="font-style: italic;"&gt;workers&lt;/span&gt; that are returning (possibly partial) &lt;span class="Apple-style-span" style="font-style: italic;"&gt;results"&lt;/span&gt; is decoupled from the act of "determining whether the overall &lt;span class="Apple-style-span" style="font-style: italic;"&gt;goal&lt;/span&gt; of the &lt;span class="Apple-style-span" style="font-style: italic;"&gt;request&lt;/span&gt; has been met".  This means that there may be a communal data space (e.g. JavaSpaces, blackboard systems, etc.) where (possibly partial) results are deposited and acted upon rather than results being returned directly via any individual worker's response.  It also means that responses with a fuzziness factor may or may not meet goals which have quality requirements, and hence,  work will continue on the original request.&lt;span class="Apple-style-span"  style="font-size:16;"&gt;&lt;span class="Apple-style-span"  style="font-size:13;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="font-size:16;"&gt;&lt;span class="Apple-style-span"  style="font-size:13;"&gt;&lt;span class="Apple-style-span"  style="font-size:16;"&gt;&lt;span class="Apple-style-span"  style="font-size:13;"&gt;&lt;span class="Apple-style-span"  style="font-size:16;"&gt;&lt;span class="Apple-style-span"  style="font-size:13;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;The Coordinator:&lt;/span&gt; The determination of which transaction(s) [and hence request(s)] are generated next is made by a workflow coordinator.  It may use a static state transition scheme (i.e. simple control flow), or it may use any number of dynamic search/optimization schemes (e.g. min-max trees, backtracking, etc.).  Its task is to monitor that progress is being made towards its goal, and reset as needed when progress has ceased.  All state transitions are transactions.  The relationship between coordinators and workers is recursive, i.e. the internal logic of a worker is handled by its own coordinator.  Multiple independent coordinators may monitor the same workflow (i.e. belt &amp;amp; suspenders).  The coordinator(s) insure that failed requestors/workers are restarted or disposed of (aka garbage-collection).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_JWiCz7S_rac/SgNM5X4vZzI/AAAAAAAAADI/qwtMPB0NvMw/s1600-h/faultExpectantDiagram.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 192px;" src="http://2.bp.blogspot.com/_JWiCz7S_rac/SgNM5X4vZzI/AAAAAAAAADI/qwtMPB0NvMw/s400/faultExpectantDiagram.gif" alt="" id="BLOGGER_PHOTO_ID_5333190932285056818" border="0" /&gt;&lt;/a&gt;&lt;div style="text-align: center;"&gt;Fig 1. The transaction players and their shared data space context&lt;br /&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6921426717100761060-4796837358705102289?l=polyglotinc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://polyglotinc.blogspot.com/feeds/4796837358705102289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6921426717100761060&amp;postID=4796837358705102289' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4796837358705102289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6921426717100761060/posts/default/4796837358705102289'/><link rel='alternate' type='text/html' href='http://polyglotinc.blogspot.com/1999/07/what-could-fault-expectant-programming.html' title='What Could Fault-Expectant Programming Mean?'/><author><name>Bruce Wallace</name><uri>http://www.blogger.com/profile/01185353603127616202</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='30' src='http://2.bp.blogspot.com/_JWiCz7S_rac/TAPch8SZX7I/AAAAAAAAAD0/egBtHLbUUFA/S220/polyglotLOGO80.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_JWiCz7S_rac/SgNM5X4vZzI/AAAAAAAAADI/qwtMPB0NvMw/s72-c/faultExpectantDiagram.gif' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
