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