You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by jm...@apache.org on 2014/08/28 02:58:15 UTC

[10/21] remove Adobe from directory names (package name still contains Adobe)

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/SuggestionManager.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/SuggestionManager.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/SuggestionManager.as
new file mode 100644
index 0000000..f792b5d
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/SuggestionManager.as
@@ -0,0 +1,1026 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package com.adobe.linguistics.spelling.core
+{
+	import com.adobe.linguistics.spelling.core.env.InternalConstants;
+	import com.adobe.linguistics.spelling.core.rule.PrefixEntry;
+	import com.adobe.linguistics.spelling.core.rule.SuffixEntry;
+	import com.adobe.linguistics.spelling.core.utils.*;
+	
+	import flash.utils.Dictionary;
+	import flash.utils.getTimer;
+	
+	public class SuggestionManager
+	{
+		
+		private var _attributeMgr:LinguisticRule;
+		private var _maxSug:int;
+		private var _languageCode:String;
+		private var _ckey:String;
+		private var _cUpperTry:String;
+		private var _cLowerTry:String;
+		private var _cAllTry:String;
+		private var _maxngramsugs:int;
+		private var _fastMode:Boolean;
+		
+		private var _word:String;
+		private var _guessSuggestions:SuggestionsResult;
+		private var _guessWordList:SuggestionsResult;
+		private var guess:Array = new Array (InternalConstants.MAX_GUESS);
+		private var gscore:Array = new Array ( InternalConstants.MAX_GUESS);
+		
+		public function SuggestionManager( attrMgr:LinguisticRule, fastMode:Boolean = true )
+		{
+			this._maxSug = InternalConstants.MAXSUGGESTION;
+			this._attributeMgr = attrMgr;
+			this._ckey = this._attributeMgr.keyString;
+
+			this._cAllTry  = this._attributeMgr.tryString;
+			this._cUpperTry = "";
+			this._cLowerTry = ""; // lower and netual...
+			for ( var i:int = 0; (this._attributeMgr.tryString != null)&&(i < this._attributeMgr.tryString.length); ++i ) {
+				if ( this._attributeMgr.tryString.charAt(i) == this._attributeMgr.tryString.charAt(i).toLocaleLowerCase() ) {
+					this._cLowerTry+=this._attributeMgr.tryString.charAt(i);
+				} else {
+					this._cUpperTry+= this._attributeMgr.tryString.charAt(i);
+				}
+				
+			}
+
+			this._maxngramsugs = InternalConstants.MAXNGRAMSUGS;
+			this._fastMode = fastMode;
+			
+			//initialized viriable for performance...
+			_word=null;
+			_guessSuggestions = new SuggestionsResult(InternalConstants.MAX_ROOTS, compareSuggestion );
+			_guessWordList = new SuggestionsResult( InternalConstants.MAX_GUESS, compareSuggestion );
+			if ( this._attributeMgr.maxNgramSuggestions > 0 ) this._maxngramsugs = this._attributeMgr.maxNgramSuggestions;
+		}
+		
+		public function get fastMode():Boolean {
+			return this._fastMode;
+		}
+		
+		public function set fastMode( value:Boolean ) :void {
+			this._fastMode = value;
+		}
+		
+		private static function compareSuggestion( obj1:*, obj2:*):int {
+			return (obj1.score-obj2.score);
+		}
+		
+		
+		public function set languageCode(value:String) :void {
+			this._languageCode = value;	
+		}
+		
+		public function get languageCode():String {
+			return this._languageCode;
+		}
+		
+		public function nsuggest( result:Array, word:String ):int {
+
+			if ( !((result.length+this._maxngramsugs) <= this._maxSug) ) return result.length;
+
+
+			var nsug:int = result.length;
+			var i:int,j:int,sc:int, opt:int, n:int = word.length;
+			var arr:Array;
+			var sd:SquigglyDictionary;
+			var dict:Dictionary;
+			_word = word;
+			var initCap:Boolean = (word.charAt(0) == word.charAt(0).toLocaleLowerCase() )? false:true;
+			var wordCapValue:int = word.charAt(0).toLocaleUpperCase().charCodeAt(0);
+			_guessSuggestions.clear();
+			
+			/* A filter based on string length, it could be */
+			var rangeOffset:int =5;
+			var endRange:int = word.length + (rangeOffset-2);
+			var startRange:int =  (word.length>(rangeOffset+2)) ? (word.length-rangeOffset):2  ;
+	
+					var counter:Number=0
+					var startTime:Number = getTimer();
+
+			// exhaustively search through all root words
+			// keeping track of the MAX_ROOTS most similar root words
+			
+			// word reversing wrapper for complex prefixes
+			
+			// set character based ngram suggestion for words with non-BMP Unicode characters
+			
+			//a filter for performance improvement...
+			var firstCodeValue:Number =word.charCodeAt(0), lastCodeValue:Number = word.charCodeAt(word.length-1);
+			
+			
+			for ( i=0;i<this._attributeMgr.dictionaryManager.dictonaryList.length; ++i ) {
+				sd = this._attributeMgr.dictionaryManager.dictonaryList[i];
+				dict = sd.dictionary;
+				
+				var lowerS:String;
+				var he:HashEntry;
+				opt = InternalConstants.NGRAM_LONGER_WORSE + InternalConstants.NGRAM_LOWERING;
+				for( var key:String in dict ) {
+					if ( (key.length < startRange) || (key.length > endRange) ) continue;
+					if ( (this._fastMode) && (firstCodeValue != key.charCodeAt(0)) && (lastCodeValue != key.charCodeAt(key.length-1)) ) continue;
+					counter++;
+
+					sc = ngram( 3, _word,key,opt) + leftCommonSubString(_word, key, initCap, wordCapValue);
+					
+					if ( sc > 0  ) {
+						if ( _guessSuggestions.size < InternalConstants.MAX_ROOTS ) {
+							if ( dict[key].affixFlagVector && 
+								(dict[key].testAffix( this._attributeMgr.forbiddenWord ) ||
+								dict[key].testAffix( this._attributeMgr.onlyInCompound) ||
+								dict[key].testAffix( this._attributeMgr.noSuggest ) ||
+								dict[key].testAffix( InternalConstants.ONLYUPCASEFLAG )
+								)) continue; 
+							_guessSuggestions.insert( new SuggestionEntry(sc,key, dict[key] ) );
+							if ( _guessSuggestions.size == InternalConstants.MAX_ROOTS ) {
+								_guessSuggestions.buildheap();
+							}
+						}else {
+							if ( sc > _guessSuggestions.front.score ) {
+								_guessSuggestions.front.score = sc;
+								_guessSuggestions.front.key =  key;
+								_guessSuggestions.front.hashEntry = dict[key];
+								_guessSuggestions.updateFront();
+							}
+						}
+					}
+				}
+			}
+			
+			var thresh:int = 0;
+			var mw:String;
+			for ( var sp:int = 1; sp < 4; ++sp) {
+				mw = word;
+				for ( var k:int=sp; k<n; k+=4) {
+					mw = mw.substring(0,k) + "*" + mw.substring(k+1);
+				}
+				thresh = thresh + ngram( n, word, mw, InternalConstants.NGRAM_ANY_MISMATCH + InternalConstants.NGRAM_LOWERING);
+			}
+			thresh = thresh /3;
+			thresh --;
+
+			// now expand affixes on each of these root words and
+			// and use length adjusted ngram scores to select
+			// possible suggestions
+			_guessWordList.clear();
+
+
+			//work arround for inconsitent ordered Dictionary table. bof
+			if ( _guessSuggestions.isEmpty() ) return result.length;
+			var lowestScore:int = _guessSuggestions.front.score;
+			var indexArr:Array;
+			if ( _guessSuggestions.size != _guessSuggestions.maxSize ){
+				indexArr=_guessSuggestions.data.slice(0,_guessSuggestions.size).sortOn("key",Array.DESCENDING | Array.RETURNINDEXEDARRAY);
+			}else{
+				indexArr=_guessSuggestions.data.sortOn("key",Array.DESCENDING | Array.RETURNINDEXEDARRAY);
+			}
+			//work arround for inconsitent ordered Dictionary table. bof
+
+			// root list;
+			for each ( i in indexArr ) {
+				//work arround for inconsitent ordered Dictionary table. bof
+				if ( i==0 || _guessSuggestions.data[i].score == lowestScore ) continue;
+				//work arround for inconsitent ordered Dictionary table. bof
+				
+				var candList:Array = new Array();
+				var candOriginalList:Array = new Array();
+				expandRootWord(candList,candOriginalList, InternalConstants.MAX_WORDS, _guessSuggestions.data[i].key, _guessSuggestions.data[i].hashEntry, word );
+				for ( j=0; j < candList.length; ++j) {
+					sc = ngram ( n, word, candList[j], InternalConstants.NGRAM_ANY_MISMATCH + InternalConstants.NGRAM_LOWERING) + leftCommonSubString(word, candList[j],initCap, wordCapValue);
+					if ( (sc>thresh) ) {
+						if ( _guessWordList.size < InternalConstants.MAX_GUESS ) {
+							_guessWordList.insert( new GuessWord(sc,candList[j], null ) );
+							if ( _guessWordList.size == InternalConstants.MAX_GUESS ) {
+								_guessWordList.buildheap();
+							}
+						}else {
+							if ( sc > _guessWordList.front.score ) {
+								_guessWordList.front.score = sc;
+								_guessWordList.front.key =  candList[j];
+								_guessWordList.front.original = null;
+								_guessWordList.updateFront();
+							}
+						}
+						
+					}
+				}
+			}
+
+			// now we are done generating guesses
+			// sort in order of decreasing score
+			var guessArr:Array = _guessWordList.toArray().sortOn("score",Array.NUMERIC | Array.DESCENDING);
+
+
+			// weight suggestions with a similarity index, based on
+			// the longest common subsequent algorithm and resort
+			var refobj:RefObject = new RefObject(0);
+			var gl:String;
+			for ( i=guessArr.length-1;i>= 0; --i ) {
+				gl = guessArr[i].key.toLocaleLowerCase();
+				var _lcs:int = StringUtils.lcslen(word, gl);
+				// same characters with different casing
+				if ( (n==gl.length) && (n == _lcs) ) {
+					guessArr[i].score += 2000;
+					break;
+				}
+				// heuristic weigthing of ngram scores
+				guessArr[i].score += 
+					// length of longest common subsequent minus length difference
+					2 * _lcs - Math.abs((int) (n - guessArr[i].key.length)) +
+					// weight length of the left common substring
+					leftCommonSubString(word, gl,initCap, wordCapValue) +
+					// weight equal character positions
+					((_lcs == StringUtils.commonCharacterPositions(word, gl, refobj)) ? 1: 0) +
+					// swap character (not neighboring)
+					((refobj.ref) ? 1000 : 0);
+			}
+
+			guessArr = guessArr.sortOn("score", Array.NUMERIC | Array.DESCENDING);
+			
+			
+			// copy over
+			var oldnsug:int = nsug;
+			var same:int = 0;
+			for ( i=0;i< guessArr.length; ++i ) {
+				if ( (nsug < this._maxSug) && (result.length < (oldnsug + this._maxngramsugs)) && (!same || (guessArr[i].score > 1000)) ) {
+					var unique:int = 1;
+					// leave only excellent suggestions, if exists
+					if ( guessArr[i].score > 1000 ) same = 1;
+					// don't suggest previous suggestions or a previous suggestion with prefixes or affixes
+					for ( j=0;j< result.length; ++j) {
+						if ( ( guessArr[i].key.indexOf(result[j]) != -1) || !checkWord(guessArr[i].key) ) unique = 0;
+					}
+					if ( unique ) {
+						result.push( guessArr[i].key );
+					}
+				}
+				
+			}
+			
+					var endTime:Number = getTimer();
+			return nsug;
+		}
+		
+		private function testValidSuggestion(element:*, gw:GuessWord):Boolean {
+			if ( gw.key.indexOf( element ) ) 
+				return false;
+			if ( !checkWord(element) ) return false; 
+			return true;
+		}
+
+		private function expandRootWord(guessWordList:Array, guessOriginalList:Array, maxn:int, root:String, he:HashEntry, badWord:String) :void {
+			// first add root word to list
+			var nh:int = 0, i:int, j:int;
+			var sfx:SuffixEntry;
+			var pfx:PrefixEntry;
+			var newWord:String;
+			var crossFlagArray:Array = new Array();
+			if ( (guessWordList.length < maxn) && 
+			!( (he.affixFlagVector != null) &&
+			( (this._attributeMgr.needAffix && he.testAffix(this._attributeMgr.needAffix)) || ( this._attributeMgr.onlyInCompound && he.testAffix(this._attributeMgr.onlyInCompound))))
+			){
+				guessWordList[nh] = root;
+				guessOriginalList[nh] = root;
+				crossFlagArray[nh] = false;
+				nh++;
+			}
+			
+			// handle suffixes
+			for ( i=0; (he.affixFlagVector !=null) && (i<he.affixFlagVector.length);++i) {
+				sfx= this._attributeMgr.suffixFlagTable[he.affixFlagVector.charAt(i)];
+				while( sfx  ) {
+					var index:int = badWord.lastIndexOf(sfx.affixKey);
+					if ( (index != -1) && ( index== (badWord.length-sfx.affixKey.length)) ) {
+						newWord = sfx.add(root);
+						if ( newWord) {
+							guessWordList[nh] = newWord;
+							guessOriginalList[nh] = root;
+							crossFlagArray[nh] = sfx.permissionToCombine;
+							nh++;
+						}
+					}
+					sfx = sfx.nextElementWithFlag; 
+				}
+			}
+			
+			// handle cross products of prefixes and suffixes
+			var n:int = nh;
+			for ( j=1;j<n;++j) {
+				if( crossFlagArray[j] ) {
+					for ( i=0;(he.affixFlagVector !=null) && (i<he.affixFlagVector.length);++i) {
+						pfx = this._attributeMgr.prefixFlagTable[he.affixFlagVector.charAt(i)];
+						while( pfx ) {
+							if ( badWord.indexOf(pfx.affixKey)== 0 ) {
+								newWord = pfx.add(guessWordList[j]);
+								if ( newWord) {
+									guessWordList[nh] = newWord;
+									guessOriginalList[nh] = root;
+									crossFlagArray[nh] = pfx.permissionToCombine;
+									nh++;
+								}
+							}
+							pfx = pfx.nextElementWithFlag;
+						}
+					}
+				}
+			}
+			
+			// now handle pure prefixes
+			for ( i=0; (he.affixFlagVector !=null) && (i<he.affixFlagVector.length);++i) {
+				pfx= this._attributeMgr.prefixFlagTable[he.affixFlagVector.charAt(i)];
+				while( pfx  ) {
+					if ( badWord.indexOf(pfx.affixKey) == 0 ) {
+						newWord = pfx.add(root);
+						if ( newWord) {
+							guessWordList[nh] = newWord;
+							guessOriginalList[nh] = root;
+							crossFlagArray[nh] = pfx.permissionToCombine;
+							nh++;
+						}
+					}
+					pfx = pfx.nextElementWithFlag; 
+				}
+			}
+				
+		}
+		
+		/*
+		 * ToDo: Since this is a generic algorithm, we might want move this code to StringUtils class.
+		 */
+		private function ngram(n:int, s1:String, s2:String, opt:int):int {
+
+			var i:int,j:int,k:int,m:int,n:int;
+	    	var nscore:int = 0, ns:int, l1:int, l2:int;
+
+			l1 = s1.length;
+			l2 = s2.length;
+			if ( opt & InternalConstants.NGRAM_LOWERING ) s2=s2.toLowerCase();
+			for ( i = 0; i<l1; i++ ) {
+				if ( s2.indexOf( s1.charAt(i) ) != -1 ) ns++;
+			}
+			nscore = nscore + ns;
+			if ( ns >= 2 ) {
+				for (  j = 2; j<=n; j++ ) {
+					ns = 0;
+					for (  i = 0; i <=(l1-j); i++ ) {
+	//					var tmp:String = s1.substr(i,i+j);
+	//					tmp = s1.substring(i,i+j);
+						if ( s2.indexOf( s1.substring(i,i+j) ) != -1 ) ns++;   // it could be signaficantly optimized If we can avoid to use substr() function....
+					}
+					nscore = nscore + ns;
+					if (ns < 2) break;
+				}
+			}
+			ns = 0;
+			if (opt & InternalConstants.NGRAM_LONGER_WORSE) ns = (l2-l1)-2;
+			if (opt & InternalConstants.NGRAM_ANY_MISMATCH) ns = Math.abs(l2-l1)-2;
+			ns = (nscore - ((ns > 0) ? ns : 0));
+			return ns;
+			return 1;
+		}
+
+		
+		/*
+		 * Deprecated function for now...
+		 * History: 
+		 *          A pre-version of implementation for error correction. After I optimized the code for performance,
+		 *          I drop this function by that time, but you know performance meassuring is a tricky problem... 
+		 * ToDo: Need a revisit when we implementing complex-affix support and compound-word support.
+		 */
+		private function ngram1(n:int, s1:String, s2:String, opt:int):int {
+	    	var nscore:int = 0, ns:int, l1:int, l2:int;
+			
+			var i:int,j:int,k:int,m:int,n:int;
+			
+			l1 = s1.length;
+			l2 = s2.length;
+			if ( opt & InternalConstants.NGRAM_LOWERING ) s2=s2.toLowerCase();
+			for (  j = 1; j<=n; j++ ) {
+				ns = 0;
+				for (  i = 0; i <=(l1-j); i++ ) {
+//					var tmp:String = s1.substr(i,i+j);
+//					tmp = s1.substring(i,i+j);
+					if ( s2.indexOf( s1.substring(i,i+j) ) != -1 ) ns++;   // it could be signaficantly optimized If we can avoid to use substr() function....
+				}
+				nscore = nscore + ns;
+				if (ns < 2) break;
+			}
+			ns = 0;
+			if (opt & InternalConstants.NGRAM_LONGER_WORSE) ns = (l2-l1)-2;
+			if (opt & InternalConstants.NGRAM_ANY_MISMATCH) ns = Math.abs(l2-l1)-2;
+			ns = (nscore - ((ns > 0) ? ns : 0));
+			return ns;
+			return 1;
+		}
+		
+		/*
+		 * ToDo: since this is a generic algorithm, we might want to move this function to StringUtils class.
+		 */
+		private function leftCommonSubString(s1:String,s2:String, initCap:Boolean, s1CapValue:int):int {
+			var res:int = 1;
+			if ( s1.charCodeAt(0) != s2.charCodeAt(0) && ( !initCap ) && (s1CapValue != s2.charCodeAt(0)) ) return 0;
+			for( var i:int=1; (i< s1.length) && (s1.charCodeAt(i) == s2.charCodeAt(i)); ++i ) {
+				res++;
+			}
+			return res;
+		}
+		
+		
+		public function suggest( result:Array, word:String, capType:int):int {
+			var nsug:int = 0;
+
+			// suggestions for an uppercase word (html -> HTML)
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = capchars(result,word,nsug);
+			}
+			
+			// perhaps we made a typical fault of spelling
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = replchars( result, word, nsug );	
+			}
+			
+			// perhaps we made chose the wrong char from a related set
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = mapchars( result, word, nsug );	
+			}
+
+			// did we swap the order of chars by mistake
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = swapchar( result, word, nsug );	
+			}
+			
+			// did we swap the order of non adjacent chars by mistake
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = longswapchar( result, word, nsug );	
+			}
+
+			// did we just hit the wrong key in place of a good char (case and keyboard)
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = badcharkey( result, word, nsug );	
+			}
+			 // did we add a char that should not be there
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = extrachar( result, word, nsug );	
+			}
+			
+			// did we forgot a char
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = forgotchar( result, word, nsug, capType );	
+			}
+
+			// did we move a char
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = movechar( result, word, nsug );	
+			}
+
+			// did we just hit the wrong key in place of a good char
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = badchar( result, word, nsug, capType );	
+			}
+			
+			// did we double two characters
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = doubletwochars( result, word, nsug );	
+			}
+			
+			// perhaps we forgot to hit space and two words ran together
+			if ( (nsug < this._maxSug) && (nsug > -1 ) ) {
+				nsug = twowords( result, word, nsug );	
+			}
+
+			return nsug;
+		}
+		
+		
+		
+		private function mapchars( result:Array, word:String, nsug:int ) :int {
+			if (word.length < 2) return nsug;
+			if ( (nsug == this._maxSug) || (this._attributeMgr.mapFilterTable.length == 0) ) return nsug;
+			var mapTable:Array = this._attributeMgr.mapFilterTable;
+			var counter:int = 0;
+			nsug = map_related(result, word, nsug, 0 ,mapTable, counter);
+			
+			return nsug;
+		}		
+
+		private function map_related( result:Array, word:String, nsug:int, startIndex:int, mapTable:Array, counter:int) :int {
+			var totalCheckCount:int = 8; // for performance issue only... 8 means four level detection...
+			var candidate:String;
+			var in_map:int = 0;
+			var j:int;
+			counter++;
+			if ( counter > totalCheckCount ) return nsug; // for performance issue only...
+			if ( nsug == this._maxSug ) return nsug;
+			if ( startIndex == word.length ) {
+				var cwrd:int = 1;
+				for (  j=0; j < result.length; ++j ) {
+					if ( result[j]== word ) cwrd=0;
+				}
+				if ( cwrd && checkWord(word) ) {
+					result.push(word);
+					nsug++;
+				}
+				return nsug;
+				
+			}
+			for ( var i:int = 0;i<mapTable.length ;++i ) {
+				if ( mapTable[i].mapCharSet.indexOf(word.charAt(startIndex)) != -1 ) {
+					in_map= 1;
+					for ( j =0; j< mapTable[i].mapCharSet.length; ++j ) {
+						candidate = word.substring(0,startIndex) +mapTable[i].mapCharSet.charAt(j)+word.substring(startIndex+1);
+						nsug = map_related(result,candidate,nsug,(startIndex+1),mapTable, counter);
+					}
+				}				
+			}
+			
+			if( !in_map) {
+				nsug = map_related(result,word,nsug,(startIndex+1),mapTable, counter);
+			}
+			return nsug;
+		} 
+		
+		private function twowords( result:Array, word:String, nsug:int ) :int {
+			var candidate:String;
+			var cwrd:int=1;
+			var count:int=0;
+			if (word.length < 3) return result.length;
+			if ( result.length >= this._maxSug ) return result.length;
+			
+			for( var i:int=1;i<word.length;++i) {
+				candidate = word.substring(0,i);
+				if ( !checkWord(candidate) ) continue;
+				candidate = word.substring(i);
+				if ( checkWord(candidate) ) {
+					candidate = word.substring(0,i) +" " + word.substring(i);
+					for ( var j:int=0; j < result.length; ++j ) {
+						if ( result[j]== candidate ) cwrd=0;
+					}
+					if ( cwrd ) {
+						if ( result.length >= this._maxSug ) return result.length;
+						result.push(candidate);
+						nsug++;
+					}
+				}
+			}
+
+			return nsug;
+		}		
+
+		private function doubletwochars( result:Array, word:String, nsug:int ) :int {
+			var candidate:String;
+			var nstate:int=0;
+			if (word.length < 5) return nsug;
+			for (var i:int=2;i<word.length;++i) {
+				if( word.charCodeAt(i) == word.charCodeAt(i-2) ) {
+					nstate++;
+					if ( nstate==3) {
+						candidate = word.substring(0,i-1)+word.substring(i+1);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+						nstate = 0;
+					}
+				}else {
+					nstate=0;
+				}
+			}
+			return nsug;
+		}
+
+		private function badchar( result:Array, word:String, nsug:int, capType:int ) :int {
+			if ( this._cAllTry == null ) return nsug;
+			if (word.length < 2) return nsug;
+			var candidate:String;
+			var i:int, j:int;			
+			switch(capType) {
+				case InternalConstants.NOCAP: {
+					// first for init capticalized case...
+					for ( i = 0; i< this._cAllTry.length;++i) {
+						candidate = this._cAllTry.charAt(i)+word.substring(1);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+					}
+					// for the rest of the word...
+					for ( i = 0; i< this._cLowerTry.length;++i) {
+						for ( j=1;j<word.length;++j) {
+							candidate = word.substring(0,j)+this._cLowerTry.charAt(i)+word.substring(j+1);
+							nsug = testSuggestion( result,candidate, nsug);
+							if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+						}
+					}
+					break;
+				}
+				case InternalConstants.INITCAP:{
+					// first for init capticalized case...
+					for ( i = 0; i< this._cAllTry.length;++i) {
+						candidate = this._cAllTry.charAt(i)+word.substring(1);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+					}
+					// for the rest of the word...
+					for ( i = 0; i< this._cLowerTry.length;++i) {
+						for ( j=1;j<word.length;++j) {
+							candidate = word.substring(0,j)+this._cLowerTry.charAt(i)+word.substring(j+1);
+							nsug = testSuggestion( result,candidate, nsug);
+							if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+						}
+					}
+					break;
+				}
+				case InternalConstants.HUHCAP: { 
+				}
+				case InternalConstants.HUHINITCAP:{ 
+					for ( i = 0; i< this._cAllTry.length;++i) {
+						for ( j=0;j<word.length;++j) {
+							candidate = word.substring(0,j)+this._cAllTry.charAt(i)+word.substring(j+1);
+							nsug = testSuggestion( result,candidate, nsug);
+							if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+						}
+					}
+					break;
+				}
+				case InternalConstants.ALLCAP: {
+					for ( i = 0; i< this._cUpperTry.length;++i) {
+						for ( j=0;j<word.length;++j) {
+							candidate = word.substring(0,j)+this._cUpperTry.charAt(i)+word.substring(j+1);
+							nsug = testSuggestion( result,candidate, nsug);
+							if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+						}
+					}
+					break;
+				}
+			}
+			
+			return nsug;
+		}		
+
+		// did we move a char
+		private function movechar( result:Array, word:String, nsug:int ) :int {
+			var candidate:String;
+			var i:int,j:int;
+			var char:String;
+			if (word.length < 3) return nsug;
+			for ( i=0;i<word.length-2;++i) {
+				char = word.charAt(i);
+				for ( j=i+2;j<word.length;++j) {
+					candidate = word.substring(0,i)+word.substring(i+1,j+1)+char+word.substring(j+1);
+					nsug = testSuggestion( result,candidate, nsug);
+					if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+				}
+			}
+			
+			for ( i=word.length-1;i>=2;--i) {
+				char = word.charAt(i);
+				for ( j=i-2;j>=0; --j) {
+					candidate = word.substring(0,j)+char+word.substring(j,i)+word.substring(i+1);
+					nsug = testSuggestion( result,candidate, nsug);
+					if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+				}
+			}
+			
+			return nsug;
+		}		
+
+		private function forgotchar( result:Array, word:String, nsug:int, capType:int ) :int {
+			if ( this._cAllTry == null ) return nsug;
+			var candidate:String;
+			var i:int, j:int;			
+			if (word.length < 2) return nsug;
+			switch(capType) {
+				case InternalConstants.NOCAP: {
+					for (i =0; i< this._cAllTry.length; ++i ) {
+						candidate= _cAllTry.charAt(i) + word.substring(0);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+					}
+
+					for (i =0; i< this._cLowerTry.length; ++i ) {
+						for ( j=1; j< word.length;j++) {
+							candidate= word.substring(0,j)+_cLowerTry.charAt(i) + word.substring(j);
+							nsug = testSuggestion( result,candidate, nsug);
+							if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+						}
+						candidate= word+_cLowerTry.charAt(i);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+					}
+					break;
+				}
+				case InternalConstants.INITCAP:{
+					// first for init capticalized case...
+					for (i =0; i< this._cAllTry.length; ++i ) {
+						candidate= _cAllTry.charAt(i) + word.substring(0);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+					}
+
+					for (i =0; i< this._cLowerTry.length; ++i ) {
+						for ( j=1; j< word.length;j++) {
+							candidate= word.substring(0,j)+_cLowerTry.charAt(i) + word.substring(j);
+							nsug = testSuggestion( result,candidate, nsug);
+							if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+						}
+						candidate= word+_cLowerTry.charAt(i);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+					}
+					break;
+				}
+				case InternalConstants.HUHCAP: { 
+				}
+				case InternalConstants.HUHINITCAP:{ 
+					for (i =0; i< this._cAllTry.length; ++i ) {
+						for ( j=1; j< word.length;j++) {
+							candidate= word.substring(0,j)+_cAllTry.charAt(i) + word.substring(j);
+							nsug = testSuggestion( result,candidate, nsug);
+							if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+						}
+						candidate= word+_cAllTry.charAt(i);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+					}
+					break;
+				}
+				case InternalConstants.ALLCAP: {
+					for (i =0; i< this._cUpperTry.length; ++i ) {
+						for ( j=0; j< word.length;j++) {
+							candidate= word.substring(0,j)+_cUpperTry.charAt(i) + word.substring(j);
+							nsug = testSuggestion( result,candidate, nsug);
+							if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+						}
+						candidate= word+_cUpperTry.charAt(i);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+					}
+					break;
+				}
+			}
+			return nsug;
+		}		
+
+		// error is word has an extra letter it does not need 
+		private function extrachar( result:Array, word:String, nsug:int ) :int {
+			var candidate:String;
+			if (word.length < 2) return nsug;
+			for ( var i:int=0; i< word.length ; ++i ) {
+				candidate = word.substring(0,i) + word.substring(i+1);
+				nsug = testSuggestion( result,candidate, nsug);
+				if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+			}
+			return nsug;
+		}		
+		
+		// error is wrong char in place of correct one (case and keyboard related version)
+		private function badcharkey( result:Array, word:String, nsug:int ) :int {
+			var candidate:String;
+			if (word.length < 2) return nsug;
+			var startIndex:int = 0;
+			// swap out each char one by one and try uppercase and neighbor
+			// keyboard chars in its place to see if that makes a good word
+			for ( var i:int =0; i<word.length; ++i) {
+				// check with uppercase letters
+				if ( word.charAt(i).toLocaleUpperCase() != word.charAt(i) ) {
+					candidate = word.substring(0,i)+word.charAt(i).toLocaleUpperCase()+word.substring(i+1);
+					nsug = testSuggestion( result,candidate, nsug);
+					if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+				}
+				// check neighbor characters in keyboard string
+				if ( this._ckey == null ) continue;
+				startIndex = this._ckey.indexOf(word.charAt(i),startIndex);
+				while ( startIndex != -1 ) {
+					if ( (startIndex!=0) && (_ckey.charAt(startIndex-1) != "|" ) ) {
+						candidate = word.substring(0,i)+_ckey.charAt(startIndex-1)+word.substring(i+1);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+					}
+					if ( (_ckey.charAt(startIndex+1)!="|") && (startIndex != _ckey.length - 1) ) {
+						candidate = word.substring(0,i)+_ckey.charAt(startIndex+1) + word.substring(i+1);
+						nsug = testSuggestion( result,candidate, nsug);
+						if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+					}
+					startIndex = this._ckey.indexOf(word.charAt(i),startIndex+1);
+				}
+			}
+			
+			return nsug;
+		}		
+
+		private function longswapchar( result:Array, word:String, nsug:int ) :int {
+			var candidate:String;
+			if (word.length < 2) return nsug;
+			for ( var i:int =0 ; i< word.length-2; ++i ) {
+				for ( var j:int = i+2;j< word.length;++j) {
+					candidate = word.substring(0,i)+ word.charAt(j) + word.substring(i+1,j) + word.charAt(i) + word.substring(j+1);
+					nsug = testSuggestion( result,candidate, nsug);
+					if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+				}
+			}
+			return nsug;
+		}		
+
+		private function swapchar( result:Array, word:String, nsug:int ) :int {
+			var candidate:String;
+			if (word.length < 2) return nsug;
+			var i:int;
+			var wl:int = word.length;
+			// try swapping adjacent chars one by one
+			for (i=0;i< wl-1;++i) {
+				candidate = word.substring(0,i)+word.charAt(i+1)+word.charAt(i) + word.substring(i+2);
+				nsug = testSuggestion( result,candidate, nsug);
+				if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+			}
+			
+			if ( wl == 4 || wl == 5 ) {
+				candidate = word.charAt(1) + word.charAt(0);
+				if ( wl == 5) candidate +=word.charAt(2);
+				candidate += word.charAt(wl - 1) + word.charAt(wl - 2); 
+				nsug = testSuggestion( result,candidate, nsug);
+				if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+				if ( wl == 5 )  {
+					candidate = word.charAt(0) + word.charAt(2) + word.charAt(1) + candidate.substr(3);
+					nsug = testSuggestion( result,candidate, nsug);
+					if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+				}
+			}
+			return nsug;
+			
+		}		
+		private function replchars( result:Array, word:String, nsug:int ) :int {
+			var candidate:String;
+			if (word.length < 2) return nsug;
+			var searchIndex:int=0;
+			if ( (this._attributeMgr.simpleFilterTable==null) || (this._attributeMgr.simpleFilterTable.length == 0) ) return nsug;
+			for ( var i:int = 0; i < this._attributeMgr.simpleFilterTable.length; ++i ) {
+				while ( (searchIndex = word.indexOf( this._attributeMgr.simpleFilterTable[i].matchString,searchIndex)) != -1 ){
+					searchIndex = searchIndex + this._attributeMgr.simpleFilterTable[i].matchString.length;
+					candidate = word.substr(0, searchIndex-this._attributeMgr.simpleFilterTable[i].matchString.length) + 
+					this._attributeMgr.simpleFilterTable[i].replacement + 
+					word.substr(searchIndex);
+					nsug = testSuggestion( result,candidate, nsug);
+					if ( nsug == -1 || nsug == this._maxSug ) return nsug;
+				}
+				
+			}
+			return nsug;
+		}
+		
+		private function capchars( result:Array, word:String, nsug:int) : int {
+			var candidate:String = word.toLocaleUpperCase();
+			return testSuggestion(result,candidate,nsug);
+		}
+		
+		private function testSuggestion(result:Array, word:String, nsug:int):int {
+			var cwrd:int=1;
+			if ( result.length >= this._maxSug ) return nsug;
+			for ( var i:int=0; i < result.length; ++i ) {
+				if ( result[i]== word ) cwrd=0;
+			}
+			
+			if ( (cwrd) && checkWord(word) ) {
+				result.push(word);
+				nsug++;
+			}
+			return nsug;
+		}
+
+		// see if a candidate suggestion is spelled correctly
+		// needs to check both root words and words with affixes
+		
+		// ToDo the following in next release...
+		// obsolote MySpell-HU modifications:
+		// return value 2 and 3 marks compounding with hyphen (-)
+		// `3' marks roots without suffix   
+
+		private function checkWord(word:String):int {
+			var rv:HashEntry = null;
+			var nosuffix:int =0;
+			if ( this._attributeMgr ) {
+				rv = _attributeMgr.lookup(word);
+				if ( rv ) {
+					if ( (rv.affixFlagVector) && ( rv.testAffix(this._attributeMgr.forbiddenWord) || rv.testAffix(this._attributeMgr.noSuggest) )  ){
+						return 0;
+					}
+					while ( rv ) {
+						if ( (rv.affixFlagVector) &&  ( rv.testAffix(this._attributeMgr.needAffix) || rv.testAffix(InternalConstants.ONLYUPCASEFLAG) || rv.testAffix(this._attributeMgr.onlyInCompound) )  ) {
+							rv = rv.next
+						}else break;
+					}
+				}else rv = _attributeMgr.optPrefixCheck2(word, 0,0) // only prefix, and prefix + suffix XXX
+				
+				if ( rv ) {
+					nosuffix = 1;
+				}else {
+					rv = _attributeMgr.optSuffixCheck2(word,0,null,0,0);
+				}
+				//this is added after we have two level suffix stripping
+				if (!rv &&  this._attributeMgr.haveContClass) {
+					rv = this._attributeMgr.optTwoSuffixCheck(word, 0, null, 0);
+					if (!rv) rv = this._attributeMgr.optTwoPrefixCheck(word,1, 0);
+				}
+				
+				// check forbidden words
+				if ( (rv) && (rv.affixFlagVector) && ( rv.testAffix(this._attributeMgr.forbiddenWord) || rv.testAffix(InternalConstants.ONLYUPCASEFLAG) 
+				|| rv.testAffix(this._attributeMgr.noSuggest) || rv.testAffix(this._attributeMgr.onlyInCompound) ) ) {
+					return 0;
+				}
+				if ( rv ) {
+					//// XXX obsolote ToDo
+					return 1;
+				}
+				
+			}
+			return 0;
+		}
+		
+	}
+}
+
+
+internal class GuessWord {
+	private var _score:int;
+	private var _key:String;
+	private var _original:String;
+	
+	public function GuessWord(score:int, key:String, original:String){
+		this.key = key;
+		this.score = score;
+		this.original = original;
+	}
+	
+	public function get score():int {
+		return this._score;
+	}
+	public function set score(value:int) :void {
+		this._score = value;
+	}
+	
+	public function get key():String {
+		return this._key;
+	}
+	public function set key(value:String) :void {
+		this._key = value;
+	}
+	public function get original():String {
+		return this._original;
+	}
+	public function set original(value:String) :void {
+		this._original = value;
+	}
+}
+
+internal class SuggestionEntry {
+	import com.adobe.linguistics.spelling.core.HashEntry;
+	private var _score:int;
+	private var _key:String;
+	private var _hashEntry:HashEntry; 
+	
+	public function SuggestionEntry(score:int, key:String, hashEntry:HashEntry) {
+		this.key = key;
+		this.score = score;
+		this.hashEntry = hashEntry;
+		
+	}
+	
+	public function get score():int {
+		return this._score;
+	}
+	public function set score(value:int) :void {
+		this._score = value;
+	}
+	
+	public function get key():String {
+		return this._key;
+	}
+	public function set key(value:String) :void {
+		this._key = value;
+	}
+	
+	public function get hashEntry():HashEntry {
+		return this._hashEntry;
+	}
+	
+	public function set hashEntry(value:HashEntry ) :void {
+		this._hashEntry = value;
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/UserDictionaryEngine.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/UserDictionaryEngine.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/UserDictionaryEngine.as
new file mode 100644
index 0000000..93ba707
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/UserDictionaryEngine.as
@@ -0,0 +1,71 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package com.adobe.linguistics.spelling.core
+{
+	import com.adobe.linguistics.spelling.UserDictionaryInternal;
+	
+	public class UserDictionaryEngine
+	{
+		// Private properties
+		private var _dictionaryList:Array;		// get only
+		private var _userDict:UserDictionaryInternal;
+
+		public function UserDictionaryEngine(ud:UserDictionaryInternal=null)
+		{
+			_dictionaryList = new Array();
+		}
+		public function addDictionary(userDictionary:UserDictionaryInternal):Boolean
+		{
+			if ( (userDictionary == null) ) return false;
+			
+			for ( var i:int = 0;i < _dictionaryList.length; ++i ) {
+				if ( userDictionary == _dictionaryList[i] )
+					return false;
+			} 
+			_dictionaryList.push(userDictionary);
+			return true;
+		}
+
+		public function removeDictionary(userDictionary:UserDictionaryInternal):Boolean
+		{
+			
+			for ( var i:int =0; i < _dictionaryList.length; ++i ) {
+				if ( userDictionary == _dictionaryList[i] ) {
+					_dictionaryList.splice(i,1);
+					return true;
+				}
+			}
+			return false;
+		}
+		
+		public function spell( word:String ) :Boolean {
+			var result:Boolean = false;
+			for ( var i:int =0; (i < _dictionaryList.length) && (!result);++i ) {
+				_userDict = _dictionaryList[i];
+				if ( _userDict ) {
+					result = (_userDict._wordList.lookup(word) != -1);
+				}
+			}
+			return result;
+		}
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Collection.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Collection.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Collection.as
new file mode 100644
index 0000000..5954c21
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Collection.as
@@ -0,0 +1,89 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+package com.adobe.linguistics.spelling.core.container
+{
+	/**
+	 * public interface Collection The root interface in the collection 
+	 * hierarchy. A collection represents a group of objects, known as 
+	 * its elements. Some collections allow duplicate elements and others 
+	 * do not. Some are ordered and others unordered. The SDK does not 
+	 * provide any direct implementations of this interface: it provides 
+	 * implementations of more specific subinterfaces like Set and List. 
+	 */
+	 
+	 /**
+	  * ToDo: add hashCode() function
+	  * 	add remove()/add() function
+	  */
+	 
+	public interface Collection
+	{
+
+		/**
+		 * The number of elements in this collection.
+		 * @Returns the number of elements in this collection.
+		 */
+		function get size():int;
+		
+		/**
+		 * Tests if the collection is empty.
+		 * 
+		 * @ Returns true if this collection contains no elements.
+		 */
+		function isEmpty():Boolean
+		
+		/**
+		 * Determines if the collection contains the specified element.
+		 * 
+		 * @ obj: element whose presence in this collection is to be tested.
+		 * 
+		 * @ Returns true if this collection contains the specified element.
+		 */
+		function contains( obj:* ) : Boolean
+		
+		/**
+		 * Removes all of the elements from this collection (optional operation).
+		 */
+		function clear():void
+		
+		/**
+		 * Returns an iterator over the elements in this collection. There are 
+		 * no guarantees concerning the order in which the elements are returned 
+		 * (unless this collection is an instance of some class that provides a guarantee). 
+		 *
+		 * @an Iterator over the elements in this collection
+		 */
+		function getIterator():Iterator
+		
+		/**
+		 * Returns an array containing all of the elements in this collection. 
+		 * If the collection makes any guarantees as to what order its elements 
+		 * are returned by its iterator, this method must return the elements 
+		 * in the same order.
+		 * 
+		 * @return An array.
+		 */
+		function toArray():Array
+		
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Enumeration.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Enumeration.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Enumeration.as
new file mode 100644
index 0000000..16611ad
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Enumeration.as
@@ -0,0 +1,28 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package com.adobe.linguistics.spelling.core.container
+{
+	public interface Enumeration
+	{
+		function hasMoreElements():Boolean;
+		function nextElement():*;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/HashTable.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/HashTable.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/HashTable.as
new file mode 100644
index 0000000..cf38c81
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/HashTable.as
@@ -0,0 +1,179 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package com.adobe.linguistics.spelling.core.container
+{
+	import flash.utils.Dictionary;
+	
+	/**
+	 * A hash table
+	 */
+	public class HashTable implements Collection
+	{
+		protected var _map:Dictionary;
+		protected var _elementNum:int;
+		
+		/**
+		 * Initializes a new hash table.
+		 * 
+		 * @param size The size of the hash table.
+		 * @param hash A hashing function.
+		 */
+		public function HashTable(useWeakReferences:Boolean = true)
+		{
+			_map = new Dictionary( useWeakReferences );
+			_elementNum = 0;
+		}
+
+		public function put(key:*, value:*) : void
+		{
+			_map[key] = value;
+			++_elementNum;
+		}
+
+		public function remove(key:*) : void
+		{
+			delete _map[key];
+			--_elementNum;
+		}
+
+		public function containsKey(key:*) : Boolean
+		{
+			return _map.hasOwnProperty( key );
+		}
+		
+		public function containsValue(value:*) : Boolean
+		{
+			for ( var key:* in _map )
+			{
+				if ( _map[key] == value )
+				{
+					return true;
+				}
+			}
+			return false;
+		}
+
+		public function contains(value:*):Boolean {
+			return containsValue(value);
+		}
+
+		public function getElement(key:* ):* {
+			return _map[key];
+		}
+				
+		/**
+		 * @inheritDoc
+		 */
+		public function clear() : void
+		{
+			for ( var key:* in _map )
+			{
+				remove( key );
+			}
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public function getIterator():Iterator
+		{
+			return null;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public function get size():int
+		{
+			return _elementNum;
+		}
+		
+		/**
+		 * @inheritDoc
+		 */
+		public function isEmpty():Boolean
+		{
+			return _elementNum == 0;
+		}
+
+		public function get keys() : Array
+		{
+			var _keys:Array = [];
+
+			for (var key:* in _map)
+			{
+				_keys.push( key );
+			}
+			return _keys;
+		}
+		
+		public function get elements() : Array
+		{
+			var _values:Array = [];
+
+ 			for each ( var value:* in _map ) {
+				_values.push( value );
+			}
+			return _values;
+		}
+
+		/**
+		 * @inheritDoc
+		 */
+		public function toArray():Array
+		{
+			return keys;
+		}
+		
+		/**
+		 * Prints out a string representing the current object.
+		 * 
+		 * @return A string representing the current object.
+		 */
+		public function toString():String
+		{
+			return "[HashTable, size=" + size + "]";
+		}
+		
+		public function get hashMap():Dictionary {
+			return this._map;
+		}
+		
+		/**
+		 * Need refine... Possible solution is that we can use two function paramter to control the input and output. 
+		 * 
+		 *
+		 */
+		public function watchEntries(func:Function=null):Array {
+			if ( func == null )
+				return null;
+			var res:Array = new Array();
+			for (var curKey:* in _map)
+			{
+				if ( func( curKey, _map[curKey] ) ) {
+					res.push( curKey );
+				}
+			}
+			return (res.length == 0)? null: res;
+		}
+		
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Heap.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Heap.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Heap.as
new file mode 100644
index 0000000..555d6a3
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Heap.as
@@ -0,0 +1,263 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+package com.adobe.linguistics.spelling.core.container
+{
+	/**
+	 * BinaryHeap implementation of priority queue. The heap is either a 
+	 * minimum or maximum heap as determined by parameters passed to constructor. 
+	 * 
+	 */
+	public final class Heap implements Collection
+	{
+		private var __size:int;
+		private var __count:int;
+		private var __compare:Function;
+		public var __heap:Array;
+		
+		/**
+		 * Create a new heap.
+		 * 
+		 * @param size The heap's maximum capacity.
+		 * @param compare A comparison function for sorting the heap's data.
+		 *        If no function is passed, the heap uses default function.
+		 */
+		public function Heap(size:int=1000, compare:Function = null)
+		{
+			__count = 0;
+			__heap = new Array(__size = size + 1);
+			
+			if (compare == null)
+				__compare = function(a:int, b:int):int { return a - b; };
+			else
+				__compare = compare;
+		}
+
+		/**
+		 * The maximum capacity.
+		 */
+		public function get maxSize():int
+		{
+			return __size;
+		}
+
+		public function isEmpty():Boolean
+		{
+			return false;
+		}
+		
+		public function toArray():Array
+		{
+			return __heap.slice(1, __count + 1);
+		}
+		
+		public function toString():String
+		{
+			return "[Heap, size=" + __size +"]";
+		}
+		
+		public function dump():String
+		{
+			var k:int = __count + 1;
+			var s:String = "Heap\n{\n";
+			for (var i:int = 1; i < k; i++)
+				s += "\t" + __heap[i] + "\n";
+			s += "\n}";
+			return s;
+		}
+		
+		/**
+		 * The front item.
+		 */
+		public function get front():*
+		{
+			return __heap[1];
+		}
+		
+		/**
+		 * Enqueues.
+		 * @param obj The data to enqueue.
+		 * @return False if the queue is full, otherwise true.
+		 */
+		public function enqueue(obj:*):Boolean
+		{
+			if (__count + 1 < __size){
+				__heap[++__count] = obj;
+				
+				var i:int = __count;
+				var tmp:* = __heap[i];
+				var v:*;
+				var parent:int = i >> 1;
+				
+				if (__compare != null)
+				{
+					while (parent > 0){
+						 v = __heap[parent];
+						if (__compare(tmp, v) < 0){
+							__heap[i] = v;
+							i = parent;
+							parent >>= 1;
+						}
+						else break;
+					}
+				}else{
+					while (parent > 0){
+						v = __heap[parent];
+						if (tmp - v < 0){
+							__heap[i] = v;
+							i = parent;
+							parent >>= 1;
+						}
+						else break;
+					}
+				}
+				__heap[i] = tmp;
+				return true;
+			}
+			return false;
+		}
+		
+		/**
+		 * Dequeues.
+		 * @return The heap's front item or null if it is empty.
+		 */
+		public function dequeue():*
+		{
+			if (__count >= 1){
+				var o:* = __heap[1];
+				
+				__heap[1] = __heap[__count];
+				delete __heap[__count];
+				
+				var tmp:* = __heap[i];
+				var i:int = 1;
+				var v:*;
+				var child:int = i << 1;
+				
+				if (__compare != null) {
+					while (child < __count) {
+						if (child < __count - 1) {
+							if (__compare(__heap[child], __heap[int(child + 1)]) > 0)
+								child++;
+						}
+						v = __heap[child];
+						if (__compare(tmp, v) > 0){
+							__heap[i] = v;
+							i = child;
+							child <<= 1;
+						}
+						else break;
+					}
+				}else{
+					while (child < __count){
+						if (child < __count - 1){
+							if (__heap[child] - __heap[int(child + 1)] > 0)
+								child++;
+						}
+						v = __heap[child];
+						if (tmp - v > 0){
+							__heap[i] = v;
+							i = child;
+							child <<= 1;
+						}
+						else break;
+					}
+				}
+				__count--;
+				__heap[i] = tmp;
+				return o;
+			}
+			return null;
+		}
+		
+		/**
+		 * Tests if a given item exists.
+		 */
+		public function contains(obj:*):Boolean
+		{
+			for (var i:int = 1; i <= __count; i++){
+				if (__heap[i] === obj)
+					return true;
+			}
+			return false;
+		}
+		
+		public function clear():void
+		{
+			__heap = new Array(__size);
+			__count = 0;
+		}
+		
+		public function getIterator():Iterator
+		{
+			return new HeapIterator(this);
+		}
+
+		public function get size():int
+		{
+			return __count;
+		}
+		
+	}
+}
+
+import com.adobe.linguistics.spelling.core.container.Heap;
+import com.adobe.linguistics.spelling.core.container.Iterator;
+
+internal class HeapIterator implements Iterator
+{
+	private var __values:Array;
+	private var __length:int;
+	private var __cursor:int;
+	
+	public function HeapIterator(heap:Heap)
+	{
+		__values = heap.toArray();
+		__cursor = 0;
+		__length = __values.length;
+	}
+	
+	public function get data():*
+	{
+		return __values[__cursor];
+	}
+	
+	public function set data(obj:*):void
+	{
+		__values[__cursor] = obj;
+	}
+	
+	public function start():void
+	{
+		__cursor = 0;
+	}
+	
+	public function hasNext():Boolean
+	{
+		return __cursor < __length;
+	}
+	
+	public function next():*
+	{
+		return __values[__cursor++];
+	}
+}
+

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Iterator.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Iterator.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Iterator.as
new file mode 100644
index 0000000..4abe889
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Iterator.as
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+package com.adobe.linguistics.spelling.core.container
+{
+	/**
+	 * public interface Iterator
+	 * An iterator over a collection. Iterator takes the place of Enumeration 
+	 * in the AS collections framework. Iterators differ from enumerations in 
+	 * two ways:
+	 * Iterators allow the caller to remove elements from the underlying 
+	 * collection during the iteration with well-defined semantics.
+	 * Method names have been improved. 
+	 */
+	public interface Iterator
+	{
+
+		/**
+		 * Grants access to the current item being referenced by the iterator.
+		 * This provides a quick way to read or write the current data.
+		 * Dirty interface, will remove in next version.
+		 */
+		function get data():*
+		function set data(obj:*):void	
+
+		/**
+		 * Seek the iterator to the first item in the collection.
+		 */
+		function start():void
+
+		/**
+		 * Returns the next element in the iteration.
+		 * 
+		 */
+		function next():*
+		
+		/**
+		 * Returns true if the iteration has more elements.
+		 * 
+		 * @Returns true if the iteration has more elements.
+		 */
+		function hasNext():Boolean
+		
+		}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Set.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Set.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Set.as
new file mode 100644
index 0000000..32525e7
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/Set.as
@@ -0,0 +1,195 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+package com.adobe.linguistics.spelling.core.container
+{
+	import flash.utils.Dictionary;
+	
+	/**
+	 * A collection that contains no duplicate elements. More formally, sets 
+	 * contain no pair of elements e1 and e2 such that e1.equals(e2), and at 
+	 * most one null element. As implied by its name, this interface models 
+	 * the mathematical set abstraction.
+	 */
+	public final class Set implements Collection
+	{
+		private var __size:int;
+		private var __set:Dictionary = new Dictionary(true);
+		
+		/**
+		 * Creates a empty set.
+		 */
+		public function Set()
+		{
+			__set = new Dictionary();			
+		}
+		
+
+		public function contains(obj:*):Boolean
+		{
+			return __set[obj] != undefined;
+		}
+		
+		public function clear():void
+		{
+			__set = new Dictionary();
+			__size = 0;
+		}
+		
+		public function get data():Dictionary {
+			return this.__set;
+		}
+		
+		public function getIterator():Iterator
+		{
+			return new SetIterator(this);
+		}
+		
+		public function get size():int
+		{
+			return __size;
+		}
+		
+		public function isEmpty():Boolean
+		{
+			return __size == 0;
+		}
+
+		/**
+		 * Reads an item from the set.
+		 * 
+		 * @param obj The item to retrieve.
+		 * @return The item matching the obj parameter or null.
+		 */
+		public function lookup(obj:*):*
+		{
+			var val:* = __set[obj];
+			return val != undefined ? val : null;
+		}
+
+		/**
+		 * Adds the specified element to this set if it is not already present (optional operation).
+		 * 
+		 * @param obj The item to be added.
+		 */
+		public function insert(obj:*):void
+		{
+			if (obj == null) return;
+			if (obj == undefined) return;
+			if (__set[obj]) return;
+			
+			__set[obj] = obj;
+			__size++;
+		}
+		
+		/**
+		 * Removes the specified element from this set if it is present (optional operation).
+		 * 
+		 * @param  obj The item to be removed
+		 * @return The removed item or null.
+		 */
+		public function remove(obj:*):Boolean
+		{
+			if (__set[obj] != undefined)
+			{
+				delete __set[obj];
+				__size--;
+				return true;
+			}
+			return false;
+		}
+		
+		public function toArray():Array
+		{
+			var a:Array = new Array(__size);
+			var j:int;
+			for (var i:* in __set) a[j++] = i;
+			return a;
+		}
+		
+		/**
+		 * Return a string representing the current object.
+		 */
+		public function toString():String
+		{
+			return "[Set, size=" + size + "]";
+		}
+		
+		/**
+		 * Prints out all elements (debug use only).
+		 */
+		public function dump():String
+		{
+			var s:String = "Set:\n";
+			for each (var i:* in __set)
+				s += "[val: " + i + "]\n";
+			return s;
+		}
+	}
+
+}
+
+
+import com.adobe.linguistics.spelling.core.container.Iterator
+import com.adobe.linguistics.spelling.core.container.Set;
+
+internal class SetIterator implements Iterator
+{
+	private var __cursor:int;
+	private var __size:int;
+	private var __s:Set;
+	private var __a:Array;
+
+	public function start():void
+	{
+		__cursor = 0;
+	}
+
+	public function get data():*
+	{
+		return __a[__cursor];
+	}
+	
+	public function set data(obj:*):void
+	{
+		__s.remove(__a[__cursor]);
+		__s.insert(obj);
+	}	
+	
+	public function SetIterator(s:Set)
+	{
+		__cursor = 0;
+		__size = s.size;
+		__s = s;
+		__a = s.toArray();
+	}
+	
+	public function next():*
+	{
+		return __a[__cursor++];
+	}
+	
+	public function hasNext():Boolean
+	{
+		return __cursor < __size;
+	}
+}

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/SparseHashTable.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/SparseHashTable.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/SparseHashTable.as
new file mode 100644
index 0000000..3a0e8d1
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/container/SparseHashTable.as
@@ -0,0 +1,283 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package com.adobe.linguistics.spelling.core.container
+{
+	import com.adobe.linguistics.spelling.core.utils.*;
+	public final class SparseHashTable implements Collection
+	{
+		
+		private var _keyTable:Array;
+		private var _elementTable:Array;
+		private var _hashSize:int;
+		private var _tableCapacity:int;
+		private var _loadFactor:Number;
+		private var _elementNum:int;
+		private var _deletedObject:Object = new Object();
+		
+		/**
+		 * A simple function for hashing strings.
+		 */
+		private function hashString(s:String):int
+		{
+			var hash:int = 0, i:int, k:int = s.length, ROTATE_LEN:int = 5;
+			for ( i =0; i < 4 && !isNaN(s.charCodeAt(i)); ++i ) {
+				hash = ( hash << 8 ) | ( s.charCodeAt(i) )
+			}
+			while ( !isNaN(s.charCodeAt(i)) ) {
+				(hash) = ((hash) << (ROTATE_LEN)) | (((hash) >> (32 - ROTATE_LEN)) & ((1 << (ROTATE_LEN))-1));
+				hash ^= ( s.charCodeAt(i) );
+				++i; 
+			}
+			return (hash > 0) ? hash : -hash; // or use uint conversion to convert minus number to plus number.... still debate//
+		}
+//		private function hashString(s:String):int
+//		{
+//			var hash:int = 0, i:int, k:int = s.length;
+//			for (i = 0; i < k; i++) hash += (i + 1) * s.charCodeAt(i);
+//			return hash;
+//		}
+		
+		/**
+		 * A simple function for hashing integers.
+		 */
+		private function hashNumber(n:Number):int
+		{
+			var i:int = int(n);
+			return int(i>0? i:-i);
+		}
+		
+		private function hash(key:*):int {
+			if (key is Number ) {
+				return hashNumber(key);
+			}else if (key is String ) {
+				return hashString(key);
+			}
+			
+			if (key.hasOwnProperty("hashCode"))
+            	return key.hashCode()>0 ? key.hashCode() : -key.hashCode();
+        	else
+            	return int(key)>0 ? int(key) : -int(key);
+		}
+
+		public function SparseHashTable(initialCapacity:int = 128, loadFactor:Number = 0.75)
+		{
+			initHash(initialCapacity, loadFactor);
+		}
+		
+		private function initHash(initialCapacity:int = 128, loadFactor:Number = 0.75):void {
+			if ( !(initialCapacity > 0) ||  !( loadFactor > 0 && loadFactor < 1) )
+				return; //input is invalid, should through exception or ...
+			_loadFactor = loadFactor;
+			_hashSize = initialCapacity;
+			_tableCapacity = MathUtils.nextPrime( int(_hashSize/loadFactor) );
+			_keyTable = new Array(_tableCapacity);
+			_elementTable = new Array(_tableCapacity);
+			_elementNum = 0;
+			clear();
+		}
+		
+		private function getKeyPosition(key:*):int {
+			var hashValue:int = hash(key);
+			var pos:int;
+			if ( hashValue < 0 ) {
+				trace ( "hashValue shouldn't be negative integer" );
+				return -1;
+			}
+			//Quadratic Probing
+			for ( var i:int =0; i < _tableCapacity; ++i ) {
+				pos = (hashValue+i*i)%_tableCapacity ; //hi=(h(key)+i*i)%m 0≤i≤m-1 
+				if ( _keyTable[pos] == null ) 
+					break;
+				if ( _keyTable[pos] == key ) {
+					return pos;
+				}
+			}
+			return -1;						
+		}
+
+		private function calculateKeyPostion(key:*):int {
+			var hashValue:int = hash(key);
+			var pos:int;
+			if ( hashValue < 0 ) {
+				trace ( "Position shouldn't be negative" );
+				return -1;
+			}
+			//Quadratic Probing
+			for ( var i:int =0; i < _tableCapacity; ++i ) {
+				pos = (hashValue+i*i)%_tableCapacity ; //hi=(h(key)+i*i)%m 0≤i≤m-1 
+				if ( (_keyTable[pos] == null ) || 
+				( _keyTable[pos] == _deletedObject ) ) {
+					// insert successfully
+					return pos;
+				}
+			}
+			return -1; // hash table is full now. it should never happen.
+			
+		}		
+		
+
+		protected function rehash():void {
+			if ( _hashSize == _elementNum ) {
+				var oldKeyTable:Array = _keyTable;
+				var oldElementTable:Array = _elementTable;
+				initHash(_hashSize*2, _loadFactor);
+				for ( var i:int =0 ; i < oldKeyTable.length; ++i ) {
+					if (oldKeyTable[i]==null 
+					|| oldKeyTable[i] == _deletedObject) {
+						continue;
+					}
+					put(oldKeyTable[i],oldElementTable[i] );
+				}
+				oldKeyTable=null;
+				oldElementTable=null;
+			}
+		}
+		
+		public function put( key:*, value:* ) :Boolean {
+			if ( _hashSize == _elementNum ) {
+				rehash();
+			}
+
+			if ( containsKey(key)  ) {
+				trace ( "Contains the same Key in the table" );
+				return false;
+			}
+			
+			var pos:int = calculateKeyPostion(key);
+			if ( pos < 0 ) {
+				trace ( "SparseHash internal error." );
+				return false;
+			}
+
+			++_elementNum;
+			_keyTable[pos] = key;
+			_elementTable[pos] = value;
+			return true;
+		}
+
+		public function remove(key:*):* {
+			var pos:int = getKeyPosition(key);
+			var res:* = (pos < 0) ? null:_elementTable[pos];
+			if ( pos >= 0 ) {
+				--_elementNum;
+				_keyTable[pos] =_deletedObject;
+				_elementTable[pos] = _deletedObject;
+			}
+			return res;
+		}
+		
+		public function contains(value:*):Boolean {
+			return containsValue(value);
+		}
+		
+		/**
+		 * Determines if the collection contains the specified element.
+		 * 
+		 * @ obj: element whose presence in this collection is to be tested.
+		 * 
+		 * @ Returns true if this collection contains the specified element.
+		 */
+		public function containsKey(key:*):Boolean {
+			var pos:int = getKeyPosition(key);
+			return (pos >= 0);	
+		}
+		
+		public function containsValue(value:*):Boolean {
+			for ( var i:int =0; i < _tableCapacity; ++i ) {
+				if ( (_keyTable[i] == null ) || 
+				( _keyTable[i] == _deletedObject ) ) {
+					continue;
+				}
+				if ( _elementTable[i].value == value ) 
+					return true;
+			}
+			return false;
+		}
+		
+		public function getElement(key:* ):* {
+			var pos:int = getKeyPosition(key);
+			return (pos < 0) ? null:_elementTable[pos];
+			
+		}
+
+		/**
+		 * The number of elements in this collection.
+		 * @Returns the number of elements in this collection.
+		 */
+		public function get size():int {
+			return _elementNum;
+		}
+		
+		public function get elements():Enumeration {
+			return null;
+		}
+		
+		public function get keys():Enumeration {
+			return null;
+		}
+		
+		/**
+		 * Tests if the collection is empty.
+		 * 
+		 * @ Returns true if this collection contains no elements.
+		 */
+		public function isEmpty():Boolean {
+			return (_elementNum==0);
+		}
+		
+		
+		/**
+		 * Removes all of the elements from this collection (optional operation).
+		 */
+		public function clear():void {
+			var i:int;
+			for( i=0;i< _tableCapacity;++i) {
+				_keyTable[i] = null;
+				_elementTable[i] = null;
+			}
+		}
+		
+		/**
+		 * Returns an iterator over the elements in this collection. There are 
+		 * no guarantees concerning the order in which the elements are returned 
+		 * (unless this collection is an instance of some class that provides a guarantee). 
+		 *
+		 * @an Iterator over the elements in this collection
+		 */
+		public function getIterator():Iterator {
+			return null;
+		}
+		
+		/**
+		 * Returns an array containing all of the elements in this collection. 
+		 * If the collection makes any guarantees as to what order its elements 
+		 * are returned by its iterator, this method must return the elements 
+		 * in the same order.
+		 * 
+		 * @return An array.
+		 */
+		public function toArray():Array {
+			return _keyTable;
+		}		
+		
+	}
+}
+

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/env/ExternalConstants.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/env/ExternalConstants.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/env/ExternalConstants.as
new file mode 100644
index 0000000..e38052e
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/env/ExternalConstants.as
@@ -0,0 +1,47 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package com.adobe.linguistics.spelling.core.env
+{
+	/*
+	 * External-Internal public Constant properties...
+	 * In the future, we might want to merge this class with InternalConstant class...
+	 */
+	
+	public class ExternalConstants
+	{
+
+		// casing
+		static public const NOCAP:int =					0;
+		static public const INITCAP:int =				1;
+		
+		
+		static public const SPELL_COMPOUND:int=			(1 << 0);
+		static public const SPELL_FORBIDDEN:int=		(1 << 1);
+		static public const SPELL_ALLCAP:int=			(1 << 2);
+		static public const SPELL_NOCAP:int=			(1 << 3);
+		static public const SPELL_INITCAP:int=			(1 << 4);
+
+		public function ExternalConstants()
+		{
+		}
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/env/InternalConstants.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/env/InternalConstants.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/env/InternalConstants.as
new file mode 100644
index 0000000..e14fc31
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/env/InternalConstants.as
@@ -0,0 +1,87 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package com.adobe.linguistics.spelling.core.env
+{
+	/*
+	 * Internal-Internal public Constant properties...
+	 * In the future, we might want to merge this class with ExternalConstant class...
+	 * This one is sharing by HunSpell related algorithm...
+	 */
+	public class InternalConstants
+	{
+		// casing
+		static public const NOCAP:int =					1;
+		static public const INITCAP:int =				2;
+		static public const ALLCAP:int =				4;
+		static public const HUHCAP:int =				8;
+		static public const HUHINITCAP:int =			16;
+
+		
+		static public const FLAG_LONG:int = 			1;
+		static public const FLAG_NUM:int = 				2;
+		static public const FLAG_UNI:int = 				3;
+		static public const FLAG_CHAR:int = 			0;
+
+		// default flags
+		static public const DEFAULTFLAGS:int = 			65510;
+		static public const FORBIDDENWORD:int = 		65511;
+		static public const ONLYUPCASEFLAG:int = 		65511;
+
+		static public const MAXWORDLEN:int =			100;
+
+		static public const FLAG_NULL:int = 			0x00;
+		
+		// affentry options
+		static public const aeXPRODUCT:int =			(1 << 0);
+		
+		static public const SPELL_KEYSTRING:String = 	"qwertyuiop|asdfghjkl|zxcvbnm"; 
+
+		// internal const for ngram algorithm.
+	    public static const NGRAM_LOWERING:int = 		(1 << 2);
+		public static const NGRAM_LONGER_WORSE:int = 	(1 << 0);
+		public static const NGRAM_ANY_MISMATCH:int = 	(1 << 1);
+
+	    static public const MAX_ROOTS:int = 			100;
+	    static public const MAX_WORDS:int = 			100;
+	    static public const MAX_GUESS:int = 			200;
+	    static public const MAXNGRAMSUGS:int=			4;
+	    static public const MAXPHONSUGS:int=			2;
+
+		static public const DEFAULTENCODING:String = 	"utf-8";
+		
+		
+		static public const MAXSUGGESTION:int =			10;
+		// internal const for ICONV or OCONV RULE.
+		static public const CONV_ICONV:Boolean=			true;
+		static public const CONV_OCONV:Boolean=			false;
+		
+		//Maximum word breaks allowed
+		static public const MAX_WORD_BREAKS:int=		10;
+		
+		//Constants for Loading of Dictionaries in Parts
+		static public const DICT_LOAD_DELAY:int=		10; //this is timeout delay between loading of two parts of dictionaries. In milliseconds
+		static public const WORDS_PER_SPLIT:int=		20000;// this is the default value of number of words to be loaded in each split.
+		public function InternalConstants()
+		{
+		}
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/error/ContentError.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/error/ContentError.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/error/ContentError.as
new file mode 100644
index 0000000..239b031
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/error/ContentError.as
@@ -0,0 +1,39 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package com.adobe.linguistics.spelling.core.error
+{
+	/*
+	 *@private
+	 * Deprecated class for now...
+	 * History: 
+	 *          In the beginning, I would like to have our own error class for critical exception. 
+	 *          After sharing this with Xie, I was convinced to drop this idea by discussing with Xie. 
+	 * ToDo: Need a revisit after we have compound word support.
+	 */
+	public class ContentError extends Error
+	{
+		public function ContentError(message:String, errorID:int)
+		{
+			super(message, errorID);
+		}
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/error/ErrorTable.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/error/ErrorTable.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/error/ErrorTable.as
new file mode 100644
index 0000000..d2dba8a
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/error/ErrorTable.as
@@ -0,0 +1,41 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package com.adobe.linguistics.spelling.core.error
+{
+	/*
+	 *@private
+	 * Deprecated class for now...
+	 * History: 
+	 *          In the beginning, I would like to have our own error class for critical exception. 
+	 *          After sharing this with Xie, I was convinced to drop this idea by discussing with Xie. 
+	 * ToDo: Need a revisit after we have compound word support.
+	 */
+	public class ErrorTable
+	{
+		
+		static public const CONTENTPARSINGERROR_ID:int=11235;
+		static public const CONTENTPARSINGERROR_MSG:String="null cannot be parsed to a squiggly dictionary";
+		public function ErrorTable()
+		{
+		}
+
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/4e4f9830/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/logging/AbstractTarget.as
----------------------------------------------------------------------
diff --git a/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/logging/AbstractTarget.as b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/logging/AbstractTarget.as
new file mode 100644
index 0000000..52e5dd6
--- /dev/null
+++ b/Squiggly/main/SpellingEngine/src/com/adobe/linguistics/spelling/core/logging/AbstractTarget.as
@@ -0,0 +1,167 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+package com.adobe.linguistics.spelling.core.logging
+{
+	import flash.errors.IllegalOperationError;
+public class AbstractTarget implements ILoggingTarget
+{
+	private var _usingLevelMaskMode:Boolean;
+    public function AbstractTarget(usingLevelMaskMode:Boolean = false)
+    {
+        super();
+        this._usingLevelMaskMode = usingLevelMaskMode;
+
+//        _id = UIDUtil.createUID();
+    }
+
+    private var _loggerCount:uint = 0;
+
+    private var _filters:Array = [ "*" ];
+
+    public function get filters():Array
+    {
+        return _filters;
+    }
+
+    public function set filters(value:Array):void
+    {
+        if (value && value.length > 0)
+        {
+            // a valid filter value will be fully qualified or have a wildcard
+            // in it.  the wild card can only be located at the end of the
+            // expression.  valid examples  xx*, xx.*,  *
+            var filter:String;
+            var index:int;
+            var message:String;
+            for (var i:uint = 0; i<value.length; i++)
+            {
+                filter = value[i];
+                  // check for invalid characters
+                if (Log.hasIllegalCharacters(filter))
+                {
+                    throw new IllegalOperationError("Please check for invalid characters.");
+                }
+
+                index = filter.indexOf("*");
+                if ((index >= 0) && (index != (filter.length -1)))
+                {
+                    throw new IllegalOperationError("Please check for invalid filters.");
+                }
+            } // for
+        }
+        else
+        {
+            // if null was specified then default to all
+            value = ["*"];
+        }
+
+        if (_loggerCount > 0)
+        {
+            Log.removeTarget(this);
+            _filters = value;
+            Log.addTarget(this);
+        }
+        else
+        {
+            _filters = value;
+        }
+    }
+
+    private var _id:String;
+
+     public function get id():String
+     {
+         return _id;
+     }
+    
+    private var _level:int = LogEventLevel.ALL;
+
+    public function get level():int
+    {
+        return _level;
+    }
+
+    /**
+     *  @private
+     */
+    public function set level(value:int):void
+    {
+    	if ( this._usingLevelMaskMode == false ) {
+	    	if ( !LogEventLevel.isValidLevel(value) ) {
+	    		throw new IllegalOperationError("Please set an valid level in the level setter.");
+	    	}
+	    	
+	    	this._mask = LogEventLevel.getUpperMask(value);
+    	}else {
+	    	if ( !LogEventLevel.isValidMask(value) ) {
+	    		throw new IllegalOperationError("Please set an valid mask in the mask setter.");
+	    	}
+	    	this._mask = value;
+    	}
+        // A change of level may impact the target level for Log.
+        Log.removeTarget(this);
+        _level = value;
+        Log.addTarget(this);        
+    }
+    
+    
+    private var _mask:int = LogEventLevel.ALL;
+    public function get mask():int {
+    	return this._mask;
+    }
+    
+    
+    public function addLogger(logger:ILogger):void
+    {
+        if (logger)
+        {
+            _loggerCount++;
+            logger.addEventListener(LogEvent.eventID, logHandler);
+        }
+    }
+
+    public function removeLogger(logger:ILogger):void
+    {
+        if (logger)
+        {
+            _loggerCount--;
+            logger.removeEventListener(LogEvent.eventID, logHandler);
+        }
+    }
+
+    public function initialized(document:Object, id:String):void
+    {
+        _id = id;
+        Log.addTarget(this);
+    }
+
+    public function logEvent(event:LogEvent):void
+    {
+    }
+
+    private function logHandler(event:LogEvent):void
+    {
+        if ( (event.level & mask) != 0)
+            logEvent(event);
+    }
+}
+
+}