<?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-2437909874160353836</id><updated>2011-12-27T04:24:20.072-08:00</updated><title type='text'>Closure Tools Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jordan N.</name><uri>http://www.blogger.com/profile/16901237984070230091</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>12</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-5991576993185942024</id><published>2011-11-12T14:58:00.000-08:00</published><updated>2011-11-12T15:04:51.103-08:00</updated><title type='text'>Introducing Closure Stylesheets</title><content type='html'>&lt;div&gt;(CSS is for programming, not for pasting)&lt;/div&gt;&lt;br /&gt;&lt;div&gt;When the &lt;a target="blank" href="http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html"&gt;Closure Tools&lt;/a&gt; were first released a little over two years ago, they gave web developers the ability to organize and optimize their JavaScript and HTML in a new way. But there was something missing, namely, a tool to help manage &lt;a target="blank" href="http://www.w3.org/Style/CSS/Overview.en.html"&gt;CSS&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You see, the nature of CSS runs contrary to the &lt;a target="blank" href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY principle&lt;/a&gt; that is exhibited in good software engineering. For example, if there is a color that should be used for multiple classes in a stylesheet, a developer has no choice but to copy-and-paste it everywhere because CSS has no concept of &lt;a target="blank" href="http://code.google.com/p/closure-stylesheets/#Variables"&gt;variables&lt;/a&gt;. Similarly, if there is a value in a stylesheet that is derived from other values, there is no way to express that because CSS also lacks &lt;a target="blank" href="http://code.google.com/p/closure-stylesheets/#Functions"&gt;functions&lt;/a&gt;. Common patterns of style blocks are duplicated over and over because CSS has no macros. All of these properties of CSS conspire to make stylesheets extremely difficult to maintain.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To this end, we are excited to introduce the missing piece in the Closure Tools suite: &lt;a target="blank" href="http://code.google.com/p/closure-stylesheets/"&gt;Closure Stylesheets&lt;/a&gt;. Closure Stylesheets is an an extension to CSS that adds variables, functions, &lt;a target="blank" href="http://code.google.com/p/closure-stylesheets/#Conditionals"&gt;conditionals&lt;/a&gt;, and &lt;a target="blank" href="http://code.google.com/p/closure-stylesheets/#Mixins"&gt;mixins&lt;/a&gt; to standard CSS. The tool also supports &lt;a target="blank" href="http://code.google.com/p/closure-stylesheets/#Minification"&gt;minification&lt;/a&gt;, &lt;a target="blank" href="http://code.google.com/p/closure-stylesheets/#Linting"&gt;linting&lt;/a&gt;, &lt;a target="blank" href="http://code.google.com/p/closure-stylesheets/#RTL_Flipping"&gt;RTL flipping&lt;/a&gt;, and CSS class &lt;a target="blank" href="http://code.google.com/p/closure-stylesheets/#Renaming"&gt;renaming&lt;/a&gt;. As the existing Closure Tools have done for JavaScript and HTML, Closure Stylesheets will help you write CSS in a maintainable way, while also empowering you to deliver optimized code to your users. We hope you enjoy it! Please let us know what you think in the &lt;a target="blank" href="https://groups.google.com/group/closure-stylesheets-discuss/?pli=1"&gt;discussion forum&lt;/a&gt;.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;i&gt;By Michael Bolin, Open Source Engineer&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;i&gt;Cross posted from the &lt;a href="http://google-opensource.blogspot.com/2011/11/introducing-closure-stylesheets.html"&gt;Google Open Source Blog&lt;/a&gt;.&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-5991576993185942024?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/5991576993185942024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=5991576993185942024&amp;isPopup=true' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/5991576993185942024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/5991576993185942024'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2011/11/introducing-closure-stylesheets.html' title='Introducing Closure Stylesheets'/><author><name>A Googler</name><uri>http://www.blogger.com/profile/07002962734146179522</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-8893508205289382761</id><published>2011-01-25T14:15:00.000-08:00</published><updated>2011-01-25T14:37:56.308-08:00</updated><title type='text'>A Property By Any Other Name, Part 3</title><content type='html'>This is the last in a series of blog posts on how Closure Compiler decides what properties. &lt;a href="http://closuretools.blogspot.com/2011/01/property-by-any-other-name-part-1.html"&gt;Part 1&lt;/a&gt; was about the &lt;code&gt;--compilation_level=ADVANCED_OPTIMIZATIONS&lt;/code&gt; flag and &lt;a href="http://closuretools.blogspot.com/2011/01/property-by-any-other-name-part-2.html"&gt;part 2&lt;/a&gt; was about renaming policies that didn't work. This blog post will be a bit of a grab bag of newer tools for better property renaming.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Using Type Checking to Fill in Missing Externs&lt;/h3&gt;&lt;br /&gt;Your &lt;a href="http://code.google.com/closure/compiler/docs/api-tutorial3.html#externs"&gt;externs file&lt;/a&gt; should declare all the properties that are defined outside of your program. If you haven't done this before, then finding all those properties can be a pain. Fortunately, Closure Compiler can point us in the right direction by checking for missing properties.&lt;br /&gt;&lt;br /&gt;There are a few ways to turn on the missing properties check. For example, you can specify the flags:&lt;br /&gt;&lt;code&gt;--warning_level=VERBOSE --jscomp_warning=missingProperties&lt;/code&gt;&lt;br /&gt;or&lt;br /&gt;&lt;code&gt;--jscomp_warning=checkTypes&lt;/code&gt;&lt;br /&gt;The compiler will try to find places where you've used dot access (&lt;code&gt;foo.bar&lt;/code&gt;) to read a property that can't possibly be defined on that object, perhaps because you've forgotten to declare it in your externs.&lt;br /&gt;&lt;br /&gt;Notice that this check is subtly different than compiler checks in more static languages, like Java. The Java compiler uses a "must-define" approach: the property &lt;code&gt;bar&lt;/code&gt; must be declared on all possible values of &lt;code&gt;foo&lt;/code&gt; (except &lt;code&gt;null&lt;/code&gt;), or it will be a compiler error. Closure Compiler uses a "may-define" approach. It only requires that some possible value of &lt;code&gt;foo&lt;/code&gt; has a property &lt;code&gt;bar&lt;/code&gt;. For example, if you have:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;function f(x) {&lt;br /&gt;  return x.apartment;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Closure Compiler will emit a warning if the &lt;code&gt;apartment&lt;/code&gt; property is not assigned anywhere in the program. Similarly, if you have:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;/** @param {Element} x */&lt;br /&gt;function f(x) {&lt;br /&gt;  return x.apartment;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;the compiler will emit a warning if the &lt;code&gt;apartment&lt;/code&gt; property is not assigned on any object that could possibly be an &lt;code&gt;Element&lt;/code&gt;. It will &lt;em&gt;not&lt;/em&gt; emit a warning if &lt;code&gt;apartment&lt;/code&gt; is assigned on some specific subtype of &lt;code&gt;Element&lt;/code&gt;, like &lt;code&gt;HTMLTextAreaElement&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;As you can see, you don't need complete type annotations to use this check, but more type annotations will get better results.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Using Type Analysis for Better Renaming&lt;/h3&gt;&lt;br /&gt;If a property is listed in the externs file under the "All Unquoted" naming policy, that property will not be renamed anywhere in the program. This is a bummer. We went through a lot of trouble to make the Closure Library events API consistent with the native browser events API. But because we gave the methods the same name as extern methods, those methods can't be renamed. Could we use type information to differentiate between method calls on user-defined objects from method calls on browser-defined objects?&lt;br /&gt;&lt;br /&gt;We can. Closure Compiler's Java API has two options: &lt;code&gt;disambiguateProperties&lt;/code&gt; and &lt;code&gt;ambiguateProperties&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Disambiguation means that Closure Compiler will look at all accesses to a property&lt;br /&gt;&lt;code&gt;x&lt;/code&gt; in the program. If two types have a property &lt;code&gt;xx&lt;/code&gt;// externs file&lt;br /&gt;/** @constructor */ function Element() {}&lt;br /&gt;Element.prototype.id;&lt;br /&gt;&lt;br /&gt;// user code&lt;br /&gt;/** @constructor */&lt;br /&gt;function MyWidget() {&lt;br /&gt;  this.id = 3;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Disambiguate properties will rename this to something like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;/** @constructor */&lt;br /&gt;function MyWidget() {&lt;br /&gt;  this.MyWidget$id = 3;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;By design, disambiguate properties gives things very verbose names, on the assumption that they will be given shorter names by the "All Unquoted" naming policy. This makes it easier to debug, because you can turn off this optimization independently of "all unquoted" property renaming.&lt;br /&gt;&lt;br /&gt;Disambiguate properties allows us to rename some properties that are in the externs file, but it creates a new problem: there are more unique properties, which makes the gzipped code bigger. To solve this problem, we use &lt;code&gt;ambiguateProperties&lt;/code&gt; to minify the number of unique properties. Ambiguate properties will look at two property names on different objects such that there's no chance those objects will appear in the same variable. Then it will give those properties the same name.&lt;br /&gt;&lt;br /&gt;Disambiguate and ambiguate properties are very conservative. They will only rename things if they are reasonably sure that it's safe to do so. (They can never be absolutely sure, because you could always pass in external objects that violate the declared types.) These optimizations only make sense when used in conjunction with "All Unquoted" renaming.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Short Names Aren't Necessarily Better&lt;/h3&gt;&lt;br /&gt;So far in this series, we've been assuming that short names make your binary smaller, and will always be better than long names.&lt;br /&gt;&lt;br /&gt;That makes sense if you're sending your entire JS file across the network. But what if your visitors had old versions of your JS in their cache? You might want to figure out what version they have, and send them only the parts that had changed.&lt;br /&gt;&lt;br /&gt;This is called &lt;a href="http://en.wikipedia.org/wiki/Delta_encoding"&gt;delta encoding&lt;/a&gt;. If the compiler is choosing the shortest possible names for your properties, then small changes to your JS may change every compiled property in the output. The delta between two versions may be as large as the original files.&lt;br /&gt;&lt;br /&gt;What we really want is a way to tell the compiler, "give these properties the shortest possible names, unless you've seen them before, and in that case give them the same name you gave them last time." The compiler has 4 flags for this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;--variable_map_input_file&lt;br /&gt;--variable_map_output_file&lt;br /&gt;--property_map_input_file&lt;br /&gt;--property_map_output_file&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The output maps from one compilation can be used as the input map for the next compilation. Although the compiler cannot guarantee that a property will be renamed the same way in both binaries, it will make a best-effort attempt to do so.&lt;br /&gt;&lt;br /&gt;That covers most of our major property renaming policies. If you have ideas for more, let us know at the &lt;a href="http://groups.google.com/group/closure-compiler-discuss"&gt;Closure Compiler discussion group&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="post-author"&gt;Posted by Nick Santos, Software Engineer&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-8893508205289382761?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/8893508205289382761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=8893508205289382761&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/8893508205289382761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/8893508205289382761'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2011/01/property-by-any-other-name-part-3.html' title='A Property By Any Other Name, Part 3'/><author><name>A Googler</name><uri>http://www.blogger.com/profile/07002962734146179522</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-955557083900945630</id><published>2011-01-21T13:52:00.001-08:00</published><updated>2011-01-21T13:59:29.701-08:00</updated><title type='text'>A Property By Any Other Name, Part 2</title><content type='html'>This is the second in a series of blog posts on how Closure Compiler decides what properties to rename with the &lt;code&gt;--compilation_level=ADVANCED_OPTIMIZATIONS&lt;/code&gt; flag. &lt;a href="http://closuretools.blogspot.com/2011/01/property-by-any-other-name-part-1.html"&gt;Part 1&lt;/a&gt; talks about the current algorithm. This blog post will focus on property renaming policies that we tried that didn't work so well.&lt;br /&gt;&lt;br /&gt;In the beginning, we tried to use coding conventions to decide when to rename things. Uppercase property names (&lt;code&gt;foo.MyMethod&lt;/code&gt;) were renamed, and lowercase property names were not renamed. This didn't work well. One man's internal code is another man's external library. Sometimes you really didn't want uppercase property names to be renamed. Changing your code to use this convention meant breaking your API.&lt;br /&gt;&lt;br /&gt;Later, we tried to move towards "smarter" algorithms, ones that did not require the programmer to be aware of renaming policies. These were called the "heuristic" property renaming policies. These algorithms looked at the entire input to the compiler, and tried to find all writes and reads to a specific property. If it saw at least one write to the property, and was reasonably sure that all the reads of that property came from those writes, then it renamed them all.&lt;br /&gt;&lt;br /&gt;In small apps, heuristic renaming policies worked well. They were not very powerful, but they were easy to migrate to. Even when you didn't declare all the properties on external objects in the externs file, you'd usually still be ok. There would be no property writes to that property name, so the compiler wouldn't try to rename it.&lt;br /&gt;&lt;br /&gt;But for medium to large apps, these advantages were a curse. Consider the following code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;/** @param {Object} json Some external JSON.&lt;br /&gt;function f(json) {&lt;br /&gt;return json.estate;&lt;br /&gt;}&lt;br /&gt;window['__receive_json'] = f;&lt;br /&gt;&lt;br /&gt;// ...&lt;br /&gt;&lt;br /&gt;// in some other code base&lt;br /&gt;Foo.prototype.estate = 3;&lt;br /&gt;f(new Foo());&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If these were the only two appearances of the property &lt;code&gt;estate&lt;/code&gt; in your binary, the compiler would rename it. The compiler can't tell that you're calling &lt;code&gt;f&lt;/code&gt; from external code, and that you expect &lt;code&gt;estate&lt;/code&gt; to be preserved.&lt;br /&gt;&lt;br /&gt;You could have this piece of code that worked for years and years. Then, somebody who you never met could add Foo.prototype.estate in a different part of the codebase. It would break your code for no obvious reason, and the breaking change would be difficult to track down. When we have common JavaScript libraries, this becomes orders of magnitude more problematic. Adding Foo.prototype.estate could break any of the 25 products that depend on your library in subtle and difficult-to-debug ways.&lt;br /&gt;&lt;br /&gt;Even if you did find the problem, how would you work around it? If this is shared code, then changing &lt;code&gt;json.estate&lt;/code&gt; to something like &lt;code&gt;json['estate']&lt;/code&gt; might break other projects that depend on it, because their binaries do expect &lt;code&gt;estate&lt;/code&gt; to get renamed.&lt;br /&gt;&lt;br /&gt;Because of these problems, most projects that use Closure Compiler do not use heuristic renaming algorithms. But heuristic renaming wasn't a total failure. We learned some useful lessons:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;If the compiler looks at your whole program to determine whether a property should be renamed, then that means a change in one part of the program can change property renaming in an unrelated part of the program.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;If your code is shared across projects, then you probably want the property to be renamed in all projects or none of them.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;When renaming properties, it's better to be transparent and 90% accurate than to be cryptic and 99% accurate.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Could we use these lessons to develop a better renaming algorithm? We'll talk about this more in Part 3.&lt;br /&gt;&lt;br /&gt;&lt;span class="post-author"&gt;Posted by Nick Santos, Software Engineer&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-955557083900945630?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/955557083900945630/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=955557083900945630&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/955557083900945630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/955557083900945630'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2011/01/property-by-any-other-name-part-2.html' title='A Property By Any Other Name, Part 2'/><author><name>A Googler</name><uri>http://www.blogger.com/profile/07002962734146179522</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-4324203188914224934</id><published>2011-01-18T13:47:00.000-08:00</published><updated>2011-01-18T14:36:56.782-08:00</updated><title type='text'>A Property By Any Other Name, Part 1</title><content type='html'>When you use Closure Compiler's &lt;code&gt;--compilation_level=ADVANCED_OPTIMIZATIONS&lt;/code&gt; flag, the compiler will try to rename properties on your objects. For example, it may rename &lt;code&gt;x.longPropertyName&lt;/code&gt; to &lt;code&gt;x.a&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Because property renaming is a complex topic, we're going to split this discussion up into three blog posts. Part 1 is about the property renaming that you get with &lt;code&gt;ADVANCED_OPTIMIZATIONS&lt;/code&gt;. Part 2 will be about other property renaming algorithms we've tried that didn't work so well. Part 3 will be about property renaming algorithms that we're currently experimenting on and are available from the Java API.&lt;br /&gt;&lt;br /&gt;If you're using Closure Compiler's Java API, you have more fine-grained control over what renaming the compiler does. The API treats variable renaming (&lt;code&gt;foo.bar&lt;/code&gt; -&gt; &lt;code&gt;a.bar&lt;/code&gt;) and property renaming (&lt;code&gt;foo.bar&lt;/code&gt; -&gt; &lt;code&gt;foo.a&lt;/code&gt;) as completely independent optimizations. You can choose a variable renaming policy and a property renaming policy. The best property renaming policy, "All Unquoted," is what you get when you use &lt;code&gt;ADVANCED_OPTIMIZATIONS&lt;/code&gt;. Most large Google projects use it. It significantly changes how we write JavaScript.&lt;br /&gt;&lt;br /&gt;In the general case, a compiler can't rename properties at compile-time. You simply don't have enough information to try. There will always be objects that come from external sources that the compiler can't see (like JSON responses from the server), and property names that are undecidable. (Consider the expression &lt;code&gt;foo[undecidableFunction()] = function(){};&lt;/code&gt;.) So property renaming can never be perfect. There will always be rules and gotchas.&lt;br /&gt;&lt;br /&gt;Before we talk about the best property renamer, "All Unquoted," we have to define what we mean by "best." Usually, we use three criteria.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Power: How much smaller does it make your code?&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Failure Cases: If it renames properties incorrectly, how easy is it to figure out what went wrong? How easy is it to fix the issue? If you make a change, how confident can you be that it won't break renaming?&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Migration: How easy is it to update a legacy codebase so that it can take advantage of property renaming?&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;"All Unquoted" renaming was designed to optimize for #2: making the failure cases easy to debug and correct. By design, the algorithm is transparent and simple.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;If a property is in the externs file, don't rename it.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;If the property appears in quotes, don't rename it.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Otherwise, rename it.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;For example, if you write the code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;var obj = {&lt;br /&gt;alice: true,&lt;br /&gt;'bob': true&lt;br /&gt;};&lt;br /&gt;obj.claire = true;&lt;br /&gt;obj.document = true;&lt;br /&gt;window['obj'] = obj;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;then you will get something that looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;var a = {&lt;br /&gt;a: true, // alice was not in quotes or in the externs file&lt;br /&gt;bob: true // bob was in quotes&lt;br /&gt;};&lt;br /&gt;a.b = true; // claire was not in quotes or in the externs file&lt;br /&gt;a.document = true; // document was in the externs file&lt;br /&gt;window.obj = a; // obj was in quotes&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you use the &lt;code&gt;--debug&lt;/code&gt; flag, the same properties still get renamed, but now it will be much easier to see what the original names were:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;var $obj$$ = {&lt;br /&gt;$alice$: true,&lt;br /&gt;'bob': true&lt;br /&gt;};&lt;br /&gt;$obj$$.$claire$ = true;&lt;br /&gt;$obj$$.document = true;&lt;br /&gt;window['obj'] = $obj$$;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This has some nice features that help debugging and development. It's straightforward for the average programmer to look at the compiled output and figure out why the compiler is renaming something, and what the name should be. If we decide that we don't want the property "claire" to be renamed, then we can change &lt;code&gt;obj.claire&lt;/code&gt; to &lt;code&gt;obj['claire']&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Furthermore, this convention makes it easier to read and refactor code written by a large team of JavaScript developers. If Bob is using "All Unquoted," and he has a method defined as &lt;code&gt;Foo.prototype.methodA = fn&lt;/code&gt;, then Alice can easily search for all calls to &lt;code&gt;methodA&lt;/code&gt; in the codebase. She doesn't have to worry about opaque accesses to the method, like &lt;code&gt;obj['method' + 'A']&lt;/code&gt;, because she knows that the compiler will break those accesses anyway.&lt;br /&gt;&lt;br /&gt;Another way to look at it is that we use the dotted access (&lt;code&gt;obj.alice&lt;/code&gt;) for compile-time property lookups, and array access (&lt;code&gt;obj['alice']&lt;/code&gt;) for run-time property lookups.&lt;br /&gt;&lt;br /&gt;But there are some big downsides to "All Unquoted." As you saw above, any property in the externs file cannot be renamed anywhere in the program. When your methods have the same names as native browser methods, they won't be renamed. It's not as powerful as it could be.&lt;br /&gt;&lt;br /&gt;Even worse, it is difficult to safely convert a legacy codebase to use this renaming policy. Because you never had to declare your "external" properties, you probably didn't, and it's a bear to find them all.&lt;br /&gt;&lt;br /&gt;Could we do better? Maybe there's additional information we could leverage to get fewer false positives and false negatives? Perhaps we could look at the type annotations, or at other property assignments in the program? We'll get to those questions in the next two posts.&lt;br /&gt;&lt;br /&gt;&lt;span class="post-author"&gt;Posted by Nick Santos, Software Engineer&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-4324203188914224934?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/4324203188914224934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=4324203188914224934&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/4324203188914224934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/4324203188914224934'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2011/01/property-by-any-other-name-part-1.html' title='A Property By Any Other Name, Part 1'/><author><name>A Googler</name><uri>http://www.blogger.com/profile/07002962734146179522</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-225960260153901521</id><published>2010-10-12T14:04:00.000-07:00</published><updated>2010-10-12T14:15:40.288-07:00</updated><title type='text'>This “this” is Your This</title><content type='html'>In &lt;a href="http://closuretools.blogspot.com/2010/08/this-var-is-my-var.html"&gt;a past blog post&lt;/a&gt;, we talked about how Closure Compiler makes it easier to share common JavaScript by ensuring that everybody declares what variables they own.&lt;br /&gt;&lt;br /&gt;Global variable uniqueness is something that we added checks for fairly early on. Some restrictions are less obvious. In this blog post we’ll talk about the &lt;code&gt;this&lt;/code&gt; keyword.&lt;br /&gt;&lt;br /&gt;Suppose Nathan wants to outsource hot dog eating contests, so that we don’t need an instance of Nathan to run one. To do so, he takes &lt;code&gt;runHotDogContest&lt;/code&gt; and &lt;code&gt;unpackHotDogs&lt;/code&gt; off the prototype, and makes them into static methods. The code now looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Nathan.runHotDogContest = function(player, boxes) {&lt;br /&gt; for (var i = 0; i &lt; boxes.length; i++) {&lt;br /&gt;   player.eatHotDogs(this.unpackHotDogs(boxes[i]));&lt;br /&gt; }&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I want to run 2 hot dog contests, so naturally, I write:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;var run = Nathan.runHotDogContest;&lt;br /&gt;run(joey, crateA);&lt;br /&gt;run(kobayashi, crateB);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The code fails with an error that &lt;code&gt;unpackHotDogs&lt;/code&gt; is not defined on &lt;code&gt;this&lt;/code&gt;.  The reason is subtle. To the person writing &lt;code&gt;Nathan.runHotDogContest&lt;/code&gt;, &lt;code&gt;this&lt;/code&gt; and &lt;code&gt;Nathan&lt;/code&gt; seem like interchangeable variables. And as long as you’re testing them by invoking them as:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Nathan.runHotDogContest(joey, crateA);&lt;br /&gt;Nathan.runHotDogContest(kobayashi, crateB);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;then they will be interchangeable.&lt;br /&gt;&lt;br /&gt;In fact, &lt;code&gt;this&lt;/code&gt; is a secret argument to the function. It’s much like any other function argument, except that it appears on the left side of the function call instead of on the right side. So &lt;code&gt;Nathan.runHotDogContest(...)&lt;/code&gt; passes &lt;code&gt;Nathan&lt;/code&gt; as the &lt;code&gt;this&lt;/code&gt; argument, and &lt;code&gt;run(...)&lt;/code&gt; passes &lt;code&gt;null&lt;/code&gt; as the &lt;code&gt;this&lt;/code&gt; argument (which JavaScript helpfully coerces to window).&lt;br /&gt;&lt;br /&gt;To make Closure Library usable, the library authors and the library users need to agree on what the arguments to a function mean. This includes &lt;code&gt;secret&lt;/code&gt; arguments like &lt;code&gt;this&lt;/code&gt;. So we’ve agreed that only constructors and prototype methods may use &lt;code&gt;this&lt;/code&gt;, and the &lt;code&gt;this&lt;/code&gt; argument must be an instanceof the relevant constructor. Closure Compiler enforces this in &lt;code&gt;--warning_level VERBOSE&lt;/code&gt;, and will often emit a warning if it sees &lt;code&gt;this&lt;/code&gt; used in a dangerous place.&lt;br /&gt;&lt;br /&gt;If you’re writing a function that expects an unusual &lt;code&gt;this&lt;/code&gt; context, you can explicitly document it with &lt;a href="http://www.google.com/url?q=http%3A%2F%2Fgoogle-styleguide.googlecode.com%2Fsvn%2Ftrunk%2Fjavascriptguide.xml%3Fshowall%3Dy%23tag-this"&gt;the &lt;code&gt;@this&lt;/code&gt; annotation&lt;/a&gt;, and the warning will go away.&lt;br /&gt;&lt;br /&gt;Good luck with all of this!&lt;br /&gt;&lt;br /&gt;&lt;span class="post-author"&gt;Posted by Nick Santos, Software Engineer&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-225960260153901521?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/225960260153901521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=225960260153901521&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/225960260153901521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/225960260153901521'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2010/10/this-this-is-your-this.html' title='This “this” is Your This'/><author><name>A Googler</name><uri>http://www.blogger.com/profile/07002962734146179522</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-5543721988577799594</id><published>2010-08-31T15:45:00.000-07:00</published><updated>2010-08-31T16:55:09.170-07:00</updated><title type='text'>Introducing Closure Linter</title><content type='html'>When collaborating with lots of engineers as we do here at Google, it’s important to keep a consistent coding style.  To this end, we recently open sourced the &lt;a href="http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml"&gt;Google JavaScript Style Guide&lt;/a&gt;.  &lt;br /&gt;&lt;br /&gt;Today we’re happy to announce we’re open sourcing a tool that will help you follow that style guide with minimal manual effort - the Closure Linter.&lt;br /&gt;&lt;br /&gt;Take for example, this code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;var x = 10&lt;br /&gt;var y=20;&lt;br /&gt;&lt;br /&gt;for(var i = 0;i &lt; 10; i++ ) {&lt;br /&gt;  x += i;&lt;br /&gt;   y -= i;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;var z = [10, 20,];&lt;br /&gt;&lt;br /&gt;x = y + z[0]&lt;br /&gt;    + 10;&lt;/pre&gt;&lt;br /&gt;When we run &lt;code&gt;gjslint --strict fixme.js&lt;/code&gt; we get&lt;br /&gt;&lt;pre&gt;Line 1, E:0010: (New error) Missing semicolon at end of line&lt;br /&gt;Line 2, E:0002: Missing space before "="&lt;br /&gt;Line 2, E:0002: Missing space after "="&lt;br /&gt;Line 4, E:0002: Missing space before "("&lt;br /&gt;Line 4, E:0002: Missing space after ";" in for statement&lt;br /&gt;Line 4, E:0001: Extra space before ")"&lt;br /&gt;Line 6, E:0006: (New error) Wrong indentation: expected any of {2} but got 3&lt;br /&gt;Line 9, E:0121: Illegal comma at end of array literal&lt;br /&gt;Line 12, E:0120: Binary operator should go on previous line "+"&lt;br /&gt;Found 9 errors, including 2 new errors, in 1 files (0 files OK).&lt;/pre&gt;&lt;br /&gt;Even better, if we run &lt;code&gt;fixjsstyle --strict fixme.js&lt;/code&gt;, 7 of the 9 errors are automatically fixed for us!&lt;br /&gt;&lt;br /&gt;We hope you can use the Closure Linter to improve your style consistency while simultaneously saving time.  More information on how to get started can be found on the &lt;a href="http://code.google.com/closure/utilities/docs/linter_howto.html"&gt;How to Use Closure Linter&lt;/a&gt; page.&lt;br /&gt;&lt;br /&gt;We welcome comments and questions in &lt;a href="http://groups.google.com/group/closure-linter-discuss"&gt;the discussion forum&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="post-author"&gt;Posted by Robby Walker and Andy Perelson, Software Engineers&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-5543721988577799594?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/5543721988577799594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=5543721988577799594&amp;isPopup=true' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/5543721988577799594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/5543721988577799594'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2010/08/introducing-closure-linter.html' title='Introducing Closure Linter'/><author><name>A Googler</name><uri>http://www.blogger.com/profile/07002962734146179522</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-1022065478972077188</id><published>2010-08-30T13:34:00.000-07:00</published><updated>2010-08-30T13:50:11.203-07:00</updated><title type='text'>This Var is My Var</title><content type='html'>The Closure Compiler you know is very different than the Closure Compiler that’s familiar to Google engineers. The defaults at Google are much stricter. It forbids duplicate global variable declarations, performs type-checking, and restricts a number of other patterns that are common in non-Closure-style JavaScript. By default, the “Google build” of Closure Compiler is like running the "open source build" of Closure Compiler with the &lt;code&gt;--warning_level VERBOSE&lt;/code&gt; flag.&lt;br /&gt;&lt;br /&gt;Why? Almost every contributor to Closure Tools works on web applications. We want to be able to share code. Part of that means we should be able to fix the shared code, and integrate it into all our apps quickly so that, for example, &lt;a href="http://blogs.msdn.com/b/ie/archive/2010/04/26/feedback-on-the-ie9-platform-preview.aspx"&gt;fixes for IE9&lt;/a&gt; will make it out to production within a reasonable time. To integrate those changes safely, we need to be confident that they won’t break anything. Compiler restrictions help us do that. Sometimes those restrictions are obvious...sometimes less so.&lt;br /&gt;&lt;br /&gt;Suppose Joey writes some library code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Joey.prototype.eatHotDogs = function(hotDogs) {&lt;br /&gt;  for (i = 0; i &lt; hotDogs.length; i++) {&lt;br /&gt;    this.eat(hotDogs[i]);&lt;br /&gt;  }&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;Next summer, Nathan writes an application to feed Joey HotDogs by the boxful:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Nathan.prototype.runHotDogContest = function(player, boxes) {&lt;br /&gt;  for (i = 0; i &lt; boxes.length; i++) {&lt;br /&gt;    player.eatHotDogs(this.unpackHotDogs(boxes[i]));&lt;br /&gt;  }&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;Surprisingly, when Nathan runs his code in a browser, it tries to feed Joey an infinite number of hot dogs and crashes the browser.&lt;br /&gt;&lt;br /&gt;The problem, of course, is that JavaScript "helpfully" declares variables for you if you forgot. No one declared &lt;code&gt;i&lt;/code&gt;, so a variable &lt;code&gt;i&lt;/code&gt; got magicked into the global scope. When Joey originally wrote his code, he tested it and it worked fine. But when Nathan tried to use it, he found that &lt;code&gt;eatHotDogs()&lt;/code&gt; was "resetting" the &lt;code&gt;i&lt;/code&gt; in his loop every time he called it.&lt;br /&gt;&lt;br /&gt;In this example, Nathan was directly calling the problematic method, and the bug was relatively easy to spot. In the general case, these bugs are "non-localized" —missing &lt;code&gt;var&lt;/code&gt; in one file may trigger a bug in an unrelated file that hasn’t been touched in years. Or it may cause a bug years later in unrelated new code. For a library shared across many codebases, non-localized bugs can stop progress quickly because it’s so hard to know where to start looking.&lt;br /&gt;&lt;br /&gt;In &lt;code&gt;VERBOSE&lt;/code&gt; mode, Closure Compiler enforces that all variables must be declared with the &lt;code&gt;var&lt;/code&gt; or &lt;code&gt;function&lt;/code&gt; or &lt;code&gt;catch&lt;/code&gt; keywords. Global variables may only be declared once. The Google JS style guide has &lt;a href="http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml#Naming"&gt;naming conventions&lt;/a&gt; to make these collisions even less likely.&lt;br /&gt;&lt;br /&gt;This rule has some corollaries that have a big impact on how we write JavaScript. For one, there must be a way to declare variables that are "owned" by the surrounding page, and not by the code under compilation. So Closure Compiler has &lt;a href="http://code.google.com/closure/compiler/docs/api-tutorial3.html#externs"&gt;externs files&lt;/a&gt;, which allow you to declare external variables. Conversely, external variables may not conflict with your code. If you use the default externs, you will not be able to name a variable &lt;code&gt;Node&lt;/code&gt; because it will conflict with &lt;a href="http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247"&gt;DOM Nodes&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Try running Closure Compiler with &lt;code&gt;--warning_level=VERBOSE&lt;/code&gt; mode and see what you find in your code!&lt;br /&gt;&lt;br /&gt;&lt;span class="post-author"&gt;Posted by Nick Santos, Software Engineer&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-1022065478972077188?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/1022065478972077188/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=1022065478972077188&amp;isPopup=true' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/1022065478972077188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/1022065478972077188'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2010/08/this-var-is-my-var.html' title='This Var is My Var'/><author><name>A Googler</name><uri>http://www.blogger.com/profile/07002962734146179522</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-4092359197588169326</id><published>2010-07-14T11:05:00.000-07:00</published><updated>2010-07-14T11:24:33.972-07:00</updated><title type='text'>Introducing the Closure Library Editor</title><content type='html'>One of the &lt;a href="http://closure-library.googlecode.com/svn/trunk/closure/goog/ui/"&gt;many UI widgets&lt;/a&gt; included in the Closure Library is a full-featured rich text editor.&lt;br /&gt; &lt;br /&gt;All modern browsers have rich text editing functionality built in &amp;mdash; unfortunately this functionality is at best inconsistent and, at worst, broken.  Closure Library’s editor is a sub-project within Closure.  It provides a common, powerful, and extensible interface that abstracts the cross-browser inconsistencies and shortcomings of rich text editing.&lt;br /&gt; &lt;br /&gt;We use the Closure editor in Gmail, Google Sites, Google Groups, and many other Google products.  We’re very happy to be able to share this editor with you as part of the Closure Library.&lt;br /&gt; &lt;br /&gt;&lt;h4&gt;Using the editor in your project&lt;/h4&gt;&lt;br /&gt;A &lt;a href="http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/demos/editor/editor.html"&gt;demo of the basic editor functionality&lt;/a&gt; is included in the source distribution, and can be tried &lt;a href="http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/editor/editor.html"&gt;here&lt;/a&gt;.&lt;br /&gt; &lt;br /&gt;The most important code is as follows.  First, we create an editable field and attach it to an element with the id &lt;code&gt;editMe&lt;/code&gt;.&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;// Create an editable field.&lt;br /&gt;var myField = new goog.editor.Field('editMe');&lt;/pre&gt; &lt;br /&gt;Next, we register editing &lt;em&gt;plugins&lt;/em&gt;.  The rich text editor uses a plugin-based architecture in order to support many products with different feature sets.  For example, in Gmail, the tab key moves the cursor to the send button, while in Google Sites it either adds 4 spaces or indents the current bulleted list.  Plugins allow us to create modular features for the Editor and let each application pick and choose which ones they need or want.  This ensures each application only brings in the code it needs, helping to minimize code size and latency.&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;// Create and register all of the editing plugins you want to use.&lt;br /&gt;myField.registerPlugin(new goog.editor.plugins.BasicTextFormatter());&lt;br /&gt;myField.registerPlugin(new goog.editor.plugins.RemoveFormatting());&lt;br /&gt;myField.registerPlugin(new goog.editor.plugins.UndoRedo());&lt;br /&gt;myField.registerPlugin(new goog.editor.plugins.ListTabHandler());&lt;br /&gt;myField.registerPlugin(new goog.editor.plugins.SpacesTabHandler());&lt;br /&gt;myField.registerPlugin(new goog.editor.plugins.EnterHandler());&lt;br /&gt;myField.registerPlugin(new goog.editor.plugins.HeaderFormatter());&lt;br /&gt;myField.registerPlugin(&lt;br /&gt;    new goog.editor.plugins.LoremIpsum('Click here to edit'));&lt;br /&gt;myField.registerPlugin(&lt;br /&gt;    new goog.editor.plugins.LinkDialogPlugin());&lt;/pre&gt;&lt;br /&gt;In a future post, we’ll discuss how you can use the plugin system to add your own custom functionality to your editor.&lt;br /&gt; &lt;br /&gt;Next we set up our toolbar:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;// Specify the buttons to add to the toolbar, using built in default buttons.&lt;br /&gt;var buttons = [&lt;br /&gt;  goog.editor.Command.BOLD,&lt;br /&gt;  goog.editor.Command.ITALIC,&lt;br /&gt;  goog.editor.Command.UNDERLINE,&lt;br /&gt;  goog.editor.Command.FONT_COLOR,&lt;br /&gt;  goog.editor.Command.BACKGROUND_COLOR,&lt;br /&gt;  goog.editor.Command.FONT_FACE,&lt;br /&gt;  goog.editor.Command.FONT_SIZE,&lt;br /&gt;  goog.editor.Command.LINK,&lt;br /&gt;  goog.editor.Command.UNDO,&lt;br /&gt;  goog.editor.Command.REDO,&lt;br /&gt;  goog.editor.Command.UNORDERED_LIST,&lt;br /&gt;  goog.editor.Command.ORDERED_LIST,&lt;br /&gt;  goog.editor.Command.INDENT,&lt;br /&gt;  goog.editor.Command.OUTDENT,&lt;br /&gt;  goog.editor.Command.JUSTIFY_LEFT,&lt;br /&gt;  goog.editor.Command.JUSTIFY_CENTER,&lt;br /&gt;  goog.editor.Command.JUSTIFY_RIGHT,&lt;br /&gt;  goog.editor.Command.SUBSCRIPT,&lt;br /&gt;  goog.editor.Command.SUPERSCRIPT,&lt;br /&gt;  goog.editor.Command.STRIKE_THROUGH,&lt;br /&gt;  goog.editor.Command.REMOVE_FORMAT&lt;br /&gt;];&lt;br /&gt;var myToolbar = goog.ui.editor.DefaultToolbar.makeToolbar(buttons,&lt;br /&gt;    goog.dom.getElement('toolbar'));&lt;br /&gt; &lt;br /&gt;// Hook the toolbar into the field.&lt;br /&gt;var myToolbarController =&lt;br /&gt;    new goog.ui.editor.ToolbarController(myField, myToolbar);&lt;/pre&gt;&lt;br /&gt;And finally, we turn on editing:&lt;br /&gt; &lt;br /&gt;&lt;pre&gt;myField.makeEditable();&lt;/pre&gt;&lt;br /&gt;When we open the file in the browser, we get an HTML editor:&lt;br /&gt; &lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_QD-u0j65A7k/TD39-wlNSJI/AAAAAAAAACA/efLsJ8MesHE/editor.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 295px;" src="http://4.bp.blogspot.com/_QD-u0j65A7k/TD39-wlNSJI/AAAAAAAAACA/efLsJ8MesHE/s500/editor.png" /&gt;&lt;/a&gt;&lt;br /&gt; &lt;br /&gt;Let us know in the comments if you’ve used or plan to use the Closure Library rich text editor in your project.  If you have questions, please post them to the &lt;a href="https://groups.google.com/group/closure-library-discuss"&gt;discussion group&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="post-author"&gt;Posted by Robby Walker, Software Engineer&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-4092359197588169326?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/4092359197588169326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=4092359197588169326&amp;isPopup=true' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/4092359197588169326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/4092359197588169326'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2010/07/introducing-closure-library-editor.html' title='Introducing the Closure Library Editor'/><author><name>Nathan Naze</name><uri>http://www.blogger.com/profile/08280236711469825420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QD-u0j65A7k/TD39-wlNSJI/AAAAAAAAACA/efLsJ8MesHE/s72-c/editor.png' height='72' width='72'/><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-4415251372544351603</id><published>2010-07-01T18:06:00.000-07:00</published><updated>2010-07-01T18:21:36.771-07:00</updated><title type='text'>Closure Compiler at O'Reilly Velocity Conference 2010</title><content type='html'>I would like to thank everyone who stuck around the booth area for my whiteboard presentation on Closure Compiler last week. It was fun meeting all the developers who share the same passion for making fast and awesome web applications! I hope everyone would continue to find Closure Compiler useful in speeding up your applications.&lt;br /&gt;&lt;br /&gt;For those who did not get a chance to attend the conference, I wanted to share the slides with you:&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://docs.google.com/present/embed?id=dgsp8w6z_80ffttw8c7&amp;size=m" frameborder="0" width="555" height="451"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;Thanks again, and if you have questions, please drop us a note on the &lt;a href="https://groups.google.com/group/closure-compiler-discuss/topics"&gt;Closure Compiler discussion list&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="post-author"&gt;Alan Leung, Software Engineer, Closure Compiler team&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-4415251372544351603?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/4415251372544351603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=4415251372544351603&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/4415251372544351603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/4415251372544351603'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2010/07/closure-compiler-at-oreilly-velocity.html' title='Closure Compiler at O&apos;Reilly Velocity Conference 2010'/><author><name>Nathan Naze</name><uri>http://www.blogger.com/profile/08280236711469825420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-2026952809427701921</id><published>2010-06-08T18:22:00.000-07:00</published><updated>2010-06-08T18:34:23.336-07:00</updated><title type='text'>Closure Library Tech Talk at Google I/O, now on YouTube</title><content type='html'>The video of our talk at Google I/O, &lt;a href="http://code.google.com/events/io/2010/sessions/closure-library.html"&gt;&lt;em&gt;Opening Up Closure Library&lt;/em&gt;&lt;/a&gt;, has been posted.&lt;br /&gt;&lt;br /&gt;&lt;object width="540" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/yp_9q3tgDnQ&amp;hl=en_US&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/yp_9q3tgDnQ&amp;hl=en_US&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="540" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://dl.google.com/googleio/2010/tech-talks-closure-library.pdf"&gt;session slides&lt;/a&gt; are also available as a PDF.&lt;br /&gt;&lt;br /&gt;&lt;span class="post-author"&gt;Posted by Nathan Naze, Closure Tools Team&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-2026952809427701921?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/2026952809427701921/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=2026952809427701921&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/2026952809427701921'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/2026952809427701921'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2010/06/closure-library-tech-talk-at-google-io.html' title='Closure Library Tech Talk at Google I/O, now on YouTube'/><author><name>Nathan Naze</name><uri>http://www.blogger.com/profile/08280236711469825420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-8185399890116765121</id><published>2010-06-04T08:51:00.001-07:00</published><updated>2010-06-04T09:07:30.840-07:00</updated><title type='text'>Closure Tools: Open for Business</title><content type='html'>When we &lt;a href="http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html"&gt;open sourced the Closure Tools&lt;/a&gt;, we were ecstatic to be getting such great and useful code out to the world. And since then, we’ve seen people do great stuff with Closure Tools. And then we got a little nervous. You see, the more cool stuff you do with Closure Tools, the more work we figured we should put into their open sourcing. Today, we’d like to describe our latest work making the Closure Tools even more open.&lt;br /&gt;&lt;br /&gt;I’m a member of the &lt;a href="http://google-opensource.blogspot.com/"&gt;Open Source Programs Office&lt;/a&gt; at Google, which means I help teams that are open sourcing Google code do it better and more easily. I’ve built a toolkit to help these teams called “Make Open Easy” (shameless plug: I’ll be presenting my work in more detail at &lt;a href="http://www.oscon.com/oscon2010/public/schedule/detail/13833"&gt;OSCON&lt;/a&gt; this year). It automates the processes of maintaining an open source codebase of Google code: publishing updates, merging patches made in subversion back into our internal source control, and keeping track of who’s done what. We’ve now “MOEified” &lt;a href="http://code.google.com/p/closure-compiler"&gt;Closure Compiler&lt;/a&gt; and &lt;a href="http://code.google.com/p/closure-library"&gt;Library&lt;/a&gt;. What does this mean for you?&lt;br /&gt;&lt;br /&gt;First, we’re going to push updates more often, regularly, and with descriptions of the changes. Updating the public version with the changes made at Google now takes minutes. For now, we’re not setting a schedule, but we expect that we shouldn’t go more than two weeks without updating the codebase in public Subversion. We hope you’ll appreciate getting code that’s fresh off the press.&lt;br /&gt;&lt;br /&gt;Second, we now want your patches! Since MOE has made merging patches written against the public codebase so easy, we want public contrubtions to the compiler and library. If there are bugs you’d like to fix or features you’d like to implement, feel free to send us a patch. We’re still going to hold patches to a high level of quality, design, and style, so consider talking to us first on our “discuss” lists (&lt;a href="https://groups.google.com/group/closure-library-discuss"&gt;closure-library-discuss&lt;/a&gt; and &lt;a href="https://groups.google.com/group/closure-compiler-discuss"&gt;closure-compiler-discuss&lt;/a&gt;). And, as before, if you have ideas but not code, we still welcome your thoughts. We’d like to work with you to shape Closure Tools.)&lt;br /&gt;&lt;br /&gt;The Closure Tools team is committed to being more transparent and collaborative but sometimes there still might be issues with releasing or accepting code. Please be patient as we work out kinks in the process.&lt;br /&gt;&lt;br /&gt;So, what’s the next feature for Closure Tools? Now’s your chance to show us!&lt;br /&gt;&lt;br /&gt;&lt;span class="post-author"&gt;Posted by Dan Bentley, Open Source Programs Office&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-8185399890116765121?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/8185399890116765121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=8185399890116765121&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/8185399890116765121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/8185399890116765121'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2010/06/closure-tools-open-for-business.html' title='Closure Tools: Open for Business'/><author><name>Nathan Naze</name><uri>http://www.blogger.com/profile/08280236711469825420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2437909874160353836.post-4670046662074372328</id><published>2010-05-19T10:45:00.000-07:00</published><updated>2010-05-18T21:41:11.938-07:00</updated><title type='text'>Welcome to the Closure Tools blog</title><content type='html'>&lt;div&gt;&lt;div&gt;Last November, we &lt;a href="http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html"&gt;released Closure Tools&lt;/a&gt; as open source software.  These web development tools encompass three major components: a &lt;a href="http://code.google.com/closure/compiler/"&gt;compiler&lt;/a&gt;, a &lt;a href="http://code.google.com/closure/library/"&gt;library&lt;/a&gt;, and a &lt;a href="http://code.google.com/closure/templates/"&gt;templating&lt;/a&gt; system.  Google engineers use these three tools to put together some of our largest web applications: Gmail, Google Docs, Google Sites, and many others. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The response has been heartening.  A number of projects have adopted Closure Compiler, both for its excellent performance as a minifier, but also for its compile-time optimizations and type checking.  Many folks have picked up Closure Library and Closure Templates as the basis for their new web projects.  Traffic on the &lt;a href="https://groups.google.com/group/closure-compiler-discuss"&gt;three&lt;/a&gt; &lt;a href="https://groups.google.com/group/closure-library-discuss"&gt;discussion&lt;/a&gt; &lt;a href="https://groups.google.com/group/closure-templates-discuss"&gt;lists&lt;/a&gt; has been growing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In conjunction with our events for the &lt;a href="http://googlecode.blogspot.com/2009/11/introducing-closure-tools.html"&gt;library&lt;/a&gt; and &lt;a href="http://code.google.com/events/io/2010/officehours.html"&gt;compiler&lt;/a&gt; at &lt;a href="http://code.google.com/events/io/2010/"&gt;Google I/O&lt;/a&gt;, we’re taking a few steps to help encourage that nascent community.  The first to mention is this blog, on which we plan to publish notes, tips, and helpful articles from engineers working on Closure Tools.  We’ve also started a &lt;a href="http://twitter.com/closuretools"&gt;Twitter account&lt;/a&gt; that you can follow. And, as of today, Closure Library joins Closure Compiler as a project that can take external patches from developers outside of Google.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So add this blog to your feed reader (perhaps Google Reader, built with Closure Tools), follow us on Twitter, and, just maybe, submit a patch. Thanks!&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;span class="post-author"&gt;Posted by Nathan Naze, Closure Tools Team&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2437909874160353836-4670046662074372328?l=closuretools.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://closuretools.blogspot.com/feeds/4670046662074372328/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2437909874160353836&amp;postID=4670046662074372328&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/4670046662074372328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2437909874160353836/posts/default/4670046662074372328'/><link rel='alternate' type='text/html' href='http://closuretools.blogspot.com/2010/05/welcome-to-closure-tools-blog.html' title='Welcome to the Closure Tools blog'/><author><name>Nathan Naze</name><uri>http://www.blogger.com/profile/08280236711469825420</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
