Remove edit menu if no group defined
[jalview.git] / src / jalview / util / Format.java
1 /*\r
2  * Cay S. Horstmann & Gary Cornell, Core Java\r
3  * Published By Sun Microsystems Press/Prentice-Hall\r
4  * Copyright (C) 1997 Sun Microsystems Inc.\r
5  * All Rights Reserved.\r
6  *\r
7  * Permission to use, copy, modify, and distribute this\r
8  * software and its documentation for NON-COMMERCIAL purposes\r
9  * and without fee is hereby granted provided that this\r
10  * copyright notice appears in all copies.\r
11  *\r
12  * THE AUTHORS AND PUBLISHER MAKE NO REPRESENTATIONS OR\r
13  * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER\r
14  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\r
15  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\r
16  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. THE AUTHORS\r
17  * AND PUBLISHER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED\r
18  * BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING\r
19  * THIS SOFTWARE OR ITS DERIVATIVES.\r
20  */\r
21 \r
22 /**\r
23  * A class for formatting numbers that follows printf conventions.\r
24  * Also implements C-like atoi and atof functions\r
25  * @version 1.03 25 Oct 1997\r
26  * @author Cay Horstmann\r
27  */\r
28 package jalview.util;\r
29 \r
30 \r
31 \r
32 /**\r
33  * DOCUMENT ME!\r
34  *\r
35  * @author $author$\r
36  * @version $Revision$\r
37  */\r
38 public class Format\r
39 {\r
40     private int width;\r
41     private int precision;\r
42     private String pre;\r
43     private String post;\r
44     private boolean leading_zeroes;\r
45     private boolean show_plus;\r
46     private boolean alternate;\r
47     private boolean show_space;\r
48     private boolean left_align;\r
49     private char fmt; // one of cdeEfgGiosxXos\r
50 \r
51     /**\r
52      * Creates a new Format object.\r
53      *\r
54      * @param s DOCUMENT ME!\r
55      */\r
56     public Format(String s)\r
57     {\r
58         width = 0;\r
59         precision = -1;\r
60         pre = "";\r
61         post = "";\r
62         leading_zeroes = false;\r
63         show_plus = false;\r
64         alternate = false;\r
65         show_space = false;\r
66         left_align = false;\r
67         fmt = ' ';\r
68 \r
69         int length = s.length();\r
70         int parse_state = 0;\r
71 \r
72         // 0 = prefix, 1 = flags, 2 = width, 3 = precision,\r
73         // 4 = format, 5 = end\r
74         int i = 0;\r
75 \r
76         while (parse_state == 0)\r
77         {\r
78             if (i >= length)\r
79             {\r
80                 parse_state = 5;\r
81             }\r
82             else if (s.charAt(i) == '%')\r
83             {\r
84                 if (i < (length - 1))\r
85                 {\r
86                     if (s.charAt(i + 1) == '%')\r
87                     {\r
88                         pre = pre + '%';\r
89                         i++;\r
90                     }\r
91                     else\r
92                     {\r
93                         parse_state = 1;\r
94                     }\r
95                 }\r
96                 else\r
97                 {\r
98                     throw new java.lang.IllegalArgumentException();\r
99                 }\r
100             }\r
101             else\r
102             {\r
103                 pre = pre + s.charAt(i);\r
104             }\r
105 \r
106             i++;\r
107         }\r
108 \r
109         while (parse_state == 1)\r
110         {\r
111             if (i >= length)\r
112             {\r
113                 parse_state = 5;\r
114             }\r
115             else if (s.charAt(i) == ' ')\r
116             {\r
117                 show_space = true;\r
118             }\r
119             else if (s.charAt(i) == '-')\r
120             {\r
121                 left_align = true;\r
122             }\r
123             else if (s.charAt(i) == '+')\r
124             {\r
125                 show_plus = true;\r
126             }\r
127             else if (s.charAt(i) == '0')\r
128             {\r
129                 leading_zeroes = true;\r
130             }\r
131             else if (s.charAt(i) == '#')\r
132             {\r
133                 alternate = true;\r
134             }\r
135             else\r
136             {\r
137                 parse_state = 2;\r
138                 i--;\r
139             }\r
140 \r
141             i++;\r
142         }\r
143 \r
144         while (parse_state == 2)\r
145         {\r
146             if (i >= length)\r
147             {\r
148                 parse_state = 5;\r
149             }\r
150             else if (('0' <= s.charAt(i)) && (s.charAt(i) <= '9'))\r
151             {\r
152                 width = ((width * 10) + s.charAt(i)) - '0';\r
153                 i++;\r
154             }\r
155             else if (s.charAt(i) == '.')\r
156             {\r
157                 parse_state = 3;\r
158                 precision = 0;\r
159                 i++;\r
160             }\r
161             else\r
162             {\r
163                 parse_state = 4;\r
164             }\r
165         }\r
166 \r
167         while (parse_state == 3)\r
168         {\r
169             if (i >= length)\r
170             {\r
171                 parse_state = 5;\r
172             }\r
173             else if (('0' <= s.charAt(i)) && (s.charAt(i) <= '9'))\r
174             {\r
175                 precision = ((precision * 10) + s.charAt(i)) - '0';\r
176                 i++;\r
177             }\r
178             else\r
179             {\r
180                 parse_state = 4;\r
181             }\r
182         }\r
183 \r
184         if (parse_state == 4)\r
185         {\r
186             if (i >= length)\r
187             {\r
188                 parse_state = 5;\r
189             }\r
190             else\r
191             {\r
192                 fmt = s.charAt(i);\r
193             }\r
194 \r
195             i++;\r
196         }\r
197 \r
198         if (i < length)\r
199         {\r
200             post = s.substring(i, length);\r
201         }\r
202     }\r
203 \r
204     /**\r
205      * Formats the number following printf conventions.\r
206      * Main limitation: Can only handle one format parameter at a time\r
207      * Use multiple Format objects to format more than one number\r
208      * @param s the format string following printf conventions\r
209      * The string has a prefix, a format code and a suffix. The prefix and suffix\r
210      * become part of the formatted output. The format code directs the\r
211      * formatting of the (single) parameter to be formatted. The code has the\r
212      * following structure\r
213      * <ul>\r
214      * <li> a % (required)\r
215      * <li> a modifier (optional)\r
216      * <dl>\r
217      * <dt> + <dd> forces display of + for positive numbers\r
218      * <dt> 0 <dd> show leading zeroes\r
219      * <dt> - <dd> align left in the field\r
220      * <dt> space <dd> prepend a space in front of positive numbers\r
221      * <dt> # <dd> use "alternate" format. Add 0 or 0x for octal or hexadecimal numbers. Don't suppress trailing zeroes in general floating point format.\r
222      * </dl>\r
223      * <li> an integer denoting field width (optional)\r
224      * <li> a period followed by an integer denoting precision (optional)\r
225      * <li> a format descriptor (required)\r
226      * <dl>\r
227      * <dt>f <dd> floating point number in fixed format\r
228      * <dt>e, E <dd> floating point number in exponential notation (scientific format). The E format results in an uppercase E for the exponent (1.14130E+003), the e format in a lowercase e.\r
229      * <dt>g, G <dd> floating point number in general format (fixed format for small numbers, exponential format for large numbers). Trailing zeroes are suppressed. The G format results in an uppercase E for the exponent (if any), the g format in a lowercase e.\r
230      * <dt>d, i <dd> integer in decimal\r
231      * <dt>x <dd> integer in hexadecimal\r
232      * <dt>o <dd> integer in octal\r
233      * <dt>s <dd> string\r
234      * <dt>c <dd> character\r
235      * </dl>\r
236      * </ul>\r
237      * @exception IllegalArgumentException if bad format\r
238      *\r
239      */\r
240     public static String getHexString(java.awt.Color color)\r
241     {\r
242         String r;\r
243         String g;\r
244         String b;\r
245         r = Integer.toHexString(color.getRed());\r
246 \r
247         if (r.length() < 2)\r
248         {\r
249             r = "0" + r;\r
250         }\r
251 \r
252         g = Integer.toHexString(color.getGreen());\r
253 \r
254         if (g.length() < 2)\r
255         {\r
256             g = "0" + g;\r
257         }\r
258 \r
259         b = Integer.toHexString(color.getBlue());\r
260 \r
261         if (b.length() < 2)\r
262         {\r
263             b = "0" + b;\r
264         }\r
265 \r
266         return r + g + b;\r
267     }\r
268 \r
269     /**\r
270     * prints a formatted number following printf conventions\r
271     * @param s a PrintStream\r
272     * @param fmt the format string\r
273     * @param x the double to print\r
274     */\r
275     public static void print(java.io.PrintStream s, String fmt, double x)\r
276     {\r
277         s.print(new Format(fmt).form(x));\r
278     }\r
279 \r
280     /**\r
281     * prints a formatted number following printf conventions\r
282     * @param s a PrintStream\r
283     * @param fmt the format string\r
284     * @param x the long to print\r
285     */\r
286     public static void print(java.io.PrintStream s, String fmt, long x)\r
287     {\r
288         s.print(new Format(fmt).form(x));\r
289     }\r
290 \r
291     /**\r
292     * prints a formatted number following printf conventions\r
293     * @param s a PrintStream\r
294     * @param fmt the format string\r
295     * @param x the character to\r
296     */\r
297     public static void print(java.io.PrintStream s, String fmt, char x)\r
298     {\r
299         s.print(new Format(fmt).form(x));\r
300     }\r
301 \r
302     /**\r
303     * prints a formatted number following printf conventions\r
304     * @param s a PrintStream, fmt the format string\r
305     * @param x a string that represents the digits to print\r
306     */\r
307     public static void print(java.io.PrintStream s, String fmt, String x)\r
308     {\r
309         s.print(new Format(fmt).form(x));\r
310     }\r
311 \r
312     /**\r
313     * Converts a string of digits (decimal, octal or hex) to an integer\r
314     * @param s a string\r
315     * @return the numeric value of the prefix of s representing a base 10 integer\r
316     */\r
317     public static int atoi(String s)\r
318     {\r
319         return (int) atol(s);\r
320     }\r
321 \r
322     /**\r
323     * Converts a string of digits (decimal, octal or hex) to a long integer\r
324     * @param s a string\r
325     * @return the numeric value of the prefix of s representing a base 10 integer\r
326     */\r
327     public static long atol(String s)\r
328     {\r
329         int i = 0;\r
330 \r
331         while ((i < s.length()) && Character.isWhitespace(s.charAt(i)))\r
332             i++;\r
333 \r
334         if ((i < s.length()) && (s.charAt(i) == '0'))\r
335         {\r
336             if (((i + 1) < s.length()) &&\r
337                     ((s.charAt(i + 1) == 'x') || (s.charAt(i + 1) == 'X')))\r
338             {\r
339                 return parseLong(s.substring(i + 2), 16);\r
340             }\r
341             else\r
342             {\r
343                 return parseLong(s, 8);\r
344             }\r
345         }\r
346         else\r
347         {\r
348             return parseLong(s, 10);\r
349         }\r
350     }\r
351 \r
352     /**\r
353      * DOCUMENT ME!\r
354      *\r
355      * @param s DOCUMENT ME!\r
356      * @param base DOCUMENT ME!\r
357      *\r
358      * @return DOCUMENT ME!\r
359      */\r
360     private static long parseLong(String s, int base)\r
361     {\r
362         int i = 0;\r
363         int sign = 1;\r
364         long r = 0;\r
365 \r
366         while ((i < s.length()) && Character.isWhitespace(s.charAt(i)))\r
367             i++;\r
368 \r
369         if ((i < s.length()) && (s.charAt(i) == '-'))\r
370         {\r
371             sign = -1;\r
372             i++;\r
373         }\r
374         else if ((i < s.length()) && (s.charAt(i) == '+'))\r
375         {\r
376             i++;\r
377         }\r
378 \r
379         while (i < s.length())\r
380         {\r
381             char ch = s.charAt(i);\r
382 \r
383             if (('0' <= ch) && (ch < ('0' + base)))\r
384             {\r
385                 r = ((r * base) + ch) - '0';\r
386             }\r
387             else if (('A' <= ch) && (ch < (('A' + base) - 10)))\r
388             {\r
389                 r = ((r * base) + ch) - 'A' + 10;\r
390             }\r
391             else if (('a' <= ch) && (ch < (('a' + base) - 10)))\r
392             {\r
393                 r = ((r * base) + ch) - 'a' + 10;\r
394             }\r
395             else\r
396             {\r
397                 return r * sign;\r
398             }\r
399 \r
400             i++;\r
401         }\r
402 \r
403         return r * sign;\r
404     }\r
405 \r
406     /**\r
407     * Converts a string of digits to an double\r
408     * @param s a string\r
409     */\r
410     public static double atof(String s)\r
411     {\r
412         int i = 0;\r
413         int sign = 1;\r
414         double r = 0; // integer part\r
415         //double f = 0; // fractional part\r
416         double p = 1; // exponent of fractional part\r
417         int state = 0; // 0 = int part, 1 = frac part\r
418 \r
419         while ((i < s.length()) && Character.isWhitespace(s.charAt(i)))\r
420             i++;\r
421 \r
422         if ((i < s.length()) && (s.charAt(i) == '-'))\r
423         {\r
424             sign = -1;\r
425             i++;\r
426         }\r
427         else if ((i < s.length()) && (s.charAt(i) == '+'))\r
428         {\r
429             i++;\r
430         }\r
431 \r
432         while (i < s.length())\r
433         {\r
434             char ch = s.charAt(i);\r
435 \r
436             if (('0' <= ch) && (ch <= '9'))\r
437             {\r
438                 if (state == 0)\r
439                 {\r
440                     r = ((r * 10) + ch) - '0';\r
441                 }\r
442                 else if (state == 1)\r
443                 {\r
444                     p = p / 10;\r
445                     r = r + (p * (ch - '0'));\r
446                 }\r
447             }\r
448             else if (ch == '.')\r
449             {\r
450                 if (state == 0)\r
451                 {\r
452                     state = 1;\r
453                 }\r
454                 else\r
455                 {\r
456                     return sign * r;\r
457                 }\r
458             }\r
459             else if ((ch == 'e') || (ch == 'E'))\r
460             {\r
461                 long e = (int) parseLong(s.substring(i + 1), 10);\r
462 \r
463                 return sign * r * Math.pow(10, e);\r
464             }\r
465             else\r
466             {\r
467                 return sign * r;\r
468             }\r
469 \r
470             i++;\r
471         }\r
472 \r
473         return sign * r;\r
474     }\r
475 \r
476     /**\r
477     * Formats a double into a string (like sprintf in C)\r
478     * @param x the number to format\r
479     * @return the formatted string\r
480     * @exception IllegalArgumentException if bad argument\r
481     */\r
482     public String form(double x)\r
483     {\r
484         String r;\r
485 \r
486         if (precision < 0)\r
487         {\r
488             precision = 6;\r
489         }\r
490 \r
491         int s = 1;\r
492 \r
493         if (x < 0)\r
494         {\r
495             x = -x;\r
496             s = -1;\r
497         }\r
498 \r
499         if (fmt == 'f')\r
500         {\r
501             r = fixed_format(x);\r
502         }\r
503         else if ((fmt == 'e') || (fmt == 'E') || (fmt == 'g') || (fmt == 'G'))\r
504         {\r
505             r = exp_format(x);\r
506         }\r
507         else\r
508         {\r
509             throw new java.lang.IllegalArgumentException();\r
510         }\r
511 \r
512         return pad(sign(s, r));\r
513     }\r
514 \r
515     /**\r
516     * Formats a long integer into a string (like sprintf in C)\r
517     * @param x the number to format\r
518     * @return the formatted string\r
519     */\r
520     public String form(long x)\r
521     {\r
522         String r;\r
523         int s = 0;\r
524 \r
525         if ((fmt == 'd') || (fmt == 'i'))\r
526         {\r
527             if (x < 0)\r
528             {\r
529                 r = ("" + x).substring(1);\r
530                 s = -1;\r
531             }\r
532             else\r
533             {\r
534                 r = "" + x;\r
535                 s = 1;\r
536             }\r
537         }\r
538         else if (fmt == 'o')\r
539         {\r
540             r = convert(x, 3, 7, "01234567");\r
541         }\r
542         else if (fmt == 'x')\r
543         {\r
544             r = convert(x, 4, 15, "0123456789abcdef");\r
545         }\r
546         else if (fmt == 'X')\r
547         {\r
548             r = convert(x, 4, 15, "0123456789ABCDEF");\r
549         }\r
550         else\r
551         {\r
552             throw new java.lang.IllegalArgumentException();\r
553         }\r
554 \r
555         return pad(sign(s, r));\r
556     }\r
557 \r
558     /**\r
559     * Formats a character into a string (like sprintf in C)\r
560     * @param x the value to format\r
561     * @return the formatted string\r
562     */\r
563     public String form(char c)\r
564     {\r
565         if (fmt != 'c')\r
566         {\r
567             throw new java.lang.IllegalArgumentException();\r
568         }\r
569 \r
570         String r = "" + c;\r
571 \r
572         return pad(r);\r
573     }\r
574 \r
575     /**\r
576     * Formats a string into a larger string (like sprintf in C)\r
577     * @param x the value to format\r
578     * @return the formatted string\r
579     */\r
580     public String form(String s)\r
581     {\r
582         if (fmt != 's')\r
583         {\r
584             throw new java.lang.IllegalArgumentException();\r
585         }\r
586 \r
587         if (precision >= 0)\r
588         {\r
589             s = s.substring(0, precision);\r
590         }\r
591 \r
592         return pad(s);\r
593     }\r
594 \r
595     /**\r
596      * DOCUMENT ME!\r
597      *\r
598      * @param c DOCUMENT ME!\r
599      * @param n DOCUMENT ME!\r
600      *\r
601      * @return DOCUMENT ME!\r
602      */\r
603     private static String repeat(char c, int n)\r
604     {\r
605         if (n <= 0)\r
606         {\r
607             return "";\r
608         }\r
609 \r
610         StringBuffer s = new StringBuffer(n);\r
611 \r
612         for (int i = 0; i < n; i++)\r
613             s.append(c);\r
614 \r
615         return s.toString();\r
616     }\r
617 \r
618     /**\r
619      * DOCUMENT ME!\r
620      *\r
621      * @param x DOCUMENT ME!\r
622      * @param n DOCUMENT ME!\r
623      * @param m DOCUMENT ME!\r
624      * @param d DOCUMENT ME!\r
625      *\r
626      * @return DOCUMENT ME!\r
627      */\r
628     private static String convert(long x, int n, int m, String d)\r
629     {\r
630         if (x == 0)\r
631         {\r
632             return "0";\r
633         }\r
634 \r
635         String r = "";\r
636 \r
637         while (x != 0)\r
638         {\r
639             r = d.charAt((int) (x & m)) + r;\r
640             x = x >>> n;\r
641         }\r
642 \r
643         return r;\r
644     }\r
645 \r
646     /**\r
647      * DOCUMENT ME!\r
648      *\r
649      * @param r DOCUMENT ME!\r
650      *\r
651      * @return DOCUMENT ME!\r
652      */\r
653     private String pad(String r)\r
654     {\r
655         String p = repeat(' ', width - r.length());\r
656 \r
657         if (left_align)\r
658         {\r
659             return pre + r + p + post;\r
660         }\r
661         else\r
662         {\r
663             return pre + p + r + post;\r
664         }\r
665     }\r
666 \r
667     /**\r
668      * DOCUMENT ME!\r
669      *\r
670      * @param s DOCUMENT ME!\r
671      * @param r DOCUMENT ME!\r
672      *\r
673      * @return DOCUMENT ME!\r
674      */\r
675     private String sign(int s, String r)\r
676     {\r
677         String p = "";\r
678 \r
679         if (s < 0)\r
680         {\r
681             p = "-";\r
682         }\r
683         else if (s > 0)\r
684         {\r
685             if (show_plus)\r
686             {\r
687                 p = "+";\r
688             }\r
689             else if (show_space)\r
690             {\r
691                 p = " ";\r
692             }\r
693         }\r
694         else\r
695         {\r
696             if ((fmt == 'o') && alternate && (r.length() > 0) &&\r
697                     (r.charAt(0) != '0'))\r
698             {\r
699                 p = "0";\r
700             }\r
701             else if ((fmt == 'x') && alternate)\r
702             {\r
703                 p = "0x";\r
704             }\r
705             else if ((fmt == 'X') && alternate)\r
706             {\r
707                 p = "0X";\r
708             }\r
709         }\r
710 \r
711         int w = 0;\r
712 \r
713         if (leading_zeroes)\r
714         {\r
715             w = width;\r
716         }\r
717         else if (((fmt == 'd') || (fmt == 'i') || (fmt == 'x') || (fmt == 'X') ||\r
718                 (fmt == 'o')) && (precision > 0))\r
719         {\r
720             w = precision;\r
721         }\r
722 \r
723         return p + repeat('0', w - p.length() - r.length()) + r;\r
724     }\r
725 \r
726     /**\r
727      * DOCUMENT ME!\r
728      *\r
729      * @param d DOCUMENT ME!\r
730      *\r
731      * @return DOCUMENT ME!\r
732      */\r
733     private String fixed_format(double d)\r
734     {\r
735         boolean removeTrailing = ((fmt == 'G') || (fmt == 'g')) && !alternate;\r
736 \r
737         // remove trailing zeroes and decimal point\r
738         if (d > 0x7FFFFFFFFFFFFFFFL)\r
739         {\r
740             return exp_format(d);\r
741         }\r
742 \r
743         if (precision == 0)\r
744         {\r
745             return (long) (d + 0.5) + (removeTrailing ? "" : ".");\r
746         }\r
747 \r
748         long whole = (long) d;\r
749         double fr = d - whole; // fractional part\r
750 \r
751         if ((fr >= 1) || (fr < 0))\r
752         {\r
753             return exp_format(d);\r
754         }\r
755 \r
756         double factor = 1;\r
757         String leading_zeroes = "";\r
758 \r
759         for (int i = 1; (i <= precision) && (factor <= 0x7FFFFFFFFFFFFFFFL);\r
760                 i++)\r
761         {\r
762             factor *= 10;\r
763             leading_zeroes = leading_zeroes + "0";\r
764         }\r
765 \r
766         long l = (long) ((factor * fr) + 0.5);\r
767 \r
768         if (l >= factor)\r
769         {\r
770             l = 0;\r
771             whole++;\r
772         }\r
773 \r
774         // CSH 10-25-97\r
775         String z = leading_zeroes + l;\r
776         z = "." + z.substring(z.length() - precision, z.length());\r
777 \r
778         if (removeTrailing)\r
779         {\r
780             int t = z.length() - 1;\r
781 \r
782             while ((t >= 0) && (z.charAt(t) == '0'))\r
783                 t--;\r
784 \r
785             if ((t >= 0) && (z.charAt(t) == '.'))\r
786             {\r
787                 t--;\r
788             }\r
789 \r
790             z = z.substring(0, t + 1);\r
791         }\r
792 \r
793         return whole + z;\r
794     }\r
795 \r
796     /**\r
797      * DOCUMENT ME!\r
798      *\r
799      * @param d DOCUMENT ME!\r
800      *\r
801      * @return DOCUMENT ME!\r
802      */\r
803     private String exp_format(double d)\r
804     {\r
805         String f = "";\r
806         int e = 0;\r
807         double dd = d;\r
808         double factor = 1;\r
809 \r
810         if (d != 0)\r
811         {\r
812             while (dd > 10)\r
813             {\r
814                 e++;\r
815                 factor /= 10;\r
816                 dd = dd / 10;\r
817             }\r
818 \r
819             while (dd < 1)\r
820             {\r
821                 e--;\r
822                 factor *= 10;\r
823                 dd = dd * 10;\r
824             }\r
825         }\r
826 \r
827         if (((fmt == 'g') || (fmt == 'G')) && (e >= -4) && (e < precision))\r
828         {\r
829             return fixed_format(d);\r
830         }\r
831 \r
832         d = d * factor;\r
833         f = f + fixed_format(d);\r
834 \r
835         if ((fmt == 'e') || (fmt == 'g'))\r
836         {\r
837             f = f + "e";\r
838         }\r
839         else\r
840         {\r
841             f = f + "E";\r
842         }\r
843 \r
844         String p = "000";\r
845 \r
846         if (e >= 0)\r
847         {\r
848             f = f + "+";\r
849             p = p + e;\r
850         }\r
851         else\r
852         {\r
853             f = f + "-";\r
854             p = p + (-e);\r
855         }\r
856 \r
857         return f + p.substring(p.length() - 3, p.length());\r
858     }\r
859 }\r