New and Updated patches (egaudet)
[webos-internals:djcin7s-modifications.git] / universal-search / universal-search-command-line.patch
1 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/TODO.txt b/usr/lib/luna/system/luna-applauncher/app/controllers/TODO.txt
2 new file mode 100644
3 index 0000000..b6afd49
4 --- /dev/null
5 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/TODO.txt
6 @@ -0,0 +1,2 @@
7 +- make command-line options work with .task as well as .quicktask.
8 +- make aliases work.  (.groceries)
9 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/calculator.js b/usr/lib/luna/system/luna-applauncher/app/controllers/calculator.js
10 new file mode 100644
11 index 0000000..b493276
12 --- /dev/null
13 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/calculator.js
14 @@ -0,0 +1,50 @@
15 +/*jslint browser: true, eqeqeq: true, undef: true */
16 +/******************************************************************************
17 +Lines above are for jslint, the JavaScript verifier.
18 +http://www.jslint.com/
19 +******************************************************************************/
20 +
21 +var Calculator = function () {
22 +       var abs         = Math.abs;
23 +       var max         = Math.max;
24 +       var min         = Math.min;
25 +       var random      = Math.random;
26 +       var ceil        = Math.ceil;
27 +       var round       = Math.round;
28 +       var floor       = Math.floor;
29 +       var E           = Math.E;
30 +       var LN10        = Math.LN10;
31 +       var LN2         = Math.LN2;
32 +       var LOG10E      = Math.LOG10E;
33 +       var LOG2E       = Math.LOG2E;
34 +       var PI          = Math.PI;
35 +       var SQRT1_2     = Math.SQRT1_2;
36 +       var SQRT2       = Math.SQRT2;
37 +       var acos        = Math.acos;
38 +       var asin        = Math.asin;
39 +       var atan        = Math.atan;
40 +       var atan2       = Math.atan2;
41 +       var cos         = Math.cos;
42 +       var exp         = Math.exp;
43 +       var log         = Math.log;
44 +       var pow         = Math.pow;
45 +       var sin         = Math.sin;
46 +       var sqrt        = Math.sqrt;
47 +       var tan         = Math.tan;
48 +       var cot         = function (x) { return 1 / tan(x); }; // cotangent
49 +       var sec         = function (x) { return 1 / cos(x); }; // secant
50 +       var csc         = function (x) { return 1 / sin(x); }; // cosecant
51 +       var log2        = function (x) { return log(x) / LN2; };
52 +       var log10       = function (x) { return log(x) / LN10; };
53 +
54 +       // I really wish we could provide a true global context
55 +       // independent from Mojo or whatever environment we happen
56 +       // to be in.
57 +       var a, b, c, d, e, f, g, h, i, j, k, l, m;
58 +       var n, o, p, q, r, s, t, u, v, w, x, y, z;
59 +       
60 +       this.calculate = function (string) {
61 +               return eval(string);
62 +       };
63 +};
64 +
65 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/getopt.js b/usr/lib/luna/system/luna-applauncher/app/controllers/getopt.js
66 new file mode 100644
67 index 0000000..0261218
68 --- /dev/null
69 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/getopt.js
70 @@ -0,0 +1,121 @@
71 +/*jslint browser: true, eqeqeq: false, undef: true */
72 +/******************************************************************************
73 +Lines above are for jslint, the JavaScript verifier.
74 +http://www.jslint.com/
75 +******************************************************************************/
76 +
77 +/*
78 +http://blog.fpmurphy.com/2010/02/javascript-shell-command-line-processing.html
79 +*/
80 +
81 +//
82 +//  getopt.js    Finnbarr P. Murphy March 2010
83 +//               modified by Darren Embry May 2010
84 +//
85 +//  Based on BSD getopt.c  Use subject to BSD license.
86 +//
87 +//  For details of how to use this function refer to
88 +//  the BSD man page for getopt(3). GNU-style long
89 +//  options are not supported.
90 +//
91 +
92 +function getopt(nargv, ostr)
93 +{
94 +       if ( typeof getopt.place == 'undefined' ) {
95 +               getopt.place = ""; // static string, option letter processing
96 +               getopt.iplace = 0; // index into string
97 +       }
98 +
99 +       var oli;                // option letter list index
100 +
101 +       if (getopt.optreset || getopt.iplace == getopt.place.length) {
102 +               getopt.optreset = false;
103 +               getopt.place = nargv[getopt.optind]; 
104 +               getopt.iplace = 0;
105 +               if (getopt.optind >= nargv.length || 
106 +                   getopt.place.charAt(getopt.iplace++) != "-") {
107 +                       // argument is absent or is not an option
108 +                       getopt.place = ""; 
109 +                       getopt.iplace = 0;
110 +                       return null;
111 +               }
112 +               getopt.optopt = getopt.place.charAt(getopt.iplace++);
113 +               if (getopt.optopt == '-' &&
114 +                   getopt.iplace == getopt.place.length) {
115 +                       // "--" => end of options
116 +                       ++getopt.optind;
117 +                       getopt.place = "";
118 +                       getopt.iplace = 0;
119 +                       return null;
120 +               }
121 +               if (getopt.optopt == 0) {
122 +                       // Solitary '-', treat as a '-' option
123 +                       getopt.place = "";
124 +                       getopt.iplace = 0;
125 +                       if (ostr.indexOf('-') == -1) {
126 +                               return null;
127 +                       }
128 +                       getopt.optopt = '-';
129 +               }
130 +       }
131 +       else {
132 +               getopt.optopt = getopt.place.charAt(getopt.iplace++);
133 +       }
134 +               
135 +       // see if option letter is what is wanted
136 +       if (getopt.optopt == ':' ||
137 +           (oli = ostr.indexOf(getopt.optopt)) == -1) {
138 +               if (getopt.iplace == getopt.place.length) {
139 +                       ++getopt.optind;
140 +               }
141 +               if (getopt.opterr && ostr.charAt(0) != ':') {
142 +                       throw new Error("illegal option -- " + getopt.optopt);
143 +               }
144 +               return ('?');
145 +       }
146 +
147 +       // does this option require an argument?
148 +       if (ostr.charAt(oli + 1) != ':') {
149 +               // does not need argument
150 +               getopt.optarg = null;
151 +               if (getopt.iplace == getopt.place.length) {
152 +                       ++getopt.optind;
153 +               }
154 +       }
155 +       else {
156 +               //  Option-argument is either the rest of this argument
157 +               //  or the entire next argument.
158 +               if (getopt.iplace < getopt.place.length) {
159 +                       getopt.optarg = getopt.place.substr(getopt.iplace);
160 +               }
161 +               else if (nargv.length > ++getopt.optind) {
162 +                       getopt.optarg = nargv[getopt.optind];
163 +               }
164 +               else {
165 +                       // option argument absent
166 +                       getopt.place = "";
167 +                       getopt.iplace = 0;
168 +                       if (ostr.charAt(0) == ':') {
169 +                               return (':');
170 +                       }
171 +                       if (getopt.opterr) {
172 +                               throw new Error(
173 +                                       "option requires an argument -- " + 
174 +                                               getopt.optopt);
175 +                       }
176 +                       return('?');
177 +               }
178 +               getopt.place = "";
179 +               getopt.iplace = 0;
180 +               ++getopt.optind;
181 +       }
182 +
183 +       return (getopt.optopt);
184 +}
185 +
186 +getopt.opterr   = true;         // throw errors
187 +getopt.optind   = 0;    // index into parent argv array
188 +getopt.optopt   = "";   // character checked for validity
189 +getopt.optreset = false; // reset getopt
190 +getopt.optarg   = "";   // option argument
191 +
192 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js b/usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js
193 index 6f3368e..88ca22e 100644
194 --- a/usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js
195 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/global-search-assistant.js
196 @@ -138,6 +138,7 @@ GlobalSearchAssistant = Class.create({
197                 searchesDiv.update(Mojo.View.render({template: 'global-search/expanded-searches-div' }));
198                 this.expandedSearchDrawer = { showExpanded: false };
199                 this.controller.setupWidget('expanded_searches_drawer', {unstyled:true, property:'showExpanded'}, this.expandedSearchDrawer);
200 +
201                 this.webDrawer = { showWeb: false };
202                 this.controller.setupWidget('web_drawer', {unstyled:true, property:'showWeb'}, this.webDrawer);
203                 
204 @@ -173,11 +174,49 @@ GlobalSearchAssistant = Class.create({
205                 
206                 this.controller.listen(this.controller.document, 'paste', this.onPaste.bindAsEventListener(this), true);
207                 
208 +               this.uscl = new USCL();
209 +               
210 +               var searchesDivUSCL = this.controller.get('searches-list-uscl');
211 +               searchesDivUSCL.update(Mojo.View.render({template: 'global-search/expanded-searches-div-uscl' }));
212 +               this.expandedSearchDrawerUSCL = { showExpanded: false };
213 +               this.controller.setupWidget('expanded_searches_drawer_uscl',
214 +                                           { unstyled:true, property:'showExpanded', 
215 +                                             scrollDisabled: true},
216 +                                           this.expandedSearchDrawerUSCL);
217 +
218 +               this.usclDrawer = { showUSCL: false };
219 +               this.controller.setupWidget('command_line_drawer', {unstyled: true, property: 'showUSCL'}, this.usclDrawer);
220 +
221 +               this.usclSearchesAttrs = {
222 +                       listTemplate: "global-search/templates/uscl-searches-list",
223 +                       itemTemplate: "global-search/templates/uscl-searches-item",
224 +                       swipeToDelete: false,
225 +                       reorderable: false,
226 +                       renderLimit: 500
227 +               };
228 +               this.usclSearchesModel = { 
229 +                       items: this.uscl.universalSearchList 
230 +               };
231 +               this.controller.setupWidget("usclSearches",
232 +                                           this.usclSearchesAttrs,
233 +                                           this.usclSearchesModel);
234 +
235 +               this.onTapUSCLHandler = this.onTapUSCL.bindAsEventListener(this);
236 +               this.controller.listen("usclSearches",
237 +                                      Mojo.Event.listTap,
238 +                                      this.onTapUSCLHandler);
239 +               
240                 this.initOnServerStart("com.palm.systemservice");
241                 
242                 this.galInit();
243         },
244    
245 +       onTapUSCL: function (event) {
246 +               var entry = this.usclSearchesModel.items[event.index];
247 +               this.runUSCL({ entry: entry,
248 +                              arg: this.currentFilter });
249 +       },
250 +   
251         ready: function() {
252                 // try to force our input field to always have focus (there are some exceptions)
253                 var input = this.searchField.querySelector('[name=searchtermInput]');
254 @@ -185,6 +224,21 @@ GlobalSearchAssistant = Class.create({
255                         input.blur = function() { this.focus(); }
256                 }
257                 this.enable(true);
258 +               this.monkeyPatch1();
259 +       },
260 +
261 +       /* allows one to disable the scrollIntoView behavior of Mojo.Widget.Drawer. */
262 +       /* WARNING: THIS MONKEY-PATCHES A PRIVATE API */
263 +       monkeyPatch1: function () {
264 +               if (this.monkeyPatched) { return; }
265 +               var monkey = Mojo.Widget.Drawer.prototype.scrollIntoView;
266 +               if (!monkey) { return; }
267 +               Mojo.Widget.Drawer.prototype.scrollIntoView = function () {
268 +                       if (this.controller.attributes.scrollDisabled) {
269 +                               return;
270 +                       }
271 +                       monkey.apply(this, arguments);
272 +               };
273         },
274         
275         isEnabled: function() {
276 @@ -1562,6 +1616,94 @@ GlobalSearchAssistant = Class.create({
277                 ApplicationService.launch('com.palm.app.browser', params);              
278         },      
279         
280 +       deactivateWithError: function (message, allowHTMLMessage) {
281 +               this.controller.showAlertDialog({
282 +                       onChoose: (function () { this.deactivate(); }).bind(this),
283 +                       title: "Error",
284 +                       message: message,
285 +                       choices: [ { label: "OK", value: "ok" } ],
286 +                       allowHTMLMessage: allowHTMLMessage
287 +               });
288 +       },
289 +
290 +       deactivateWithWarning: function (message, allowHTMLMessage) {
291 +               this.controller.showAlertDialog({
292 +                       onChoose: (function () { this.deactivate(); }).bind(this),
293 +                       title: "Warning",
294 +                       message: message,
295 +                       choices: [ { label: "OK", value: "ok" } ],
296 +                       allowHTMLMessage: allowHTMLMessage
297 +               });
298 +       },
299 +
300 +       runUSCL: function (o) {
301 +               if (!this.uscl) {
302 +                       this.deactivate();
303 +               }
304 +               var result;
305 +               try {
306 +                       if (o instanceof Object) {
307 +                               // when someone types something and taps
308 +                               // one of the extended universal search
309 +                               // items we added.
310 +                               result = this.uscl.run(o.entry, o.arg);
311 +                       }
312 +                       else {
313 +                               // We assume it's a string at this
314 +                               // point.  This is when someone types a
315 +                               // universal search string containing a
316 +                               // USCL command and hits Enter.  Whether
317 +                               // it contains a USCL command is
318 +                               // determined by
319 +                               // this.uscl.isCommandString() before we
320 +                               // get to this point.
321 +                               result = this.uscl.runString(o);
322 +                       }
323 +               }
324 +               catch (e) {
325 +                       if (e instanceof USCLError) {
326 +                               this.deactivateWithError(e.message);
327 +                               // remember, kids, don't deactivate
328 +                               // right away!
329 +                               return;
330 +                       }
331 +                       else {
332 +                               throw e;
333 +                       }
334 +               }
335 +               if (result === false) {
336 +                       // don't deactivate; let something else do it
337 +               }
338 +               else if (!result) {
339 +                       this.deactivate();
340 +               }
341 +               else if (result instanceof Function) {
342 +                       if (!result.noDeactivate) {
343 +                               this.deactivate();
344 +                       }
345 +                       result.apply(this);
346 +               }
347 +               else if (result instanceof Object) {
348 +                       this.controller.showAlertDialog({
349 +                               onChoose: (function () { this.deactivate(); }).bind(this),
350 +                               title: result.title,
351 +                               message: result.message,
352 +                               choices: [ { label: "OK", value: "ok" } ]
353 +                       });
354 +               }
355 +               else if (result.constructor && result.constructor === String) {
356 +                       this.controller.showAlertDialog({
357 +                               onChoose: (function () { this.deactivate(); }).bind(this),
358 +                               title: "Result",
359 +                               message: result,
360 +                               choices: [ { label: "OK", value: "ok" } ]
361 +                       });
362 +               }
363 +               else {
364 +                       this.deactivate();
365 +               }
366 +       },
367 +
368         toggleSearchListDivs: function() {
369                 if(!this.enterKeyActionItem){
370                         this.enterKeyActionItem = 'search'
371 @@ -1572,16 +1714,40 @@ GlobalSearchAssistant = Class.create({
372                                         $('webtext').innerHTML = this.currentFilter;
373                                         this.webDrawer.showWeb = true;
374                                         this.controller.modelChanged(this.webDrawer);
375 +                                       this.usclDrawer.showUSCL = false;
376 +                                       this.controller.modelChanged(this.usclDrawer);
377 +                               }
378 +                               else if (this.uscl.isCommandString(this.currentFilter)) {
379 +                                       $('uscl-text').innerHTML = this.currentFilter;
380 +                                       this.webDrawer.showWeb = false;
381 +                                       this.controller.modelChanged(this.webDrawer);
382 +                                       this.usclDrawer.showUSCL = true;
383 +                                       this.controller.modelChanged(this.usclDrawer);
384                                 }
385                                 else {
386                                         this.webDrawer.showWeb =  false ;
387                                         this.controller.modelChanged(this.webDrawer);
388 +                                       this.usclDrawer.showUSCL = false;
389 +                                       this.controller.modelChanged(this.usclDrawer);
390                                 }
391                                 $('find').removeClassName('single');
392                                 $('find').addClassName('first');
393                                 this.searchField.removeClassName('text-hidden');
394                                 this.expandedSearchDrawer.showExpanded = true;
395                                 this.controller.modelChanged(this.expandedSearchDrawer);
396 +
397 +                               if (this.uscl.show) {
398 +                                       this.usclSearchesModel.items = 
399 +                                               this.uscl.getUniversalSearchCommandList();
400 +                                       this.controller.modelChanged(this.usclSearchesModel);
401 +                                       this.controller.get('searchesDivUSCL').show();
402 +                                       this.expandedSearchDrawerUSCL.showExpanded = true;
403 +                               }
404 +                               else {
405 +                                       this.controller.get('searchesDivUSCL').hide();
406 +                                       this.expandedSearchDrawerUSCL.showExpanded = false;
407 +                               }
408 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
409                         } else {//find...
410                                 if (this.dialDiv.visible() || this.numberDiv.visible()) {
411                                         this.searchField.addClassName('text-hidden');
412 @@ -1591,6 +1757,11 @@ GlobalSearchAssistant = Class.create({
413                                 }
414                                 this.expandedSearchDrawer.showExpanded = false;
415                                 this.controller.modelChanged(this.expandedSearchDrawer);
416 +
417 +                               this.controller.get('searchesDivUSCL').hide();
418 +                               this.expandedSearchDrawerUSCL.showExpanded = false;
419 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
420 +
421                                 $('find').removeClassName('first');
422                                 $('find').addClassName('single');
423                         }
424 @@ -1605,16 +1776,39 @@ GlobalSearchAssistant = Class.create({
425                                         $('webtext').innerHTML = this.currentFilter;
426                                         this.webDrawer.showWeb = true;
427                                         this.controller.modelChanged(this.webDrawer);
428 +                                       this.usclDrawer.showUSCL = false;
429 +                                       this.controller.modelChanged(this.usclDrawer);
430 +                               }
431 +                               else if (this.uscl.isCommandString(this.currentFilter)) {
432 +                                       $('uscl-text').innerHTML = this.currentFilter;
433 +                                       this.webDrawer.showWeb = false;
434 +                                       this.controller.modelChanged(this.webDrawer);
435 +                                       this.usclDrawer.showUSCL = true;
436 +                                       this.controller.modelChanged(this.usclDrawer);
437                                 }
438                                 else {
439                                         this.webDrawer.showWeb = false;
440                                         this.controller.modelChanged(this.webDrawer);
441 +                                       this.usclDrawer.showUSCL = false;
442 +                                       this.controller.modelChanged(this.usclDrawer);
443                                 }
444                                 $('find').removeClassName('single');
445                                 $('find').addClassName('first');
446                                 this.searchField.removeClassName('text-hidden');
447                                 this.expandedSearchDrawer.showExpanded = true;
448                                 this.controller.modelChanged(this.expandedSearchDrawer);
449 +
450 +                               if (this.uscl.show) {
451 +                                       this.usclSearchesModel.items = this.uscl.getUniversalSearchCommandList();
452 +                                       this.controller.modelChanged(this.usclSearchesModel);
453 +                                       this.controller.get('searchesDivUSCL').show();
454 +                                       this.expandedSearchDrawerUSCL.showExpanded = true;
455 +                               }
456 +                               else {
457 +                                       this.controller.get('searchesDivUSCL').hide();
458 +                                       this.expandedSearchDrawerUSCL.showExpanded = false;
459 +                               }
460 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
461                         } else {//find...
462                                 if (this.dialDiv.visible() || this.numberDiv.visible()) {
463                                         this.searchField.addClassName('text-hidden');
464 @@ -1624,6 +1818,11 @@ GlobalSearchAssistant = Class.create({
465                                 }
466                                 this.expandedSearchDrawer.showExpanded = false;
467                                 this.controller.modelChanged(this.expandedSearchDrawer);
468 +
469 +                               this.controller.get('searchesDivUSCL').hide();
470 +                               this.expandedSearchDrawerUSCL.showExpanded = false;
471 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
472 +
473                                 $('find').removeClassName('first');
474                                 $('find').addClassName('single');
475                         }
476 @@ -1643,6 +1842,11 @@ GlobalSearchAssistant = Class.create({
477                                 this.searchExplicitlyExpanded = false;
478                                 this.expandedSearchDrawer.showExpanded = false;
479                                 this.controller.modelChanged(this.expandedSearchDrawer);
480 +
481 +                               this.controller.get('searchesDivUSCL').hide();
482 +                               this.expandedSearchDrawerUSCL.showExpanded = false;
483 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
484 +
485                                 $('find').removeClassName('first');
486                                 $('find').addClassName('single');
487                                 if (this.dialDiv.visible() || this.numberDiv.visible()) {
488 @@ -1658,21 +1862,46 @@ GlobalSearchAssistant = Class.create({
489                                         $('webtext').innerHTML = this.currentFilter;
490                                         this.webDrawer.showWeb = true;
491                                         this.controller.modelChanged(this.webDrawer);
492 +                                       this.usclDrawer.showUSCL = false;
493 +                                       this.controller.modelChanged(this.usclDrawer);
494 +                               }
495 +                               else if (this.uscl.isCommandString(this.currentFilter)) {
496 +                                       $('uscl-text').innerHTML = this.currentFilter;
497 +                                       this.webDrawer.showWeb = false;
498 +                                       this.controller.modelChanged(this.webDrawer);
499 +                                       this.usclDrawer.showUSCL = true;
500 +                                       this.controller.modelChanged(this.usclDrawer);
501                                 }
502                                 else {
503                                         this.webDrawer.showWeb = false;
504                                         this.controller.modelChanged(this.webDrawer);
505 +                                       this.usclDrawer.showUSCL = false;
506 +                                       this.controller.modelChanged(this.usclDrawer);
507                                 }
508                                 $('find').removeClassName('single');
509                                 $('find').addClassName('first');
510                                 this.searchField.removeClassName('text-hidden');
511                                 this.expandedSearchDrawer.showExpanded = true;
512                                 this.controller.modelChanged(this.expandedSearchDrawer);
513 +
514 +                               if (this.uscl.show) {
515 +                                       this.usclSearchesModel.items = this.uscl.getUniversalSearchCommandList();
516 +                                       this.controller.modelChanged(this.usclSearchesModel);
517 +                                       this.controller.get('searchesDivUSCL').show();
518 +                                       this.expandedSearchDrawerUSCL.showExpanded = true;
519 +                               }
520 +                               else {
521 +                                       this.controller.get('searchesDivUSCL').hide();
522 +                                       this.expandedSearchDrawerUSCL.showExpanded = false;
523 +                               }
524 +                               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
525                         }
526                 } else {
527                         var url = target.id;
528                         if (url == "web")
529                                 this.launchBrowser(this.currentFilter);
530 +                       else if (url == "uscl")
531 +                               this.runUSCL(this.currentFilter);
532                 }
533         },
534         
535 @@ -1931,6 +2160,13 @@ GlobalSearchAssistant = Class.create({
536                 this.gpsInfo = undefined;
537                 if(this.highlightTarget != null)
538                         this.highlightTarget.removeClassName('selected');
539 +
540 +               this.usclDrawer.showUSCL =  false ;
541 +               this.controller.modelChanged(this.usclDrawer);
542 +               this.controller.get('searchesDivUSCL').hide();
543 +               this.expandedSearchDrawerUSCL.showExpanded = false;
544 +               this.controller.modelChanged(this.expandedSearchDrawerUSCL);
545 +               $('uscl').removeClassName('selected');
546         },
547         
548    webSiteString: function(s){
549 @@ -1976,6 +2212,7 @@ GlobalSearchAssistant = Class.create({
550         //clear search':
551         $(this.defaultSearchEngine).removeClassName('palm-focus');
552         $('web').removeClassName('palm-focus');
553 +       $('uscl').removeClassName('palm-focus');
554    },
555    highlightSelection: function() {
556         
557 @@ -2049,6 +2286,24 @@ GlobalSearchAssistant = Class.create({
558                 $(this.defaultSearchEngine).removeClassName('palm-focus');
559                 $('web').removeClassName('palm-focus');
560         }
561 +
562 +       if (this.enterKeyActionItem === "search") {
563 +               if (this.webDrawer.showWeb == true) {
564 +                       $('uscl').removeClassName('palm-focus');
565 +               }
566 +               else if (this.usclDrawer.showUSCL == true) {
567 +                       $(this.defaultSearchEngine).removeClassName('palm-focus');
568 +                       $('web').removeClassName('palm-focus');
569 +                       this.highlightTarget = $('uscl');
570 +                       $('uscl').addClassName('palm-focus');
571 +               }
572 +               else if (this.expandedSearchDrawer.showExpanded == true) {
573 +                       $('uscl').removeClassName('palm-focus');
574 +               }
575 +       }
576 +       else {
577 +               $('uscl').removeClassName('palm-focus');
578 +       }
579    },
580    
581    enterKeyAction: function(){
582 @@ -2146,6 +2401,8 @@ GlobalSearchAssistant = Class.create({
583                         }
584                         if (this.webDrawer.showWeb == true)
585                                 this.launchBrowser(this.currentFilter);
586 +                       else if (this.usclDrawer.showUSCL == true)
587 +                               this.runUSCL(this.currentFilter);
588                         else {
589                                 this.launchBrowser(this.URLs[this.defaultSearchEngine] + encodeURIComponent(this.currentFilter));
590                         }
591 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-entries.txt b/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-entries.txt
592 new file mode 100644
593 index 0000000..d51f1a0
594 --- /dev/null
595 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-entries.txt
596 @@ -0,0 +1,124 @@
597 +Each entry in USCL#entries can be an object containing the following
598 +properties:
599 +
600 +       title
601 +
602 +               String displayed in help and in the extended Universal
603 +               Search menu.
604 +
605 +       usage
606 +
607 +               Either a string or an array.
608 +
609 +               If it's a string, you only specify the arguments.
610 +               
611 +               If it's an array of strings, each string also specifies
612 +               the name of the command.
613 +
614 +               usage: "add|delete <var>word</var> ..."
615 +
616 +               usage: [
617 +                       ".foo add <var>word</var> ...",
618 +                       ".foo delete <var>word</var> ..."
619 +               ]
620 +
621 +       example
622 +
623 +               Either a string or an array.  
624 +
625 +               If it's a string, you only specify the arguments.
626 +               
627 +               If it's an array of strings, each string also specifies
628 +               the name of the command.
629 +
630 +               example: "add five"
631 +
632 +               example: [".foo add five six seven", ".foo delete nine"]
633 +
634 +       description
635 +
636 +               A string describing what the command does.
637 +
638 +       ONE of the following:
639 +
640 +               url
641 +
642 +                       The command simply opens a new web browser
643 +                       pointing to the specified url where %s is
644 +                       replaced with the arguments you specified,
645 +                       URL-encoded.
646 +
647 +                       example: "http://www.imdb.com/find?s=all&q="
648 +
649 +               method
650 +
651 +                       Usually internal.
652 +
653 +                       Usually only used for builtins implemented by
654 +                       your author.
655 +
656 +                       A function taking a single string.
657 +
658 +               appId and param
659 +
660 +                       Usually internal.
661 +
662 +                       The application specified by appId is launched
663 +                       with the following property:
664 +
665 +                               parameters: {
666 +                                       id: (appId),
667 +                                       params: {
668 +                                               (param): (string argument)
669 +                                       }
670 +                               }
671 +
672 +       excludeFromUniversalSearch (optional boolean, defaults to false)
673 +
674 +               Usually internal.
675 +
676 +               If true, do not add this command to the extended
677 +               Universal Search menu.
678 +
679 +               This is typically used for commands already built in.
680 +
681 +       argumentsOptional (optional)
682 +
683 +               Usually internal.
684 +
685 +               Normally, at least one argument *must* be passed to a
686 +               command.  Setting this property to true dismisses that
687 +               requirement.
688 +
689 +       preprocess (optional)
690 +
691 +               Usually internal.
692 +       
693 +               A function that takes a string and returns a string.
694 +               Is applied to arguments before further work is done.
695 +
696 +               Usually only used this with entries that specify the url
697 +               property.
698 +
699 +       emulatorOnly (optional boolean, defaults to false)
700 +
701 +               Usually internal.
702 +
703 +               If true, command only works in the emulator.  Usually
704 +               used by your humble author for command that haven't
705 +               undergone extensive testing yet.
706 +
707 +       noArguments
708 +
709 +               Usually internal.
710 +
711 +               Describes what to do if no arguments are supplied to the
712 +               command.  Not presently used.  
713 +
714 +               noArguments: { appId: "com.palm.app.example" }
715 +
716 +or a string, in which case the entry is an alias to another entry
717 +specified by the property's value.
718 +
719 +
720 +
721 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-flow.txt b/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-flow.txt
722 new file mode 100644
723 index 0000000..4023f00
724 --- /dev/null
725 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-flow.txt
726 @@ -0,0 +1,31 @@
727 +USE CASE 1     USE CASE 2      USE CASE 3
728 +----------------------- ----------------------- -----------------------
729 +user types something,  user types something    user types something
730 +then taps a search item containing a command,  containing a command,
731 +       then taps the cmd: item then hits Enter.
732 +
733 +"pizza 40204"  "pizza 40204 .maps"     "pizza 40204 .maps"
734 +       or ".maps pizza 40204"  or ".maps pizza 40204"
735 +
736 +GlobalSearchAssistant# GlobalSearchAssistant#  GlobalSearchAssistant#
737 +onTapUSCL(event)       selectedSearch(event)   enterKeyAction()
738 +
739 +GlobalSearchAssistant# GlobalSearchAssistant#  GlobalSearchAssistant#
740 +runUSCL({      runUSCL(        runUSCL(
741 +  "entry": entry,        "pizza 40204 .maps"     "pizza 40204 .maps"
742 +  "arg": "pizza 40204" )       )
743 +})
744 +
745 +USCL#run(entry,        USCL#runString(cF)      USCL#runString(cF)
746 +  "pizza 40204")
747 +
748 +       USCL#run("maps",        USCL#run("maps",
749 +         "pizza 40204")          "pizza 40204")
750 +
751 +USCL#runEntry(entry,   USCL#runEntry(entry,    USCL#runEntry(entry,
752 +  "pizza 40204")         "pizza 40204")          "pizza 40204")
753 +
754 +# Local Variables: #
755 +# tab-stop-list: (24 48 72 96 120 144 168) #
756 +# tab-width: 24 #
757 +# End: #
758 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-list.js b/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-list.js
759 new file mode 100644
760 index 0000000..a74bf4b
761 --- /dev/null
762 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-list.js
763 @@ -0,0 +1,63 @@
764 +/*jslint browser: true, eqeqeq: true, undef: true */
765 +/*global Mojo */
766 +/******************************************************************************
767 +Lines above are for jslint, the JavaScript verifier.
768 +http://www.jslint.com/
769 +******************************************************************************/
770 +
771 +function UsclHelpCommandListAssistant (params) {
772 +       this.uscl = params.uscl;
773 +}
774 +
775 +UsclHelpCommandListAssistant.prototype.setup = function () {
776 +       this.stageController = this.controller.stageController;
777 +       this.items = this.uscl.getHelpCommandList();
778 +       this.controller.setupWidget("command-list", {
779 +               listTemplate: "uscl-help-command-list/templates/list",
780 +               itemTemplate: "uscl-help-command-list/templates/item",
781 +               swipeToDelete: false,
782 +               reorderable: false,
783 +               renderLimit: this.items.length
784 +       }, this.itemsModel = {
785 +               items: this.items
786 +       });
787 +       this.showCommandHandler = this.showCommandTap.bindAsEventListener(this);
788 +       this.controller.listen("command-list", Mojo.Event.listTap,
789 +                              this.showCommandHandler);
790 +       
791 +       var body = this.stageController.document.getElementsByTagName("body");
792 +       body[0].addClassName("uscl-body");
793 +};
794 +
795 +UsclHelpCommandListAssistant.prototype.activate = function () {
796 +       this.showNextCommand();
797 +};
798 +
799 +UsclHelpCommandListAssistant.prototype.showCommandTap = function (event) {
800 +       this.stageController.pushScene("uscl-help-command-view", {
801 +               items: this.items,
802 +               index: event.index
803 +       });
804 +};
805 +
806 +UsclHelpCommandListAssistant.prototype.showNextCommand = function () {
807 +       if (this.uscl.nextEntryToShow !== undefined &&
808 +           this.uscl.nextEntryToShow !== null) {
809 +               this.showEntry(this.uscl.nextEntryToShow);
810 +               this.uscl.nextEntryToShow = null;
811 +       }
812 +};
813 +
814 +UsclHelpCommandListAssistant.prototype.showEntry = function (entry) {
815 +       if (entry) {
816 +               this.stageController.pushScene("uscl-help-command-view", {
817 +                       item: entry
818 +               });
819 +       }
820 +};
821 +
822 +UsclHelpCommandListAssistant.prototype.cleanup = function () {
823 +       this.controller.stopListening("command-list", Mojo.Event.listTap,
824 +                                     this.showCommandHandler);
825 +};
826 +
827 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-view.js b/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-view.js
828 new file mode 100644
829 index 0000000..f592d8d
830 --- /dev/null
831 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/uscl-help-command-view.js
832 @@ -0,0 +1,86 @@
833 +/*jslint browser: true, eqeqeq: true, undef: true */
834 +/*global Mojo */
835 +/******************************************************************************
836 +Lines above are for jslint, the JavaScript verifier.
837 +http://www.jslint.com/
838 +******************************************************************************/
839 +
840 +function UsclHelpCommandViewAssistant (params) {
841 +       if ("items" in params && "index" in params) {
842 +               this.items = params.items;
843 +               this.item = this.items[params.index];
844 +       }
845 +       else if ("item" in params) {
846 +               this.item = params.item;
847 +       }
848 +}
849 +
850 +UsclHelpCommandViewAssistant.prototype.setup = function () {
851 +       this.stageController = this.controller.stageController;
852 +       this.controller.get("title").innerHTML =
853 +               this.item.title;
854 +       this.controller.get("description").innerHTML =
855 +               this.item.description;
856 +
857 +       if (this.item.aka && this.item.aka.length) {
858 +               this.controller.get("aka").innerHTML =
859 +                       this.item.aka.map(function (s) {
860 +                               return "<kbd class='alias'>." + s + "</kbd>";
861 +                       }).joinAnd();
862 +       }
863 +       else {
864 +               this.controller.get("akaDiv").hide();
865 +       }
866 +
867 +       if ("usage" in this.item) {
868 +               if (typeof(this.item.usage) === "object" &&
869 +                   this.item.usage.constructor === Array) {
870 +                       this.controller.get("usage").innerHTML =
871 +                               "<br />" +
872 +                               this.item.usage.join("<br />");
873 +               }
874 +               else {
875 +                       this.controller.get("usage").innerHTML =
876 +                               "." + this.item.commandName + " " +
877 +                               this.item.usage;
878 +               }
879 +       }
880 +       else {
881 +               this.controller.get("usage").innerHTML = 
882 +                       "." + this.item.commandName;
883 +       }
884 +
885 +       if ("options" in this.item) {
886 +               var dl = this.controller.get("options");
887 +               this.item.options.forEach(function (option) {
888 +                       dl.innerHTML += "<dt><kbd>" + option.synopsis + "</kbd></dt>" +
889 +                               "<dd>" + option.description + "</dd>";
890 +               });
891 +       }
892 +       else {
893 +               this.controller.get("optionsDiv").hide();
894 +       }
895 +
896 +       if ("example" in this.item) {
897 +               if (typeof(this.item.example) === "object" &&
898 +                   this.item.example.constructor === Array) {
899 +                       this.controller.get("example-title").innerHTML =
900 +                               "Examples";
901 +                       this.controller.get("example").innerHTML =
902 +                               "<br />" +
903 +                               this.item.example.join("<br />");
904 +               }
905 +               else {
906 +                       this.controller.get("example").innerHTML =
907 +                               "." + this.item.commandName + " " +
908 +                               this.item.example;
909 +               }
910 +       }
911 +       else {
912 +               this.controller.get("exampleDiv").hide();
913 +       }
914 +
915 +       var body = this.stageController.document.getElementsByTagName("body");
916 +       body[0].addClassName("uscl-body");
917 +};
918 +
919 diff --git a/usr/lib/luna/system/luna-applauncher/app/controllers/uscl.js b/usr/lib/luna/system/luna-applauncher/app/controllers/uscl.js
920 new file mode 100644
921 index 0000000..7e78946
922 --- /dev/null
923 +++ b/usr/lib/luna/system/luna-applauncher/app/controllers/uscl.js
924 @@ -0,0 +1,1818 @@
925 +/*jslint browser: true, eqeqeq: true, undef: true, evil: true */
926 +/*global Mojo, Class, Ajax, Calculator, $H, PalmSystem, getopt */
927 +/******************************************************************************
928 +Lines above are for jslint, the JavaScript verifier.
929 +http://www.jslint.com/
930 +******************************************************************************/
931 +
932 +//-----------------------------------------------------------------------------
933 +// Additional String Methods
934 +//-----------------------------------------------------------------------------
935 +
936 +if (!String.prototype.trim) {
937 +       String.prototype.trim = function () {
938 +               return this.replace(/^\s+/, "").replace(/\s+$/, "");
939 +       };
940 +}
941 +if (!String.prototype.normalizeSpace) {
942 +       String.prototype.normalizeSpace = function () {
943 +               return this.trim().replace(/\s+/g, " ");
944 +       };
945 +}
946 +if (!String.prototype.toBoolean) {
947 +       String.prototype.toBoolean = function (errorType) {
948 +               var s = this.toLowerCase().normalizeSpace();
949 +               var i = parseInt(s, 10);
950 +               if (!isNaN(i)) {
951 +                       return (i !== 0);
952 +               }
953 +               switch (s) {
954 +               case "yes":
955 +               case "y":
956 +               case "true":
957 +               case "t":
958 +               case "on":
959 +               case "enable":
960 +               case "enabled":
961 +                       return true;
962 +               case "no":
963 +               case "n":
964 +               case "false":
965 +               case "f":
966 +               case "off":
967 +               case "disable":
968 +               case "disabled":
969 +                       return false;
970 +               default:
971 +                       if (errorType) {
972 +                               throw new errorType("Invalid argument");
973 +                       }
974 +                       else {
975 +                               return undefined;
976 +                       }
977 +               }
978 +       };
979 +}
980 +if (!String.prototype.format) {
981 +       // Implements Mojo.Log.xxx-ish formatting.  It's no sprintf, but it's
982 +       // good enough for now.
983 +       String.prototype.format = function () {
984 +               var args = Array.prototype.slice.call(arguments, 0);
985 +               var result = this.replace(/%[%jsoidf]/g, function (str) {
986 +                       switch (str) {
987 +                       case "%o":
988 +                               return Object.inspect(args.shift());
989 +                       case "%j":
990 +                               return Object.toJSON(args.shift());
991 +                       case "%%":
992 +                               return "%";
993 +                       }
994 +                       return args.shift();
995 +               });
996 +               return result;
997 +       };
998 +}
999 +if (!String.prototype.splitArguments) {
1000 +       String.prototype.splitArguments = function (rx) {
1001 +               if (!rx) {
1002 +                       rx = /\s+/;
1003 +               }
1004 +               if (/\S/.test(this)) {
1005 +                       return this.normalizeSpace().split(rx);
1006 +               }
1007 +               else {
1008 +                       return [];
1009 +               }
1010 +       };
1011 +}
1012 +if (!Array.prototype.forEach2) {
1013 +       // A version of Array#forEach that stops the loop if the
1014 +       // specified function returns false.  This special behavior is
1015 +       // influenced by jQuery's each() methods.  Based on MIT-licensed
1016 +       // code from: http://tinyurl.com/yh9nvwb
1017 +       // (https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/ForEach)
1018 +       Array.prototype.forEach2 = function(fun /*, thisp*/) {
1019 +               var len = this.length >>> 0;
1020 +               if (typeof fun !== "function") {
1021 +                       throw new TypeError();
1022 +               }
1023 +               var thisp = arguments[1];
1024 +               for (var i = 0; i < len; i++) {
1025 +                       if (i in this) {
1026 +                               var ret = fun.call(thisp, this[i], i, this);
1027 +                               if (ret === false) {
1028 +                                       return;
1029 +                               }
1030 +                       }
1031 +               }
1032 +       };              
1033 +}
1034 +if (!Array.prototype.joinAnd) {
1035 +       Array.prototype.joinAnd = function () {
1036 +               if (this.length <= 2) {
1037 +                       return this.join(" and ");
1038 +               }
1039 +               else {
1040 +                       return this.slice(0, this.length - 1).join(", ") +
1041 +                               ", and " + this[this.length - 1];
1042 +               }
1043 +       };
1044 +}
1045 +if (!Array.prototype.getopt) {
1046 +       Array.prototype.getopt = function (optstr, errorType) {
1047 +               try {
1048 +                       optstr = optstr.replace(/^:/, "");
1049 +                       var result = {};
1050 +                       var opt;
1051 +                       getopt.optreset = true; // reinitialize
1052 +                       getopt.opterr = true;   // reinitialize
1053 +                       getopt.optind = 0;      // reinitialize
1054 +                       while ((opt = getopt(this, optstr)) !== null) {
1055 +                               if (getopt.optarg === null) {
1056 +                                       result[opt] = true;
1057 +                               }
1058 +                               else {
1059 +                                       result[opt] = getopt.optarg;
1060 +                               }
1061 +                       }
1062 +                       this.splice(0, getopt.optind);
1063 +                       return result;
1064 +               }
1065 +               catch (e) {
1066 +                       throw new errorType(e.message);
1067 +               }
1068 +       };
1069 +}
1070 +
1071 +//-----------------------------------------------------------------------------
1072 +// A special exception class for errors.
1073 +//-----------------------------------------------------------------------------
1074 +
1075 +var USCLError = function (message) {
1076 +       Error.apply(this, arguments);
1077 +       this.message = message; // ugh, why on Earth do I have to do this?
1078 +};
1079 +USCLError.prototype = new Error();
1080 +USCLError.prototype.constructor = USCLError;
1081 +USCLError.prototype.name = "USCLError";
1082 +
1083 +//*****************************************************************************
1084 +// The good stuff lies here.
1085 +//*****************************************************************************
1086 +
1087 +var USCL = Class.create({
1088 +
1089 +       //---------------------------------------------------------------------
1090 +       // Initialization
1091 +       //---------------------------------------------------------------------
1092 +
1093 +       initialize: function () {
1094 +               this.inEmulator = /desktop/.test(PalmSystem.version);
1095 +               this.initBuiltinFlags();
1096 +               this.build();
1097 +               this.show = false;
1098 +               this.loadPreferences();
1099 +               this.hiddenFlags = {};
1100 +               this.updateFromLocalFile();
1101 +       },
1102 +
1103 +       loadPreferences: function () {
1104 +               this.db = new Mojo.Depot({ name: "uscl", replace: false },
1105 +                                        this.onLoadDatabase.bind(this),
1106 +                                        function () { /* don't care */ });
1107 +       },
1108 +       
1109 +       onLoadDatabase: function () {
1110 +               var that = this;
1111 +               this.db.get("show", 
1112 +                           function (o) { that.show = o; },
1113 +                           function () { that.show = false; });
1114 +               this.db.get("hiddenFlags", 
1115 +                           function (o) { that.hiddenFlags = o || {}; },
1116 +                           function () { that.hiddenFlags = {}; });
1117 +       },
1118 +
1119 +       setShow: function (flag) {
1120 +               this.show = flag;
1121 +               this.db.add("show", this.show, 
1122 +                           function () { /* don't care */ },
1123 +                           function () { /* don't care */ });
1124 +       },
1125 +
1126 +       saveHiddenFlags: function () {
1127 +               this.db.add("hiddenFlags", this.hiddenFlags,
1128 +                           function () { /* don't care */ },
1129 +                           function () { /* don't care */ });
1130 +       },
1131 +       
1132 +       build: function () {
1133 +               this.fixTitles();
1134 +               this.buildSupportingAppList();
1135 +       },
1136 +
1137 +       fixTitles: function () {
1138 +               var commandName;
1139 +               var entry;
1140 +               for (commandName in this.entries) {
1141 +                       if (this.entries.hasOwnProperty(commandName)) {
1142 +                               entry = this.entries[commandName];
1143 +                               if (typeof(entry) === "object") {
1144 +                                       if (!("title" in entry)) {
1145 +                                               entry.title = commandName;
1146 +                                       }
1147 +                                       entry.titleSort = entry.title.toLowerCase();
1148 +                               }
1149 +                       }
1150 +               }
1151 +       },
1152 +
1153 +       buildSupportingAppList: function () {
1154 +               this.apps = {};
1155 +               this.appListRequest = 
1156 +                       new Mojo.Service.Request("palm://com.palm.applicationManager", {
1157 +                               method: 'searchApps',
1158 +                               parameters: {'keyword': 'iGrokTheCommandLine'},
1159 +                               onSuccess: this.handleSupportingAppResults.bind(this, "iGrokTheCommandLine"),
1160 +                               onFailure: this.handleSupportingAppResults.bind(this, "iGrokTheCommandLine")
1161 +                       });
1162 +               this.appListRequest2 = 
1163 +                       new Mojo.Service.Request("palm://com.palm.applicationManager", {
1164 +                               method: 'searchApps',
1165 +                               parameters: {'keyword': 'iCanBeRefreshed'},
1166 +                               onSuccess: this.handleSupportingAppResults.bind(this, "iCanBeRefreshed"),
1167 +                               onFailure: this.handleSupportingAppResults.bind(this, "iCanBeRefreshed")
1168 +                       });
1169 +               this.appListRequest3 =
1170 +                       new Mojo.Service.Request("palm://com.palm.applicationManager", {
1171 +                               method: 'listApps',
1172 +                               parameters: {},
1173 +                               onSuccess: this.handleInstalledApp.bind(this),
1174 +                               onFailure: this.handleInstalledApp.bind(this)
1175 +                       });
1176 +       },
1177 +
1178 +       handleInstalledApp: function (response) {
1179 +               var that = this;
1180 +               var apps = response.apps;
1181 +               if (!apps) { return; }
1182 +               this.appInstalled = {};
1183 +               apps.forEach(function (app) {
1184 +                       that.appInstalled[app.id] = true;
1185 +               });
1186 +       },
1187 +
1188 +       handleSupportingAppResults: function (keyword, response) {
1189 +               var that = this;
1190 +               var apps = response.apps;
1191 +               if (!apps) { return; }
1192 +               this.apps[keyword] = {};
1193 +               apps.forEach(function (app) {
1194 +                       var id = app.id;
1195 +                       var launchPoint = app.launchPoint;
1196 +                       that.apps[keyword][launchPoint] = true;
1197 +               });
1198 +       },
1199 +
1200 +       //---------------------------------------------------------------------
1201 +       // hidden flags
1202 +       //---------------------------------------------------------------------
1203 +
1204 +       clearAllHiddenFlags: function () {
1205 +               this.hiddenFlags = {};
1206 +               this.saveHiddenFlags();
1207 +       },
1208 +       
1209 +       setHiddenFlags: function (a) {
1210 +               var warnings = [];
1211 +               a.forEach(function (command) {
1212 +                       command = command.replace(/^\./, "").toLowerCase();
1213 +                       var finalCommand = this.unalias(command);
1214 +                       if (finalCommand) {
1215 +                               this.hiddenFlags[finalCommand] = true;
1216 +                       }
1217 +                       else {
1218 +                               warnings.push("." + command);
1219 +                       }
1220 +               }, this);
1221 +               this.saveHiddenFlags();
1222 +               return warnings;
1223 +       },
1224 +
1225 +       clearHiddenFlags: function (a) {
1226 +               var warnings = [];
1227 +               a.forEach(function (command) {
1228 +                       command = command.replace(/^\./, "").toLowerCase();
1229 +                       var finalCommand = this.unalias(command);
1230 +                       if (finalCommand) {
1231 +                               delete this.hiddenFlags[finalCommand];
1232 +                       }
1233 +                       else {
1234 +                               warnings.push("." + command);
1235 +                       }
1236 +               }, this);
1237 +               this.saveHiddenFlags();
1238 +               return warnings;
1239 +       },
1240 +
1241 +       //---------------------------------------------------------------------
1242 +       // .quickNote functionality
1243 +       //---------------------------------------------------------------------
1244 +
1245 +       noteColors: ["pink", "yellow", "green", "blue"],
1246 +
1247 +       randomNoteColor: function () {
1248 +               return this.noteColors[Math.floor(Math.random() * this.noteColors.length)];
1249 +       },
1250 +
1251 +       newNoteTimestamp: function () {
1252 +               return Mojo.Format.formatDate(new Date(), "short").replace(/ /, "\n");
1253 +       },
1254 +
1255 +       checkForAppRunning: function (appid, onRunning, onNotRunning) {
1256 +               var checkIfRunning = function (event) {
1257 +                       var isRunning = false;
1258 +                       event.documents.forEach2(function (d) {
1259 +                               var a = d.appId.split(/\s+/);
1260 +                               if (a && a.length && a[0] === appid) {
1261 +                                       isRunning = true;
1262 +                                       return false;
1263 +                               }
1264 +                       });
1265 +                       if (isRunning) {
1266 +                               if (onRunning) {
1267 +                                       onRunning();
1268 +                               }
1269 +                       }
1270 +                       else {
1271 +                               if (onNotRunning) {
1272 +                                       onNotRunning();
1273 +                               }
1274 +                       }
1275 +               };
1276 +               var request = new Mojo.Service.Request("palm://com.palm.lunastats", {
1277 +                       method: "getStats",
1278 +                       parameters: {},
1279 +                       onSuccess: checkIfRunning,
1280 +                       onFailure: function (event) {
1281 +                               if (event.documents) {
1282 +                                       checkIfRunning(event);
1283 +                               }
1284 +                       }
1285 +               });
1286 +       },
1287 +       
1288 +       quickNoteWarning: "Because you are running Notes and " + 
1289 +               "do not have the latest version " + 
1290 +               "of the USCL Notes Patch installed, " + 
1291 +               "please close and reopen Notes.  " + 
1292 +               "Your quicknote has been entered, " + 
1293 +               "but <i>may</i> not be shown until " + 
1294 +               "you close and reopen Notes.",
1295 +
1296 +       quickNoteCommand: function (text) {
1297 +               var that = this;
1298 +               var fun = function () {
1299 +                       var globalSearch = this;
1300 +                       var onRunning = function () {
1301 +                               if (that.apps &&
1302 +                                   that.apps.iCanBeRefreshed &&
1303 +                                   that.apps.iCanBeRefreshed["com.palm.app.notes_default"]) {
1304 +                                       globalSearch.controller.serviceRequest(
1305 +                                               "palm://com.palm.applicationManager", {
1306 +                                                       method: "launch",
1307 +                                                       parameters: {
1308 +                                                               id: "com.palm.app.notes",
1309 +                                                               params: { refresh: true }
1310 +                                                       }
1311 +                                               }
1312 +                                       );
1313 +                                       globalSearch.deactivate();
1314 +                               }
1315 +                               else {
1316 +                                       globalSearch.deactivateWithWarning(that.quickNoteWarning, true);
1317 +                               }
1318 +                       };
1319 +                       var onNotRunning = function () {
1320 +                               globalSearch.deactivate();
1321 +                       };
1322 +                       var noteText = text + "\n\n" + that.newNoteTimestamp() + "\n";
1323 +                       var request = new Mojo.Service.Request("palm://com.palm.notes", {
1324 +                               method: "saveNote",
1325 +                               parameters: {
1326 +                                       text: noteText,
1327 +                                       color: that.randomNoteColor()
1328 +                               },
1329 +                               onComplete: function () {
1330 +                                       that.checkForAppRunning("com.palm.app.notes",
1331 +                                                               onRunning,
1332 +                                                               onNotRunning);
1333 +                               }
1334 +                       });
1335 +               };
1336 +               fun.noDeactivate = true;
1337 +               return fun;
1338 +       },
1339 +
1340 +       //---------------------------------------------------------------------
1341 +       // .task, .tasklist
1342 +       //---------------------------------------------------------------------
1343 +
1344 +       createTaskList: function (name, callback) {
1345 +               var that = this;
1346 +               var request = new Mojo.Service.Request("palm://com.palm.tasks", {
1347 +                       method: "saveTaskList",
1348 +                       parameters: {
1349 +                               name: name
1350 +                       },
1351 +                       onComplete: function (response) {
1352 +                               Mojo.Log.info("NEW TASK LIST ID: %j", response.id);
1353 +                               if (callback) {
1354 +                                       callback(response.id);
1355 +                               }
1356 +                       }
1357 +               });
1358 +       },
1359 +
1360 +       getOrCreateTaskList: function (name, callback) {
1361 +               var that = this;
1362 +               var request = new Mojo.Service.Request("palm://com.palm.tasks", {
1363 +                       method: "getTaskLists",
1364 +                       parameters: { },
1365 +                       onComplete: function (response) {
1366 +                               var list = response.list;
1367 +                               for (var i = 0; i < list.length; ++i) {
1368 +                                       Mojo.Log.info("GETTASKLISTS [%j]: %j", i, list[i]);
1369 +                                       if (list[i].name === name) {
1370 +                                               Mojo.Log.info("EXISTING TASK LIST ID: %j", list[i].id);
1371 +                                               if (callback) {
1372 +                                                       callback(list[i].id);
1373 +                                               }
1374 +                                               return;
1375 +                                       }
1376 +                               }
1377 +                               that.createTaskList(name, callback);
1378 +                       }
1379 +               });
1380 +       },
1381 +
1382 +       createTask: function (taskListId, subject, callback) {
1383 +               var request = new Mojo.Service.Request("palm://com.palm.tasks", {
1384 +                       method: "saveTask",
1385 +                       parameters: {
1386 +                               subject: subject,
1387 +                               taskListId: taskListId
1388 +                       },
1389 +                       onComplete: function (response) {
1390 +                               Mojo.Log.info("NEW TASK: taskListId = %j, id = %j, subject = %j",
1391 +                                             taskListId, response.id, subject);
1392 +                               if (callback) {
1393 +                                       callback(taskListId, response.id);
1394 +                               }
1395 +                       }
1396 +               });
1397 +       },
1398 +       
1399 +       createTasks: function (taskListId, subjects,
1400 +                              callback, callback_each) {
1401 +               var that = this;
1402 +               var len = subjects.length;
1403 +               var remaining = subjects.length;
1404 +               var taskIds = [];
1405 +               Mojo.Log.info("createTasks: remaining === %d", remaining);
1406 +               for (var i = 0; i < len; i++) {
1407 +                       (function (i) {
1408 +                               that.createTask(taskListId, subjects[i],
1409 +                                               function (taskListId, taskId) {
1410 +                                                       taskIds[i] = taskId;
1411 +                                                       Mojo.Log.info("taskIds[%d] === %d; taskIds.length = %d", i, taskId, taskIds.length);
1412 +                                                       if (callback_each) {
1413 +                                                               callback_each(taskListId, taskId);
1414 +                                                       }
1415 +                                                       remaining--;
1416 +                                                       Mojo.Log.info("createTasks: after decrement, remaining === %d", remaining);
1417 +                                                       if (remaining === 0) {
1418 +                                                               Mojo.Log.info("=== 0");
1419 +                                                               if (callback) {
1420 +                                                                       Mojo.Log.info("there's a callback");
1421 +                                                                       callback(taskListId, taskIds);
1422 +                                                               }
1423 +                                                       }
1424 +                                               });
1425 +                       })(i);
1426 +               }
1427 +       },
1428 +
1429 +       quickTaskWarning: "Because you are running Tasks and " +
1430 +               "do not have the USCL Tasks Patch " +
1431 +               "installed, please close and reopen " +
1432 +               "Tasks.  Your tasks have been added, " +
1433 +               "but <i>may</i> not be shown until " + 
1434 +               "you close and reopen Tasks.",
1435 +       
1436 +       taskWarning: "Your tasks have been added, " +
1437 +               "but because you do not have the USCL Tasks Patch installed, " +
1438 +               "I cannot launch Tasks and take you to the task list.",
1439 +
1440 +       taskCommand: function (options, args) {
1441 +               var that = this;
1442 +               var fun = function () {
1443 +                       var globalSearch = this;
1444 +                       var taskListName = (options && options.taskListName) ? 
1445 +                               options.taskListName : "Unfiled";
1446 +                       var onRunning = function (taskListId, taskIds) {
1447 +                               var params = { details: { show: {
1448 +                                       taskListId: taskListId, 
1449 +                                       taskId: taskIds[taskIds.length - 1]
1450 +                               } } };
1451 +                               if (true || that.appWorksWithUSCL("com.palm.app.tasks")) {
1452 +                                       if (options && options.launchTasks) {
1453 +                                               globalSearch.controller.serviceRequest(
1454 +                                                       "palm://com.palm.applicationManager", {
1455 +                                                               method: "launch",
1456 +                                                               parameters: {
1457 +                                                                       id: "com.palm.app.tasks",
1458 +                                                                       params: params
1459 +                                                               }
1460 +                                                       }
1461 +                                               );
1462 +                                       }
1463 +                                       else {
1464 +                                               globalSearch.controller.serviceRequest(
1465 +                                                       "palm://com.palm.applicationManager", {
1466 +                                                               method: "launch",
1467 +                                                               parameters: {
1468 +                                                                       id: "com.palm.app.tasks",
1469 +                                                                       params: params
1470 +                                                               }
1471 +                                                       }
1472 +                                               );
1473 +                                       }
1474 +                                       globalSearch.deactivate();
1475 +                               }
1476 +                               else {
1477 +                                       globalSearch.deactivateWithWarning(that.quickTaskWarning, true);
1478 +                               }
1479 +                       };
1480 +                       var onNotRunning = function (taskListId, taskIds) {
1481 +                               var params = { details: { show: {
1482 +                                       taskListId: taskListId, 
1483 +                                       taskId: taskIds[taskIds.length - 1]
1484 +                               } } };
1485 +                               if (options && options.launchTasks) {
1486 +                                       if (true || that.appWorksWithUSCL("com.palm.app.tasks")) {
1487 +                                               globalSearch.controller.serviceRequest(
1488 +                                                       "palm://com.palm.applicationManager", {
1489 +                                                               method: "launch",
1490 +                                                               parameters: {
1491 +                                                                       id: "com.palm.app.tasks",
1492 +                                                                       params: params
1493 +                                                               }
1494 +                                                       }
1495 +                                               );
1496 +                                               globalSearch.deactivate();
1497 +                                       }
1498 +                                       else {
1499 +                                               globalSearch.deactivateWithWarning(that.taskWarning, true);
1500 +                                       }
1501 +                               }
1502 +                               globalSearch.deactivate();
1503 +                       };
1504 +                       var onComplete = function (taskListId, taskIds) {
1505 +                               that.checkForAppRunning("com.palm.app.tasks",
1506 +                                                       onRunning.curry(taskListId, taskIds),
1507 +                                                       onNotRunning.curry(taskListId, taskIds));
1508 +                       };
1509 +                       that.getOrCreateTaskList(taskListName, 
1510 +                                                function (taskListId) {
1511 +                                                        that.createTasks(taskListId, args,
1512 +                                                                         onComplete);
1513 +                                                });
1514 +               };
1515 +               fun.noDeactivate = true;
1516 +               return fun;
1517 +       },
1518 +               
1519 +       //---------------------------------------------------------------------
1520 +       // .calc
1521 +       //---------------------------------------------------------------------
1522 +
1523 +       calcCommand: function (s) {
1524 +               // Yes, I'm aware that eval is usually evil.  The user
1525 +               // chooses to use 'calc' at their own risk.  I'm only
1526 +               // using it here because I'm too lazy at the moment to
1527 +               // write an infix expression calculator.
1528 +               if (!this.calculator) {
1529 +                       this.calculator = new Calculator();
1530 +               }
1531 +               var result;
1532 +               try {
1533 +                       result = this.calculator.calculate(s);
1534 +               }
1535 +               catch (e) {
1536 +                       return {
1537 +                               title: "Error",
1538 +                               message: e
1539 +                       };
1540 +               }
1541 +               return {
1542 +                       title: "Calculator",
1543 +                       message: s + " \u2192 " + Object.toJSON(result)
1544 +               };
1545 +       },
1546 +
1547 +       //---------------------------------------------------------------------
1548 +       // .restart, .rescan
1549 +       //---------------------------------------------------------------------
1550 +
1551 +       restartCommand: function (arg) {
1552 +               var r;
1553 +               switch (arg) {
1554 +               case "luna":
1555 +                       try {
1556 +                               r = new Mojo.Service.Request(
1557 +                                       'luna://org.webosinternals.ipkgservice',
1558 +                                       { method: 'restartLuna' }
1559 +                               );
1560 +                       }
1561 +                       catch (e1) {
1562 +                               throw new USCLError('Error Restarting Luna: ' + e1.message);
1563 +                       }
1564 +                       break;
1565 +               case "java":
1566 +                       try {
1567 +                               r = new Mojo.Service.Request(
1568 +                                       'palm://org.webosinternals.ipkgservice',
1569 +                                       { method: 'restartJava' }
1570 +                               );
1571 +                       }
1572 +                       catch (e2) {
1573 +                               throw new USCLError('Error restarting Java: ' + e2.message);
1574 +                       }
1575 +                       break;
1576 +               }
1577 +       },
1578 +
1579 +       rescanCommand: function () {
1580 +               try {
1581 +                       var r = new Mojo.Service.Request(
1582 +                               'palm://org.webosinternals.ipkgservice',
1583 +                               { method: 'rescan' }
1584 +                       );
1585 +               }
1586 +               catch (e) {
1587 +                       throw new USCLError('Error Rescanning: ' + e.message);
1588 +               }
1589 +       },
1590 +
1591 +       //---------------------------------------------------------------------
1592 +       // .show; .hide
1593 +       //---------------------------------------------------------------------
1594 +
1595 +       showCommand: function (args) {
1596 +               if (args && args.length === 1 && args[0] === "all") {
1597 +                       this.clearAllHiddenFlags();
1598 +                       return undefined;
1599 +               }
1600 +               else if (args && args.length) {
1601 +                       var warnings = this.clearHiddenFlags(args);
1602 +                       if (warnings && warnings.length) {
1603 +                               return {
1604 +                                       title: "Warning",
1605 +                                       message: "The following commands do not exist: " + warnings.join(", ")
1606 +                               };
1607 +                       }
1608 +                       else {
1609 +                               return undefined;
1610 +                       }
1611 +               }
1612 +               else {
1613 +                       this.setShow(true);
1614 +                       return {
1615 +                               title: "Show Additional Searches",
1616 +                               message: "Additional searches will now appear in Universal Search."
1617 +                       };
1618 +               }
1619 +       },
1620 +
1621 +       hideCommand: function (args) {
1622 +               if (args && args.length) {
1623 +                       var warnings = this.setHiddenFlags(args);
1624 +                       if (warnings && warnings.length) {
1625 +                               return {
1626 +                                       title: "Warning",
1627 +                                       message: "The following commands do not exist: " + warnings.join(", ")
1628 +                               };
1629 +                       }
1630 +                       else {
1631 +                               return undefined;
1632 +                       }
1633 +               }
1634 +               else {
1635 +                       this.setShow(false);
1636 +                       return {
1637 +                               title: "Hide Additional Searches",
1638 +                               message: "Additional searches will no longer appear in Universal Search."
1639 +                       };
1640 +               }
1641 +       },
1642 +
1643 +       //---------------------------------------------------------------------
1644 +       // .update
1645 +       //---------------------------------------------------------------------
1646 +
1647 +       updateCommand: function () {
1648 +               var fun = function () {
1649 +                       var globalSearch = this;
1650 +                       this.uscl.updateFromLocalFile({
1651 +                               onFailure: function (response) {
1652 +                                       if (response.status === 404) {
1653 +                                               globalSearch.deactivateWithError("uscl.json not found.");
1654 +                                       }
1655 +                                       else {
1656 +                                               globalSearch.deactivateWithError("Unexpected error updating from uscl.json.");
1657 +                                       }
1658 +                               },
1659 +                               onParseFailure: function (response) {
1660 +                                       globalSearch.deactivateWithError("Syntax error in uscl.json.");
1661 +                               },
1662 +                               onParseSuccess: function (response) {
1663 +                                       globalSearch.deactivate();
1664 +                               }
1665 +                       });
1666 +               };
1667 +               fun.noDeactivate = true;
1668 +               return fun;
1669 +       },
1670 +
1671 +       //---------------------------------------------------------------------
1672 +       // Builtin Commands
1673 +       //---------------------------------------------------------------------
1674 +
1675 +       categories: [
1676 +               // not in use yet
1677 +               { name: "search", title: "Search" },
1678 +               { name: "reference", title: "Reference" },
1679 +               { name: "utilities", title: "Utilities" },
1680 +               { name: "location", title: "Location" },
1681 +               { name: "system", title: "System" }
1682 +       ],
1683 +
1684 +       entries: {
1685 +               "calc": {       // BUILTIN
1686 +                       title: "Calculator",
1687 +                       usage: "<var>expression</var>",
1688 +                       example: [
1689 +                               ".calc (37 * 1.8) + 32",
1690 +                               ".calc sin(PI / 2)",
1691 +                               ".calc Math.sin(Math.PI / 2)"
1692 +                       ],
1693 +                       description: ("Perform a calculation.  " + 
1694 +                                     "Can also evaluate other JavaScript expressions.  " +
1695 +                                     "Use at your own risk.  " +
1696 +                                     "Functions and constants in the core Math object " +
1697 +                                     "can be used with or without the 'Math.' prefix.  " +
1698 +                                     "More complex calculations (such as unit conversions) " +
1699 +                                     "can be sent to Google (see .google) " +
1700 +                                     "or Wolfram Alpha (see .wolfram)."),
1701 +                       method: function (s) {
1702 +                               return this.calcCommand(s);
1703 +                       },
1704 +                       noArguments: {
1705 +                               appId: "com.palm.app.calculator"
1706 +                       }
1707 +               },
1708 +               "c": "calc",
1709 +               "eval": "calc",
1710 +
1711 +               "imdb": {       // BASICS
1712 +                       title: "IMDB.com",
1713 +                       usage: "<var>query</var>",
1714 +                       example: "the big lebowski",
1715 +                       description: ("Search movies, TV shows, actors, directors, " + 
1716 +                                     "producers, and more on IMDB.com."),
1717 +                       url: "http://www.imdb.com/find?s=all&q=",
1718 +                       noArguments: {
1719 +                               url: "http://www.imdb.com/"
1720 +                       }
1721 +               },
1722 +               "i": "imdb", // keytoss alias
1723 +
1724 +               "dict": {       // BASICS
1725 +                       title: "Dictionary.com",
1726 +                       usage: "<var>word</var>",
1727 +                       example: "ebullient",
1728 +                       description: "Find a word on Dictionary.com.",
1729 +                       url: "http://m.reference.com/d/search.html?q=",
1730 +                       noArguments: {
1731 +                               url: "http://m.reference.com/d/"
1732 +                       }
1733 +               },
1734 +               "d": "dict",
1735 +
1736 +               "thes": {       // BASICS
1737 +                       title: "Thesaurus.com",
1738 +                       usage: "<var>word</var>",
1739 +                       example: "ebullient",
1740 +                       description: "Find a word on Thesaurus.com.",
1741 +                       url: "http://m.reference.com/t/search.html?q=",
1742 +                       noArguments: {
1743 +                               url: "http://m.reference.com/t/"
1744 +                       }
1745 +               },
1746 +               "th": "thes",
1747 +
1748 +               "ebay": {       // BASICS
1749 +                       title: "eBay",
1750 +                       usage: "<var>item</var>",
1751 +                       example: "mp3 player",
1752 +                       description: "Find something on eBay.com.",
1753 +                       url: "http://m.ebay.com/Pages/SearchResults.aspx?emvAD=320x320&emvcc=0&sv=",
1754 +                       noArguments: {
1755 +                               url: "http://m.ebay.com/"
1756 +                       }
1757 +               },
1758 +               "e": "ebay", // keytoss alias
1759 +
1760 +               "yahoo": {      // BASICS
1761 +                       title: "Yahoo!",
1762 +                       usage: "<var>keywords</var>",
1763 +                       example: "laptop reviews",
1764 +                       description: "Search Yahoo!",
1765 +                       url: "http://m.yahoo.com/w/search/oneSearch?p=",
1766 +                       noArguments: {
1767 +                               url: "http://m.yahoo.com/search"
1768 +                       }
1769 +               },
1770 +               "y": "yahoo",
1771 +
1772 +               "gis": {        // BASICS
1773 +                       title: "Google Images",
1774 +                       usage: "<var>keywords</var>",
1775 +                       example: "pirate hat",
1776 +                       description: "Search Google Images.",
1777 +                       url: "http://www.google.com/m/search?client=ms-palm-webOS&channel=iss&site=images&q=",
1778 +                       noArguments: {
1779 +                               url: "http://images.google.com/m/"
1780 +                       }
1781 +               },
1782 +               "gi": "gis", // keytoss alias
1783 +               
1784 +               "shop": {       // BASICS
1785 +                       title: "Google Product Search",
1786 +                       usage: "<var>keywords</var>",
1787 +                       example: "palm pre",
1788 +                       description: "Search for prices on Google Products.",
1789 +                       url: "http://www.google.com/m/search?client=ms-palm-webOS&channel=iss&site=products&q=",
1790 +                       noArguments: {
1791 +                               url: "http://products.google.com/m/"
1792 +                       }
1793 +               },
1794 +               "froogle": "shop",
1795 +               "gp": "shop", // keytoss alias
1796 +
1797 +               "news": {       // BASICS
1798 +                       title: "Google News Search",
1799 +                       usage: "<var>keywords</var>",
1800 +                       example: "obama",
1801 +                       description: "Search Google News.",
1802 +                       url: "http://www.google.com/m/search?client=ms-palm-webOS&channel=iss&site=news&q=",
1803 +                       noArguments: {
1804 +                               url: "http://news.google.com/m/"
1805 +                       }
1806 +               },
1807 +               "gn": "news", // keytoss alias
1808 +               
1809 +               "google": {     // BUILTIN FOR COMPLETENESS
1810 +                       excludeFromUniversalSearch: true,
1811 +                       title: "Google",
1812 +                       usage: "<var>keywords</var>",
1813 +                       example: "hummus recipe",
1814 +                       description: "Search Google.",
1815 +                       url: "www.google.com/m/search?client=ms-palm-webOS&channel=iss&q=",
1816 +                       noArguments: {
1817 +                               url: "http://www.google.com/m/"
1818 +                       }
1819 +               },
1820 +               "g": "google",
1821 +
1822 +               "amazon": {     // BASICS
1823 +                       title: "Amazon",
1824 +                       usage: "<var>keywords</var>",
1825 +                       example: "i am america and so can you",
1826 +                       description: "Search for products on Amazon.com.",
1827 +                       url: "http://www.amazon.com/gp/aw/s/ref=is_box_?k=",
1828 +                       noArguments: {
1829 +                               url: "http://www.amazon.com/gp/aw"
1830 +                       }
1831 +               },
1832 +               "az": "amazon",
1833 +               "am": "amazon", // keytoss alias
1834 +
1835 +               "wikipedia": {  // BUILTIN FOR COMPLETENESS
1836 +                       excludeFromUniversalSearch: true,
1837 +                       title: "Wikipedia",
1838 +                       usage: "<var>keywords</var>",
1839 +                       example: "isaac newton",
1840 +                       description: "Search Wikipedia, the online encyclopedia that anyone can edit.",
1841 +                       url: "http://en.m.wikipedia.org/wiki/Special:Search?search=",
1842 +                       noArguments: {
1843 +                               url: "http://en.m.wikipedia.org/"
1844 +                       }
1845 +               },
1846 +               "wiki": "wikipedia",
1847 +               "w": "wikipedia",
1848 +
1849 +               "wolfram": {    // BASICS for now
1850 +                       title: "Wolfram Alpha",
1851 +                       usage: "<var>keywords</var>",
1852 +                       example: [
1853 +                               ".wa June 23, 1988",
1854 +                               ".wa new york",
1855 +                               ".wa IBM Apple",
1856 +                               ".wa $250 + 15%",
1857 +                               ".wa x**2 sin(x)"
1858 +                       ],
1859 +                       description: "Query something on Wolfram Alpha.  Dates, cities, stocks, and equations.  Go nuts!",
1860 +                       url: "http://www.wolframalpha.com/input/?i=",
1861 +                       noArguments: {
1862 +                               url: "http://www.wolframalpha.com/"
1863 +                       }
1864 +               },
1865 +               "wa": "wolfram",
1866 +       
1867 +               "youtube": {
1868 +                       "title": "YouTube",
1869 +                       "usage": "<var>keywords</var>",
1870 +                       "example": "petra haden the who",
1871 +                       "description": "Find videos on YouTube.",
1872 +                       "url": "http://m.youtube.com/results?is_adult=True&hl=en&gl=US&client=mv-google&q=",
1873 +                       "noArguments": {
1874 +                               "url": "http://m.youtbue.com/"
1875 +                       }
1876 +               },
1877 +               "yt": "youtube",
1878 +
1879 +               "keytoss": {    // BUILTIN
1880 +                       title: "KeyToss",
1881 +                       usage: [
1882 +                               ".keytoss <var>command</var> <var>keywords</var>",
1883 +                               ".kt <var>command</var> <var>keywords</var>",
1884 +                               "..<var>command</var> <var>keywords</var>"
1885 +                       ],
1886 +                       example: [
1887 +                               ".keytoss af wtf",
1888 +                               ".kt af omg",
1889 +                               "..af bbq"
1890 +                       ],
1891 +                       description: ("Perform a search via the KeyToss mobile portal.<br />" + 
1892 +                                     "You do not need to type the at sign (<kbd>@</kbd>) before the <i>command</i>.<br />" + 
1893 +                                     "Use <nobr><kbd>.keywords|.kt kt list</kbd></nobr> or <nobr><kbd>..kt list</kbd></nobr> " + 
1894 +                                     "to get a list of commands to pass to KeyToss."),
1895 +                       preprocess: function (s) {
1896 +                               return s.replace(/^\s*@\s*/, "");
1897 +                       },
1898 +                       url: "http://pre.keytoss.com/parse.php5?pv=131&term=%40",
1899 +                       noArguments: {
1900 +                               url: "http://pre.keytoss.com/"
1901 +                       }
1902 +               },
1903 +               "kt": "keytoss",
1904 +
1905 +               "note": {       // BUILTIN
1906 +                       title: "New Note",
1907 +                       usage: "<var>text</var>",
1908 +                       example: "I like pie.",
1909 +                       description: "Quickly create a new note.",
1910 +                       appId: "com.palm.app.notes",
1911 +                       param: "newNoteText",
1912 +                       noArguments: {
1913 +                               appId: "com.palm.app.notes"
1914 +                       }
1915 +               },
1916 +               "memo": "note",
1917 +               "m": "note",
1918 +               "n": "note",
1919 +
1920 +               "quicknote": {  // BUILTIN
1921 +                       title: "New Note (without launch)",
1922 +                       usage: "<var>text</var>",
1923 +                       example: "I like pie.",
1924 +                       description: "Quickly create a new note, without launching the Notes application.",
1925 +                       method: function (text) {
1926 +                               return this.quickNoteCommand(text);
1927 +                       }
1928 +               },
1929 +               "quickmemo": "quicknote",
1930 +               "qmemo": "quicknote",
1931 +               "qnote": "quicknote",
1932 +               "qm": "quicknote",
1933 +               "qn": "quicknote",
1934 +
1935 +               "quickevent": {
1936 +                       title: "Quick Event",
1937 +                       usage: [ "<small>" + 
1938 +                                ".qe <var>evt</var> <var>time</var>-[<var>time</var>] [<var>date</var>] [@|in|at <var>loc</var>]<br />" +
1939 +                                ".qe <var>evt</var> ad- [<var>date</var>] [@|in|at <var>loc</var>]" + 
1940 +                                "</small>" ],
1941 +                       example: [
1942 +                               ".qe Lunch 11am-12:15pm next wed at Hotel Astoria",
1943 +                               ".qe Haircut 1500-1600 1/30 at Fred's",
1944 +                               ".qe Valentine's Day ad- 2/14"
1945 +                       ],
1946 +                       description: "If the Quick Event app (available through Preware) is installed, use it to add an event to your calendar.  " + 
1947 +                               "<kbd>ad-</kbd> indicates an all-day event.",
1948 +                       method: function (arg) {
1949 +                               return this.launchQuickEvent(arg);
1950 +                       }
1951 +               },
1952 +               "qe": "quickevent",
1953 +
1954 +               "task": {
1955 +                       title: "New Task (launches Tasks app)",
1956 +                       usage: "[<var>option</var> ...] <var>task</var>; ...",
1957 +                       example: [
1958 +                               ".task finish project foo; present proposal",
1959 +                               ".task -s , -c Groceries skim milk, juice"
1960 +                       ],
1961 +                       description: "Create one or more new tasks, and launch the Tasks application.",
1962 +                       options: [
1963 +                               { synopsis: "-c <var>category</var>",
1964 +                                 description: "tasks are added to the specified category instead of &lsquo;Unfiled&rsquo;" },
1965 +                               { synopsis: "-s <var>char</var>",
1966 +                                 description: "tasks are separated by the specified character (and any optional whitespace before and/or after) instead of the semicolon"
1967 +                               },
1968 +                               { synopsis: "-s space",
1969 +                                 description: "tasks are separated by whitespace"
1970 +                               },
1971 +                               { synopsis: "-s /<var>regex</var>/",
1972 +                                 description: "tasks are separated by the specified regular expression (you must supply the whitespace yourself)"
1973 +                               },
1974 +                               { synopsis: "-q",
1975 +                                 description: "do not launch the Tasks application unless it&lsquo;s already launched"
1976 +                               }
1977 +                       ],
1978 +                       method: function (arg) {
1979 +                               var args = arg.splitArguments();
1980 +                               var options = args.getopt("c:s:q", USCLError);
1981 +                               if ("c" in options) {
1982 +                                       options.taskListName = options.c;
1983 +                                       delete options.c;
1984 +                               }
1985 +                               if ("q" in options) {
1986 +                                       options.launchTasks = false;
1987 +                                       delete options.q;
1988 +                               }
1989 +                               else {
1990 +                                       options.launchTasks = true;
1991 +                               }
1992 +                               arg = args.join(" ");
1993 +
1994 +                               var rx;
1995 +                               if ("s" in options) {
1996 +                                       if (options.s === "\\" ||
1997 +                                           options.s === "(" || options.s === ")" ||
1998 +                                           options.s === "[" || options.s === "]" ||
1999 +                                           options.s === "{" || options.s === "}" ||
2000 +                                           options.s === "." ||
2001 +                                           options.s === "|" ||
2002 +                                           options.s === "^" || options.s === "$" ||
2003 +                                           options.s === "+" || options.s === "?" ||
2004 +                                           options.s === "*") {
2005 +                                               rx = new RegExp("\\s*\\" + options.s + "\\s*");
2006 +                                       }
2007 +                                       else if (options.s.length === 1) {
2008 +                                               rx = new RegExp("\\s*" + options.s + "\\s*");
2009 +                                       }
2010 +                                       else if (options.s === "space") {
2011 +                                               rx = /\s+/;
2012 +                                       }
2013 +                                       else if (/^\/(.*)\/$/) {
2014 +                                               rx = RegExp.$1;
2015 +                                               rx = new RegExp(rx);
2016 +                                       }
2017 +                                       else {
2018 +                                               throw new USCLError("-s: invalid argument");
2019 +                                       }
2020 +                               }
2021 +                               else {
2022 +                                       rx = /\s*;\s*/;
2023 +                               }
2024 +                               args = arg.splitArguments(rx);
2025 +                               Mojo.Log.info("  re-split args: %j", args);
2026 +                               return this.taskCommand(options, args);
2027 +                       }
2028 +               },
2029 +               "todo": "task",
2030 +               "t": "task",
2031 +
2032 +               "quicktask": {
2033 +                       title: "New Task (no launch)",
2034 +                       usage: "<var>task</var>; ...",
2035 +                       example: "finish project foo; present proposal",
2036 +                       description: "Create one or more new tasks without launching the Tasks application.  If Tasks is already launched, jump to it.  Accepts the same command-line options as <kbd>.task</kbd>.",
2037 +                       aliasedTo: ".task -q %s"
2038 +               },
2039 +               "quicktodo": "quicktask",
2040 +               "qt": "quicktask",
2041 +