1 var comb = exports, date;
  2 
  3 comb.isString = function(obj) {
  4     var undef;
  5     return obj != undef && (typeof obj == "string" || obj instanceof String);
  6 };
  7 
  8 var FORMAT_REGEX = /%((?:-?\+?.?\d*)?|(?:\[[^\[|\]]*\]))?([sjdDZ])/g;
  9 var INTERP_REGEX = /{(?:\[([^\[|\]]*)\])?(\w+)}/g;
 10 var STR_FORMAT = /(-?)(\+?)([A-Z|a-z|\W]?)([1-9][0-9]*)?$/;
 11 var OBJECT_FORMAT = /([1-9][0-9]*)$/g;
 12 
 13 var formatString = function(string, format) {
 14     var match = format.match(STR_FORMAT), ret = string, cString = comb.string;
 15     if (match) {
 16         var isLeftJustified = match[1], padChar = match[3], width = match[4];
 17         if (width) {
 18             width = parseInt(width);
 19             if (ret.length < width) {
 20                 ret = cString.pad(ret, width, padChar, isLeftJustified);
 21             } else {
 22                 ret = cString.truncate(ret, width);
 23             }
 24         }
 25     }
 26     return ret;
 27 };
 28 
 29 var formatNumber = function(number, format) {
 30     if (typeof number == "number") {
 31         var cString = comb.string, ret = "" + number;
 32         var match = format.match(STR_FORMAT);
 33         if (match) {
 34             var isLeftJustified = match[1], signed = match[2], padChar = match[3], width = match[4];
 35             if (signed) {
 36                 ret = (number > 0 ? "+" : "") + ret;
 37             }
 38             if (width) {
 39                 width = parseInt(width);
 40                 if (ret.length < width) {
 41                     ret = cString.pad(ret, width, padChar || "0", isLeftJustified);
 42                 } else {
 43                     ret = cString.truncate(ret, width);
 44                 }
 45             }
 46 
 47         }
 48     } else {
 49         throw new Error("comb.string.format : when using %d the parameter must be a number!");
 50     }
 51     return ret;
 52 };
 53 
 54 var formatObject = function(object, format) {
 55     var ret,  match = format.match(OBJECT_FORMAT), spacing = 0;
 56     if (match) {
 57         spacing = parseInt(match[0]);
 58         if (isNaN(spacing)) spacing = 0;
 59     }
 60     try {
 61         ret = JSON.stringify(object, null, spacing);
 62     } catch(e) {
 63         throw new Error("comb.string.format : Unable to parse json from ", object);
 64     }
 65     return ret;
 66 };
 67 
 68 
 69 var styles = {
 70     //styles
 71     bold      : 1,
 72     bright    : 1,
 73     italic    : 3,
 74     underline : 4,
 75     blink     : 5,
 76     inverse   : 7,
 77     crossedOut : 9,
 78 
 79     red       : 31,
 80     green     : 32,
 81     yellow    : 33,
 82     blue      : 34,
 83     magenta   : 35,
 84     cyan      : 36,
 85     white     : 37,
 86 
 87     redBackground       : 41,
 88     greenBackground     : 42,
 89     yellowBackground    : 43,
 90     blueBackground      : 44,
 91     magentaBackground   : 45,
 92     cyanBackground      : 46,
 93     whiteBackground     : 47,
 94 
 95     encircled : 52,
 96     overlined : 53,
 97     grey      : 90,
 98     black     : 90
 99 };
100 
101 /**@namespace comb characters*/
102 comb.characters = {
103     /**
104      * ☺
105      */
106     SMILEY : "☺",
107     /**
108      * ☻
109      */
110     SOLID_SMILEY : "☻",
111 
112     /**
113      * ♥
114      */
115     HEART:"♥",
116     /**
117      * ♦
118      */
119     DIAMOND : "♦",
120     /**
121      * ♣
122      */
123     CLOVE : "♣",
124     /**
125      * ♠
126      */
127     SPADE : "♠",
128     /**
129      * •
130      */
131     DOT: "•",
132     /**
133      * ◘
134      */
135     SQUARE_CIRCLE: "◘",
136     /**
137      * ○
138      */
139     CIRCLE: "○",
140     /**
141      * ◙
142      */
143     FILLED_SQUARE_CIRCLE: "◙",
144     /**
145      * ♂
146      */
147     MALE : "♂",
148     /**
149      * ♀
150      */
151     FEMALE : "♀",
152     /**
153      * ♪
154      */
155     EIGHT_NOTE: "♪",
156     /**
157      * ♫
158      */
159     DOUBLE_EIGHT_NOTE: "♫",
160     /**
161      * ☼
162      */
163     SUN : "☼",
164     /**
165      * ►
166      */
167     PLAY : "►",
168     /**
169      * ◄
170      */
171     REWIND : "◄",
172     /**
173      * ↕
174      */
175     UP_DOWN : "↕",
176     /**
177      * ¶
178      */
179     PILCROW : "¶",
180     /**
181      * §
182      */
183     SECTION : "§",
184     /**
185      * ▬
186      */
187     THICK_MINUS : "▬",
188     /**
189      * ↨
190      */
191     SMALL_UP_DOWN : "↨",
192     /**
193      * ↑
194      */
195     UP_ARROW : "↑",
196     /**
197      * ↓
198      */
199     DOWN_ARROW: "↓",
200     /**
201      * →
202      */
203     RIGHT_ARROW : "→",
204     /**
205      * ←
206      */
207     LEFT_ARROW: "←",
208     /**
209      * ∟
210      */
211     RIGHT_ANGLE: "∟",
212     /**
213      * ↔
214      */
215     LEFT_RIGHT_ARROW: "↔",
216     /**
217      * ▲
218      */
219     TRIANGLE: "▲",
220     /**
221      * ▼
222      */
223     DOWN_TRIANGLE: "▼",
224 
225     /**
226      * ⌂
227      */
228     HOUSE : "⌂",
229     /**
230      * Ç
231      */
232     C_CEDILLA: "Ç",
233     /**
234      * ü
235      */
236     U_UMLAUT: "ü",
237     /**
238      * é
239      */
240     E_ACCENT: "é",
241     /**
242      * â
243      */
244     A_LOWER_CIRCUMFLEX: "â",
245     /**
246      * ä
247      */
248     A_LOWER_UMLAUT: "ä",
249     /**
250      * à
251      */
252     A_LOWER_GRAVE_ACCENT: "à",
253     /**
254      * å
255      */
256     A_LOWER_CIRCLE_OVER: "å",
257     /**
258      * ç
259      */
260     C_LOWER_CIRCUMFLEX: "ç",
261     /**
262      * ê
263      */
264     E_LOWER_CIRCUMFLEX: "ê",
265     /**
266      * ë
267      */
268     E_LOWER_UMLAUT: "ë",
269     /**
270      * è
271      */
272     E_LOWER_GRAVE_ACCENT: "è",
273     /**
274      * ï
275      */
276     I_LOWER_UMLAUT: "ï",
277     /**
278      * î
279      */
280     I_LOWER_CIRCUMFLEX: "î",
281     /**
282      * ì
283      */
284     I_LOWER_GRAVE_ACCENT: "ì",
285     /**
286      * Ä
287      */
288     A_UPPER_UMLAUT: "Ä",
289     /**
290      * Å
291      */
292     A_UPPER_CIRCLE: "Å",
293     /**
294      * É
295      */
296     E_UPPER_ACCENT: "É",
297     /**
298      * æ
299      */
300     A_E_LOWER: "æ",
301     /**
302      * Æ
303      */
304     A_E_UPPER: "Æ",
305     /**
306      * ô
307      */
308     O_LOWER_CIRCUMFLEX: "ô",
309     /**
310      * ö
311      */
312     O_LOWER_UMLAUT: "ö",
313     /**
314      * ò
315      */
316     O_LOWER_GRAVE_ACCENT: "ò",
317     /**
318      * û
319      */
320     U_LOWER_CIRCUMFLEX: "û",
321     /**
322      * ù
323      */
324     U_LOWER_GRAVE_ACCENT: "ù",
325     /**
326      * ÿ
327      */
328     Y_LOWER_UMLAUT: "ÿ",
329     /**
330      * Ö
331      */
332     O_UPPER_UMLAUT: "Ö",
333     /**
334      * Ü
335      */
336     U_UPPER_UMLAUT: "Ü",
337 
338     /**
339      * ¢
340      */
341     CENTS: "¢",
342     /**
343      * £
344      */
345     POUND: "£",
346     /**
347      * ¥
348      */
349     YEN: "¥",
350     /**
351      * ¤
352      */
353     CURRENCY : "¤",
354 
355     /**
356      * ₧
357      */
358     PTS: "₧",
359     /**
360      * ƒ
361      */
362     FUNCTION: "ƒ",
363     /**
364      * á
365      */
366     A_LOWER_ACCENT: "á",
367     /**
368      * í
369      */
370     I_LOWER_ACCENT: "í",
371     /**
372      * ó
373      */
374     O_LOWER_ACCENT: "ó",
375     /**
376      * ú
377      */
378     U_LOWER_ACCENT: "ú",
379     /**
380      * ñ
381      */
382     N_LOWER_TILDE: "ñ",
383     /**
384      * Ñ
385      */
386     N_UPPER_TILDE: "Ñ",
387     /**
388      * ª
389      */
390     A_SUPER: "ª",
391     /**
392      * º
393      */
394     O_SUPER: "º",
395     /**
396      * ¿
397      */
398     UPSIDEDOWN_QUESTION: "¿",
399     /**
400      * ⌐
401      */
402     SIDEWAYS_L : "⌐",
403     /**
404      * ¬
405      */
406     NEGATION: "¬",
407     /**
408      * ½
409      */
410     ONE_HALF : "½",
411     /**
412      * ¼
413      */
414     ONE_FOURTH: "¼",
415     /**
416      * ¡
417      */
418     UPSIDEDOWN_EXCLAMATION: "¡",
419     /**
420      * «
421      */
422     DOUBLE_LEFT: "«",
423     /**
424      * »
425      */
426     DOUBLE_RIGHT: "»",
427     /**
428      * ░
429      */
430     LIGHT_SHADED_BOX: "░",
431     /**
432      * ▒
433      */
434     MEDIUM_SHADED_BOX: "▒",
435     /**
436      * ▓
437      */
438     DARK_SHADED_BOX: "▓",
439     /**
440      * │
441      */
442     VERTICAL_LINE: "│",
443 
444     /**
445      * ┤
446      */
447     MAZE__SINGLE_RIGHT_T: "┤",
448     /**
449      * ┐
450      */
451     MAZE_SINGLE_RIGHT_TOP: "┐",
452     /**
453      * ┘
454      */
455     MAZE_SINGLE_RIGHT_BOTTOM_SMALL: "┘",
456     /**
457      * ┌
458      */
459     MAZE_SINGLE_LEFT_TOP_SMALL: "┌",
460     /**
461      * └
462      */
463     MAZE_SINGLE_LEFT_BOTTOM_SMALL: "└",
464     /**
465      * ├
466      */
467     MAZE_SINGLE_LEFT_T: "├",
468     /**
469      * ┴
470      */
471     MAZE_SINGLE_BOTTOM_T: "┴",
472     /**
473      * ┬
474      */
475     MAZE_SINGLE_TOP_T: "┬",
476     /**
477      * ┼
478      */
479     MAZE_SINGLE_CENTER: "┼",
480     /**
481      * ─
482      */
483     MAZE_SINGLE_HORIZONTAL_LINE: "─",
484 
485     /**
486      * ╡
487      */
488     MAZE_SINGLE_RIGHT_DOUBLECENTER_T: "╡",
489     /**
490      * ╛
491      */
492     MAZE_SINGLE_RIGHT_DOUBLE_BL: "╛",
493     /**
494      * ╢
495      */
496     MAZE_SINGLE_RIGHT_DOUBLE_T: "╢",
497     /**
498      * ╖
499      */
500     MAZE_SINGLE_RIGHT_DOUBLEBOTTOM_TOP: "╖",
501     /**
502      * ╕
503      */
504     MAZE_SINGLE_RIGHT_DOUBLELEFT_TOP: "╕",
505     /**
506      * ╞
507      */
508     MAZE_SINGLE_LEFT_DOUBLE_T: "╞",
509 
510     /**
511      * ╧
512      */
513     MAZE_SINGLE_BOTTOM_DOUBLE_T: "╧",
514     /**
515      * ╤
516      */
517     MAZE_SINGLE_TOP_DOUBLE_T: "╤",
518     /**
519      * ╥
520      */
521     MAZE_SINGLE_TOP_DOUBLECENTER_T: "╥",
522     /**
523      * ╨
524      */
525     MAZE_SINGLE_BOTTOM_DOUBLECENTER_T: "╨",
526     /**
527      * ╘
528      */
529     MAZE_SINGLE_LEFT_DOUBLERIGHT_BOTTOM: "╘",
530     /**
531      * ╒
532      */
533     MAZE_SINGLE_LEFT_DOUBLERIGHT_TOP: "╒",
534     /**
535      * ╓
536      */
537     MAZE_SINGLE_LEFT_DOUBLEBOTTOM_TOP: "╓",
538     /**
539      * ╙
540      */
541     MAZE_SINGLE_LEFT_DOUBLETOP_BOTTOM: "╙",
542     /**
543      * Γ
544      */
545     MAZE_SINGLE_LEFT_TOP: "Γ",
546     /**
547      * ╜
548      */
549     MAZE_SINGLE_RIGHT_BOTTOM: "╜",
550     /**
551      * ╟
552      */
553     MAZE_SINGLE_LEFT_CENTER: "╟",
554     /**
555      * ╫
556      */
557     MAZE_SINGLE_DOUBLECENTER_CENTER: "╫",
558     /**
559      * ╪
560      */
561     MAZE_SINGLE_DOUBLECROSS_CENTER: "╪",
562 
563 
564     /**
565      * ╣
566      */
567     MAZE_DOUBLE_LEFT_CENTER: "╣",
568     /**
569      * ║
570      */
571     MAZE_DOUBLE_VERTICAL: "║",
572     /**
573      * ╗
574      */
575     MAZE_DOUBLE_RIGHT_TOP: "╗",
576     /**
577      * ╝
578      */
579     MAZE_DOUBLE_RIGHT_BOTTOM: "╝",
580     /**
581      * ╚
582      */
583     MAZE_DOUBLE_LEFT_BOTTOM: "╚",
584     /**
585      * ╔
586      */
587     MAZE_DOUBLE_LEFT_TOP: "╔",
588     /**
589      * ╩
590      */
591     MAZE_DOUBLE_BOTTOM_T: "╩",
592     /**
593      * ╦
594      */
595     MAZE_DOUBLE_TOP_T : "╦",
596     /**
597      * ╠
598      */
599     MAZE_DOUBLE_LEFT_T: "╠",
600     /**
601      * ═
602      */
603     MAZE_DOUBLE_HORIZONTAL: "═",
604     /**
605      * ╬
606      */
607     MAZE_DOUBLE_CROSS: "╬",
608 
609     /**
610      * █
611      */
612     SOLID_RECTANGLE: "█",
613     /**
614      * ▌
615      */
616     THICK_LEFT_VERTICAL: "▌",
617     /**
618      * ▐
619      */
620     THICK_RIGHT_VERTICAL: "▐",
621     /**
622      * ▄
623      */
624     SOLID_SMALL_RECTANGLE_BOTTOM: "▄",
625     /**
626      * ▀
627      */
628     SOLID_SMALL_RECTANGLE_TOP: "▀",
629 
630     /**
631      * Φ
632      */
633     PHI_UPPER: "Φ",
634 
635     /**
636      * ∞
637      */
638     INFINITY: "∞",
639     /**
640      * ∩
641      */
642     INTERSECTION: "∩",
643     /**
644      * ≡
645      */
646     DEFINITION: "≡",
647     /**
648      * ±
649      */
650     PLUS_MINUS: "±",
651     /**
652      * ≥
653      */
654     GT_EQ: "≥",
655     /**
656      * ≤
657      */
658     LT_EQ: "≤",
659     /**
660      * ⌠
661      */
662     THEREFORE: "⌠",
663     /**
664      * ∵
665      */
666     SINCE : "∵",
667     /**
668      * ∄
669      */
670     DOESNOT_EXIST : "∄",
671     /**
672      * ∃
673      */
674     EXISTS : "∃",
675     /**
676      * ∀
677      */
678     FOR_ALL :"∀",
679     /**
680      * ⊕
681      */
682     EXCLUSIVE_OR : "⊕",
683     /**
684      * ⌡
685      */
686     BECAUSE: "⌡",
687     /**
688      * ÷
689      */
690     DIVIDE: "÷",
691     /**
692      * ≈
693      */
694     APPROX: "≈",
695 
696     /**
697      * °
698      */
699     DEGREE: "°",
700     /**
701      * ∙
702      */
703     BOLD_DOT: "∙",
704     /**
705      * ·
706      */
707     DOT_SMALL: "·",
708     /**
709      * √
710      */
711     CHECK: "√",
712     /**
713      * ✗
714      */
715     ITALIC_X : "✗",
716     /**
717      * ⁿ
718      */
719     SUPER_N: "ⁿ",
720     /**
721      * ²
722      */
723     SQUARED: "²",
724     /**
725      * ³
726      */
727     CUBED : "³",
728     /**
729      * ■
730      */
731     SOLID_BOX: "■",
732     /**
733      * ‰
734      */
735     PERMILE : "‰",
736     /**
737      * ®
738      */
739     REGISTERED_TM : "®",
740     /**
741      * ©
742      */
743     COPYRIGHT : "©",
744     /**
745      * ™
746      */
747     TRADEMARK : "™",
748 
749     /**
750      * β
751      */
752     BETA: "β",
753     /**
754      * γ
755      */
756     GAMMA: "γ",
757     /**
758      * ζ
759      */
760     ZETA: "ζ",
761     /**
762      * η
763      */
764     ETA: "η",
765     /**
766      * ι
767      */
768     IOTA: "ι",
769     /**
770      * κ
771      */
772     KAPPA: "κ",
773     /**
774      * λ
775      */
776     LAMBDA: "λ",
777     /**
778      * ν
779      */
780     NU: "ν",
781     /**
782      * ξ
783      */
784     XI: "ξ",
785     /**
786      * ο
787      */
788     OMICRON: "ο",
789     /**
790      * ρ
791      */
792     RHO: "ρ",
793     /**
794      * υ
795      */
796     UPSILON: "υ",
797     /**
798      * φ
799      */
800     CHI_LOWER: "φ",
801     /**
802      * χ
803      */
804     CHI_UPPER: "χ",
805     /**
806      * ψ
807      */
808     PSI : "ψ",
809     /**
810      * α
811      */
812     ALPHA: "α",
813     /**
814      * ß
815      */
816     ESZETT: "ß",
817     /**
818      * π
819      */
820     PI: "π",
821     /**
822      * Σ
823      */
824     SIGMA_UPPER: "Σ",
825     /**
826      * σ
827      */
828     SIGMA_LOWER: "σ",
829     /**
830      * µ
831      */
832     MU: "µ",
833     /**
834      * τ
835      */
836     TAU: "τ",
837     /**
838      * Θ
839      */
840     THETA: "Θ",
841     /**
842      * Ω
843      */
844     OMEGA: "Ω",
845     /**
846      * δ
847      */
848     DELTA: "δ",
849     /**
850      * φ
851      */
852     PHI_LOWER: "φ",
853     /**
854      * ε
855      */
856     EPSILON: "ε"
857 
858 
859 }
860 
861 /**@namespace String utilities*/
862 comb.string = {
863     /**
864      * Pads a string
865      *
866      * @example
867      *
868      * comb.string.pad("STR", 5, " ", true) => "STR  "
869      * comb.string.pad("STR", 5, "$") => "$$STR"
870      *
871      * @param {String} string the string to pad
872      * @param {Number} length the length of the string when padded
873      * @param {String} [ch= " "] character to pad the string with
874      * @param {Boolean} [end=false] if true then the padding is added to the end
875      *
876      * @returns {String} the padded string
877      */
878     pad : function(string, length, ch, end) {
879         string = "" + string; //check for numbers
880         ch = ch || " ";
881         var strLen = string.length;
882         while (strLen < length) {
883             if (end) {
884                 string += ch;
885             } else {
886                 string = ch + string;
887             }
888             strLen++;
889         }
890         return string;
891     },
892 
893     /**
894      * Truncates a string to the specified length.
895      * @example
896      *
897      * //from the beginning
898      * comb.string.truncate("abcdefg", 3) => "abc";
899      * //from the end
900      * comb.string.truncate("abcdefg", 3,true) => "efg"
901      * //omit the length
902      * comb.string.truncate("abcdefg") => "abcdefg"
903      *
904      * @param {String} string the string to truncate
905      * @param {Number} [length = -1] the max length of the string, if the string is
906      *                              shorter than the length then the string is returned.
907      * @param {Boolean} [end=false] truncate starting at the end of the string
908      *
909      * @return {String} the truncated string.
910      */
911     truncate : function(string, length, end) {
912         var ret = string;
913         if (comb.isString(ret)) {
914             if (string.length > length) {
915                 if (end) {
916                     var l = string.length;
917                     ret = string.substring(l - length, l);
918                 } else {
919                     ret = string.substring(0, length);
920                 }
921             }
922         } else {
923             ret = comb.string.truncate("" + ret, length);
924         }
925         return ret;
926     },
927 
928     /**
929      * Formats a string with the specified format
930      *
931      * @example
932      *
933      *  var format = comb.string.format;
934      *
935      *  format("%s, %s", ["Hello", "World"]) => "Hello, World";
936      *  format("%[ 10]s, %[- 10]s", ["Hello", "World"])
937      *      => "     Hello, World     ";
938      *  format("%-!10s, %#10s, %10s and %-10s",
939      *                          "apple", "orange", "bananas", "watermelons")
940      *      => "apple!!!!!, ####orange,    bananas and watermelon"
941      *  format("%+d, %+d, %10d, %-10d, %-+#10d, %10d",
942      *                          1,-2, 1, 2, 3, 100000000000)
943      *      => "+1, -2, 0000000001, 2000000000, +3########, 1000000000"
944      *  format("%[h:mm a]D", [date]) => 7:32 PM - local -
945      *  format("%[h:mm a]Z", [date]) => 12:32 PM - UTC
946      *  //When using object formats they must be in an array otherwise
947      *  //format will try to interpolate the properties into the string.
948      *  format("%j", [{a : "b"}])
949      *      => '{"a":"b"}'
950      *  format("%1j, %4j", [{a : "b"}, {a : "b"}])
951      *      => '{\n "a": "b"\n},\n{\n    "a": "b"\n}'
952      *  format("{hello}, {world}", {hello : "Hello", world : "World")
953      *      => "Hello, World";
954      *  format({[-s10]apple}, {[%#10]orange}, {[10]banana} and {[-10]watermelons}",
955      *                      {
956      *                          apple : "apple",
957      *                          orange : "orange",
958      *                          banana : "bananas",
959      *                          watermelons : "watermelons"
960      *        });
961      *      => applesssss, ####orange,    bananas and watermelon
962      *
963      * @param {String} str the string to format, if you want to use a spacing character as padding (other than \\s) then put your format in brackets.
964      *  <ol>
965      *      <li>String Formats %[options]s</li>
966      *          <ul>
967      *              <li>- : left justified</li>
968      *              <li>Char : padding character <b>Excludes d,j,s</b></li>
969      *              <li>Number : width</li>
970      *          </ul>
971      *      </li>
972      *      <li>Number Formats %[options]d</li>
973      *          <ul>
974      *              <li>- : left justified</li>
975      *              <li>+ : signed number</li>
976      *              <li>Char : padding character <b>Excludes d,j,s</b></li>
977      *              <li>Number : width</li>
978      *          </ul>
979      *      </li>
980      *      <li>Object Formats %[options]j</li>
981      *          <ul>
982      *              <li>Number : spacing for object properties.</li>
983      *          </ul>
984      *      </li>
985      *  </ol>
986      *
987      *
988      * @param {Object|Array|Arguments...} obj the parameters to replace in the string
989      *                                    if an array is passed then the array is used sequentially
990      *                                    if an object is passed then the object keys are used
991      *                                    if a variable number of args are passed then they are used like an array
992      *
993      * @returns {String} the formatted string
994      */
995     format : function(str, obj) {
996         !date && (date = require("./date"));
997         if (obj instanceof Array) {
998             var i = 0, len = obj.length;
999             //find the matches
1000             return str.replace(FORMAT_REGEX, function(m, format, type) {
1001                 var replacer, ret;
1002                 if (i < len) {
1003                     replacer = obj[i++];
1004                 } else {
1005                     //we are out of things to replace with so
1006                     //just return the match?
1007                     return m;
1008                 }
1009                 if (m == "%s" || m == "%d" || m == "%D") {
1010                     //fast path!
1011                     ret = replacer;
1012                 }else if(m == "%Z"){
1013                     ret = replacer.toUTCString();
1014                 } else if (m == "%j") {
1015                     try {
1016                         ret = JSON.stringify(replacer);
1017                     } catch(e) {
1018                         throw new Error("comb.string.format : Unable to parse json from ", replacer);
1019                     }
1020                 } else {
1021                     format = format.replace(/^\[|\]$/g, "");
1022                     switch (type) {
1023                         case "s":
1024                             ret = formatString(replacer, format);
1025                             break;
1026                         case "d":
1027                             ret = formatNumber(replacer, format);
1028                             break;
1029                         case "j":
1030                             ret = formatObject(replacer, format);
1031                             break;
1032                         case "D":
1033                             ret = date.date.format(replacer, format);
1034                             break;
1035                         case "Z":
1036                             ret = date.date.format(replacer, format, true);
1037                             break;
1038                     }
1039                 }
1040                 return ret;
1041             });
1042         } else if (typeof obj == "object") {
1043             return str.replace(INTERP_REGEX, function(m, format, value) {
1044                 value = obj[value];
1045                 if (value) {
1046                     if (format) {
1047                         if (comb.isString(value)) {
1048                             return formatString(value, format);
1049                         } else if (typeof value == "number") {
1050                             return formatNumber(value, format);
1051                         } else if (date.isDate(value)) {
1052                             return date.date.format(value, format);
1053                         } else if (typeof value == "object") {
1054                             return formatObject(value, format);
1055                         }
1056                     } else {
1057                         return "" + value;
1058                     }
1059                 }
1060                 return m;
1061             });
1062         } else {
1063             var args = Array.prototype.slice.call(arguments).slice(1);
1064             return exports.string.format(str, args);
1065         }
1066     },
1067 
1068     /**
1069      * Converts a string to an array
1070      *
1071      * @example
1072      *
1073      * comb.string.toArray("a|b|c|d", "|") => ["a","b","c","d"]
1074      * comb.string.toArray("a", "|") => ["a"]
1075      * comb.string.toArray("", "|") => []
1076      *
1077      * @param {String} str the string to parse
1078      * @param {String} delimeter the delimeter to use
1079      */
1080     toArray : function(testStr, delim) {
1081         var ret = [];
1082         if (testStr) {
1083             if (testStr.indexOf(delim) > 0) return testStr.replace(/\s+/g, "").split(delim);
1084             else return [testStr];
1085         }
1086         return ret;
1087     },
1088 
1089     /**
1090      * Returns a string duplicated n times;
1091      *
1092      * @example
1093      *
1094      * comb.string.multiply("HELLO", 5) => "HELLOHELLOHELLOHELLOHELLO"
1095      *
1096      *
1097      */
1098     multiply : function(str, times) {
1099         var ret = [];
1100         if (times) {
1101             for (var i = 0; i < times; i++) {
1102                 ret.push(str);
1103             }
1104         }
1105         return ret.join("");
1106     },
1107 
1108     /**
1109      * Styles a string according to the specified styles.
1110      *
1111      * @example
1112      * //style a string red
1113      * comb.string.style('myStr', 'red');
1114      * //style a string red and bold
1115      * comb.string.style('myStr', ['red', bold]);
1116      *
1117      * @param {String} str The string to style.
1118      * @param {String|Array} styles the style or styles to apply to a string.
1119      *          options include :
1120      *          <ul>
1121      *             <li>bold</li>
1122      *             <li>bright</li>
1123      *             <li>italic</li>
1124      *             <li>underline</li>
1125      *             <li>inverse</li>
1126      *             <li>crossedOut</li>
1127      *             <li>blink</li>
1128      *             <li>red</li>
1129      *             <li>green</li>
1130      *             <li>yellow</li>
1131      *             <li>blue</li>
1132      *             <li>magenta</li>
1133      *             <li>cyan</li>
1134      *             <li>white</li>
1135      *             <li>redBackground</li>
1136      *             <li>greenBackground</li>
1137      *             <li>yellowBackground</li>
1138      *             <li>blueBackground</li>
1139      *             <li>magentaBackground</li>
1140      *             <li>cyanBackground</li>
1141      *             <li>whiteBackground</li>
1142      *             <li>grey</li>
1143      *             <li>black</li>
1144      *
1145      *          </ul>
1146      */
1147     style : function(str, options) {
1148         var ret = str;
1149         if (options) {
1150             if (ret instanceof Array) {
1151                 ret = ret.map(function(s) {
1152                     return comb.string.style(s, options);
1153                 })
1154             } else if (options instanceof Array) {
1155                 options.forEach(function(option) {
1156                     ret = comb.string.style(ret, option);
1157                 });
1158             } else if (options in styles) {
1159                 ret = '\x1B[' + styles[options] + 'm' + str + '\x1B[0m';
1160             }
1161         }
1162         return ret;
1163     }
1164 };
1165 
1166 
1167