Showing posts with label google. Show all posts
Showing posts with label google. Show all posts

Friday, September 27, 2013

How to Revert Chrome's New Tab Page

How to Solve It

If you just want to solve this, here you go. If you don't know what the problem is, jump down to Chrome's Bad New Tab Page Update below.

Solution

Visit chrome://flags

Ctrl+F for "Instant"

Set both "Instant..." settings to Disabled

Chrome asks you to Relaunch it. Do so.

Chrome's Bad New Tab Page Update

Chrome used to have a great New Tab page: the top 8 sites you visit appeared every time you'd open a new window or tab, with nice big buttons scaled to whatever size screen you were on. For those of us who used it, rather than having google.com as our homepage - Google appears to have decided we must be mistaken, and has turned the New Tab page into the Google.com homepage. The top 8 sites are now stuffed into a tiny area below - on small screens they end up below the fold, and on large screens they're miniscule compared to their former selves.

There's also no undo/disable/revert clearly visible. But it turns out there is a way to fix it buried in Chrome.

Tuesday, September 17, 2013

Getting Formulas to Stick in Google Spreadsheets

I admit I overuse Google Spreadsheets - I use it for all my estimates, tracking tasks, many things I should use much better task-specific tools for.

With that admission out of the way, my overuse leads me to frequently setting up a spreadsheet like this, where some number of columns are being summed into row 2. The obvious way to sum something like that is:

=sum(B3:B1000)

Then hope you never hit 1000 rows. Smart spreadsheeters will note you can do better than hope with a bit of a weirdo syntax:

=sum(B3:B)

Which sums everything from B3 down, infinitely. But that still doesn't solve the problem I run into: Someone, sometimes me, adds a row to the top of the spreadsheet, right at row 3, and Google Spreadsheets unhelpfully, silently, "fixes" my formula for me:

=sum(B4:B)

My sum is now off by just a little, and if it's a big spreadsheet I am not going to notice. Terrible things have come of this. Strangely Google Spreadsheets even screws up attempts to prevent this, like =sum(B$3:B) - it still "fixes" the range when you add a row, breaking the range. So, to solve it, you basically have to trick Google Spreadsheets into not trying to be smart, with an indirect function:

=sum(indirect("B3:B"))

By stuffing the cell range into a string and then using indirect to pass that to sum, you can add rows to the top all you like, and the B3:B range holds. Take that Spreadsheets.

Thursday, June 6, 2013

Getting Started with Google Closure on Windows - 2013

Google Closure Library, Buried Away

Google has a library of highly tested, highly performant code called Closure that's been open source for several years now. I don't see a lot of examples of people using it, and I think that's in part because the documentation is pretty lacking, and it's all done in its own Google-internal sort of way that makes it pretty hard to get started with or blend with other builds. Here's a walkthrough for getting started with it on Windows.

In this example I'm going to get a build of the WYSIWYG editor compiled out, but it should be easy enough to follow the same steps for any major feature of the Closure library. I want to take that minified script I compile rarely (maybe just the once), pull it into a .Net project and use it with jQuery and other more common tools. This might sound like overkill - afterall a big foundational library like jQuery is going to overlap a lot of functionality with the sprawling Google Closure library. But one nicety of Google's Closure approach is that it does dead code removal - that is, if you properly tell it exactly what parts you intend to use, it eliminates everything else in the minification process leaving you just the narrow slice of the library you wanted, even if that's made up of bits across 100s of files.

"If you properly tell it" turns out to be a tall order though, as we'll see below. Let's start with getting a basic build.

Environment

You'll need Java installed (the basic JRE download on the homepage is fine - you aren't writing any Java yourself so the JDK isn't necessary, though it won't hurt), and Python 2.x - not Python 3.x or above. As of this writing, I cannot find anywhere in the documentation that specifies this, but Python 3.x will fail with obscure UTF8 Decode errors when you attempt to build. And yes, you do need Python to get a Closure build going. I'll also recommend that you put them someplace that ignores Windows/Java issues with spaces that's convenient to type - for example I put mine at C:\System\Java\jre\1.6 and C:\System\Python\27.

(Side note: One alternative you might find is to use the Google Page Speed tool which minifies scripts on a page for you. This alternative doesn't really do the same thing - it makes many individual minified files for you instead of one minified package.)

If you don't have Git installed, you'll need to install it - for example TortoiseGit.

Next you'll want to make a folder where you want to put this all together, and check out the closure lib to a subfolder - I called mine goog. The remote origin should point to:

https://code.google.com/p/closure-library/

So at this point you've got a workspace folder with just one subfolder, goog, that has the entire Closure library in it including some of the build tools.

Next you'll need a build of the compiler itself, which I happened to put in a subfolder named compiler.

You now have all the tools you need.

Tell It What You Want To Use

The next step is to tell the compiler what parts you want to use, so it knows what to minify and what to leave out as dead code. You'll probably also want to be able to test this works both minified and not, so we'll cover building a simple test page.

In your workspace folder, make 3 files: index.html, script.js, and externs.js. None of these will end up in your final build so don't worry about the stupid names.

In script.js, your goal is to declare the parts of the library you need. You may want to start by just messing around in index.html to test and see what methods you need to call to get your work done. Here's the source I ended up with for index.html and script.js, which I'll walk you through:

index.html:

<!DOCTYPE html>
<html>
<head>
<title>Basic Editor</title>
<style>
body {
font: 10pt Verdana;
}

#editor {
padding: 5px;
border: 1px solid #000;
}
</style>
</head>
<body>

<p>Edit below.</p>

<div id=editor>Some sample text here.</div>

<p>Edit above.</p>

<script src="goog/closure/goog/base.js"></script>
<script>
goog.require('goog.editor.SeamlessField');
</script>
<script src="script.js"></script>
<!--<script src="editor.min.js"></script>-->
<script>
(new Editor('editor')).makeEditable();
</script>
</body>
</html>

script.js:

goog.provide('Editor');

goog.require('goog.editor.SeamlessField');

window['Editor'] = goog.editor.SeamlessField;
goog.editor.SeamlessField.prototype['makeEditable'] = goog.editor.SeamlessField.prototype.makeEditable;

So let's walk through what's going on. In the HTML file, I start by including base.js - you need to include this to get all the goog.whatever calls to work. I then open a script tag and call goog.require on the one class I intend to use on this page. That call implicitly calls a lot of document.write() calls for all the dependencies that script has, and finally a document.write() call for the SeamlessField file itself. All these calls to document.write() are why the calls to goog.require() must go in their own script tag, with calls depending on those scripts places in a separate, following script tag. Don't worry about all this inefficient lazy loading - it won't be part of your final build.

I then include script.js, and finally, I run some test code that mimics in a very basic way how I intend to use the minified results. Make sure to call all the Closure methods you'll be using on your actual site to verify they export correctly.

So now script.js, the file that's technically going to be minified by our build. In this example it's a pretty spartan file that's just telling the compiler what to do, but you can write actual code here as well and it will work fine (and be minified).

The call to goog.provide() is a requirement of the compiler - you have to provide at least one class. In this case we're renaming goog.editor.SeamlessField to Editor to get rid of the namespace for easier minification - if you don't you'll have to jump through further hoops to export the entire namespace, which I don't recommend doing.

The call to goog.require() you may notice is redundant - it's called both on the page and in script.js. This is harmless when debugging - the second call is smart enough to just return after taking no action. In the minified script this is necessary for the compiler to know what dependency tree to search during minification.

If you had multiple things to provide or require, you would just call them again - always provide calls first, then require calls.

The following 2 lines are called exports in Closure terminology. You're basically abusing the fact that window['Editor'] is for all intents and purposes the same thing as window.Editor, or simply, Editor, in Javascript - window['Editor'] minifies out as simply Editor and guarantees that function by that exact name is available to external code.

Likewise the second line is abusing the fact that goog.editor.SeamlessField.prototype['makeEditable'] is the same thing as goog.editor.SeamlessField.prototype.makeEditable, and causes the compiler to guarantee that the method won't be renamed so you can reliably call it from outside code (or, it may be renamed then exported by assigning it to a method of the same name at the end, if that's more efficient).

Note that you can't use this shorter declaration to export a method:

Editor.prototype['makeEditable'] = Editor.prototype.makeEditable;

Nor this:

window['Editor'].prototype['makeEditable'] = window['Editor'].prototype.makeEditable;

The first will fail to minify correctly (the method is lost), and the second will minify inefficiently - it will work but use up more bytes than necessary.

Make It Work With JQuery

Before moving on to compiling, there's one last detail to sort out - the compiler is going to use whatever single-character names JS allows to rename everything in the local and global namespace. One of those is $ sign, which if you intend to use this with jQuery is a problem - since you very likely already have a lot of code that assumes $ refers to jQuery. You can prevent the minifier from using symbols like this via externs.

externs.js:

function $(selector, context) {};

Simple as that - you're not actually building jQuery here, just telling Closure there's an outside function with that name, so exclude it from the eligible list that global variables can be renamed to. It technically doesn't even need to be this much - you could even just do this:

$ = {};

But there are scenarios where you actually call these externs from your code, at which point you may want the compiler to help you verify you're calling it correctly - thus the function and arguments.

Compiling

The compile command is not going to be short, so I recommend you actually work with it in a .bat file to keep your life simple. That way as you rework it you have a lot less to retype each time.

build.bat:

python goog\closure\bin\build\closurebuilder.py -c compiler\compiler.jar --root=.\ --namespace="Editor" -o compiled -f "--externs=externs.js" -f "--compilation_level=ADVANCED_OPTIMIZATIONS" --output_file=editor.min.js

So here it is all coming together. This calls the closurebuilder script via Python, which searches all the --root arguments you specify for dependencies. Only the js files in these folders are considered (HTML and CSS files are fine for testing but are ignored so far as the compilation is concerned - this isn't full-page minification). The namespace argument tells the script which of these files provides something you actually want to keep - the code in all other files is considered eligible for dead code removal. The -f arguments are flags you want to pass directly to the compiler - the most important being ADVANCED_OPTIMIZATIONS to ensure you get the dead code removal benefit. This Python script builds the dependencies tree then calls the compiler in Java with the (lengthy) arguments necessary to get exactly what you wanted.

It may help to know that if you Shift + right-click a folder, "Open command window here" is one of the options - you can then run build.bat easily from that window.

Here's a link to the minified version I ended up with.

Testing

To verify the minified result is what you want, just comment out all the scripts in the HTML page and uncomment the minified one:

<!--<script src="goog/closure/goog/base.js"></script>
<script>
goog.require('goog.editor.SeamlessField');
</script>
<script src="script.js"></script>-->
<script src="editor.min.js"></script>
<script>
(new Editor('editor')).makeEditable();
</script>
</body>

Run it and there you go, a minified slice of Google's Closure Library you can take and use in other projects with other libraries and even other minifiers.

My minified results were just 11k, as opposed to the 17.4mb the entire library adds up to unminified.

Thursday, September 15, 2011

Surviving Google's Blogpocalypse

I attempted to login to my Google Apps version of Gmail one day and was instead presented with a page I couldn't circumvent. Over 20 checkboxes, several tabs that didn't look like tabs, and a lot of confusing options. Eventually I was able to access Gmail again.

The next time I attempted to login to Blogger however, things went poorly. As it turns out this transition does not have a migration path for Blogger/Blogspot, so you have to migrate manually.

Migrating manually is not obvious or easy. Here's the steps I had to take - maybe they'll help others:
  1. Choose the option to create a new personal Gmail account for your blog. You'll need to go through the usual Gmail signup process where you create another username, another password to remember, and have to enter another arbitrary security question.
  2. Login with the new Gmail account. You can signout of your existing account, or do this in an Incognito window or another browser to skip the logout step.
  3. Now you have access to your blog again! ...but you don't want to have to use this other random Gmail account to edit it every time.
  4. Get to Settings > Permissions
    1. In the old look: Under the blog name, click Settings, then the Permissions tab.
    2. In the new look: Click the blog name, click Settings, and look under Permissions.
  5. Click Add Authors, and add your old Apps account - except - you can't just add it normally - the operation just quietly fails with no open invite, no indication the invite went out, no email, and no indication of an error. Instead, you need to use an alias for your account. If you have multiple domains associated with your account this is simple - use one of the alias domains. If you don't, you'll need to create an Alias for your user in the Domain Admin, then invite that Alias.
  6. Check your email for the invite, and accept.
  7. Come back to the incognito window (or, sadly, logout and login as the ephemeral Gmail account you created). Get to Settings > Permissions again, and now change your invited self to Admin instead of Author.
  8. You can finally return to using Blogger the way you always did before Google ruined your day.
I'd like to point out that this transition really should have been entirely under the covers - as a user, I login with my Google Apps email address to edit my blog. I want to keep doing so. That Google is going through a major systems changeover shouldn't require me going through all of this trouble. If the transition is going to be mandatory, it should have waited until all products could be migrated automatically. Instead a lot of non-technical users had to deal with this insane process that offers no support.

Google is notoriously poor at customer support. I actually recall standing at TGIF listening to a Googler ask the founders why customers are pushed to post their problems to Support forums no one reads, getting no response unless an employee happens to take it upon themselves to look into it, or it makes it onto the front page of Slashdot. Sergey Brin's actual response was, "Well we shouldn't resolve these issues by having a big customer service department. We should resolve them by writing better code." I really should've grabbed a mic and described a metaphorical situation in which a farmer starts closing the barn door after his cow wanders off, but alas.

This is the support thread for this problem: It's safe to assume no Google employee will ever respond to it, let alone read it. http://www.google.com/support/forum/p/blogger/thread?tid=239869e385664e6b&hl=en&fid=239869e385664e6b0004acf9193ad5a4