001/*
002Copyright (c) 2011+, HL7, Inc
003All rights reserved.
004
005Redistribution and use in source and binary forms, with or without modification, 
006are permitted provided that the following conditions are met:
007
008 * Redistributions of source code must retain the above copyright notice, this 
009   list of conditions and the following disclaimer.
010 * Redistributions in binary form must reproduce the above copyright notice, 
011   this list of conditions and the following disclaimer in the documentation 
012   and/or other materials provided with the distribution.
013 * Neither the name of HL7 nor the names of its contributors may be used to 
014   endorse or promote products derived from this software without specific 
015   prior written permission.
016
017THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
018ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
019WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
020IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
021INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
022NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
023PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
024WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
025ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
026POSSIBILITY OF SUCH DAMAGE.
027
028 */
029package org.hl7.fhir.instance.utilities;
030
031import java.io.BufferedInputStream;
032import java.io.ByteArrayInputStream;
033import java.io.ByteArrayOutputStream;
034import java.io.File;
035import java.io.FileInputStream;
036import java.io.FileOutputStream;
037import java.io.FilenameFilter;
038import java.io.IOException;
039import java.io.InputStream;
040import java.io.UnsupportedEncodingException;
041import java.net.URLEncoder;
042import java.nio.channels.FileChannel;
043import java.util.ArrayList;
044import java.util.List;
045import java.util.Map;
046import java.util.UUID;
047
048import javax.sound.sampled.AudioFormat;
049import javax.sound.sampled.AudioSystem;
050import javax.sound.sampled.SourceDataLine;
051import javax.xml.transform.Transformer;
052import javax.xml.transform.TransformerFactory;
053import javax.xml.transform.URIResolver;
054import javax.xml.transform.stream.StreamResult;
055import javax.xml.transform.stream.StreamSource;
056
057import net.sf.saxon.TransformerFactoryImpl;
058
059import org.apache.commons.io.FileUtils;
060
061public class Utilities {
062
063//       private static final String TOKEN_REGEX = "^a-z[A-Za-z0-9]*$";
064
065
066  private static final String OID_REGEX = "[0-2](\\.(0|[1-9]([0-9])*))*";
067
068  /**
069     * Returns the plural form of the word in the string.
070     * 
071     * Examples:
072     * 
073     * <pre>
074     *   inflector.pluralize(&quot;post&quot;)               #=&gt; &quot;posts&quot;
075     *   inflector.pluralize(&quot;octopus&quot;)            #=&gt; &quot;octopi&quot;
076     *   inflector.pluralize(&quot;sheep&quot;)              #=&gt; &quot;sheep&quot;
077     *   inflector.pluralize(&quot;words&quot;)              #=&gt; &quot;words&quot;
078     *   inflector.pluralize(&quot;the blue mailman&quot;)   #=&gt; &quot;the blue mailmen&quot;
079     *   inflector.pluralize(&quot;CamelOctopus&quot;)       #=&gt; &quot;CamelOctopi&quot;
080     * </pre>
081     * 
082     * 
083     * 
084     * Note that if the {@link Object#toString()} is called on the supplied object, so this method works for non-strings, too.
085     * 
086     * 
087     * @param word the word that is to be pluralized.
088     * @return the pluralized form of the word, or the word itself if it could not be pluralized
089     * @see #singularize(Object)
090     */
091    public static String pluralizeMe( String word ) {
092        Inflector inf = new Inflector();
093        return inf.pluralize(word);
094    }
095    
096  
097        public static boolean isInteger(String string) {
098                try {
099                        int i = Integer.parseInt(string);
100                        return i != i+1;
101                } catch (Exception e) {
102                        return false;
103                }
104        }
105        
106        public static boolean isDecimal(String string) {
107                try {
108                        float r = Float.parseFloat(string);
109                        return r != r + 1; // just to suppress the hint
110                } catch (Exception e) {
111                        return false;
112                }
113        }
114        
115        public static String camelCase(String value) {
116          return new Inflector().camelCase(value.trim().replace(" ", "_"), false);
117        }
118        
119        public static String escapeXml(String doco) {
120                if (doco == null)
121                        return "";
122                
123                StringBuilder b = new StringBuilder();
124                for (char c : doco.toCharArray()) {
125                  if (c == '<')
126                          b.append("&lt;");
127                  else if (c == '>')
128                          b.append("&gt;");
129                  else if (c == '&')
130                          b.append("&amp;");
131      else if (c == '"')
132        b.append("&quot;");
133                  else 
134                          b.append(c);
135                }               
136                return b.toString();
137        }
138
139        
140        public static String capitalize(String s)
141        {
142                if( s == null ) return null;
143                if( s.length() == 0 ) return s;
144                if( s.length() == 1 ) return s.toUpperCase();
145                
146                return s.substring(0, 1).toUpperCase() + s.substring(1);
147        }
148        
149  public static void copyDirectory(String sourceFolder, String destFolder, FileNotifier notifier) throws Exception {
150    CSFile src = new CSFile(sourceFolder);
151    if (!src.exists())
152      throw new Exception("Folder " +sourceFolder+" not found");
153    createDirectory(destFolder);
154    
155   String[] files = src.list();
156   for (String f : files) {
157     if (new CSFile(sourceFolder+File.separator+f).isDirectory()) {
158       if (!f.startsWith(".")) // ignore .svn...
159         copyDirectory(sourceFolder+File.separator+f, destFolder+File.separator+f, notifier);
160     } else {
161       if (notifier != null)
162         notifier.copyFile(sourceFolder+File.separator+f, destFolder+File.separator+f);
163       copyFile(new CSFile(sourceFolder+File.separator+f), new CSFile(destFolder+File.separator+f));
164     }
165   }
166  }
167        
168  public static void copyFile(String source, String dest) throws IOException {
169    copyFile(new File(source), new File(dest));
170  }
171
172        public static void copyFile(File sourceFile, File destFile) throws IOException {
173                if(!destFile.exists()) {
174                        if (!new CSFile(destFile.getParent()).exists()) {
175                                createDirectory(destFile.getParent());
176                        }
177                        destFile.createNewFile();
178                }
179
180                FileChannel source = null;
181                FileChannel destination = null;
182
183                try {
184                        source = new FileInputStream(sourceFile).getChannel();
185                        destination = new FileOutputStream(destFile).getChannel();
186                        destination.transferFrom(source, 0, source.size());
187                }
188                finally {
189                        if(source != null) {
190                                source.close();
191                        }
192                        if(destination != null) {
193                                destination.close();
194                        }
195                }
196        }
197
198  public static boolean checkFolder(String dir, List<String> errors)
199        throws IOException
200  {
201          if (!new CSFile(dir).exists()) {
202      errors.add("Unable to find directory "+dir);
203      return false;
204    } else {
205      return true;
206    }
207  }
208
209  public static boolean checkFile(String purpose, String dir, String file, List<String> errors) 
210        throws IOException
211  {
212    if (!new CSFile(dir+file).exists()) {
213      errors.add("Unable to find "+purpose+" file "+file+" in "+dir);
214      return false;
215    } else {
216      return true;
217    }
218  }
219
220  public static String asCSV(List<String> strings) {
221    StringBuilder s = new StringBuilder();
222    boolean first = true;
223    for (String n : strings) {
224      if (!first)
225        s.append(",");
226      s.append(n);
227      first = false;
228    }
229    return s.toString();
230  }
231
232  public static String asHtmlBr(String prefix, List<String> strings) {
233    StringBuilder s = new StringBuilder();
234    boolean first = true;
235    for (String n : strings) {
236      if (!first)
237        s.append("<br/>");
238      s.append(prefix);
239      s.append(n);
240      first = false;
241    }
242    return s.toString();
243  }
244
245  public static void clearDirectory(String folder) throws IOException {
246    File dir = new File(folder);
247    if (dir.exists())
248      FileUtils.cleanDirectory(dir);
249//        String[] files = new CSFile(folder).list();
250//        if (files != null) {
251//                for (String f : files) {
252//                        File fh = new CSFile(folder+File.separatorChar+f);
253//                        if (fh.isDirectory()) 
254//                                clearDirectory(fh.getAbsolutePath());
255//                        fh.delete();
256//                }
257//        }
258  }
259
260  public static void createDirectory(String path) throws IOException{
261    new CSFile(path).mkdirs();    
262  }
263
264  public static String changeFileExt(String name, String ext) {
265    if (name.lastIndexOf('.') > -1)
266      return name.substring(0, name.lastIndexOf('.')) + ext;
267    else
268      return name+ext;
269  }
270  
271  public static String cleanupTextString( String contents )
272  {
273          if( contents == null || contents.trim().equals("") )
274                  return null;
275          else
276                  return contents.trim();
277  }
278
279
280  public static boolean noString(String v) {
281    return v == null || v.equals("");
282  }
283
284
285  public static byte[] saxonTransform(Map<String, byte[]> files, byte[] source, byte[] xslt) throws Exception {
286    TransformerFactory f = new net.sf.saxon.TransformerFactoryImpl();
287    f.setAttribute("http://saxon.sf.net/feature/version-warning", Boolean.FALSE);
288    StreamSource xsrc = new StreamSource(new ByteArrayInputStream(xslt));
289    f.setURIResolver(new ZipURIResolver(files));
290    Transformer t = f.newTransformer(xsrc);
291 
292    t.setURIResolver(new ZipURIResolver(files));
293    StreamSource src = new StreamSource(new ByteArrayInputStream(source));
294    ByteArrayOutputStream out = new ByteArrayOutputStream();
295    StreamResult res = new StreamResult(out);
296    t.transform(src, res);
297    return out.toByteArray();    
298  }
299  
300  public static byte[] transform(Map<String, byte[]> files, byte[] source, byte[] xslt) throws Exception {
301    TransformerFactory f = TransformerFactory.newInstance();
302    f.setAttribute("http://saxon.sf.net/feature/version-warning", Boolean.FALSE);
303    StreamSource xsrc = new StreamSource(new ByteArrayInputStream(xslt));
304    f.setURIResolver(new ZipURIResolver(files));
305    Transformer t = f.newTransformer(xsrc);
306
307    t.setURIResolver(new ZipURIResolver(files));
308    StreamSource src = new StreamSource(new ByteArrayInputStream(source));
309    ByteArrayOutputStream out = new ByteArrayOutputStream();
310    StreamResult res = new StreamResult(out);
311    t.transform(src, res);
312    return out.toByteArray();    
313  }
314  
315  public static void bytesToFile(byte[] content, String filename) throws Exception {
316    FileOutputStream out = new FileOutputStream(filename);
317    out.write(content);
318    out.close();
319    
320  }
321
322  public static String saxonTransform(String source, String xslt) throws Exception {
323    TransformerFactoryImpl f = new net.sf.saxon.TransformerFactoryImpl();
324    f.setAttribute("http://saxon.sf.net/feature/version-warning", Boolean.FALSE);
325    StreamSource xsrc = new StreamSource(new FileInputStream(xslt));
326    Transformer t = f.newTransformer(xsrc);
327    StreamSource src = new StreamSource(new FileInputStream(source));
328    StreamResult res = new StreamResult(new ByteArrayOutputStream());
329    t.transform(src, res);
330    return res.getOutputStream().toString();   
331  }
332
333  public static void saxonTransform(String xsltDir, String source, String xslt, String dest, URIResolver alt) throws Exception {
334        saxonTransform(xsltDir, source, xslt, dest, alt, null);
335  }
336
337  public static void saxonTransform(String xsltDir, String source, String xslt, String dest, URIResolver alt, Map<String, String> params) throws Exception {
338    TransformerFactoryImpl f = new net.sf.saxon.TransformerFactoryImpl();
339    f.setAttribute("http://saxon.sf.net/feature/version-warning", Boolean.FALSE);
340    StreamSource xsrc = new StreamSource(new FileInputStream(xslt));
341    f.setURIResolver(new MyURIResolver(xsltDir, alt));
342    Transformer t = f.newTransformer(xsrc);
343                if (params != null) {
344                        for (Map.Entry<String, String> entry : params.entrySet()) {
345                                t.setParameter(entry.getKey(), entry.getValue());
346                        }
347        }
348    
349    t.setURIResolver(new MyURIResolver(xsltDir, alt));
350    StreamSource src = new StreamSource(new FileInputStream(source));
351    StreamResult res = new StreamResult(new FileOutputStream(dest));
352    t.transform(src, res);    
353  }
354  
355  public static void transform(String xsltDir, String source, String xslt, String dest, URIResolver alt) throws Exception {
356
357    TransformerFactory f = TransformerFactory.newInstance();
358    StreamSource xsrc = new StreamSource(new FileInputStream(xslt));
359    f.setURIResolver(new MyURIResolver(xsltDir, alt));
360    Transformer t = f.newTransformer(xsrc);
361
362    t.setURIResolver(new MyURIResolver(xsltDir, alt));
363    StreamSource src = new StreamSource(new FileInputStream(source));
364    StreamResult res = new StreamResult(new FileOutputStream(dest));
365    t.transform(src, res);
366    
367  }
368
369
370  public static String appendSlash(String definitions) {
371            return definitions.endsWith(File.separator) ? definitions : definitions+File.separator;
372          }
373
374  public static String appendForwardSlash(String definitions) {
375            return definitions.endsWith("/") ? definitions : definitions+"/";
376          }
377
378
379  public static String fileTitle(String file) {
380    if (file == null)
381      return null;
382    String s = new File(file).getName();
383    return s.indexOf(".") == -1? s : s.substring(0, s.indexOf("."));
384  }
385
386
387  public static String systemEol()
388  {
389          return System.getProperty("line.separator");
390  }
391
392  public static String normaliseEolns(String value) {
393    return value.replace("\r\n", "\r").replace("\n", "\r").replace("\r", "\r\n");
394  }
395
396
397  public static String unescapeXml(String xml) throws Exception {
398    if (xml == null)
399      return null;
400    
401    StringBuilder b = new StringBuilder();
402    int i = 0;
403    while (i < xml.length()) {
404      if (xml.charAt(i) == '&') {
405        StringBuilder e = new StringBuilder();
406        i++;
407        while (xml.charAt(i) != ';') {
408          e.append(xml.charAt(i));
409          i++;
410        }
411        if (e.toString().equals("lt")) 
412          b.append("<");
413        else if (e.toString().equals("gt")) 
414          b.append(">");
415        else if (e.toString().equals("amp")) 
416          b.append("&");
417        else if (e.toString().equals("quot")) 
418          b.append("\"");
419        else if (e.toString().equals("mu"))
420          b.append((char)956);          
421        else
422          throw new Exception("unknown XML entity \""+e.toString()+"\"");
423      }  else
424        b.append(xml.charAt(i));
425      i++;
426    }   
427    return b.toString();
428  }
429
430
431  public static boolean isPlural(String word) {
432    word = word.toLowerCase();
433    if ("restricts".equals(word) || "contains".equals(word) || "data".equals(word) || "specimen".equals(word))
434      return false;
435    Inflector inf = new Inflector();
436    return !inf.singularize(word).equals(word);
437  }
438
439
440  public static String padLeft(String src, char c, int len) {
441    StringBuilder s = new StringBuilder();
442    for (int i = 0; i < len - src.length(); i++)
443      s.append(c);
444    s.append(src);
445    return s.toString();
446    
447  }
448
449
450  public static String path(String... args) {
451    StringBuilder s = new StringBuilder();
452    boolean d = false;
453    for(String arg: args) {
454      if (!d)
455        d = !noString(arg);
456      else if (!s.toString().endsWith(File.separator))
457        s.append(File.separator);
458      String a = arg;
459      a = a.replace("\\", File.separator);
460      if (s.length() > 0 && a.startsWith(File.separator))
461        a = a.substring(File.separator.length());
462        
463      if ("..".equals(a)) {
464        int i = s.substring(0, s.length()-1).lastIndexOf(File.separator);
465        s = new StringBuilder(s.substring(0, i+1));
466      } else
467        s.append(a);
468    }
469    return s.toString();
470  }
471
472  public static String pathReverse(String... args) {
473    StringBuilder s = new StringBuilder();
474    boolean d = false;
475    for(String arg: args) {
476      if (!d)
477        d = !noString(arg);
478      else if (!s.toString().endsWith("/"))
479        s.append("/");
480      s.append(arg);
481    }
482    return s.toString();
483  }
484
485
486
487//  public static void checkCase(String filename) {
488//    File f = new CSFile(filename);
489//    if (!f.getName().equals(filename))
490//      throw new Exception("Filename  ")
491//    
492//  }
493
494  public static String nmtokenize(String cs) {
495    StringBuilder s = new StringBuilder();
496    for (int i = 0; i < cs.length(); i++) {
497      char c = cs.charAt(i);
498      if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_')
499        s.append(c);
500      else if (c != ' ')
501        s.append("."+Integer.toString(c));
502    }
503    return s.toString();
504  }
505
506
507  public static boolean isToken(String tail) {
508    if (tail == null || tail.length() == 0)
509      return false;
510    boolean result = isAlphabetic(tail.charAt(0));
511    for (int i = 1; i < tail.length(); i++) {
512        result = result && (isAlphabetic(tail.charAt(i)) || isDigit(tail.charAt(i)) || (tail.charAt(i) == '_')  || (tail.charAt(i) == '[') || (tail.charAt(i) == ']'));
513    }
514    return result;
515  }
516
517
518  private static boolean isDigit(char c) {
519    return (c >= '0') && (c <= '9');
520  }
521
522
523  private static boolean isAlphabetic(char c) {
524    return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
525  }
526
527
528  public static String getDirectoryForFile(String filepath) {
529    File f = new File(filepath);
530    return f.getParent();
531  }
532
533  public static String appendPeriod(String s) {
534    if (Utilities.noString(s))
535      return s;
536    s = s.trim();
537    if (s.endsWith(".") || s.endsWith("?"))
538      return s;
539    return s+".";
540  }
541
542
543  public static String removePeriod(String s) {
544    if (Utilities.noString(s))
545      return s;
546    if (s.endsWith("."))
547      return s.substring(0, s.length()-1);
548    return s;
549  }
550
551
552        public static String stripBOM(String string) {
553          return string.replace("\uFEFF", "");
554  }
555
556
557  public static String oidTail(String id) {
558    if (id == null || !id.contains("."))
559      return id;
560    return id.substring(id.lastIndexOf(".")+1);
561  }
562
563
564  public static String oidRoot(String id) {
565    if (id == null || !id.contains("."))
566      return id;
567    return id.substring(0, id.indexOf("."));
568  }
569
570  public static String escapeJava(String doco) {
571    if (doco == null)
572      return "";
573    
574    StringBuilder b = new StringBuilder();
575    for (char c : doco.toCharArray()) {
576      if (c == '\r')
577        b.append("\\r");
578      else if (c == '\n')
579        b.append("\\n");
580      else if (c == '"')
581        b.append("\\\"");
582      else if (c == '\\')
583        b.append("\\\\");
584      else 
585        b.append(c);
586    }   
587    return b.toString();
588  }
589
590
591  public static String[] splitByCamelCase(String name) {
592    List<String> parts = new ArrayList<String>();
593    StringBuilder b = new StringBuilder();
594    for (int i = 0; i < name.length(); i++) {
595      if (i > 0 && Character.isUpperCase(name.charAt(i))) {
596        parts.add(b.toString());
597        b = new StringBuilder();
598      }
599      b.append(Character.toLowerCase(name.charAt(i)));
600    }
601    parts.add(b.toString());
602    return parts.toArray(new String[] {} );
603  }
604
605
606  public static String encodeUri(String v) {
607    return v.replace(" ", "%20").replace("?", "%3F").replace("=", "%3D");
608  }
609  
610
611
612        public static String normalize(String s) {
613                if (noString(s))
614                        return null;
615          StringBuilder b = new StringBuilder();
616          boolean isWhitespace = false;
617          for (int i = 0; i < s.length(); i++) {
618                char c = s.charAt(i);
619                if (!Character.isWhitespace(c)) { 
620                        b.append(Character.toLowerCase(c));
621                        isWhitespace = false;
622                } else if (!isWhitespace) {
623                        b.append(' ');
624                        isWhitespace = true;                    
625                } 
626          }
627          return b.toString().trim();
628  }
629
630  public static String normalizeSameCase(String s) {
631    if (noString(s))
632      return null;
633    StringBuilder b = new StringBuilder();
634    boolean isWhitespace = false;
635    for (int i = 0; i < s.length(); i++) {
636      char c = s.charAt(i);
637      if (!Character.isWhitespace(c)) { 
638        b.append(c);
639        isWhitespace = false;
640      } else if (!isWhitespace) {
641        b.append(' ');
642        isWhitespace = true;        
643      } 
644    }
645    return b.toString().trim();
646  }
647
648
649  public static void copyFileToDirectory(File source, File destDir) throws IOException {
650        copyFile(source, new File(path(destDir.getAbsolutePath(), source.getName())));
651  }
652
653
654        public static boolean isWhitespace(String s) {
655          boolean ok = true;
656          for (int i = 0; i < s.length(); i++)
657                ok = ok && Character.isWhitespace(s.charAt(i));
658          return ok;
659          
660  }
661
662
663  public static String URLEncode(String string) {
664    try {
665      return URLEncoder.encode(string, "UTF-8");
666    } catch (UnsupportedEncodingException e) {
667      throw new Error(e.getMessage());
668    }
669  }
670
671
672  public static boolean existsInList(String value, String... array) {
673    for (String s : array)
674      if (value.equals(s))
675          return true;
676    return false;
677  }
678
679  public static boolean existsInListNC(String value, String... array) {
680    for (String s : array)
681      if (value.equalsIgnoreCase(s))
682          return true;
683    return false;
684  }
685
686
687  public static String getFileNameForName(String name) {
688    return name.toLowerCase();
689  }
690
691  public static void deleteTempFiles() throws IOException {
692    File file = createTempFile("test", "test");
693    String folder = getDirectoryForFile(file.getAbsolutePath());
694    String[] list = new File(folder).list(new FilenameFilter() {
695      public boolean accept(File dir, String name) {
696        return name.startsWith("ohfu-");
697      }
698    });
699    if (list != null) {
700      for (String n : list) {
701        new File(path(folder, n)).delete();
702      }
703    }
704  }
705
706  public static File createTempFile(String prefix, String suffix) throws IOException {
707 // this allows use to eaily identify all our dtemp files and delete them, since delete on Exit doesn't really work.
708    File file = File.createTempFile("ohfu-"+prefix, suffix);  
709    file.deleteOnExit();
710    return file;
711  }
712
713
714        public static boolean isAsciiChar(char ch) {
715                return ch >= ' ' && ch <= '~'; 
716  }
717
718
719  public static String makeUuidUrn() {
720    return "urn:uuid:"+UUID.randomUUID().toString().toLowerCase();
721  }
722
723  public static boolean isURL(String s) {
724    boolean ok = s.matches("^http(s{0,1})://[a-zA-Z0-9_/\\-\\.]+\\.([A-Za-z/]{2,5})[a-zA-Z0-9_/\\&\\?\\=\\-\\.\\~\\%]*");
725    return ok;
726 }
727
728
729  public static String escapeJson(String value) {
730    if (value == null)
731      return "";
732    
733    StringBuilder b = new StringBuilder();
734    for (char c : value.toCharArray()) {
735      if (c == '\r')
736        b.append("\\r");
737      else if (c == '\n')
738        b.append("\\n");
739      else if (c == '"')
740        b.append("\\\"");
741      else if (c == '\'')
742        b.append("\\'");
743      else if (c == '\\')
744        b.append("\\\\");
745      else 
746        b.append(c);
747    }   
748    return b.toString();
749  }
750
751  public static String humanize(String code) {
752    StringBuilder b = new StringBuilder();
753    boolean lastBreak = true;
754    for (char c : code.toCharArray()) {
755      if (Character.isLetter(c)) {
756        if (lastBreak)
757          b.append(Character.toUpperCase(c));
758        else { 
759          if (Character.isUpperCase(c))
760            b.append(" ");          
761          b.append(c);
762        }
763        lastBreak = false;
764      } else {
765        b.append(" ");
766        lastBreak = true;
767      }
768    }
769    if (b.length() == 0)
770      return code;
771    else 
772      return b.toString();
773  }
774
775
776  public static String uncapitalize(String s) {
777    if( s == null ) return null;
778    if( s.length() == 0 ) return s;
779    if( s.length() == 1 ) return s.toLowerCase();
780    
781    return s.substring(0, 1).toLowerCase() + s.substring(1);
782  }
783
784
785  public static int charCount(String s, char c) {
786          int res = 0;
787          for (char ch : s.toCharArray())
788                if (ch == c)
789                  res++;
790          return res;
791  }
792
793
794  // http://stackoverflow.com/questions/3780406/how-to-play-a-sound-alert-in-a-java-application
795  public static float SAMPLE_RATE = 8000f;
796  
797  public static void tone(int hz, int msecs) {
798      tone(hz, msecs, 1.0);
799   }
800
801  public static void tone(int hz, int msecs, double vol) {
802    try {
803      byte[] buf = new byte[1];
804      AudioFormat af = 
805          new AudioFormat(
806              SAMPLE_RATE, // sampleRate
807              8,           // sampleSizeInBits
808              1,           // channels
809              true,        // signed
810              false);      // bigEndian
811      SourceDataLine sdl;
812      sdl = AudioSystem.getSourceDataLine(af);
813      sdl.open(af);
814      sdl.start();
815      for (int i=0; i < msecs*8; i++) {
816        double angle = i / (SAMPLE_RATE / hz) * 2.0 * Math.PI;
817        buf[0] = (byte)(Math.sin(angle) * 127.0 * vol);
818        sdl.write(buf,0,1);
819      }
820      sdl.drain();
821      sdl.stop();
822      sdl.close();
823    } catch (Exception e) {
824    }
825  }
826
827
828  public static boolean isOid(String cc) {
829    return cc.matches(OID_REGEX) && cc.lastIndexOf('.') > 5;
830  }
831
832
833  public static boolean equals(String one, String two) {
834    if (one == null && two == null)
835      return true;
836    if (one == null || two == null)
837      return false;
838    return one.equals(two);
839  }
840
841
842  public static void deleteAllFiles(String folder, String type) {
843    File src = new File(folder);
844    String[] files = src.list();
845    for (String f : files) {
846      if (new File(folder+File.separator+f).isDirectory()) {
847        deleteAllFiles(folder+File.separator+f, type);
848      } else if (f.endsWith(type)) {
849        new File(folder+File.separator+f).delete();
850      }
851    }
852    
853  }
854
855  public static boolean compareIgnoreWhitespace(File f1, File f2) throws IOException {
856    InputStream in1 = null;
857    InputStream in2 = null;
858    try {
859      in1 = new BufferedInputStream(new FileInputStream(f1));
860      in2 = new BufferedInputStream(new FileInputStream(f2));
861
862      int expectedByte = in1.read();
863      while (expectedByte != -1) {
864        boolean w1 = isWhitespace(expectedByte);
865        if (w1)
866          while (isWhitespace(expectedByte))
867            expectedByte = in1.read();
868        int foundByte = in2.read();
869        if (w1) {
870          if (!isWhitespace(foundByte))
871            return false;
872          while (isWhitespace(foundByte))
873            foundByte = in2.read();
874        }
875        if (expectedByte != foundByte) 
876          return false;
877        expectedByte = in1.read();
878      }
879      if (in2.read() != -1) {
880        return false;
881      }
882      return true;
883    } finally {
884      if (in1 != null) {
885        try {
886          in1.close();
887        } catch (IOException e) {}
888      }
889      if (in2 != null) {
890        try {
891          in2.close();
892        } catch (IOException e) {}
893      }
894    }
895  }
896  
897  private static boolean isWhitespace(int b) {
898    return b == 9 || b == 10 || b == 13 || b == 32;
899  }
900
901
902  public static boolean compareIgnoreWhitespace(String fn1, String fn2) throws IOException {
903    return compareIgnoreWhitespace(new File(fn1), new File(fn2));
904  }
905
906
907  public static boolean isAbsoluteUrl(String ref) {
908    return ref.startsWith("http:") || ref.startsWith("https:") || ref.startsWith("urn:uuid:") || ref.startsWith("urn:oid:") ;
909  }
910
911
912}