Return-Path: X-Original-To: apmail-chemistry-commits-archive@www.apache.org Delivered-To: apmail-chemistry-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id CB35C179AC for ; Mon, 6 Apr 2015 17:14:12 +0000 (UTC) Received: (qmail 51203 invoked by uid 500); 6 Apr 2015 17:14:12 -0000 Delivered-To: apmail-chemistry-commits-archive@chemistry.apache.org Received: (qmail 51069 invoked by uid 500); 6 Apr 2015 17:14:12 -0000 Mailing-List: contact commits-help@chemistry.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@chemistry.apache.org Delivered-To: mailing list commits@chemistry.apache.org Received: (qmail 50637 invoked by uid 99); 6 Apr 2015 17:14:12 -0000 Received: from eris.apache.org (HELO hades.apache.org) (140.211.11.105) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 06 Apr 2015 17:14:12 +0000 Received: from hades.apache.org (localhost [127.0.0.1]) by hades.apache.org (ASF Mail Server at hades.apache.org) with ESMTP id 56800AC0E2D for ; Mon, 6 Apr 2015 17:14:12 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r946533 [7/10] - in /websites/staging/chemistry/trunk/content: ./ java/0.13.0/maven/chemistry-opencmis-test/ java/0.13.0/maven/chemistry-opencmis-test/chemistry-opencmis-test-util/ java/0.13.0/maven/chemistry-opencmis-test/chemistry-opencmi... Date: Mon, 06 Apr 2015 17:14:11 -0000 To: commits@chemistry.apache.org From: buildbot@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20150406171412.56800AC0E2D@hades.apache.org> Added: websites/staging/chemistry/trunk/content/java/0.13.0/maven/chemistry-opencmis-test/chemistry-opencmis-test-util/xref/org/apache/chemistry/opencmis/util/content/loremipsum/LoremIpsum.html ============================================================================== --- websites/staging/chemistry/trunk/content/java/0.13.0/maven/chemistry-opencmis-test/chemistry-opencmis-test-util/xref/org/apache/chemistry/opencmis/util/content/loremipsum/LoremIpsum.html (added) +++ websites/staging/chemistry/trunk/content/java/0.13.0/maven/chemistry-opencmis-test/chemistry-opencmis-test-util/xref/org/apache/chemistry/opencmis/util/content/loremipsum/LoremIpsum.html Mon Apr 6 17:14:10 2015 @@ -0,0 +1,1189 @@ + + + + +LoremIpsum xref + + + +
+
+1   /*
+2    * Licensed to the Apache Software Foundation (ASF) under one
+3    * or more contributor license agreements.  See the NOTICE file
+4    * distributed with this work for additional information
+5    * regarding copyright ownership.  The ASF licenses this file
+6    * to you under the Apache License, Version 2.0 (the
+7    * "License"); you may not use this file except in compliance
+8    * with the License.  You may obtain a copy of the License at
+9    *
+10   * http://www.apache.org/licenses/LICENSE-2.0
+11   *
+12   * Unless required by applicable law or agreed to in writing,
+13   * software distributed under the License is distributed on an
+14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+15   * KIND, either express or implied.  See the License for the
+16   * specific language governing permissions and limitations
+17   * under the License.
+18   */
+19  package org.apache.chemistry.opencmis.util.content.loremipsum;
+20  
+21  import java.io.IOException;
+22  import java.io.StringWriter;
+23  import java.util.ArrayList;
+24  import java.util.Arrays;
+25  import java.util.HashMap;
+26  import java.util.HashSet;
+27  import java.util.List;
+28  import java.util.Map;
+29  import java.util.Random;
+30  import java.util.Set;
+31  
+32  /**
+33   * A generator of lorem ipsum text ported from the Python implementation at
+34   * http://code.google.com/p/lorem-ipsum-generator/. Note: original code licensed
+35   * under the BSD license
+36   * 
+37   */
+38  public class LoremIpsum {
+39  
+40      private static class WordLengthPair {
+41          public int len1;
+42          public int len2;
+43  
+44          public WordLengthPair(int len1, int len2) {
+45              this.len1 = len1;
+46              this.len2 = len2;
+47          }
+48  
+49          @Override
+50          public String toString() {
+51              return "WordLengthPair: len1: " + len1 + ", len2: " + len2;
+52          }
+53  
+54          @Override
+55          public boolean equals(Object other) {
+56              if (this == null || other == null) {
+57                  return false;
+58              }
+59              if (other.getClass() != getClass()) {
+60                  return false;
+61              }
+62  
+63              return (len1 == ((WordLengthPair) other).len1 && len2 == ((WordLengthPair) other).len2);
+64          }
+65  
+66          @Override
+67          public int hashCode() {
+68              return len1 ^ len2;
+69          }
+70      }
+71  
+72      /**
+73       * Delimiters that end sentences.
+74       * 
+75       * @type {Array.<string>}
+76       * @private
+77       */
+78      private static final String DELIMITERS_SENTENCES[] = { ".", "?", "!" };
+79  
+80      /**
+81       * Regular expression for splitting a text into sentences.
+82       * 
+83       * @type {RegExp}
+84       * @private
+85       */
+86      private static final String SENTENCE_SPLIT_REGEX = "[\\.\\?\\!]";
+87  
+88      /**
+89       * Delimiters that end words.
+90       * 
+91       * @type {Array.<string>}
+92       * @private
+93       */
+94      private static final String DELIMITERS_WORDS[] = { ".", ",", "?", "!" };
+95  
+96      /**
+97       * Regular expression for splitting text into words.
+98       * 
+99       * @type {RegExp}
+100      * @private
+101      */
+102     private static final String WORD_SPLIT_REGEX = "\\s";
+103 
+104     private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+105 
+106     /**
+107      * Words that can be used in the generated output. Maps a word-length to a
+108      * list of words of that length.
+109      * 
+110      * @type {goog.structs.Map}
+111      * @private
+112      */
+113     private Map<Integer, List<String>> words;
+114 
+115     /**
+116      * Chains of three words that appear in the sample text Maps a pair of
+117      * word-lengths to a third word-length and an optional piece of trailing
+118      * punctuation (for example, a period, comma, etc.).
+119      * 
+120      * @type {goog.structs.Map}
+121      * @private
+122      */
+123     private Map<WordLengthPair, List<WordInfo>> chains;
+124 
+125     /**
+126      * Pairs of word-lengths that can appear at the beginning of sentences.
+127      * 
+128      * @type {Array}
+129      */
+130     private List<WordLengthPair> starts;
+131 
+132     /**
+133      * Average sentence length in words.
+134      * 
+135      * @type {number}
+136      * @private
+137      */
+138     private double sentenceMean;
+139 
+140     /**
+141      * Sigma (sqrt of Objectiance) for the sentence length in words.
+142      * 
+143      * @type {number}
+144      * @private
+145      */
+146     private double sentenceSigma;
+147 
+148     /**
+149      * Average paragraph length in sentences.
+150      * 
+151      * @type {number}
+152      * @private
+153      */
+154     private double paragraphMean;
+155 
+156     /**
+157      * Sigma (sqrt of variance) for the paragraph length in sentences.
+158      * 
+159      * @type {number}
+160      * @private
+161      */
+162     private double paragraphSigma;
+163 
+164     /**
+165      * Sample that the generated text is based on .
+166      * 
+167      * @type {string}
+168      */
+169     private String sample = SAMPLE;
+170 
+171     /**
+172      * Dictionary of words.
+173      * 
+174      * @type {string}
+175      */
+176     private String dictionary = DICT;
+177 
+178     /**
+179      * Picks a random element of the array.
+180      * 
+181      * @param {Array} array The array to pick from.
+182      * @return {*} An element from the array.
+183      */
+184     private WordInfo randomChoice(WordInfo[] array) {
+185         return array[randomInt(array.length)];
+186     };
+187 
+188     private String randomChoice(String[] array) {
+189         return array[randomInt(array.length)];
+190     };
+191 
+192     private int randomInt(int length) {
+193         return randomGenerator.nextInt(length);
+194     }
+195 
+196     private static class WordInfo {
+197         int len;
+198         String delim;
+199     }
+200 
+201     private Random randomGenerator = new Random();
+202 
+203     /**
+204      * Generates random strings of "lorem ipsum" text, based on the word
+205      * distribution of a sample text, using the words in a dictionary.
+206      * 
+207      * @constructor
+208      */
+209     public LoremIpsum() {
+210         generateChains(this.sample);
+211         generateStatistics(this.sample);
+212         initializeDictionary(this.dictionary);
+213     };
+214 
+215     public LoremIpsum(String sample, String dictionary) {
+216         this.sample = sample;
+217         this.dictionary = dictionary;
+218         generateChains(this.sample);
+219         generateStatistics(this.sample);
+220         initializeDictionary(this.dictionary);
+221     };
+222 
+223     public LoremIpsum(String sample, String[] newDictionary) {
+224         this.sample = sample;
+225         this.dictionary = null;
+226         generateChains(this.sample);
+227         generateStatistics(this.sample);
+228         initializeDictionary(newDictionary);
+229     };
+230 
+231     public LoremIpsum(String sample) {
+232         this.sample = sample;
+233         String[] dictWords = filterNotEmptyOrWhiteSpace(sample.split("[^\\p{L}]"/* "\\W" */)).toArray(new String[0]);
+234         Set<String> dict = new HashSet<String>(Arrays.asList(dictWords));
+235         dictWords = dict.toArray(new String[0]);
+236         Arrays.sort(dictWords);
+237 
+238         generateChains(this.sample);
+239         generateStatistics(this.sample);
+240         initializeDictionary(dictWords);
+241     };
+242 
+243     /**
+244      * Generates a single lorem ipsum paragraph, of random length.
+245      * 
+246      * @param {boolean} optStartWithLorem Whether to start the sentence with the
+247      *        standard "Lorem ipsum..." first sentence.
+248      * @return {string} The generated sentence.
+249      */
+250     public String generateParagraph(boolean optStartWithLorem) {
+251         // The length of the paragraph is a normally distributed random
+252         // Objectiable.
+253         Double paragraphLengthDbl = randomNormal(this.paragraphMean, this.paragraphSigma);
+254         int paragraphLength = Math.max((int) Math.floor(paragraphLengthDbl), 1);
+255 
+256         // Construct a paragraph from a number of sentences.
+257         List<String> paragraph = new ArrayList<String>();
+258         boolean startWithLorem = optStartWithLorem;
+259         while (paragraph.size() < paragraphLength) {
+260             String sentence = this.generateSentence(startWithLorem);
+261             paragraph.add(sentence);
+262             startWithLorem = false;
+263         }
+264 
+265         StringBuffer result = new StringBuffer();
+266         // Form the paragraph into a string.
+267         for (String sentence : paragraph) {
+268             result.append(sentence);
+269             result.append(" ");
+270         }
+271         return result.toString();
+272     }
+273 
+274     /**
+275      * Generates a single sentence, of random length.
+276      * 
+277      * @param {boolean} optStartWithLorem Whether to start the setnence with the
+278      *        standard "Lorem ipsum..." first sentence.
+279      * @return {string} The generated sentence.
+280      */
+281     public String generateSentence(boolean optStartWithLorem) {
+282         if (this.chains.size() == 0 || this.starts.size() == 0) {
+283             throw new RuntimeException("No chains created (Invalid sample text?)");
+284         }
+285 
+286         if (this.words.size() == 0) {
+287             throw new RuntimeException("No dictionary");
+288         }
+289 
+290         // The length of the sentence is a normally distributed random
+291         // Objectiable.
+292         double sentenceLengthDbl = randomNormal(this.sentenceMean, this.sentenceSigma);
+293         int sentenceLength = Math.max((int) Math.floor(sentenceLengthDbl), 1);
+294 
+295         String wordDelimiter = ""; // Defined here in case while loop doesn't
+296                                    // run
+297 
+298         // Start the sentence with "Lorem ipsum...", if desired
+299         List<String> sentence;
+300 
+301         if (optStartWithLorem) {
+302             String lorem = "lorem ipsum dolor sit amet, consecteteur adipiscing elit";
+303             sentence = new ArrayList<String>(Arrays.asList(splitWords(lorem)));
+304             if (sentence.size() > sentenceLength) {
+305                 sentence.subList(0, sentenceLength);
+306             }
+307             String lastWord = sentence.get(sentence.size() - 1);
+308             String lastChar = lastWord.substring(lastWord.length() - 1);
+309             if (contains(DELIMITERS_WORDS, lastChar)) {
+310                 wordDelimiter = lastChar;
+311             }
+312         } else {
+313             sentence = new ArrayList<String>();
+314         }
+315 
+316         WordLengthPair previous = new WordLengthPair(0, 0);
+317 
+318         // Generate a sentence from the "chains"
+319         while (sentence.size() < sentenceLength) {
+320             // If the current starting point is invalid, choose another randomly
+321             if (!this.chains.containsKey(previous)) {
+322                 previous = this.chooseRandomStart_();
+323             }
+324 
+325             // Choose the next "chain" to go to. This determines the next word
+326             // length we use, and whether there is e.g. a comma at the end of
+327             // the word.
+328             WordInfo chain = randomChoice(this.chains.get(previous).toArray(new WordInfo[0]));
+329             int wordLength = chain.len;
+330 
+331             // If the word delimiter contained in the chain is also a sentence
+332             // delimiter, then we don"t include it because we don"t want the
+333             // sentence to end prematurely (we want the length to match the
+334             // sentence_length value).
+335             if (contains(DELIMITERS_SENTENCES, chain.delim)) {
+336                 wordDelimiter = "";
+337             } else {
+338                 wordDelimiter = chain.delim;
+339             }
+340 
+341             // Choose a word randomly that matches (or closely matches) the
+342             // length we're after.
+343             int closestLength = chooseClosest(this.words.keySet().toArray(new Integer[0]), wordLength);
+344             String word = randomChoice(this.words.get(closestLength).toArray(new String[0]));
+345 
+346             sentence.add(word + wordDelimiter);
+347             previous = new WordLengthPair(previous.len2, wordLength);
+348 
+349         }
+350 
+351         // Finish the sentence off with capitalisation, a period and
+352         // form it into a string
+353         StringBuffer result = new StringBuffer();
+354         for (String s : sentence) {
+355             result.append(s);
+356             result.append(" ");
+357         }
+358         result.deleteCharAt(result.length() - 1);
+359 
+360         result.replace(0, 1, result.substring(0, 1).toUpperCase());
+361         int strLen = result.length() - 1;
+362         if (wordDelimiter.length() > 0 && wordDelimiter.charAt(0) == result.charAt(strLen)) {
+363             result.deleteCharAt(strLen);
+364         }
+365         result.append(".");
+366         return result.toString();
+367     }
+368 
+369     public String getSample() {
+370         return sample;
+371     }
+372 
+373     public void setSample(String sample) {
+374         this.sample = sample;
+375         generateChains(this.sample);
+376         generateStatistics(this.sample);
+377     }
+378 
+379     public String getDictionary() {
+380         return dictionary;
+381     }
+382 
+383     public void setDictionary(String dictionary) {
+384         this.dictionary = dictionary;
+385         initializeDictionary(this.dictionary);
+386     }
+387 
+388     /**
+389      * Generates multiple paragraphs of text, with begin before the paragraphs,
+390      * end after the paragraphs, and between between each two paragraphs.
+391      */
+392     private String generateMarkupParagraphs(String begin, String end, String between, int quantity,
+393             boolean startWithLorem) {
+394 
+395         StringBuffer text = new StringBuffer();
+396 
+397         text.append(begin);
+398         String para = generateParagraph(startWithLorem);
+399         text.append(para);
+400         while (text.length() < quantity) {
+401             para = generateParagraph(false);
+402             text.append(para);
+403             if (text.length() < quantity) {
+404                 text.append(between);
+405             }
+406         }
+407 
+408         text.append(end);
+409         return text.toString();
+410     }
+411 
+412     /**
+413      * Generates multiple paragraphs of text, with begin before the paragraphs,
+414      * end after the paragraphs, and between between each two paragraphs.
+415      * 
+416      * @throws IOException
+417      */
+418     private void generateMarkupParagraphs(Appendable writer, String begin, String end, String between, int quantity,
+419             boolean startWithLorem) throws IOException {
+420 
+421         int len = begin.length();
+422         writer.append(begin);
+423         String para = generateParagraph(startWithLorem);
+424         len += para.length();
+425         writer.append(para);
+426         while (len < quantity) {
+427             para = generateParagraph(false);
+428             len += para.length();
+429             writer.append(para);
+430             if (len < quantity) {
+431                 writer.append(between);
+432                 len += para.length();
+433             }
+434         }
+435 
+436         writer.append(end);
+437     }
+438 
+439     /**
+440      * Generates multiple sentences of text, with begin before the sentences,
+441      * end after the sentences, and between between each two sentences.
+442      */
+443     private String generateMarkupSentences(String begin, String end, String between, int quantity,
+444             boolean startWithLorem) {
+445 
+446         StringBuffer text = new StringBuffer();
+447         text.append(begin);
+448         String sentence = generateSentence(startWithLorem);
+449         text.append(sentence);
+450 
+451         while (text.length() < quantity) {
+452             sentence = generateSentence(false);
+453             text.append(sentence);
+454             if (text.length() < quantity) {
+455                 text.append(between);
+456             }
+457         }
+458 
+459         text.append(end);
+460         return text.toString();
+461     }
+462 
+463     /**
+464      * Generates the chains and starts values required for sentence generation.
+465      * 
+466      * @param {string} sample The same text.
+467      * @private
+468      */
+469     private void generateChains(String sample) {
+470 
+471         String[] words = splitWords(sample);
+472         WordInfo[] wordInfos = generateWordInfo(words);
+473         WordLengthPair previous = new WordLengthPair(0, 0);
+474         List<WordLengthPair> starts = new ArrayList<WordLengthPair>();
+475         List<String> delimList = Arrays.asList(DELIMITERS_SENTENCES);
+476         Map<WordLengthPair, List<WordInfo>> chains = new HashMap<WordLengthPair, List<WordInfo>>();
+477 
+478         for (WordInfo wi : wordInfos) {
+479             if (wi.len == 0) {
+480                 continue;
+481             }
+482 
+483             List<WordInfo> value = chains.get(previous);
+484             if (null == value) {
+485                 chains.put(previous, new ArrayList<WordInfo>());
+486             } else {
+487                 chains.get(previous).add(wi);
+488             }
+489 
+490             if (delimList.contains(wi.delim)) {
+491                 starts.add(previous);
+492             }
+493 
+494             previous.len1 = previous.len2;
+495             previous.len2 = wi.len;
+496         }
+497 
+498         if (chains.isEmpty()) {
+499             throw new RuntimeException("Invalid sample text.");
+500         }
+501 
+502         this.chains = chains;
+503         this.starts = starts;
+504     }
+505 
+506     /**
+507      * Calculates the mean and standard deviation of sentence and paragraph
+508      * lengths.
+509      * 
+510      * @param {string} sample The same text.
+511      * @private
+512      */
+513     private void generateStatistics(String sample) {
+514         this.generateSentenceStatistics(sample);
+515         this.generateParagraphStatistics(sample);
+516     }
+517 
+518     /**
+519      * Calculates the mean and standard deviation of the lengths of sentences
+520      * (in words) in a sample text.
+521      * 
+522      * @param {string} sample The same text.
+523      * @private
+524      */
+525     private void generateSentenceStatistics(String sample) {
+526         List<String> sentences = filterNotEmptyOrWhiteSpace(splitSentences(sample));
+527         int sentenceLengths[] = new int[sentences.size()];
+528         for (int i = 0; i < sentences.size(); i++) {
+529             String[] words = splitWords(sentences.get(i));
+530             sentenceLengths[i] = words.length;
+531         }
+532         this.sentenceMean = mean(sentenceLengths);
+533         this.sentenceSigma = sigma(sentenceLengths);
+534     }
+535 
+536     /**
+537      * Calculates the mean and standard deviation of the lengths of paragraphs
+538      * (in sentences) in a sample text.
+539      * 
+540      * @param {string} sample The same text.
+541      * @private
+542      */
+543     private void generateParagraphStatistics(String sample) {
+544         List<String> paragraphs = filterNotEmptyOrWhiteSpace(splitParagraphs(sample));
+545 
+546         int paragraphLengths[] = new int[paragraphs.size()];
+547         for (int i = 0; i < paragraphs.size(); i++) {
+548             String[] sentences = splitSentences(paragraphs.get(i));
+549             paragraphLengths[i] = sentences.length;
+550         }
+551 
+552         this.paragraphMean = mean(paragraphLengths);
+553         this.paragraphSigma = sigma(paragraphLengths);
+554     }
+555 
+556     /**
+557      * Sets the generator to use a given selection of words for generating
+558      * sentences with.
+559      * 
+560      * @param {string} dictionary The dictionary to use.
+561      */
+562     private void initializeDictionary(String dictionary) {
+563         String[] dictionaryWords = splitWords(dictionary);
+564         initializeDictionary(dictionaryWords);
+565     }
+566 
+567     private void initializeDictionary(String[] dictionaryWords) {
+568         words = new HashMap<Integer, List<String>>();
+569         for (String word : dictionaryWords) {
+570             List<String> wordWithLen = words.get(word.length());
+571             if (null == wordWithLen) {
+572                 List<String> list = new ArrayList<String>();
+573                 list.add(word);
+574                 words.put(word.length(), list);
+575             } else {
+576                 wordWithLen.add(word);
+577             }
+578         }
+579 
+580         if (words.size() == 0) {
+581             throw new RuntimeException("Invalid dictionary.");
+582         }
+583     }
+584 
+585     /**
+586      * Picks a random starting chain.
+587      * 
+588      * @return {string} The starting key.
+589      * @private
+590      */
+591     private WordLengthPair chooseRandomStart_() {
+592         Set<WordLengthPair> keys = chains.keySet();
+593         Set<WordLengthPair> validStarts = new HashSet<WordLengthPair>(starts);
+594         validStarts.retainAll(keys);
+595         int index = randomInt(validStarts.size());
+596         WordLengthPair wlPair = validStarts.toArray(new WordLengthPair[0])[index];
+597         return wlPair;
+598     }
+599 
+600     /**
+601      * Splits a piece of text into paragraphs.
+602      * 
+603      * @param {string} text The text to split.
+604      * @return {Array.<string>} An array of paragraphs.
+605      * @private
+606      */
+607 
+608     static String[] splitParagraphs(String text) {
+609         return filterNotEmptyOrWhiteSpace(text.split("\n")).toArray(new String[0]);
+610     }
+611 
+612     /**
+613      * Splits a piece of text into sentences.
+614      * 
+615      * @param {string} text The text to split.
+616      * @return {Array.<string>} An array of sentences.
+617      * @private
+618      */
+619     static String[] splitSentences(String text) {
+620         return filterNotEmptyOrWhiteSpace(text.split(SENTENCE_SPLIT_REGEX)).toArray(new String[0]);
+621     }
+622 
+623     /**
+624      * Splits a piece of text into words..
+625      * 
+626      * @param {string} text The text to split.
+627      * @return {Array.<string>} An array of words.
+628      * @private
+629      */
+630     static String[] splitWords(String text) {
+631         return filterNotEmptyOrWhiteSpace(text.split(WORD_SPLIT_REGEX)).toArray(new String[0]);
+632     }
+633 
+634     /**
+635      * Find the number in the list of values that is closest to the target.
+636      * 
+637      * @param {Array.<number>} values The values.
+638      * @param {number} target The target value.
+639      * @return {number} The closest value.
+640      */
+641     static int chooseClosest(Integer[] values, int target) {
+642         int closest = values[0];
+643         for (int value : values) {
+644             if (Math.abs(target - value) < Math.abs(target - closest)) {
+645                 closest = value;
+646             }
+647         }
+648 
+649         return closest;
+650     }
+651 
+652     /**
+653      * Gets info about a word used as part of the lorem ipsum algorithm.
+654      * 
+655      * @param {string} word The word to check.
+656      * @return {Array} A two element array. The first element is the size of the
+657      *         word. The second element is the delimiter used in the word.
+658      * @private
+659      */
+660     private static WordInfo getWordInfo(String word) {
+661         WordInfo ret = new WordInfo();
+662         for (String delim : DELIMITERS_WORDS) {
+663             if (word.endsWith(delim)) {
+664                 ret.len = word.length() - delim.length();
+665                 ret.delim = delim;
+666                 return ret;
+667             }
+668         }
+669         ret.len = word.length();
+670         ret.delim = "";
+671         return ret;
+672     }
+673 
+674     private static WordInfo[] generateWordInfo(String[] words) {
+675         WordInfo[] result = new WordInfo[words.length];
+676         int i = 0;
+677         for (String word : words) {
+678             result[i++] = getWordInfo(word);
+679         }
+680         return result;
+681     }
+682 
+683     /**
+684      * Constant used for {@link #randomNormal_}.
+685      * 
+686      * @type {number}
+687      * @private
+688      */
+689     private static final double NV_MAGICCONST_ = 4 * Math.exp(-0.5) / Math.sqrt(2.0);
+690 
+691     /**
+692      * Generates a random number for a normal distribution with the specified
+693      * mean and sigma.
+694      * 
+695      * @param {number} mu The mean of the distribution.
+696      * @param {number} sigma The sigma of the distribution.
+697      * @private
+698      */
+699     private static double randomNormal(double mu, double sigma) {
+700         double z = 0.0d;
+701         while (true) {
+702             double u1 = Math.random();
+703             double u2 = 1.0d - Math.random();
+704             z = NV_MAGICCONST_ * (u1 - 0.5d) / u2;
+705             double zz = z * z / 4.0d;
+706             if (zz <= -Math.log(u2)) {
+707                 break;
+708             }
+709         }
+710         return mu + z * sigma;
+711     }
+712 
+713     /**
+714      * Returns the text if it is not empty or just whitespace.
+715      * 
+716      * @param {string} text the text to check.
+717      * @return {boolean} Whether the text is neither empty nor whitespace.
+718      * @private
+719      */

[... 461 lines stripped ...]