Search This Blog

Friday, August 17, 2012

Featuring "Vim and Vi Tips: Essential Vim and Vi Editor Skills, 2nd ed."

A co-worker friend sent all the devs in the office a link to the Kindle edition of Vim and Vi Tips: Essential Vim and Vi Editor Skills, 2nd ed. today after a friend of his had sent it to him.

The book is a solid resource on vim, and it's currently free on Amazon. To get your copy, just click the cover below and go.

If you don't have a Kindle, don't worry: you should be able to read it with Amazon's built-in delivery system; if not, they also offer a free Kindle App for just about any device you could own, ranging from smartphones to tablets to computers.

Related posts: Colorizing Vim: How To Change Color Schemes in Vim

Saturday, July 14, 2012

Regular Expressions in JavaScript

Note: This regular expressions reference guide was first compiled from resources on the net for a presentation at work slightly over two years ago (May 5, 2010). I am just now posting it here, partly because I finally got around to adding proper regular expression highlighting to the JavaScript highlighter used on this blog. :)

Pattern Flags

Three pattern flags may be specified with regular expressions: g, i, and m.
  1. g = global, performs a global search
  2. i = ignore case, is case insensitive
  3. m = multiline, treats line endings/beginnings like string terminators when used with ^ and/or $

Using Literal Notation

JavaScript regular expressions are commonly created using literal notation (via opening and closing forward slashes / /). Pattern flags can be specified after the second slash.
// match all 7-digit numbers globally
var phonenumber = /\d{7}/g;
Note: Normally you will want to use the literal notation if you know the pattern you need to use in advance, as it results in cleaner syntax and boasts a slight performance gain. (Literals are compiled as source code; extended objects are not.)

Native RegExp Constructor:

Native JavaScript contains its own RegExp constructor, useful for building dynamic regular expressions when you do not know ahead of time the pattern value.

There are three main things to remember when using the RegExp object:
  1. The string portion of the pattern goes inside quotation marks.
  2. The escapes of special characters need to be escaped with a back slash (\).
  3. An optional second parameter allows pattern flags to be passed.
For example:
// a simple digit-only RegEx with a global flag
var myRegExp = new RegExp('\\d', 'g');
// with variable (can be +'d with string for complex expressions)
var myRegExp = new RegExp(someVar, 'g');

Regular Expression Methods

Format: RegExp.test(string);

Simplest, least costly method. Returns boolean true or false.
// returns true because "i" is specified
// returns false
Format: RegExp.exec(string);

Similar to match(), except that the parameter is the string, not the regular expression. Returns array of matches, or null if no match is found. Note that the 0-item index will always be the full pattern match.
var match = /s(amp)le/i.exec('Sample text');
// returns ['Sample', 'amp']
As with exec(), the regular expression is the first refinement, the string the parameter.
Format: string.match(RegExp);

Functionally identical to exec() in all ways, except refinement and parameter is reversed. Also returns null or an array with 0-item being the full string.

Returns -1 if not found or index of match.

Note: Does NOT support global searches; the g pattern flag is not supported.
'Amy and George were married'.search(/george/i); // returns 8
Format: string.split(RegExp);

Converts strings into array, splitting the string on literal or regex delimiter and puts the chunks in the array. Does NOT return the delimiter(s).
// returns the array ["1", "2", "3", "4", "5"] because
// the regular expression factors in discrepancy in spacing
var oldString = '1,2, 3,   4,    5';
var newString = oldString.split(/\s*,\s*/);
Format: string.replace(searchFor, replaceWith);

This particular method has a lot of flexibility. We can use string literals for the search and replace values:
'My car is hot'.replace('car', 'girl');
// returns "My girl is hot"
We can use regular expressions and call back the captured values up to 9 places ($1$9):
// Matching on word boundaries with a space between,
// capturing the boundaries.
var reorderName = 'Mary Jane'.replace(/(\b) (\b)/, "$2, $1");
// Returns "Jane, Mary"
But what if you need to replace multiple characters, not just re-order or replace single values? replace() also supports anonymous functions:
// The string portion of the pattern goes inside
// quotation marks. Special characters need to be escaped
// with a back slash (An optional second paramater allows
// pattern flags to be passed.)
var testStr = 'He wrote, "2 < 3 is a true statement" on the board.';
// match any of these characters
var myRx = /[><"'&]/g;
var escapedString = testStr.replace(myRx, function(match) {
    switch (match) {
        case '<':
            return '&lt;';
        case '>':
            return '&gt;';
        case '"':
            return '&quot;';
        case "'":
            return '&#039;';
        case '&':
            return '&amp;';
Or, we can simply pass in an existing method, provided it accepts a single parameter. Note that we do not add the invocation () to the function name or pass it any variables: The replace() method will automatically call the passed function.
// Function: replaceChars
var replaceChars = function(match) {
    switch (match) {
        case '<':
            return '&lt;';
        case '>':
            return '&gt;';
        case '"':
            return '&quot;';
        case "'":
            return '&#039;';
        case '&':
            return '&amp;';
// no invocation or passed values
var escapedStr2 = testStr.replace(myRx, replaceChars);

// The results are identical
// He wrote, &quot;2 &lt; 3 is a true statement&quot; on the board.
// He wrote, &quot;2 &lt; 3 is a true statement&quot; on the board.
Pattern Flags (Switches)
Property Description Example
 i Ignore the case of characters. /The/i matches "the" and "The" and "tHe"
 g Global search for all occurrences of a pattern /ain/g matches both "ain"s in "No pain no gain", instead of just the first.
 gi Global search, ignore case. /it/gi matches all "it"s in "It is our IT department"
 m Multiline mode. Causes ^ to match beginning of line or beginning of string. Causes $ to match end of line or end of string. JavaScript1.5+ only. /hip$/m matches "hip" as well as "hip\nhop"
Position Matching
Symbol Description Example
 ^ Only matches the beginning of a string. /^The/ matches "The" in "The night" but not "In The Night"
 $ Only matches the end of a string. /and$/ matches "and" in "Land" but not "landing"
 \b Matches any word boundary (test characters must exist at the beginning or end of a word within the string) /ly\b/ matches "ly" in "This is really cool."
 \B Matches any non-word boundary. /\Bor/ matches “or” in "normal" but not "origami."
(?=pattern) A positive look ahead. Requires that pattern is within the input. Pattern is not included as part of the actual match. /(?=Chapter)\d+/ matches any digits when it's preceded by the words "Chapter", such as 2 in "Chapter 2", though not "I have 2 kids."
(?!pattern) A negative look ahead. Requires that pattern is not within the input. Pattern is not included as part of the actual match. /JavaScript(?! Kit)/ matches any occurrence of the word "JavaScript" except when it's inside the phrase "JavaScript Kit"
Symbol Description
Alphanumeric All alphabetical and numerical characters match themselves literally. So /2 days/ will match "2 days" inside a string.
\O Matches NUL character.
 \n Matches a new line character
 \f Matches a form feed character
 \r Matches carriage return character
 \t Matches a tab character
 \v Matches a vertical tab character
[\b] Matches a backspace.
 \xxx Matches the ASCII character expressed by the octal number xxx.

\50 matches left parentheses character "("
 \xdd Matches the ASCII character expressed by the hex number dd

\x28 matches left parentheses character "("
 \uxxxx Matches the ASCII character expressed by the UNICODE xxxx.

\u00A3 matches "£"
The backslash (\) is also used when you wish to match a special character literally. For example, if you wish to match the symbol $ literally instead of have it signal the end of the string, backslash it: \$
Character Classes
Symbol Description Example
 [xyz] Match any one character enclosed in the character set. You may use a hyphen to denote range. For example. /[a-z]/ matches any letter in the alphabet, /[0-9]/ any single digit. /[AN]BC/ matches "ABC" and "NBC" but not "BBC" since the leading “B” is not in the set.
 [^xyz] Match any one character not enclosed in the character set. The caret indicates that none of the characters should match.

NOTE: the caret used within a character class is not to be confused with the caret that denotes the beginning of a string. Negation is only performed within the square brackets.
/[^AN]BC/ matches "BBC" but not "ABC" or "NBC".
 . (Dot). Match any character except newline or another Unicode line terminator. /b.t/ matches "bat", "bit", "bet" and so on.
 \w Match any alphanumeric character including the underscore. Equivalent to [a-zA-Z0-9_]. /\w/g matches "200" in "200%"
 \W Match any single non-word character. Equivalent to [^a-zA-Z0-9_]. /\W/ matches "%" in "200%"
 \d Match any single digit. Equivalent to [0-9].
 \D Match any non-digit. Equivalent to [^0-9]. /\D/g matches "No " in "No 342222"
 \s Match any single space character. Equivalent to [ \t\r\n\v\f].
 \S Match any single non-space character. Equivalent to [^ \t\r\n\v\f].
Symbol Description Example
{x} Match exactly x occurrences of a regular expression. /\d{5}/ matches 5 digits.
{x,} Match x or more occurrences of a regular expression. /\s{2,}/ matches at least 2 whitespace characters.
{x,y} Matches x to y number of occurrences of a regular expression. /\d{2,4}/ matches at least 2 but no more than 4 digits.
? Match zero or one occurrences. Equivalent to {0,1}. /a\s?b/ matches "ab" or "a b".
* Match zero or more occurrences. Equivalent to {0,}. /we*/ matches "w" in "why" and "wee" in "between", but nothing in "bad"
+ Match one or more occurrences. Equivalent to {1,}. /fe+d/ matches both "fed" and "feed"
Alternation & Grouping
Symbol Description Example
( ) Grouping characters together to create a clause. May be nested. /(abc)+(def)/ matches one or more occurrences of "abc" followed by one occurrence of "def".
( ) Apart from grouping characters (see above), parenthesis also serve to capture the desired subpattern within a pattern. The values of the subpatterns can then be retrieved using RegExp.$1, RegExp.$2 etc after the pattern itself is matched or compared. For example, the following matches "2 chapters" in "We read 2 chapters in 3 days", and furthermore isolates the value "2":

var myString = "We read 2 \
chapters in 3 days";

var needle = /(\d+) chapters/;

// matches "2 chapters"

// alerts captured subpattern,
// or "2"

The subpattern can also be back referenced later within the main pattern. See "Back References" below.
The following finds the text "John Doe" and swaps their positions, so it becomes "Doe John":

"John Doe"
.replace(/(John) (Doe)/, "$2 $1");
(?:x) Matches x but does not capture it. In other words, no numbered references are created for the items within the parenthesis. /(?:.d){2}/ matches but doesn't capture "cdad".
x(?=y) Positive lookahead: Matches x only if it's followed by y. Note that y is not included as part of the match, acting only as a required conditon. /George(?= Bush)/ matches "George" in "George Bush" but not "George Michael" or
"George Orwell".

/Java(?=Script|Hut)/ matches "Java" in "JavaScript" or "JavaHut" but not "JavaLand".
x(?!y) Negative lookahead: Matches x only if it's NOT followed by y. Note that y is not included as part of the match, acting only as a required conditon. /^\d+(?! years)/ matches "5" in "5 days" or "5 oranges", but not "5 years".
| Alternation combines clauses into one regular expression and then matches any of the individual clauses. Similar to OR statement. /(ab)|(cd)|(ef)/ matches "ab" or "cd" or "ef".
Back References
Symbol Description
( )\n \n (where n is a number from 1 to 9) when added to the end of a regular expression pattern allows you to back reference a subpattern within the pattern, so the value of the subpattern is remembered and used as part of the matching. A subpattern is created by surrounding it with parenthesis within the pattern.

Think of \n as a dynamic variable that is replaced with the value of the subpattern it references. For example:


is equivalent to the pattern /hubbahubba/, as \1 is replaced with the value of the first subpattern within the pattern, or (hubba), to form the final pattern.

Lets say you want to match any word that occurs twice in a row, such as "hubba hubba." The expression to use would be:


\1 is replaced with the value of the first subpattern's match to essentially mean "match any word, followed by a space, followed by the same word again."

If there were more than one set of parentheses in the pattern string you would use \2 or \3 to match the desired subpattern based on the order of the left parenthesis for that subpattern.

In the example:

/(a (b (c)))/

\1 references (a (b (c))), \2 references (b (c)), and \3 references (c).
Regular expressions to match JavaScript comments:
// match single-line comments (like this one) globally
// match multi-line comments (/* ... */) globally
// or combine both patterns in one using "|" (pipe)
// wrap in parens to capture and callback: "(pattern)|(pattern2)"
// as perhaps used in an auto syntax highlighter...
myJSString.replace(/(\/\*([^\*]|\*(?!\/))*\*\/)|(\/\/.*)/g, function(match) {
    return '<span class="comment">' + match + '</span>';
Validate e-mail addresses:

Monday, May 07, 2012

Perl Diver 2.33: Download and Installation

If you write—or need to maintain—Perl scripts, it can be incredibly helpful to have a way to print out all your environmental variables, installed modules, and the like, much like PHP's phpinfo().

Up until 2006, a site called—no longer in service—offered a free program you could install called Perl Diver. Version 2 of the script offered a lot of extra functionality. The last version of the script to be released was 2.33, which fixed an exploitable hole in the module parameter for versions 2.x prior to this release.

The bottom line is that Perl Diver is still an excellent tool, and it's a shame to see the fixed version leave the public realm with no place to download.

Download, Basic Installation:

After searching everywhere for a copy, I finally secured one, and am again offering the script to the public.

If you have git access, obtaining a copy from GitHub is as simple as:
# as ssh
git clone git://
# as https
git clone
Otherwise, download a copy of the perldiver zip. Installation should be a matter of unzipping the contents of this file wherever you keep your Perl scripts.

If you do not have git access (file permissions are automatically retained in git), you will also need to give the script execution permission, either using the following command:
chmod +x
Or via an FTP program like FileZilla, setting to "755": refer to this blog post if you don't know how to do that.

If you need to change the extension to .cgi, you will also need to change the file name in perldiver.conf:
# only if you change the file extension to "cgi"
'script_name'      => 'perldiver.cgi',

Hide From Search Engines:

To keep the search engines from indexing the page in their results—you probably don't want to broadcast your server's environmental variables to the entire world—you should also create an entry in your robots.txt file.

If you don't have one already, create a plain text file and enter the following lines (assuming that the directory in which you're including Perl Diver is cgi-bin):
User-agent: *
Disallow: cgi-bin/perldiver
Save your file with the name robots.txt, and then upload this file to your web server's root directory.

All paths specified in the file are relative to root; you can check your file at this link or, if you have a free account, you can use Google's Webmaster Tools for the same. For more info on robots.txt files, see Google's Block or remove pages using a robots.txt file.

Password Protecting:

It's also a really good idea that you keep the script from hackers manually fishing for info. Perl Diver is used on a lot of websites, and hackers have learned to look for unprotected copies. You can avoid this type of hack by password protecting the perldiver directory. Assuming that you use Apache, directions follow.

You will need to replace Apache's example username rbowen below with the username used when you access scripts from your site via http / https. Here is the relevant excerpt from Apache's Authentication, Authorization and Access Control page:

Getting it working

Here's the basics of password protecting a directory on your server.

You'll need to create a password file. This file should be placed somewhere not accessible from the web. This is so that folks cannot download the password file. For example, if your documents are served out of /usr/local/apache/htdocs you might want to put the password file(s) in /usr/local/apache/passwd.

To create the file, use the htpasswd utility that came with Apache. This will be located in the bin directory of wherever you installed Apache. To create the file, type:
htpasswd -c /usr/local/apache/passwd/passwords rbowen
htpasswd will ask you for the password, and then ask you to type it again to confirm it:
$ htpasswd -c /usr/local/apache/passwd/passwords rbowen
New password: mypassword
Re-type new password: mypassword
Adding password for user rbowen
If htpasswd is not in your path, of course you'll have to type the full path to the file to get it to run. On my server, it's located at /usr/local/apache/bin/htpasswd

Next, you'll need to configure the server to request a password and tell the server which users are allowed access. You can do this either by editing the httpd.conf file or using an .htaccess file. For example, if you wish to protect the directory /usr/local/apache/htdocs/secret, you can use the following directives, either placed in the file /usr/local/apache/htdocs/secret/.htaccess, or placed in httpd.conf inside a <Directory /usr/local/apache/apache/htdocs/secret> section.
AuthType Basic
AuthName "Restricted Files"
AuthUserFile /usr/local/apache/passwd/passwords
Require user rbowen
For additional details, see the full Apache manual page.

Saturday, May 05, 2012

pss: The Command-line Search Tool I Never Leave Home Without


Ever since I discovered the Python tool pss, I fell in love. It's blazingly fast and drop-dead simple to use. 99% of the time, you just type:
pss "search phrase"
The idea is pss REGEXP: you can use an escape character if you need to search for a character literal:
pss "\$method = 'post'"
or triple escape if searching for a single pattern (that is, an unquoted string):
pss \\\$method
I tend to think of pss as a sort of "grep+" for this kind of searching:* it's automatically recursive, whereas grep is not, and it ignores certain file types by default. (These can all be configured: for additional information, see Announcing pss, pss0.3.5, and Usage samples.)


Assuming that you have Python installed on your machine (if not, grab it here), you can install pss using pip:
pip install pss
If you do not have pip, you should be able to just type:
easy_install pip
pip install pss
Finally, if you don't have easy_install either, you can get the toolkit / directions at setuptools 0.6c11.

* grep is still invaluable for piped searches:

tail package.json | grep "MIT +no-false-attribs" 
yum list available | grep mysql

And don't forget find...

1. When you want to search for file / directory names:
# find the php.ini config file starting at the /etc directory
find /etc -name 'php.ini'
# find all .php files starting at local directory (.)
find . -name '*.php'
2. When you want to bulk-replace file extensions:
# change .JPG to .jpg for all files starting at local directory
find . -name '*.JPG' -exec rename -s .JPG .jpg {} \;
3. When you want to bulk delete files:
# delete all .pyc files starting at local directory
# GNU find
find . -name '*.pyc' -delete
# Universal
find . -name '*.pyc' | xargs rm -f {} \;

Sunday, April 29, 2012

Colorizing Vim: How To Change Color Schemes in Vim

Colorizing Vim

Note: It is recommended (but not required) that you download VimConf, the vim customization we use at IWS: simply follow the directions under Setup on the GitHub page.

Also, if you're on Mac OSX, you will want to use iTerm2 if you don't already, as it supports 256 colors and provides improved functionality over the native Terminal app.

Changing your vim colors is pretty easy, particularly if all you are doing is installing pre-packaged color schemes.

First, navigate to the .vim subdirectory:
# with VimConf
cd ~/VimConf/.vim

# without VimConf
cd ~/.vim

Then check and see if you have a colors directory:

If not, make one...
mkdir colors

then switch into it...
cd colors

Google Code's Vim Color Scheme Test has screen shots and links for 428 different vim schemes. Under the heading Browse By File Type at the bottom of the page, select the language you'd like to see the vim screen shots in. This will take you to the page of screen shots, which take a while to load, as there are 428 schemes in 428 iframes. (Smiles.)

Above each screen shot is the name of the scheme, which doubles as a direct link to the scheme's source file. Just right click the scheme's name, then select Copy Link Address (in Chrome) or Copy Link Location (in Firefox) from the context menu.

Jellybeans color scheme

Once copied, you can use wget + paste to park the file directly in your colors directory without further modification. For example, I selected the following schemes, all of which are compatible with 256 colors:*


Finally, to actually use a color scheme you downloaded, open your vimrc file...
# with VimConf
vim ~/VimConf/.vimrc_custom

# without
vim ~/.vimrc

...and add colorscheme, a space, and the name of the file (minus the extension). Using jellybeans.vim as the example, it would look like so:

colorscheme jellybeans

Then save your file, and...


Related posts: Featuring "Vim and Vi Tips: Essential Vim and Vi Editor Skills, 2nd ed."

* I mention 256 colors for a reason: not all of the featured schemes render correctly (at least without disabling your 256 color support). Many offer a "256" version, however, as seen in the sample links above.

A second thing to note is that if you load a scheme and get weird load errors, that usually is because the file was saved on a Windows machine and the line endings are bonked (Unix/Linux uses \n, Mac \r, and Windows \r\n).

There are probably better solutions, but my approach was to...
cat affected_file.vim

copy the readout in my terminal, empty the file with...
> affected_file.vim

then open the now empty file in vim...
vim affected_file.vim

make sure that I'm in paste mode...
# with VimConf

# without
:set nonumber

go into insert mode

and manually paste the contents back in.

Friday, February 10, 2012

Firefox 10 Context Menu: Inspect Element versus Inspect Element with Firebug

If you use Firebug and find yourself wanting to inspect an element in Firefox 10 or higher only to be surprised by a dark modal background and breadcrumb trail that looks (and functions) considerably different than the one you're used to seeing when inspecting an element in Firebug...

...there is a work-around for removing the option from the context menu leaving only the usual "Inspect Element with Firebug" at the bottom; see for details.

Sunday, October 30, 2011

How to migrate mail from one Gmail account to another on Windows, including Chats

This is the Microsoft Windows version of this article (though it contains screen shots from Mac). The Mac OSX version can be found here.

Recently at work, we got a new Gmail domain and had to switch from one Gmail account to another.

You can migrate your mail easily using POP3, but POP3 won't get your chats or preserve your labels. The superior solution is IMAP, even if it's a little more cumbersome. And even if you have already migrated using POP3, IMAP will still allow you to retrieve your chats and work for you on a tag-by-tag basis.

IMAP requires bit of a work-around—you must first fully download all your files to your machine, and only then can you migrate them back again into your new Gmail account.

Here's everything you need to get set up.

First, the downloads.
  1. Download Mozilla Thunderbird and install on your machine.
  2. Download and unzip the toIMAP files (we'll set these up later)
Now log in to your usual (old) Gmail account.


1. Click the gear icon in the upper-right corner and select Mail settings:

2. Click the Forwarding and POP/IMAP tab, scroll down to IMAP Access, and make sure it is turned on:

3. Click Labels and make sure that Chats and any other labels you want migrated are checked. (Note: If you already used the POP3 solution, you might want to limit only to Chats.)

4. Open Thunderbird, click Create a new account and use the address you want to pull the mail from, then click Continue:

Note: The wizard should smartly detect the proper settings; if not, you can click Manual config and enter the IMAP and SMTP settings shown below:

5. Click Create Account and let Thunderbird start downloading; this may take hours, and it goes without saying that the more mail you have, the longer the process will be. If you have to shut down for a while, to easily restart where you left off, just open Thunderbird, right-click, and click Get Messages in the context menu:

6. Log in to your new account and repeat steps 1 and 2 above for it. Make sure that you re-create any custom labels you used in your old account:

Now... go find something else to do for a few hours and come back to step 7 after Thunderbird (eventually) finishes.

7. Yay! Your e-mail finally downloaded! Rejoicing, right-click your account name, and click Settings (last option in the screen shot for step 5). Navigate to Server Settings, and copy the Local directory path at the bottom.

8. Open a new folder, and paste this address in the location bar. Keep this window open, as you'll need it for the following steps:

9. Go to Start > All Programs > Accessories > Notepad and start the program. Use it to open the toIMAP.cfg file in the toIMAP folder you downloaded to your Desktop. Make sure your configuration file is set up like the one below, subbing in your username and password:
     'host' : '',
     'ssl': True
10. Save the file and close it. Your configuration file is now set; all that is left is to run the file.

Go to your Windows Start menu and type cmd.exe in the search box, pressing ENTER. The Windows command-line prompt will open.

You'll need to be at the same level as the file; for Microsoft Vista, the path would be (where "YOU" is your username): C:\Users\YOU\Desktop\toIMAP. To do this, you'll need to change directories (cd) into the folder on your desktop:
cd C:\Users\YOU\Desktop\toIMAP
To run the uploader script, you'll use the following convention while still sitting at the level in step 9:
toIMAP.exe -m path_i_just_copied/FOLDER_NAME -f FOLDER_NAME
For example, if I want to upload the folder "admin stuff" (shown in step 8), I would type (surrounding my file path with quotation marks to bypass the space between "admin" and "stuff"):
toIMAP.exe -m "C:\Users\YOU\AppData\Roaming\Thunderbird\Profiles\76sexgps.default\ImapMail\\admin stuff" -f "admin stuff"
Some Gmail flags like Starred may need to omit the -f "admin stuff" part.

To specify a different Gmail tag than the name of the Thunderbird folder, just pass -f the new name, making sure that the tag already exists in your new account per step 6.

For example, to move your chats, you will not be able to use the same "Chats" name for your tag as that is reserved by Google. You'll need to create a new tag in your new account—I used "Archived Chats"—then import using the additional -f flag:
toIMAP.exe -m "C:\Users\YOU\AppData\Roaming\Thunderbird\Profiles\76sexgps.default\ImapMail\\[Gmail].sbd\Chats" -f "Archived Chats"
If your upload gets interrupted at any point, see the toIMAP directions on how to resume where you left off.

11. Repeat step 10 for as many folders as you need to migrate. Once you have gone through every folder you want backed up, you're done. Bliss is yours.