      1 var comb = exports, date, misc = require("./misc");
      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 (!misc.isUndefined(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