/***** BEGIN LICENSE BLOCK ***** {{{
Version: MPL 1.1/GPL 2.0/LGPL 2.1
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
(c) 2006-2007: Martin Stubenschrott First there was a Navigator, then there was an Explorer. Later it was time for a Konqueror. Now it\'s time for an Imperator, the VIMperator :) Vimperator is a free browser add-on for Firefox, which makes it look and behave like the Vim text editor. ' +
'It has similar key bindings, and you could call it a modal webbrowser, as key bindings differ according to which mode you are in. Warning: To provide the most authentic Vim experience, the Firefox menubar and toolbar were hidden. If you really need them, type: Since Vimperator\'s GUI is embedded into a toolbar, it may look too 3D-like with the default theme. For best experience, I therefore recommend the Whitehart theme. Vimperator was written by Martin Stubenschrott. If you appreciate my work on Vimperator, you can either send me greetings, patches ' +
'or make a donation: ' +
' The denotion of modifier keys is like in Vim, so C- means the Control key, M- the Meta key, A- the Alt key and S- the Shift key.
Be aware that not all Firefox extensions work, because Vimperator overrides some keybindings and changes Firefox's GUI.",
function() { openURLsInNewTab("chrome://mozapps/content/extensions/extensions.xul", true); },
null
],
[
["back", "ba"],
"Go back in the browser history",
"Count is supported, :3back goes back 3 pages in the browser history.",
function(args, special, count) { stepInHistory(count > 0 ? -1 * count : -1); },
null
],
[
["bdelete", "bd", "bwipeout", "bw", "bunload", "bun", "tabclose", "tabc"],
"Delete current buffer (=tab)",
"Count WILL be supported in future releases, then :2bd removes two tabs and the one the right is selected.
Do :bdelete! to select the tab to the left after removing the current tab.",
function (args, special, count) { tab_remove (count, special, 0); },
null
],
[
["beep"],
"Play a system beep",
null,
beep,
null
],
[
["bmadd"],
"Add a bookmark",
"Usage: :bmadd [-t \"my custom title\"] [-T \"comma,separated,tags\"] [url]
" +
"If you don't add a custom title, either the title of the webpage or the URL will be taken as the title.
"+
"Tags WILL be some mechanism to classify bookmarks. Assume, you tag a url with the tags \"linux\" and \"computer\" you'll be able to search for bookmarks containing these tags.
" +
"You can omit the optional [url] field, so just do :bmadd to bookmark the currently loaded web page with a default title and without any tags.",
bmadd,
null
],
[
["bmdel"],
"Delete a bookmark",
"Usage: :bmdel [-T \"comma,separated,tags\"] <url>
" +
"Deletes all bookmarks which matches the url AND the specified tags. Use <Tab> key on a regular expression to complete the url which you want to delete.",
bmdel,
function(filter) { return get_bookmark_completions(filter); }
],
[
["bookmarks", "bm"],
"Show bookmarks",
"Usage: :bm [-T \"comma,separated,tags\"] <regexp>
" +
"Open the preview window at the bottom of the screen for all bookmarks which match the regexp either in the title or URL.
" +
"Close this window with :pclose or open entries with double click in the current tab or middle click in a new tab.",
bmshow,
function(filter) { return get_bookmark_completions(filter); }
],
[
["buffer", "b"],
"Go to buffer number n. Full completion works.",
null,
function (args) { tab_go(args.split(":")[0]); },
function (filter) {return get_buffer_completions(filter);}
],
[
["buffers", "files", "ls"],
"Shows a list of all buffers.",
null,
function (args) {bufshow("", false);},
null
],
[
["downloads", "dl"],
"Show progress of current downloads",
"Open the original Firefox download dialog in a new tab.
" +
"Here, downloads can be paused, canceled and resumed.",
function() { openURLsInNewTab("chrome://mozapps/content/downloads/downloads.xul", true); },
null
],
[
["echo", "ec"],
"Display a string at the bottom of the window",
"Echo all arguments of this command. Useful for showing informational messages.
Multiple lines WILL be seperated by \\n.",
echo,
null
],
[
["echoerr", "echoe"],
"Display an error string at the bottom of the window",
"Echo all arguments of this command highlighted in red. Useful for showing important messages.
Multiple lines WILL be seperated by \\n.",
echoerr,
null
],
[
["execute", "exe"],
"Run any javascript command through eval()",
"Acts as a javascript interpreter by passing the argument to eval().
"+
":exec alert('Hello world') would show a dialog box with the text \"Hello world\".
"+
"The special version :execute! will open the javascript console of Firefox.",
function(args, special) {
if (special) // open javascript console
openURLsInNewTab("chrome://global/content/console.xul", true);
else
eval(args);
},
null
],
[
["forward", "fw"],
"Go forward in the browser history",
"Count is supported, :3forward goes forward 3 pages in the browser history.",
function(count) { stepInHistory(count > 0 ? count : 1); },
null
],
[
["hardcopy", "ha"],
"Print current document",
"Open a GUI dialog where you can select the printer, number of copies, orientation, etc.",
function() { goDoCommand('cmd_print'); },
null
],
[
["help", "h"],
"Open help window",
"Open the help window in the current tab. You WILL be able to show a specific section with :help commands.",
help,
function(filter) { return get_help_completions(filter); }
],
[
["history", "hs"],
"Show recently visited URLs",
"Usage: :hs <regexp>
" +
"Open the preview window at the bottom of the screen for all history items which match the regexp either in the title or URL.
" +
"Close this window with :pclose or open entries with double click in the current tab or middle click in a new tab.",
hsshow,
function(filter) { return get_history_completions(filter); }
],
[
["mark"],
"Mark current location within the webpage",
"Not implemented yet",
function (args) { set_location_mark(args); },
null
],
[
["marks"],
"Show all location marks of current webpage",
"Not implemented yet",
function (args) { set_location_mark(args); },
null
],
[
["open", "o", "op", "edit", "e"],
"Open one ore more URLs",
"Usage: :open <url> [| <url>]
" +
"Opens one ore more URLs in the current buffer.
"+
"Multiple URLs can be separated with the | character.
" +
"Each |-separated token is analazed and in this order:
"+
"
"+
"You WILL be able to use :open wiki linus torvalds will open the wikipedia entry for linux torvalds).:open linus torvalds will open a google search for linux torvalds).:open www.osnews.com | www.slashdot.org will open OSNews in the current, and Slashdot in a new background tab).:open [-T \"linux\"] torvalds<Tab> to complete bookmarks with tag \"linux\" and which contain \"torvalds\". Note that -T support is only available for tab completion, not for the actual command.
"+
"The items which are completed on <Tab> are specified in the 'complete' option.
"+
"Without argument, reloads the current page.
"+
"Without argument but with !, reloads the current page skipping the cache.",
function(args, special)
{
if(args.length > 0)
openURLs(args);
else
{
if (special)
BrowserReloadSkipCache();
else
BrowserReload();
}
},
function(filter) { return get_url_completions(filter); }
],
[
["pclose", "pc"],
"Close preview window on bottom of screen",
null,
function() { preview_window.hidden = true; },
null
],
[
["preferences", "prefs"],
"Show Browser Preferences",
"You can change the browser preferences from this dialog.
Be aware that not all Firefox preferences work, because Vimperator overrides some keybindings and changes Firefox's GUI.
"+
"Works like :set!, but opens the dialog in a new window instead of a new tab. Use this, if you experience problems/crashes when using :set!",
openPreferences,
null
],
[
["quit", "q"],
"Quit current tab or quit Vimperator if this was the last tab",
"When quitting Vimperator, the session is not stored.",
function (args) { tab_remove(1, false, 1); },
null
],
[
["quitall", "quita", "qall", "qa"],
"Quit Vimperator",
"Quit Vimperator, no matter how many tabs/windows are open. The session is not stored.",
function (args) { quit(false); },
null
],
[
["reload", "re"],
"Reload current page",
"Forces reloading of the current page, or of all open pages, if ! is given.",
function(args, special) { reload(special); },
null
],
[
["restart"],
"Restarts the browser",
"Forces the browser to restart.",
restart,
null
],
[
["saveas", "sav"],
"Save current web page to disk",
"Open the original Firefox \"Save page as...\" dialog in a new tab.
" +
"There, you can save the current web page to disk with various options.",
function() { goDoCommand('Browser:SavePage'); },
null
],
[
["set", "se"],
"Set an option",
"Permanently change an option. In contrast to Vim options are stored throughout sessions.
"+
"Boolean options must be set with :set option and :set nooption.
"+
":set without an argument opens about:config in a new tab to change advanced Firefox options.
"+
":set! opens the GUI preference panel from Firefox in a new tab.
"+
":set option? or :set option shows the current value of the option.
"+
":set option+=foo and :set option-=foo WILL add/remove foo from list options.
",
set,
function(filter) { return get_settings_completions(filter); }
],
[
["source", "so"],
"Load a local javascript file and execute it",
"The .vimperatorrc file in your home directory is always sourced at start up.
"+
"~ is supported as a shortcut for the $HOME directory.",
source,
null
],
[
["tabnext", "tn", "tnext"],
"Switch to the next tab",
"Cycles to the first tab, when the last is selected.",
function(args, special, count) { tab_go(0); },
null
],
[
["tabopen", "t", "to", "topen", "tabedit", "tabe", "tabnew"],
"Open one or more URLs in a new tab",
"Like :open but open URLs in a new tab. If used with !, the 'tabopen' value of the 'activate' setting is negated.",
function (args, special) { if (args.length > 0) openURLsInNewTab(args, !special); else openURLsInNewTab("about:blank", true); },
function (filter) { return get_url_completions(filter); }
],
[
["tabprevious", "tp", "tprev", "tprevious"],
"Switch to the previous tab",
"Cycles to the last tab, when the first is selected.",
function(args, count) { tab_go(-1); },
null
],
[
["undo", "u"],
"Undo closing of a tab",
"If a count is given, don't close the last but the n'th last tab",
function(args, special, count) { if(count < 1) count = 1; undoCloseTab(count-1); },
null
],
[
["qmarkadd", "qmadd"],
"Mark a URL with a letter for quick access",
"Not implemented yet",
function(args) { set_url_mark("mark", "url"); }, // FIXME
function(filter) { return [["a", ""], ["b", ""]]; }
],
[
["qmarkdel", "qmdel"],
"Mark a URL with a letter for quick access",
"Not implemented yet",
function(args) { set_url_mark("mark", "url"); }, // FIXME
function(filter) { return [["a", ""], ["b", ""]]; }
],
[
["qmarks", "qms"],
"Shows marked URLs",
"Not implemented yet",
function(args) { show_url_marks(args); }, // FIXME
null
],
[
["version", "ve"],
"Show version information",
null,
function () { echo("Vimperator version: " + g_vimperator_version); },
null
],
[
["winopen", "w", "wo", "wopen"],
"Open an URL in a new window",
"Not implemented yet",
function () { echo("winopen not yet implemented"); },
null
],
[
["xall", "xa", "wqall", "wqa", "wq"],
"Save the session and quit",
"Quit Vimperator, no matter how many tabs/windows are open. The session is stored.",
function (args) { quit(true); },
null
],
[
["zoom", "zo"],
"Set zoom value of the webpage",
"Usage: :zoom 150 zooms to 150% text size.
"+
"Zoom value can be between 25 and 500%. If it is omitted, zoom is reset to 100%.",
zoom_to,
null
]
];/*}}}*/
/* all built-in normal mode commands of Vimperator
* format:
* [
* 0: [all shortcuts of this command],
* 1: description,
* 2: helptext
* 3: function (arguments in this order: args, special, count)
* ]
*/
var g_mappings = [/*{{{*/
[
["]f"],
"Focus next frame",
"Flashes the next frame in order with a red color, to quickly show where keyboard focus is.
"+
"This may not work correctly for frames with lots of CSS code.",
focusNextFrame
],
[
["b"],
"Open a prompt to switch buffers",
"Typing the corresponding number opens switches to this buffer",
function (args) { bufshow("", true); openVimperatorBar('buffer '); }
],
[
["B"],
"Toggle buffer list",
"Toggle the preview window with all currently opened tabs.",
buffer_preview_toggle,
],
[
["d"],
"Delete current buffer (=tab)",
"Count WILL be supported in future releases, then 2d removes two tabs and the one the right is selected.",
function(count) { tab_remove(count, false, 0); }
],
[
["D"],
"Delete current buffer (=tab)",
"Count WILL be supported in future releases, then 2D removes two tabs and the one the left is selected.",
function(count) { tab_remove(count, true, 0); }
],
[
["ge"],
"Execute a JavaScript code",
"Go Execute works like :execute.
"+
"This mapping is for debugging purposes, and may be removed in future.",
function(count) { openVimperatorBar('execute '); }
],
[
["gh"],
"Go home",
"Opens the homepage in the current tab.",
BrowserHome
],
[
["gH"],
"Go home in a new tab",
"Opens the homepage in a new tab.",
function(count) { openURLsInNewTab("", true); BrowserHome(); }
],
[
["gP"],
"Open (put) an URL based on the current Clipboard contents in a new buffer",
"Works like P, but inverts the 'activate' setting.",
function(count) { openURLsInNewTab(readFromClipboard(), false); }
],
[
["gt", "
"+
"Count is supported, 3gt goes to the third tab.",
function(count) { tab_go(count > 0 ? count : 0); }
],
[
["gT", "
"+
"Count is supported, 3gt goes to the third tab.",
function(count) { tab_go(count > 0 ? count :-1); }
],
[
["o"],
"Open one or more URLs in the current tab",
"See :open for more details",
function(count) { openVimperatorBar('open '); }
],
[
["O"],
"Open one ore more URLs in the current tab, based on current location",
"Works like o, but preselects current URL in the :open query.",
function(count) { openVimperatorBar('open ' + getCurrentLocation()); }
],
[
["p", "p",
function(count) { openURLs(readFromClipboard()); }
],
[
["P"],
"Open (put) an URL based on the current Clipboard contents in a new buffer",
"Works like p, but opens a new tab.
"+
"Whether the new buffer is activated, depends on the 'activate' setting.",
function(count) { openURLsInNewTab(readFromClipboard(), true); }
],
[
["r"],
"Reload current page",
"Forces reloading of the current page.",
function(count) { reload(false); }
],
[
["R"],
"Reload all pages",
"Forces reloading of all open pages.",
function(count) { reload(true); }
],
[
["t"],
"Open one or more URLs in a new tab",
"Like o but open URLs in a new tab."+
"See :tabopen for more details",
function(count) { openVimperatorBar('tabopen '); }
],
[
["T"],
"Open one ore more URLs in a new tab, based on current location",
"Works like t, but preselects current URL in the :tabopen query.",
function(count) { openVimperatorBar('tabopen ' + getCurrentLocation()); }
],
[
["u"],
"Undo closing of a tab",
"If a count is given, don't close the last but the n'th last tab",
function(count) { execute_command(count, 'undo', false, ''); }
],
[
["y"],
"Yank current location to the Clipboard",
"Under UNIX the location is also put into the selection, which can be pasted with the middle mouse button.",
yankCurrentLocation
],
[
["zi", "+"],
"Zoom in",
"Zoom in current web page by 25%.
"+
"Currently no count supported.",
function(count) { zoom_in(1); }
],
[
["zI"],
"Zoom in more",
"Zoom in current web page by 100%.
"+
"Currently no count supported.",
function(count) { zoom_in(4); }
],
[
["zo", "-"],
"Zoom out",
"Zoom out current web page by 25%.
"+
"Currently no count supported.",
function(count) { zoom_in(-1); }
],
[
["zO"],
"Zoom out more",
"Zoom out current web page by 100%.
"+
"Currently no count supported.",
function(count) { zoom_in(-4); }
],
[
["zz"],
"Set zoom value of the webpage",
"150zz zooms to 150% text size.
"+
"Zoom value can be between 25 and 500%. If it is omitted, zoom is reset to 100%.",
zoom_to
],
[
["ZQ"],
"Quit Vimperator",
"Quit Vimperator, no matter how many tabs/windows are open. The session is not stored.
" +
"Works like :qall.",
function(count) { quit(false); }
],
[
["ZZ"],
"Save the session and quit",
"Quit Vimperator, no matter how many tabs/windows are open. The session is stored.
" +
"Works like :xall.",
function(count) { quit(true); }
],
/* scrolling commands */
[
["0", "^"],
"Scroll to the absolute left of the document",
"Unlike in vim, 0 and ^ work exactly the same way.",
function(count) { scrollBufferAbsolute(0, -1); }
],
[
["$"],
"Scroll to the absolute right of the document",
null,
function(count) { scrollBufferAbsolute(100, -1); }
],
[
["gg", "35gg vertically goes to 35% of the document",
function(count) { scrollBufferAbsolute(-1, count > 0 ? count : 0); }
],
[
["G", "35G vertically goes to 35% of the document",
function(count) { scrollBufferAbsolute(-1, count >= 0 ? count : 100); }
],
[
["h", "10h will move 10 times as much to the left.
"+
"If the document cannot scroll more, a beep is emmited (unless 'beep' is turned off).",
function(count) { scrollBufferRelative(-1, 0); }
],
[
["j", "10j will move 10 times as much down.
"+
"If the document cannot scroll more, a beep is emmited (unless 'beep' is turned off).",
function(count) { scrollBufferRelative(0, 1); }
],
[
["k", "10k will move 10 times as much up.
"+
"If the document cannot scroll more, a beep is emmited (unless 'beep' is turned off).",
function(count) { scrollBufferRelative(0, -1); }
],
[
["l", "10l will move 10 times as much to the right.
"+
"If the document cannot scroll more, a beep is emmited (unless 'beep' is turned off).",
function(count) { scrollBufferRelative(1, 0); }
],
[
["3H goes back 3 steps.",
function(count) { stepInHistory(count > 0 ? -1 * count : -1); }
],
[
["L", "3L goes forward 3 steps.",
function(count) { stepInHistory(count > 0 ? count : 1); }
],
/* hint managment */
[
["f"],
"Start QuickHint mode",
"In QuickHint mode, every hintable item (according to the 'hinttags' XPath query) is assigned a label.
"+
"If you then press the keys for a label, it is followed as soon as it can be uniquely identified and this mode is stopped. Or press <Esc> to stop this mode.
"+
"If you write the hint in ALLCAPS, the hint is followed in a background tab.",
function(count) { hah.enableHahMode(HINT_MODE_QUICK); }
],
[
["F"],
"Start AlwaysHint mode",
"In AlwaysHint mode, every hintable item (according to the 'hinttags' XPath query) is assigned a label.
"+
"If you then press the keys for a label, it is followed as soon as it can be uniquely identified. Labels stay active after following a hint in this mode, press <Esc> to stop this mode.
"+
"This hint mode is especially useful for browsing large sites like Forums as hints are automatically regenerated when switching to a new document.
"+
"Also, most Ctrl-prefixed shortcut keys are available in this mode for navigation.",
function(count) { hah.enableHahMode(HINT_MODE_ALWAYS); }
],
[
[";"],
"Start ExtendedHint mode",
"ExtendedHint mode is useful, since in this mode you can yank link locations, or open them in a new window.
"+
"If you want to yank the location of hint AB, press ; to start this hint mode.
"+
"Then press AB to select the hint. Now press y to yank its location.
"+
"Actions for selected hints in ExtendedHint mode are:
"+
"
"+
"Multiple hints can be seperated by commas where it makes sense. y to yank its locationo to open its location in the current tabt to open its location in a new tabO to open its location in an :open query (not implemented yet)T to open its location in an :tabopen query (not implemented yet)s to save its destination (not implemented yet)<C-w> to open its destination in a new window;AB,AC,ADt opens AB, AC and AD in a new tab.
"+
"Hintable elements for this mode can be set in the 'extendedhinttags' XPath string.",
function(count) { hah.enableHahMode(HINT_MODE_EXTENDED); }
],
/* search managment */
[
["n"],
"Find next",
"Repeat the last \"/\" 1 time (until count is supported).",
// don't use a closure for this, is just DoesNotWork (TM)
function(count) { gFindBar.onFindAgainCmd(); } // this does not work, why?: goDoCommand('cmd_findAgain'); }
],
[
["N"],
"Find previous",
"Repeat the last \"/\" 1 time (until count is supported) in the opposite direction.",
// don't use a closure for this, is just DoesNotWork (TM)
function(count) { gFindBar.onFindPreviousCmd(); } // this does not work, why?: goDoCommand('cmd_findPrevious'); }
],
/* vimperator managment */
[
[":help <F1> (jumping to a specific section not implemented yet).",
function(count) { help(null); }
],
[
[":"],
"Start command line mode",
"In command line mode, you can perform extended commands, which may require arguments.",
function(count) { openVimperatorBar(null); }
],
[
["I"],
"Disable vimperator keys",
"Starts an 'ignorekeys' mode, where all keys except <Esc> are passed to the next event handler.
"+
"This is especially useful, if JavaScript controlled forms like the RichEdit form fields of GMail don't work anymore.
" +
"To exit this mode, press <Esc>. If you also need to pass <Esc>"+
"in this mode to the webpage, prepend it with <C-v>.",
function(count) { addMode(MODE_ESCAPE_ALL_KEYS);}
],
[
["<C-v>.
"+
"Also works to unshadow Firefox shortcuts like <C-o> which are otherwise hidden in Vimperator.
"+
"When in 'ignorekeys' mode (activated by <I>), <C-v> will pass the next key to Vimperator instead of the webpage.",
function(count) { addMode(MODE_ESCAPE_ONE_KEY); }
],
[
["
"+
"Also focuses the web page, in case a form field has focus, and eats our key presses.",
onEscape
],
/* quick bookmark access - will be customizable in future*/
[
["'b"],
"These quick bookmarks will be customizable in future releases, ignore for now",
null,
function(count) { openURLs('www.bwin.com'); }
],
[
["'o"],
"These quick bookmarks will be customizable in future releases, ignore for now",
null,
function(count) { openURLs('www.osnews.com'); }
],
[
["'s"],
"These quick bookmarks will be customizable in future releases, ignore for now",
null,
function(count) { openURLs('www.derstandard.at'); }
],
[
["'w"],
"These quick bookmarks will be customizable in future releases, ignore for now",
null,
function(count) { openURLs('wetter.orf.at'); }
],
[
["'t"],
"These quick bookmarks will be customizable in future releases, ignore for now",
null,
function(count) { openURLs('www.tvinfo.de'); }
],
[
["\"b"],
"These quick bookmarks will be customizable in future releases, ignore for now",
null,
function(count) { openURLsInNewTab('www.bwin.com'); }
],
[
["\"o"],
"These quick bookmarks will be customizable in future releases, ignore for now",
null,
function(count) { openURLsInNewTab('www.osnews.com'); }
],
[
["\"s"],
"These quick bookmarks will be customizable in future releases, ignore for now",
null,
function(count) { openURLsInNewTab('www.derstandard.at'); }
],
[
["\"w"],
"These quick bookmarks will be customizable in future releases, ignore for now",
null,
function(count) { openURLsInNewTab('wetter.orf.at'); }
],
[
["\"t"],
"These quick bookmarks will be customizable in future releases, ignore for now",
null,
function(count) { openURLsInNewTab('www.tvinfo.de'); }
]
];/*}}}*/
var g_insert_mappings = [ /*{{{*/
["xxx", "todo"],
["Vimperator
' +
'Introduction
' +
':set guioptions=mT to get it back. ' +
'If you don\'t like Vimperator at all, you can uninstall it by typing :addons and remove/disable it. ' +
'If you like it, but can\'t remember the shortcuts, press F1 or :help to get this help window back.';
var command = " ';
}
return ret;
}
function makeSettingsHelpString(command)
{
var ret = "";
ret = command[5] + " (default: ";
for (var j=0; j < commands[i][0].length; j++)
{
var cmd_name = commands[i][0][j];
cmd_name = cmd_name.replace(//g, ">");
if (j==0) // color the first item differently
command += " " +beg+ cmd_name +end+ '
';
else
command += "" +beg+ cmd_name +end+ '
';
}
ret += command + '';
if (commands[i][1])
ret += '' + commands[i][1] + '
'; // the short description
if (func)
ret += func.call(this, commands[i]);
if (commands[i][2])
{
if(func)
ret += "
"
ret += commands[i][2]; // the help description
}
ret += '";
if (command[5] == "boolean")
{
if(command[6] == true)
ret += "on";
else
ret += "off";
}
else
ret += command[6];
ret += ")";
return ret;
}
var mappings = 'Mappings
'+
''
mappings += makeHelpString(g_mappings, "#102663", "", "", null);
mappings += '
What is the meaning of life, the universe and everything?
' +
'Douglas Adams, the only person who knew what this question really was about is
' +
'now dead, unfortunately. So now you might wonder what the meaning of death
' +
'is...