/** @license Hyphenator X.Y.Z - client side hyphenation for webbrowsers
 *  Copyright (C) 2010  Mathias Nater, Zürich (mathias at mnn dot ch)
 *  Project and Source hosted on http://code.google.com/p/hyphenator/
 * 
 *  This JavaScript code is free software: you can redistribute
 *  it and/or modify it under the terms of the GNU Lesser
 *  General Public License (GNU LGPL) as published by the Free Software
 *  Foundation, either version 3 of the License, or (at your option)
 *  any later version.  The code is distributed WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS
 *  FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
 *
 *  As additional permission under GNU GPL version 3 section 7, you
 *  may distribute non-source (e.g., minimized or compacted) forms of
 *  that code without the copy of the GNU GPL normally required by
 *  section 4, provided you include this license notice and a URL
 *  through which recipients can access the Corresponding Source.
 */
 
/* 
 *  Comments are jsdoctoolkit formatted. See http://code.google.com/p/jsdoc-toolkit/
 */
 
/* The following comment is for JSLint: */
/*global window, ActiveXObject, unescape */
/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, regexp: true, sub: true, newcap: true, immed: true, evil: true, eqeqeq: false */


/**
 * @constructor
 * @description Provides all functionality to do hyphenation, except the patterns that are loaded
 * externally.
 * @author Mathias Nater, <a href = "mailto:mathias@mnn.ch">mathias@mnn.ch</a>
 * @version X.Y.Z
 * @namespace Holds all methods and properties
 * @example
 * &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
 * &lt;script type = "text/javascript"&gt;
 *   Hyphenator.run();
 * &lt;/script&gt;
 */
var Hyphenator = (function (window) {

	var
	/**
	 * @name Hyphenator-supportedLang
	 * @description
	 * A key-value object that stores supported languages.
	 * The key is the bcp47 code of the language and the value
	 * is the (abbreviated) filename of the pattern file.
	 * @type {Object.<string, string>}
	 * @private
	 * @example
	 * Check if language lang is supported:
	 * if (supportedLang.hasOwnProperty(lang))
	 */
	supportedLang = {
		'be': 'be.js',
		'cs': 'cs.js',
		'da': 'da.js',
		'bn': 'bn.js',
		'de': 'de.js',
		'el': 'el-monoton.js',
		'el-monoton': 'el-monoton.js',
		'el-polyton': 'el-polyton.js',
		'en': 'en-us.js',
		'en-gb': 'en-gb.js',
		'en-us': 'en-us.js',
		'es': 'es.js',
		'fi': 'fi.js',
		'fr': 'fr.js',
		'grc': 'grc.js',
		'gu': 'gu.js',
		'hi': 'hi.js',
		'hu': 'hu.js',
		'hy': 'hy.js',
		'it': 'it.js',
		'kn': 'kn.js',
		'la': 'la.js',
		'lt': 'lt.js',
		'lv': 'lv.js',
		'ml': 'ml.js',
		'no': 'no-nb.js',
		'no-nb': 'no-nb.js',
		'nl': 'nl.js',
		'or': 'or.js',
		'pa': 'pa.js',
		'pl': 'pl.js',
		'pt': 'pt.js',
		'ru': 'ru.js',
		'sl': 'sl.js',
		'sv': 'sv.js',
		'ta': 'ta.js',
		'te': 'te.js',
		'tr': 'tr.js',
		'uk': 'uk.js'
	},

	/**
	 * @name Hyphenator-languageHint
	 * @description
	 * An automatically generated string to be displayed in a prompt if the language can't be guessed.
	 * The string is generated using the supportedLang-object.
	 * @see Hyphenator-supportedLang
	 * @type {string}
	 * @private
	 * @see Hyphenator-autoSetMainLanguage
	 */

	languageHint = (function () {
		var k, r = '';
		for (k in supportedLang) {
			if (supportedLang.hasOwnProperty(k)) {
				r += k + ', ';
			}
		}
		r = r.substring(0, r.length - 2);
		return r;
	}()),
	
	/**
	 * @name Hyphenator-prompterStrings
	 * @description
	 * A key-value object holding the strings to be displayed if the language can't be guessed
	 * If you add hyphenation patterns change this string.
	 * @type {Object.<string,string>}
	 * @private
	 * @see Hyphenator-autoSetMainLanguage
	 */	
	prompterStrings = {
		'be': 'Мова гэтага сайта не можа быць вызначаны аўтаматычна. Калі ласка пакажыце мову:',
		'cs': 'Jazyk této internetové stránky nebyl automaticky rozpoznán. Určete prosím její jazyk:',
		'da': 'Denne websides sprog kunne ikke bestemmes. Angiv venligst sprog:',
		'de': 'Die Sprache dieser Webseite konnte nicht automatisch bestimmt werden. Bitte Sprache angeben:',
		'en': 'The language of this website could not be determined automatically. Please indicate the main language:',
		'es': 'El idioma del sitio no pudo determinarse autom%E1ticamente. Por favor, indique el idioma principal:',
		'fi': 'Sivun kielt%E4 ei tunnistettu automaattisesti. M%E4%E4rit%E4 sivun p%E4%E4kieli:',
		'fr': 'La langue de ce site n%u2019a pas pu %EAtre d%E9termin%E9e automatiquement. Veuillez indiquer une langue, s.v.p.%A0:',
		'hu': 'A weboldal nyelvét nem sikerült automatikusan megállapítani. Kérem adja meg a nyelvet:',
		'hy': 'Չհաջողվեց հայտնաբերել այս կայքի լեզուն։ Խնդրում ենք նշեք հիմնական լեզուն՝',
		'it': 'Lingua del sito sconosciuta. Indicare una lingua, per favore:',
		'kn': 'ಜಾಲ ತಾಣದ ಭಾಷೆಯನ್ನು ನಿರ್ಧರಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ದಯವಿಟ್ಟು ಮುಖ್ಯ ಭಾಷೆಯನ್ನು ಸೂಚಿಸಿ:',
		'lt': 'Nepavyko automatiškai nustatyti šios svetainės kalbos. Prašome įvesti kalbą:',
		'lv': 'Šīs lapas valodu nevarēja noteikt automātiski. Lūdzu norādiet pamata valodu:',
		'ml': 'ഈ വെ%u0D2C%u0D4D%u200Cസൈറ്റിന്റെ ഭാഷ കണ്ടുപിടിയ്ക്കാ%u0D28%u0D4D%u200D കഴിഞ്ഞില്ല. ഭാഷ ഏതാണെന്നു തിരഞ്ഞെടുക്കുക:',
		'nl': 'De taal van deze website kan niet automatisch worden bepaald. Geef de hoofdtaal op:',
		'no': 'Nettstedets språk kunne ikke finnes automatisk. Vennligst oppgi språk:',
		'pt': 'A língua deste site não pôde ser determinada automaticamente. Por favor indique a língua principal:',
		'ru': 'Язык этого сайта не может быть определен автоматически. Пожалуйста укажите язык:',
		'sl': 'Jezika te spletne strani ni bilo mogoče samodejno določiti. Prosim navedite jezik:',
		'sv': 'Spr%E5ket p%E5 den h%E4r webbplatsen kunde inte avg%F6ras automatiskt. V%E4nligen ange:',
		'tr': 'Bu web sitesinin dili otomatik olarak tespit edilememiştir. Lütfen dökümanın dilini seçiniz%A0:',
		'uk': 'Мова цього веб-сайту не може бути визначена автоматично. Будь ласка, вкажіть головну мову:'
	},
	
	/**
	 * @name Hyphenator-basePath
	 * @description
	 * A string storing the basepath from where Hyphenator.js was loaded.
	 * This is used to load the patternfiles.
	 * The basepath is determined dynamically by searching all script-tags for Hyphenator.js
	 * If the path cannot be determined http://hyphenator.googlecode.com/svn/trunk/ is used as fallback.
	 * @type {string}
	 * @private
	 * @see Hyphenator-loadPatterns
	 */
	basePath = (function () {
		var s = document.getElementsByTagName('script'), i = 0, p, src, t;
		while (!!(t = s[i++])) {
			if (!t.src) {
				continue;
			}
			src = t.src;
			p = src.indexOf('Hyphenator.js');
			if (p !== -1) {
				return src.substring(0, p);
			}
		}
		return 'http://hyphenator.googlecode.com/svn/trunk/';
	}()),

	/**
	 * @name Hyphenator-isLocal
	 * @description
	 * isLocal is true, if Hyphenator is loaded from the same domain, as the webpage, but false, if
	 * it's loaded from an external source (i.e. directly from google.code)
	 */
	isLocal = (function () {
		var re = false;
		if (window.location.href.indexOf(basePath) !== -1) {
			re = true;
		}
		return re;
	}()),
	
	/**
	 * @name Hyphenator-documentLoaded
	 * @description
	 * documentLoaded is true, when the DOM has been loaded. This is set by runOnContentLoaded
	 */
	documentLoaded = false,
	documentCount = 0,
	
	/**
	 * @name Hyphenator-persistentConfig
	 * @description
	 * if persistentConfig is set to true (defaults to false), config options and the state of the 
	 * toggleBox are stored in DOM-storage (according to the storage-setting). So they haven't to be
	 * set for each page.
	 */	
	persistentConfig = false,	

	/**
	 * @name Hyphenator-contextWindow
	 * @description
	 * contextWindow stores the window for the document to be hyphenated.
	 * If there are frames this will change.
	 * So use contextWindow instead of window!
	 */
	contextWindow = window,

	/**
	 * @name Hyphenator-doFrames
	 * @description
	 * switch to control if frames/iframes should be hyphenated, too
	 * defaults to false (frames are a bag of hurt!)
	 */
	doFrames = false,
	
	/**
	 * @name Hyphenator-dontHyphenate
	 * @description
	 * A key-value object containing all html-tags whose content should not be hyphenated
	 * @type {Object.<string,boolean>}
	 * @private
	 * @see Hyphenator-hyphenateElement
	 */
	dontHyphenate = {'script': true, 'code': true, 'pre': true, 'img': true, 'br': true, 'samp': true, 'kbd': true, 'var': true, 'abbr': true, 'acronym': true, 'sub': true, 'sup': true, 'button': true, 'option': true, 'label': true, 'textarea': true, 'input': true},

	/**
	 * @name Hyphenator-enableCache
	 * @description
	 * A variable to set if caching is enabled or not
	 * @type boolean
	 * @default true
	 * @private
	 * @see Hyphenator.config
	 * @see hyphenateWord
	 */
	enableCache = true,

	/**
	 * @name Hyphenator-storageType
	 * @description
	 * A variable to define what html5-DOM-Storage-Method is used ('none', 'local' or 'session')
	 * @type {string}
	 * @default 'none'
	 * @private
	 * @see Hyphenator.config
	 */	
	storageType = 'local',

	/**
	 * @name Hyphenator-storage
	 * @description
	 * An alias to the storage-Method defined in storageType.
	 * Set by Hyphenator.run()
	 * @type {Object|undefined}
	 * @default null
	 * @private
	 * @see Hyphenator.run
	 */	
	storage,
	
	/**
	 * @name Hyphenator-enableReducedPatternSet
	 * @description
	 * A variable to set if storing the used patterns is set
	 * @type boolean
	 * @default false
	 * @private
	 * @see Hyphenator.config
	 * @see hyphenateWord
	 * @see Hyphenator.getRedPatternSet
	 */	
	enableReducedPatternSet = false,
	
	/**
	 * @name Hyphenator-enableRemoteLoading
	 * @description
	 * A variable to set if pattern files should be loaded remotely or not
	 * @type boolean
	 * @default true
	 * @private
	 * @see Hyphenator.config
	 * @see Hyphenator-loadPatterns
	 */
	enableRemoteLoading = true,
	
	/**
	 * @name Hyphenator-displayToggleBox
	 * @description
	 * A variable to set if the togglebox should be displayed or not
	 * @type boolean
	 * @default false
	 * @private
	 * @see Hyphenator.config
	 * @see Hyphenator-toggleBox
	 */
	displayToggleBox = false,
	
	/**
	 * @name Hyphenator-hyphenateClass
	 * @description
	 * A string containing the css-class-name for the hyphenate class
	 * @type {string}
	 * @default 'hyphenate'
	 * @private
	 * @example
	 * &lt;p class = "hyphenate"&gt;Text&lt;/p&gt;
	 * @see Hyphenator.config
	 */
	hyphenateClass = 'hyphenate',

	/**
	 * @name Hyphenator-dontHyphenateClass
	 * @description
	 * A string containing the css-class-name for elements that should not be hyphenated
	 * @type {string}
	 * @default 'donthyphenate'
	 * @private
	 * @example
	 * &lt;p class = "donthyphenate"&gt;Text&lt;/p&gt;
	 * @see Hyphenator.config
	 */
	dontHyphenateClass = 'donthyphenate',
	
	/**
	 * @name Hyphenator-min
	 * @description
	 * A number wich indicates the minimal length of words to hyphenate.
	 * @type {number}
	 * @default 6
	 * @private
	 * @see Hyphenator.config
	 */	
	min = 6,
	
	/**
	 * @name Hyphenator-orphanControl
	 * @description
	 * Control how the last words of a line are handled:
	 * level 1 (default): last word is hyphenated
	 * level 2: last word is not hyphenated
	 * level 3: last word is not hyphenated and last space is non breaking
	 * @type {number}
	 * @default 1
	 * @private
	 */
	orphanControl = 1,
	
	/**
	 * @name Hyphenator-isBookmarklet
	 * @description
	 * Indicates if Hyphanetor runs as bookmarklet or not.
	 * @type boolean
	 * @default false
	 * @private
	 */	
	isBookmarklet = (function () {
		var loc = null, re = false, jsArray = document.getElementsByTagName('script'), i, l;
		for (i = 0, l = jsArray.length; i < l; i++) {
			if (!!jsArray[i].getAttribute('src')) {
				loc = jsArray[i].getAttribute('src');
			}
			if (!loc) {
				continue;
			} else if (loc.indexOf('Hyphenator.js?bm=true') !== -1) {
				re = true;
			}
		}
		return re;
	}()),
	
	/**
	 * @name Hyphenator-mainLanguage
	 * @description
	 * The general language of the document. In contrast to {@link Hyphenator-defaultLanguage},
	 * mainLanguage is defined by the client (i.e. by the html or by a prompt).
	 * @type {string|null}
	 * @private
	 * @see Hyphenator-autoSetMainLanguage
	 */	
	mainLanguage = null,

	/**
	 * @name Hyphenator-defaultLanguage
	 * @description
	 * The language defined by the developper. This language setting is defined by a config option.
	 * It is overwritten by any html-lang-attribute and only taken in count, when no such attribute can
	 * be found (i.e. just before the prompt).
	 * @type {string|null}
	 * @private
	 * @see Hyphenator-autoSetMainLanguage
	 */	
	defaultLanguage = '',

	/**
	 * @name Hyphenator-elements
	 * @description
	 * An array holding all elements that have to be hyphenated. This var is filled by
	 * {@link Hyphenator-gatherDocumentInfos}
	 * @type {Array}
	 * @private
	 */	
	elements = [],
	
	/**
	 * @name Hyphenator-exceptions
	 * @description
	 * An object containing exceptions as comma separated strings for each language.
	 * When the language-objects are loaded, their exceptions are processed, copied here and then deleted.
	 * @see Hyphenator-prepareLanguagesObj
	 * @type {Object}
	 * @private
	 */	
	exceptions = {},
	
	countObjProps = function (obj) {
		var k, l = 0;
		for (k in obj) {
			if (obj.hasOwnProperty(k)) {
				l++;
			}
		}
		return l;
	},
	/**
	 * @name Hyphenator-docLanguages
	 * @description
	 * An object holding all languages used in the document. This is filled by
	 * {@link Hyphenator-gatherDocumentInfos}
	 * @type {Object}
	 * @private
	 */	
	docLanguages = {},


	/**
	 * @name Hyphenator-state
	 * @description
	 * A number that inidcates the current state of the script
	 * 0: not initialized
	 * 1: loading patterns
	 * 2: ready
	 * 3: hyphenation done
	 * 4: hyphenation removed
	 * @type {number}
	 * @private
	 */	
	state = 0,

	/**
	 * @name Hyphenator-url
	 * @description
	 * A string containing a RegularExpression to match URL's
	 * @type {string}
	 * @private
	 */	
	url = '(\\w*:\/\/)?((\\w*:)?(\\w*)@)?((([\\d]{1,3}\\.){3}([\\d]{1,3}))|((www\\.|[a-zA-Z]\\.)?[a-zA-Z0-9\\-\\.]+\\.([a-z]{2,4})))(:\\d*)?(\/[\\w#!:\\.?\\+=&%@!\\-]*)*',
	//      protocoll     usr     pwd                    ip               or                          host                 tld        port               path
	/**
	 * @name Hyphenator-mail
	 * @description
	 * A string containing a RegularExpression to match mail-adresses
	 * @type {string}
	 * @private
	 */	
	mail = '[\\w-\\.]+@[\\w\\.]+',

	/**
	 * @name Hyphenator-urlRE
	 * @description
	 * A RegularExpressions-Object for url- and mail adress matching
	 * @type {RegExp}
	 * @private
	 */		
	urlOrMailRE = new RegExp('(' + url + ')|(' + mail + ')', 'i'),

	/**
	 * @name Hyphenator-zeroWidthSpace
	 * @description
	 * A string that holds a char.
	 * Depending on the browser, this is the zero with space or an empty string.
	 * zeroWidthSpace is used to break URLs
	 * @type {string}
	 * @private
	 */		
	zeroWidthSpace = (function () {
		var zws, ua = navigator.userAgent.toLowerCase();
		zws = String.fromCharCode(8203); //Unicode zero width space
		if (ua.indexOf('msie 6') !== -1) {
			zws = ''; //IE6 doesn't support zws
		}
		if (ua.indexOf('opera') !== -1 && ua.indexOf('version/10.00') !== -1) {
			zws = ''; //opera 10 on XP doesn't support zws
		}
		return zws;
	}()),
	
	/**
	 * @name Hyphenator-createElem
	 * @description
	 * A function alias to document.createElementNS or document.createElement
	 * @type {function(string, Object)}
	 * @private
	 */		
	createElem = function (tagname, context) {
		context = context || contextWindow;
		if (document.createElementNS) {
			return context.document.createElementNS('http://www.w3.org/1999/xhtml', tagname);
		} else if (document.createElement) {
			return context.document.createElement(tagname);
		}
	},
	
	/**
	 * @name Hyphenator-onHyphenationDone
	 * @description
	 * A method to be called, when the last element has been hyphenated or the hyphenation has been
	 * removed from the last element.
	 * @see Hyphenator.config
	 * @type {function()}
	 * @private
	 */		
	onHyphenationDone = function () {},

	/**
	 * @name Hyphenator-onError
	 * @description
	 * A function that can be called upon an error.
	 * @see Hyphenator.config
	 * @type {function(Object)}
	 * @private
	 */		
	onError = function (e) {
		window.alert("Hyphenator.js says:\n\nAn Error ocurred:\n" + e.message);
	},

	/**
	 * @name Hyphenator-selectorFunction
	 * @description
	 * A function that has to return a HTMLNodeList of Elements to be hyphenated.
	 * By default it uses the classname ('hyphenate') to select the elements.
	 * @see Hyphenator.config
	 * @type {function()}
	 * @private
	 */		
	selectorFunction = function () {
		var tmp, el = [], i, l;
		if (document.getElementsByClassName) {
			el = contextWindow.document.getElementsByClassName(hyphenateClass);
		} else {
			tmp = contextWindow.document.getElementsByTagName('*');
			l = tmp.length;
			for (i = 0; i < l; i++)
			{
				if (tmp[i].className.indexOf(hyphenateClass) !== -1 && tmp[i].className.indexOf(dontHyphenateClass) === -1) {
					el.push(tmp[i]);
				}
			}
		}
		return el;
	},

	/**
	 * @name Hyphenator-intermediateState
	 * @description
	 * The value of style.visibility of the text while it is hyphenated.
	 * @see Hyphenator.config
	 * @type {string}
	 * @private
	 */		
	intermediateState = 'hidden',
	
	/**
	 * @name Hyphenator-hyphen
	 * @description
	 * A string containing the character for in-word-hyphenation
	 * @type {string}
	 * @default the soft hyphen
	 * @private
	 * @see Hyphenator.config
	 */
	hyphen = String.fromCharCode(173),
	
	/**
	 * @name Hyphenator-urlhyphen
	 * @description
	 * A string containing the character for url/mail-hyphenation
	 * @type {string}
	 * @default the zero width space
	 * @private
	 * @see Hyphenator.config
	 * @see Hyphenator-zeroWidthSpace
	 */
	urlhyphen = zeroWidthSpace,

	/**
	 * @name Hyphenator-safeCopy
	 * @description
	 * Defines wether work-around for copy issues is active or not
	 * Not supported by Opera (no onCopy handler)
	 * @type boolean
	 * @default true
	 * @private
	 * @see Hyphenator.config
	 * @see Hyphenator-registerOnCopy
	 */
	safeCopy = true,
	
	/**
	 * @name Hyphenator-Expando
	 * @description
	 * This custom object stores data for elements: storing data directly in elements
	 * (DomElement.customData = foobar;) isn't a good idea. It would lead to conflicts
	 * in form elements, when the form has a child with name="foobar". Therefore, this
	 * solution follows the approach of jQuery: the data is stored in an object and
	 * referenced by a unique attribute of the element. The attribute has a name that 
	 * is built by the prefix "HyphenatorExpando_" and a random number, so if the very
	 * very rare case occurs, that there's already an attribute with the same name, a
	 * simple reload is enough to make it function.
	 * @private
	 */		
	Expando = (function () {
		var container = {},
			name = "HyphenatorExpando_" + Math.random(),
			uuid = 0;
		return {
			getDataForElem : function (elem) {
				return container[elem[name].id];
			},
			setDataForElem : function (elem, data) {
				var id;
				if (elem[name] && elem[name].id !== '') {
					id = elem[name].id;
				} else {
					id = uuid++;
					elem[name] = {'id': id}; //object needed, otherways it is reflected in HTML in IE
				}
				container[id] = data;
			},
			appendDataForElem : function (elem, data) {
				var k;
				for (k in data) {
					if (data.hasOwnProperty(k)) {
						container[elem[name].id][k] = data[k];
					}
				}
			},
			delDataOfElem : function (elem) {
				delete container[elem[name]];
			}
		};
	}()),
		
	/*
	 * runOnContentLoaded is based od jQuery.bindReady()
	 * see
	 * jQuery JavaScript Library v1.3.2
	 * http://jquery.com/
	 *
	 * Copyright (c) 2009 John Resig
	 * Dual licensed under the MIT and GPL licenses.
	 * http://docs.jquery.com/License
	 *
	 * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
	 * Revision: 6246
	 */
	/**
	 * @name Hyphenator-runOnContentLoaded
	 * @description
	 * A crossbrowser solution for the DOMContentLoaded-Event based on jQuery
	 * <a href = "http://jquery.com/</a>
	 * I added some functionality: e.g. support for frames and iframes…
	 * @param {Object} w the window-object
	 * @param {function()} f the function to call onDOMContentLoaded
	 * @private
	 */
	runOnContentLoaded = function (w, f) {
		var DOMContentLoaded = function () {}, toplevel, hyphRunForThis = {};
		if (documentLoaded && !hyphRunForThis[w.location.href]) {
			f();
			hyphRunForThis[w.location.href] = true;
			return;
		}
		function init(context) {
			contextWindow = context || window;
			if (!hyphRunForThis[contextWindow.location.href] && (!documentLoaded || contextWindow != window.parent)) {
				documentLoaded = true;
				f();
				hyphRunForThis[contextWindow.location.href] = true;
			}
		}
		
		function doScrollCheck() {
			try {
				// If IE is used, use the trick by Diego Perini
				// http://javascript.nwbox.com/IEContentLoaded/
				document.documentElement.doScroll("left");
			} catch (error) {
				setTimeout(doScrollCheck, 1);
				return;
			}
		
			// and execute any waiting functions
			init(window);
		}

		function doOnLoad() {
			var i, haveAccess, fl = window.frames.length;
			if (doFrames && fl > 0) {
				for (i = 0; i < fl; i++) {
					haveAccess = undefined;
					//try catch isn't enough for webkit
					try {
						//opera throws only on document.toString-access
						haveAccess = window.frames[i].document.toString();
					} catch (e) {
						haveAccess = undefined;
					}
					if (!!haveAccess) {
						init(window.frames[i]);
					}
				}
				contextWindow = window;
				f();
				hyphRunForThis[window.location.href] = true;
			} else {
				init(window);
			}
		}
		
		// Cleanup functions for the document ready method
		if (document.addEventListener) {
			DOMContentLoaded = function () {
				document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
				if (doFrames && window.frames.length > 0) {
					//we are in a frameset, so do nothing but wait for onload to fire
					return;
				} else {
					init(window);
				}
			};
		
		} else if (document.attachEvent) {
			DOMContentLoaded = function () {
				// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
				if (document.readyState === "complete") {
					document.detachEvent("onreadystatechange", DOMContentLoaded);
					if (doFrames && window.frames.length > 0) {
						//we are in a frameset, so do nothing but wait for onload to fire
						return;
					} else {
						init(window);
					}
				}
			};
		}

		// Mozilla, Opera and webkit nightlies currently support this event
		if (document.addEventListener) {
			// Use the handy event callback
			document.addEventListener("DOMContentLoaded", DOMContentLoaded, false);
			
			// A fallback to window.onload, that will always work
			window.addEventListener("load", doOnLoad, false);

		// If IE event model is used
		} else if (document.attachEvent) {
			// ensure firing before onload,
			// maybe late but safe also for iframes
			document.attachEvent("onreadystatechange", DOMContentLoaded);
			
			// A fallback to window.onload, that will always work
			window.attachEvent("onload", doOnLoad);

			// If IE and not a frame
			// continually check to see if the document is ready
			toplevel = false;
			try {
				toplevel = window.frameElement === null;
			} catch (e) {}

			if (document.documentElement.doScroll && toplevel) {
				doScrollCheck();
			}
		}

	},



	/**
	 * @name Hyphenator-getLang
	 * @description
	 * Gets the language of an element. If no language is set, it may use the {@link Hyphenator-mainLanguage}.
	 * @param {Object} el The first parameter is an DOM-Element-Object
	 * @param {boolean} fallback The second parameter is a boolean to tell if the function should return the {@link Hyphenator-mainLanguage}
	 * if there's no language found for the element.
	 * @private
	 */
	getLang = function (el, fallback) {
		if (!!el.getAttribute('lang')) {
			return el.getAttribute('lang').toLowerCase();
		}
		// The following doesn't work in IE due to a bug when getAttribute('xml:lang') in a table
		/*if (!!el.getAttribute('xml:lang')) {
			return el.getAttribute('xml:lang').substring(0, 2);
		}*/
		//instead, we have to do this (thanks to borgzor):
		try {
			if (!!el.getAttribute('xml:lang')) {
				return el.getAttribute('xml:lang').toLowerCase();
			}
		} catch (ex) {}
		if (el.tagName !== 'HTML') {
			return getLang(el.parentNode, true);
		}
		if (fallback) {
			return mainLanguage;
		}
		return null;
	},
	
	/**
	 * @name Hyphenator-autoSetMainLanguage
	 * @description
	 * Retrieves the language of the document from the DOM.
	 * The function looks in the following places:
	 * <ul>
	 * <li>lang-attribute in the html-tag</li>
	 * <li>&lt;meta http-equiv = "content-language" content = "xy" /&gt;</li>
	 * <li>&lt;meta name = "DC.Language" content = "xy" /&gt;</li>
	 * <li>&lt;meta name = "language" content = "xy" /&gt;</li>
	 * </li>
	 * If nothing can be found a prompt using {@link Hyphenator-languageHint} and {@link Hyphenator-prompterStrings} is displayed.
	 * If the retrieved language is in the object {@link Hyphenator-supportedLang} it is copied to {@link Hyphenator-mainLanguage}
	 * @private
	 */		
	autoSetMainLanguage = function (w) {
		w = w || contextWindow;
		var el = w.document.getElementsByTagName('html')[0],
			m = w.document.getElementsByTagName('meta'),
			i, text, e, ul;
		mainLanguage = getLang(el, false);
		if (!mainLanguage) {
			for (i = 0; i < m.length; i++) {
				//<meta http-equiv = "content-language" content="xy">	
				if (!!m[i].getAttribute('http-equiv') && (m[i].getAttribute('http-equiv').toLowerCase() === 'content-language')) {
					mainLanguage = m[i].getAttribute('content').toLowerCase();
				}
				//<meta name = "DC.Language" content="xy">
				if (!!m[i].getAttribute('name') && (m[i].getAttribute('name').toLowerCase() === 'dc.language')) {
					mainLanguage = m[i].getAttribute('content').toLowerCase();
				}			
				//<meta name = "language" content = "xy">
				if (!!m[i].getAttribute('name') && (m[i].getAttribute('name').toLowerCase() === 'language')) {
					mainLanguage = m[i].getAttribute('content').toLowerCase();
				}
			}
		}
		//get lang for frame from enclosing document
		if (!mainLanguage && doFrames && contextWindow != window.parent) {
			autoSetMainLanguage(window.parent);
		}
		//fallback to defaultLang if set
		if (!mainLanguage && defaultLanguage !== '') {
			mainLanguage = defaultLanguage;
		}
		//ask user for lang
		if (!mainLanguage) {
			text = '';
			ul = navigator.language ? navigator.language : navigator.userLanguage;
			ul = ul.substring(0, 2);
			if (prompterStrings.hasOwnProperty(ul)) {
				text = prompterStrings[ul];
			} else {
				text = prompterStrings.en;
			}
			text += ' (ISO 639-1)\n\n' + languageHint;
			mainLanguage = window.prompt(unescape(text), ul).toLowerCase();
		}
		if (!supportedLang.hasOwnProperty(mainLanguage)) {
			if (supportedLang.hasOwnProperty(mainLanguage.split('-')[0])) { //try subtag
				mainLanguage = mainLanguage.split('-')[0];
			} else {
				e = new Error('The language "' + mainLanguage + '" is not yet supported.');
				throw e;
			}
		}
	},
    
	/**
	 * @name Hyphenator-gatherDocumentInfos
	 * @description
	 * This method runs through the DOM and executes the process()-function on:
	 * - every node returned by the {@link Hyphenator-selectorFunction}.
	 * The process()-function copies the element to the elements-variable, sets its visibility
	 * to intermediateState, retrieves its language and recursivly descends the DOM-tree until
	 * the child-Nodes aren't of type 1
	 * @private
	 */		
	gatherDocumentInfos = function () {
		var elToProcess, tmp, i = 0,
		process = function (el, hide, lang) {
			var n, i = 0, hyphenatorSettings = {};
			if (hide && intermediateState === 'hidden') {
				if (!!el.getAttribute('style')) {
					hyphenatorSettings.hasOwnStyle = true;
				} else {
					hyphenatorSettings.hasOwnStyle = false;					
				}
				hyphenatorSettings.isHidden = true;
				el.style.visibility = 'hidden';
			}
			if (el.lang && typeof(el.lang) === 'string') {
				hyphenatorSettings.language = el.lang.toLowerCase(); //copy attribute-lang to internal lang
			} else if (lang) {
				hyphenatorSettings.language = lang.toLowerCase();
			} else {
				hyphenatorSettings.language = getLang(el, true);
			}
			lang = hyphenatorSettings.language;
			if (supportedLang[lang]) {
				docLanguages[lang] = true;
			} else {
				if (supportedLang.hasOwnProperty(lang.split('-')[0])) { //try subtag
					lang = lang.split('-')[0];
					hyphenatorSettings.language = lang;
				} else if (!isBookmarklet) {
					onError(new Error('Language ' + lang + ' is not yet supported.'));
				}
			}
			Expando.setDataForElem(el, hyphenatorSettings);			
			
			elements.push(el);
			while (!!(n = el.childNodes[i++])) {
				if (n.nodeType === 1 && !dontHyphenate[n.nodeName.toLowerCase()] &&
					n.className.indexOf(dontHyphenateClass) === -1 && !(n in elToProcess)) {
					process(n, false, lang);
				}
			}
		};
		if (isBookmarklet) {
			elToProcess = contextWindow.document.getElementsByTagName('body')[0];
			process(elToProcess, false, mainLanguage);
		} else {
			elToProcess = selectorFunction();
			while (!!(tmp = elToProcess[i++]))
			{
				process(tmp, true, '');
			}			
		}
		if (!Hyphenator.languages.hasOwnProperty(mainLanguage)) {
			docLanguages[mainLanguage] = true;
		} else if (!Hyphenator.languages[mainLanguage].prepared) {
			docLanguages[mainLanguage] = true;
		}
		if (elements.length > 0) {
			Expando.appendDataForElem(elements[elements.length - 1], {isLast : true});
		}
	},
		 
	/**
	 * @name Hyphenator-convertPatterns
	 * @description
	 * Converts the patterns from string '_a6' to object '_a':'_a6'.
	 * The result is stored in the {@link Hyphenator-patterns}-object.
	 * @private
	 * @param {string} lang the language whose patterns shall be converted
	 */		
	convertPatterns = function (lang) {
		var plen, anfang, ende, pats, pat, key, tmp = {};
		pats = Hyphenator.languages[lang].patterns;
		for (plen in pats) {
			if (pats.hasOwnProperty(plen)) {
				plen = parseInt(plen, 10);
				anfang = 0;
				ende = plen;
				while (!!(pat = pats[plen].substring(anfang, ende))) {
					key = pat.replace(/\d/g, '');
					tmp[key] = pat;
					anfang = ende;
					ende += plen;
				}
			}
		}
		Hyphenator.languages[lang].patterns = tmp;
		Hyphenator.languages[lang].patternsConverted = true;
	},

	/**
	 * @name Hyphenator-convertExceptionsToObject
	 * @description
	 * Converts a list of comma seprated exceptions to an object:
	 * 'Fortran,Hy-phen-a-tion' -> {'Fortran':'Fortran','Hyphenation':'Hy-phen-a-tion'}
	 * @private
	 * @param {string} exc a comma separated string of exceptions (without spaces)
	 */		
	convertExceptionsToObject = function (exc) {
		var w = exc.split(', '),
			r = {},
			i, l, key;
		for (i = 0, l = w.length; i < l; i++) {
			key = w[i].replace(/-/g, '');
			if (!r.hasOwnProperty(key)) {
				r[key] = w[i];
			}
		}
		return r;
	},
	
	/**
	 * @name Hyphenator-loadPatterns
	 * @description
	 * Adds a &lt;script&gt;-Tag to the DOM to load an externeal .js-file containing patterns and settings for the given language.
	 * If the given language is not in the {@link Hyphenator-supportedLang}-Object it returns.
	 * One may ask why we are not using AJAX to load the patterns. The XMLHttpRequest-Object 
	 * has a same-origin-policy. This makes the isBookmarklet-functionality impossible.
	 * @param {string} lang The language to load the patterns for
	 * @private
	 * @see Hyphenator-basePath
	 */
	loadPatterns = function (lang) {
		var url, xhr, head, script;
		if (supportedLang[lang] && !Hyphenator.languages[lang]) {
	        url = basePath + 'patterns/' + supportedLang[lang];
		} else {
			return;
		}
		if (isLocal && !isBookmarklet) {
			//check if 'url' is available:
			xhr = null;
			if (typeof XMLHttpRequest !== 'undefined') {
				xhr = new XMLHttpRequest();
			}
			if (!xhr) {
				try {
					xhr  = new ActiveXObject("Msxml2.XMLHTTP");
				} catch (e) {
					xhr  = null;
				}
			}
			if (xhr) {
				xhr.open('HEAD', url, false);
				xhr.setRequestHeader('Cache-Control', 'no-cache');
				xhr.send(null);
				if (xhr.status === 404) {
					onError(new Error('Could not load\n' + url));
					delete docLanguages[lang];
					return;
				}
			}
		}
		if (createElem) {
			head = window.document.getElementsByTagName('head').item(0);
			script = createElem('script', window);
			script.src = url;
			script.type = 'text/javascript';
			head.appendChild(script);
		}
	},
	
	/**
	 * @name Hyphenator-prepareLanguagesObj
	 * @description
	 * Adds a cache to each language and converts the exceptions-list to an object.
	 * If storage is active the object is stored there.
	 * @private
	 * @param {string} lang the language ob the lang-obj
	 */		
	prepareLanguagesObj = function (lang) {
		var lo = Hyphenator.languages[lang], wrd;
		if (!lo.prepared) {	
			if (enableCache) {
				lo.cache = {};
				//Export
				lo['cache'] = lo.cache;
			}
			if (enableReducedPatternSet) {
				lo.redPatSet = {};
			}
			//add exceptions from the pattern file to the local 'exceptions'-obj
			if (lo.hasOwnProperty('exceptions')) {
				Hyphenator.addExceptions(lang, lo.exceptions);
				delete lo.exceptions;
			}
			//copy global exceptions to the language specific exceptions
			if (exceptions.hasOwnProperty('global')) {
				if (exceptions.hasOwnProperty(lang)) {
					exceptions[lang] += ', ' + exceptions.global;
				} else {
					exceptions[lang] = exceptions.global;
				}
			}
			//move exceptions from the the local 'exceptions'-obj to the 'language'-object
			if (exceptions.hasOwnProperty(lang)) {
				lo.exceptions = convertExceptionsToObject(exceptions[lang]);
				delete exceptions[lang];
			} else {
				lo.exceptions = {};
			}
			convertPatterns(lang);
			wrd = '[\\w' + lo.specialChars + '@' + String.fromCharCode(173) + String.fromCharCode(8204) + '-]{' + min + ',}';
			lo.genRegExp = new RegExp('(' + url + ')|(' + mail + ')|(' + wrd + ')', 'gi');
			lo.prepared = true;
		}
		if (!!storage) {
			try {
				storage.setItem('Hyphenator_' + lang, window.JSON.stringify(lo));
			} catch (e) {
				//onError(e);
			}
		}
		
	},
	
	/**
	 * @name Hyphenator-prepare
	 * @description
	 * This funtion prepares the Hyphenator-Object: If RemoteLoading is turned off, it assumes
	 * that the patternfiles are loaded, all conversions are made and the callback is called.
	 * If storage is active the object is retrieved there.
	 * If RemoteLoading is on (default), it loads the pattern files and waits until they are loaded,
	 * by repeatedly checking Hyphenator.languages. If a patterfile is loaded the patterns are
	 * converted to their object style and the lang-object extended.
	 * Finally the callback is called.
	 * @param {function()} callback to call, when all patterns are loaded
	 * @private
	 */
	prepare = function (callback) {
		var lang, interval, tmp1, tmp2;
		if (!enableRemoteLoading) {
			for (lang in Hyphenator.languages) {
				if (Hyphenator.languages.hasOwnProperty(lang)) {
					prepareLanguagesObj(lang);
				}
			}
			state = 2;
			callback();
			return;
		}
		// get all languages that are used and preload the patterns
		state = 1;
		for (lang in docLanguages) {
			if (docLanguages.hasOwnProperty(lang)) {
				if (!!storage && storage.getItem('Hyphenator_' + lang)) {
					Hyphenator.languages[lang] = window.JSON.parse(storage.getItem('Hyphenator_' + lang));
					if (exceptions.hasOwnProperty('global')) {
						tmp1 = convertExceptionsToObject(exceptions.global);
						for (tmp2 in tmp1) {
							if (tmp1.hasOwnProperty(tmp2)) {
								Hyphenator.languages[lang].exceptions[tmp2] = tmp1[tmp2];
							}
						}
					}
					//Replace exceptions since they may have been changed:
					if (exceptions.hasOwnProperty(lang)) {
						tmp1 = convertExceptionsToObject(exceptions[lang]);
						for (tmp2 in tmp1) {
							if (tmp1.hasOwnProperty(tmp2)) {
								Hyphenator.languages[lang].exceptions[tmp2] = tmp1[tmp2];
							}
						}
						delete exceptions[lang];
					}
					//Replace genRegExp since it may have been changed:
					tmp1 = '[\\w' + Hyphenator.languages[lang].specialChars + '@' + String.fromCharCode(173) + String.fromCharCode(8204) + '-]{' + min + ',}';
					Hyphenator.languages[lang].genRegExp = new RegExp('(' + url + ')|(' + mail + ')|(' + tmp1 + ')', 'gi');
					
					delete docLanguages[lang];
					continue;
				} else {
					loadPatterns(lang);
				}
			}
		}
		// if all patterns are loaded from storage: callback
		if (countObjProps(docLanguages) === 0) {
			state = 2;
			callback();
			return;
		}
		// else async wait until patterns are loaded, then callback
		interval = window.setInterval(function () {
			var finishedLoading = true, lang;
			for (lang in docLanguages) {
				if (docLanguages.hasOwnProperty(lang)) {
					finishedLoading = false;
					if (!!Hyphenator.languages[lang]) {
						delete docLanguages[lang];
						//do conversion while other patterns are loading:
						prepareLanguagesObj(lang);
					}
				}
			}
			if (finishedLoading) {
				//console.log('callig callback for ' + contextWindow.location.href);
				window.clearInterval(interval);
				state = 2;
				callback();
			}
		}, 100);
	},

	/**
	 * @name Hyphenator-switchToggleBox
	 * @description
	 * Creates or hides the toggleBox: a small button to turn off/on hyphenation on a page.
	 * @see Hyphenator.config
	 * @private
	 */		
	toggleBox = function () {
		var myBox, bdy, myIdAttribute, myTextNode, myClassAttribute,
		text = (Hyphenator.doHyphenation ? 'Hy-phen-a-tion' : 'Hyphenation');
		if (!!(myBox = contextWindow.document.getElementById('HyphenatorToggleBox'))) {
			myBox.firstChild.data = text;
		} else {
			bdy = contextWindow.document.getElementsByTagName('body')[0];
			myBox = createElem('div', contextWindow);
			myIdAttribute = contextWindow.document.createAttribute('id');
			myIdAttribute.nodeValue = 'HyphenatorToggleBox';
			myClassAttribute = contextWindow.document.createAttribute('class');
			myClassAttribute.nodeValue = dontHyphenateClass;
			myTextNode = contextWindow.document.createTextNode(text);
			myBox.appendChild(myTextNode);
			myBox.setAttributeNode(myIdAttribute);
			myBox.setAttributeNode(myClassAttribute);
			myBox.onclick =  Hyphenator.toggleHyphenation;
			myBox.style.position = 'absolute';
			myBox.style.top = '0px';
			myBox.style.right = '0px';
			myBox.style.margin = '0';
			myBox.style.backgroundColor = '#AAAAAA';
			myBox.style.color = '#FFFFFF';
			myBox.style.font = '6pt Arial';
			myBox.style.letterSpacing = '0.2em';
			myBox.style.padding = '3px';
			myBox.style.cursor = 'pointer';
			myBox.style.WebkitBorderBottomLeftRadius = '4px';
			myBox.style.MozBorderRadiusBottomleft = '4px';
			bdy.appendChild(myBox);
		}
	},

	/**
	 * @name Hyphenator-hyphenateWord
	 * @description
	 * This function is the heart of Hyphenator.js. It returns a hyphenated word.
	 *
	 * If there's already a {@link Hyphenator-hypen} in the word, the word is returned as it is.
	 * If the word is in the exceptions list or in the cache, it is retrieved from it.
	 * If there's a '-' put a zeroWidthSpace after the '-' and hyphenate the parts.
	 * @param {string} lang The language of the word
	 * @param {string} word The word
	 * @returns string The hyphenated word
	 * @public
	 */	
	hyphenateWord = function (lang, word) {
		var lo = Hyphenator.languages[lang],
			parts, i, l, w, wl, s, hypos, p, maxwins, win, pat = false, patk, c, t, n, numb3rs, inserted, hyphenatedword, val, subst, ZWNJpos = [];
		if (word === '') {
			return '';
		}
		if (word.indexOf(hyphen) !== -1) {
			//word already contains shy; -> leave at it is!
			return word;
		}
		if (enableCache && lo.cache.hasOwnProperty(word)) { //the word is in the cache
			return lo.cache[word];
		}
		if (lo.exceptions.hasOwnProperty(word)) { //the word is in the exceptions list
			return lo.exceptions[word].replace(/-/g, hyphen);
		}
		if (word.indexOf('-') !== -1) {
			//word contains '-' -> hyphenate the parts separated with '-'
			parts = word.split('-');
			for (i = 0, l = parts.length; i < l; i++) {
				parts[i] = hyphenateWord(lang, parts[i]);
			}
			return parts.join('-');
		}
		w = '_' + word + '_';
		if (word.indexOf(String.fromCharCode(8204)) !== -1) {
			parts = w.split(String.fromCharCode(8204));
			w = parts.join('');
			for (i = 0, l = parts.length; i < l; i++) {
				parts[i] = parts[i].length.toString();
			}
			parts.pop();
			ZWNJpos = parts;
		}
		wl = w.length;
		s = w.split('');
		if (!!lo.charSubstitution) {
			for (subst in lo.charSubstitution) {
				if (lo.charSubstitution.hasOwnProperty(subst)) {
					w = w.replace(new RegExp(subst, 'g'), lo.charSubstitution[subst]);
				}
			}
		}
		if (word.indexOf("'") !== -1) {
			w = w.toLowerCase().replace("'", "’"); //replace APOSTROPHE with RIGHT SINGLE QUOTATION MARK (since the latter is used in the patterns)
		} else {
			w = w.toLowerCase();
		}
		//finally the core hyphenation algorithm
		hypos = [];
		numb3rs = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}; //check for member is faster then isFinite()
		n = wl - lo.shortestPattern;
		for (p = 0; p <= n; p++) {
			maxwins = Math.min((wl - p), lo.longestPattern);
			for (win = lo.shortestPattern; win <= maxwins; win++) {
				if (lo.patterns.hasOwnProperty(patk = w.substring(p, p + win))) {
					pat = lo.patterns[patk];
					if (enableReducedPatternSet && (typeof pat === 'string')) {
						lo.redPatSet[patk] = pat;
					}
					if (typeof pat === 'string') {
						//convert from string 'a5b' to array [1,5] (pos,value)
						t = 0;
						val = [];
						for (i = 0; i < pat.length; i++) {
							if (!!(c = numb3rs[pat.charAt(i)])) {
								val.push(i - t, c);
								t++;								
							}
						}
						pat = lo.patterns[patk] = val;
					}
				} else {
					continue;
				}
				for (i = 0; i < pat.length; i++) {
					c = p - 1 + pat[i];
					if (!hypos[c] || hypos[c] < pat[i + 1]) {
						hypos[c] = pat[i + 1];
					}
					i++;
				}
			}
		}
		inserted = 0;
		for (i = lo.leftmin; i <= (wl - 2 - lo.rightmin); i++) {
			if (ZWNJpos.length > 0 && ZWNJpos[0] === i) {
				ZWNJpos.shift();
				s.splice(i + inserted - 1, 0, String.fromCharCode(8204));
				inserted++;
			}			
			if (!!(hypos[i] & 1)) {
				s.splice(i + inserted + 1, 0, hyphen);
				inserted++;
			}
		}
		hyphenatedword = s.slice(1, -1).join('');
		if (enableCache) {
			lo.cache[word] = hyphenatedword;
		}
		return hyphenatedword;
	},
		
	/**
	 * @name Hyphenator-hyphenateURL
	 * @description
	 * Puts {@link Hyphenator-urlhyphen} after each no-alphanumeric char that my be in a URL.
	 * @param {string} url to hyphenate
	 * @returns string the hyphenated URL
	 * @public
	 */
	hyphenateURL = function (url) {
		return url.replace(/([:\/\.\?#&_,;!@]+)/gi, '$&' + urlhyphen);
	},

	/**
	 * @name Hyphenator-removeHyphenationFromElement
	 * @description
	 * Removes all hyphens from the element. If there are other elements, the function is
	 * called recursively.
	 * Removing hyphens is usefull if you like to copy text. Some browsers are buggy when the copy hyphenated texts.
	 * @param {Object} el The element where to remove hyphenation.
	 * @public
	 */
	removeHyphenationFromElement = function (el) {
		var h, i = 0, n;
		switch (hyphen) {
		case '|':
			h = '\\|';
			break;
		case '+':
			h = '\\+';
			break;
		case '*':
			h = '\\*';
			break;
		default:
			h = hyphen;
		}
		while (!!(n = el.childNodes[i++])) {
			if (n.nodeType === 3) {
				n.data = n.data.replace(new RegExp(h, 'g'), '');
				n.data = n.data.replace(new RegExp(zeroWidthSpace, 'g'), '');
			} else if (n.nodeType === 1) {
				removeHyphenationFromElement(n);
			}
		}
	},
	
	
	/**
	 * @name Hyphenator-registerOnCopy
	 * @description
	 * Huge work-around for browser-inconsistency when it comes to
	 * copying of hyphenated text.
	 * The idea behind this code has been provided by http://github.com/aristus/sweet-justice
	 * sweet-justice is under BSD-License
	 * @private
	 */
	registerOnCopy = function (el) {
		var body = el.ownerDocument.getElementsByTagName('body')[0],
		shadow,
		selection,
		range,
		rangeShadow,
		restore,
		oncopyHandler = function (e) {
			e = e || window.event;
			var target = e.target || e.srcElement,
			currDoc = target.ownerDocument,
			body = currDoc.getElementsByTagName('body')[0],
			targetWindow = 'defaultView' in currDoc ? currDoc.defaultView : currDoc.parentWindow;
			if (target.tagName && dontHyphenate[target.tagName.toLowerCase()]) {
				//Safari needs this
				return;
			}
			//create a hidden shadow element
			shadow = currDoc.createElement('div');
			shadow.style.overflow = 'hidden';
			shadow.style.position = 'absolute';
			shadow.style.top = '-5000px';
			shadow.style.height = '1px';
			body.appendChild(shadow);
			if (!!window.getSelection) {
				//FF3, Webkit
				selection = targetWindow.getSelection();
				range = selection.getRangeAt(0);
				shadow.appendChild(range.cloneContents());
				removeHyphenationFromElement(shadow);
				selection.selectAllChildren(shadow);
				restore = function () {
					shadow.parentNode.removeChild(shadow);
					selection.addRange(range);
				};
			} else {
				// IE
				selection = targetWindow.document.selection;
				range = selection.createRange();
				shadow.innerHTML = range.htmlText;
				removeHyphenationFromElement(shadow);
				rangeShadow = body.createTextRange();
				rangeShadow.moveToElementText(shadow);
				rangeShadow.select();
				restore = function () {
					shadow.parentNode.removeChild(shadow);
					if (range.text !== "") {
						range.select();
					}
				};
			}
			window.setTimeout(restore, 0);
		};
		if (!body) {
			return;
		}
		el = el || body;
		if (window.addEventListener) {
			el.addEventListener("copy", oncopyHandler, false);
		} else {
			el.attachEvent("oncopy", oncopyHandler);
		}
	},
	

	/**
	 * @name Hyphenator-hyphenateElement
	 * @description
	 * Takes the content of the given element and - if there's text - replaces the words
	 * by hyphenated words. If there's another element, the function is called recursively.
	 * When all words are hyphenated, the visibility of the element is set to 'visible'.
	 * @param {Object} el The element to hyphenate
	 * @private
	 */
	hyphenateElement = function (el) {
		var hyphenatorSettings = Expando.getDataForElem(el),
			lang = hyphenatorSettings.language, hyphenate, n, i,
			controlOrphans = function (part) {
				var h, r;
				switch (hyphen) {
				case '|':
					h = '\\|';
					break;
				case '+':
					h = '\\+';
					break;
				case '*':
					h = '\\*';
					break;
				default:
					h = hyphen;
				}
				if (orphanControl >= 2) {
					//remove hyphen points from last word
					r = part.split(' ');
					r[1] = r[1].replace(new RegExp(h, 'g'), '');
					r[1] = r[1].replace(new RegExp(zeroWidthSpace, 'g'), '');
					r = r.join(' ');
				}
				if (orphanControl === 3) {
					//replace spaces by non breaking spaces
					r = r.replace(/[ ]+/g, String.fromCharCode(160));
				}
				return r;
			};
		if (Hyphenator.languages.hasOwnProperty(lang)) {
			hyphenate = function (word) {
				if (!Hyphenator.doHyphenation) {
					return word;
				} else if (urlOrMailRE.test(word)) {
					return hyphenateURL(word);
				} else {
					return hyphenateWord(lang, word);
				}
			};
			if (safeCopy && (el.tagName.toLowerCase() !== 'body')) {
				registerOnCopy(el);
			}
			i = 0;
			while (!!(n = el.childNodes[i++])) {
				if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate!
					n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate);
					if (orphanControl !== 1) {
						n.data = n.data.replace(/[\S]+ [\S]+$/, controlOrphans);
					}
				}
			}
		}
		if (hyphenatorSettings.isHidden && intermediateState === 'hidden') {
			el.style.visibility = 'visible';
			if (!hyphenatorSettings.hasOwnStyle) {
				el.setAttribute('style', ''); // without this, removeAttribute doesn't work in Safari (thanks to molily)
				el.removeAttribute('style');
			} else {
				if (el.style.removeProperty) {
					el.style.removeProperty('visibility');
				} else if (el.style.removeAttribute) { // IE
					el.style.removeAttribute('visibility');
				}  
			}
		}
		if (hyphenatorSettings.isLast) {
			state = 3;
			documentCount--;
			if (documentCount > (-1000) && documentCount <= 0) {
				documentCount = (-2000);
				onHyphenationDone();
			}
		}
	},
	

	/**
	 * @name Hyphenator-hyphenateDocument
	 * @description
	 * Calls hyphenateElement() for all members of elements. This is done with a setTimout
	 * to prevent a "long running Script"-alert when hyphenating large pages.
	 * Therefore a tricky bind()-function was necessary.
	 * @private
	 */
	hyphenateDocument = function () {
		function bind(fun, arg) {
			return function () {
				return fun(arg);
			};
		}
		var i = 0, el;
		while (!!(el = elements[i++])) {
			if (el.ownerDocument.location.href === contextWindow.location.href) {
				window.setTimeout(bind(hyphenateElement, el), 0);
			}
		}
	},

	/**
	 * @name Hyphenator-removeHyphenationFromDocument
	 * @description
	 * Does what it says ;-)
	 * @private
	 */
	removeHyphenationFromDocument = function () {
		var i = 0, el;
		while (!!(el = elements[i++])) {
			removeHyphenationFromElement(el);
		}
		state = 4;
	},
		
	/**
	 * @name Hyphenator-createStorage
	 * @description
	 * inits the private var storage depending of the setting in storageType
	 * and the supported features of the system.
	 * @private
	 */
	createStorage = function () {
		try {
			if (storageType !== 'none' &&
				typeof(window.localStorage) !== 'undefined' &&
				typeof(window.sessionStorage) !== 'undefined' &&
				typeof(window.JSON.stringify) !== 'undefined' &&
				typeof(window.JSON.parse) !== 'undefined') {
				switch (storageType) {
				case 'session':
					storage = window.sessionStorage;
					break;
				case 'local':
					storage = window.localStorage;
					break;
				default:
					storage = undefined;
					break;
				}
			}
		} catch (f) {
			//FF throws an error if DOM.storage.enabled is set to false
		}
	},
	
	/**
	 * @name Hyphenator-storeConfiguration
	 * @description
	 * Stores the current config-options in DOM-Storage
	 * @private
	 */
	storeConfiguration = function () {
		if (!storage) {
			return;
		}
		var settings = {
			'STORED': true,
			'classname': hyphenateClass,
			'donthyphenateclassname': dontHyphenateClass,
			'minwordlength': min,
			'hyphenchar': hyphen,
			'urlhyphenchar': urlhyphen,
			'togglebox': toggleBox,
			'displaytogglebox': displayToggleBox,
			'remoteloading': enableRemoteLoading,
			'enablecache': enableCache,
			'onhyphenationdonecallback': onHyphenationDone,
			'onerrorhandler': onError,
			'intermediatestate': intermediateState,
			'selectorfunction': selectorFunction,
			'safecopy': safeCopy,
			'doframes': doFrames,
			'storagetype': storageType,
			'orphancontrol': orphanControl,
			'dohyphenation': Hyphenator.doHyphenation,
			'persistentconfig': persistentConfig,
			'defaultlanguage': defaultLanguage
		};
		storage.setItem('Hyphenator_config', window.JSON.stringify(settings));
	},
	
	/**
	 * @name Hyphenator-restoreConfiguration
	 * @description
	 * Retrieves config-options from DOM-Storage and does configuration accordingly
	 * @private
	 */
	restoreConfiguration = function () {
		var settings;
		if (storage.getItem('Hyphenator_config')) {
			settings = window.JSON.parse(storage.getItem('Hyphenator_config'));
			Hyphenator.config(settings);
		}
	};

	return {
		
		/**
		 * @name Hyphenator.version
		 * @memberOf Hyphenator
		 * @description
		 * String containing the actual version of Hyphenator.js
		 * [major release].[minor releas].[bugfix release]
		 * major release: new API, new Features, big changes
		 * minor release: new languages, improvements
		 * @public
         */		
		version: 'X.Y.Z',

		/**
		 * @name Hyphenator.doHyphenation
		 * @description
		 * If doHyphenation is set to false (defaults to true), hyphenateDocument() isn't called.
		 * All other actions are performed.
		 */		
		doHyphenation: true,
		
		/**
		 * @name Hyphenator.languages
		 * @memberOf Hyphenator
		 * @description
		 * Objects that holds key-value pairs, where key is the language and the value is the
		 * language-object loaded from (and set by) the pattern file.
		 * The language object holds the following members:
		 * <table>
		 * <tr><th>key</th><th>desc></th></tr>
		 * <tr><td>leftmin</td><td>The minimum of chars to remain on the old line</td></tr>
		 * <tr><td>rightmin</td><td>The minimum of chars to go on the new line</td></tr>
		 * <tr><td>shortestPattern</td><td>The shortes pattern (numbers don't count!)</td></tr>
		 * <tr><td>longestPattern</td><td>The longest pattern (numbers don't count!)</td></tr>
		 * <tr><td>specialChars</td><td>Non-ASCII chars in the alphabet.</td></tr>
		 * <tr><td>patterns</td><td>the patterns</td></tr>
		 * </table>
		 * And optionally (or after prepareLanguagesObj() has been called):
		 * <table>
		 * <tr><td>exceptions</td><td>Excpetions for the secified language</td></tr>
		 * </table>
		 * @public
         */		
		languages: {},
		

		/**
		 * @name Hyphenator.config
			 * @description
		 * Config function that takes an object as an argument. The object contains key-value-pairs
		 * containig Hyphenator-settings. This is a shortcut for calling Hyphenator.set...-Methods.
		 * @param {Object} obj <table>
		 * <tr><th>key</th><th>values</th><th>default</th></tr>
		 * <tr><td>classname</td><td>string</td><td>'hyphenate'</td></tr>
		 * <tr><td>donthyphenateclassname</td><td>string</td><td>''</td></tr>
		 * <tr><td>minwordlength</td><td>integer</td><td>6</td></tr>
		 * <tr><td>hyphenchar</td><td>string</td><td>'&amp;shy;'</td></tr>
		 * <tr><td>urlhyphenchar</td><td>string</td><td>'zero with space'</td></tr>
		 * <tr><td>togglebox</td><td>function</td><td>see code</td></tr>
		 * <tr><td>displaytogglebox</td><td>boolean</td><td>false</td></tr>
		 * <tr><td>remoteloading</td><td>boolean</td><td>true</td></tr>
		 * <tr><td>enablecache</td><td>boolean</td><td>true</td></tr>
		 * <tr><td>enablereducedpatternset</td><td>boolean</td><td>false</td></tr>
		 * <tr><td>onhyphenationdonecallback</td><td>function</td><td>empty function</td></tr>
		 * <tr><td>onerrorhandler</td><td>function</td><td>alert(onError)</td></tr>
		 * <tr><td>intermediatestate</td><td>string</td><td>'hidden'</td></tr>
		 * <tr><td>selectorfunction</td><td>function</td><td>[…]</td></tr>
		 * <tr><td>safecopy</td><td>boolean</td><td>true</td></tr>
		 * <tr><td>doframes</td><td>boolean</td><td>false</td></tr>
		 * <tr><td>storagetype</td><td>string</td><td>'none'</td></tr>
		 * </table>
		 * @public
		 * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
         * &lt;script type = "text/javascript"&gt;
         *     Hyphenator.config({'minwordlength':4,'hyphenchar':'|'});
         *     Hyphenator.run();
         * &lt;/script&gt;
         */
		config: function (obj) {
			var assert = function (name, type) {
					if (typeof obj[name] === type) {
						return true;
					} else {
						onError(new Error('Config onError: ' + name + ' must be of type ' + type));
						return false;
					}
				},
				key;

			if (obj.hasOwnProperty('storagetype')) {
				if (assert('storagetype', 'string')) {
					storageType = obj.storagetype;
				}
				if (!storage) {
					createStorage();
				}			
			}
			if (!obj.hasOwnProperty('STORED') && storage && obj.hasOwnProperty('persistentconfig') && obj.persistentconfig === true) {
				restoreConfiguration();
			}
			
			for (key in obj) {
				if (obj.hasOwnProperty(key)) {
					switch (key) {
					case 'STORED':
						break;
					case 'classname':
						if (assert('classname', 'string')) {
							hyphenateClass = obj[key];
						}
						break;
					case 'donthyphenateclassname':
						if (assert('donthyphenateclassname', 'string')) {
							dontHyphenateClass = obj[key];
						}						
						break;
					case 'minwordlength':
						if (assert('minwordlength', 'number')) {
							min = obj[key];
						}
						break;
					case 'hyphenchar':
						if (assert('hyphenchar', 'string')) {
							if (obj.hyphenchar === '&shy;') {
								obj.hyphenchar = String.fromCharCode(173);
							}
							hyphen = obj[key];
						}
						break;
					case 'urlhyphenchar':
						if (obj.hasOwnProperty('urlhyphenchar')) {
							if (assert('urlhyphenchar', 'string')) {
								urlhyphen = obj[key];
							}
						}
						break;
					case 'togglebox':
						if (assert('togglebox', 'function')) {
							toggleBox = obj[key];
						}
						break;
					case 'displaytogglebox':
						if (assert('displaytogglebox', 'boolean')) {
							displayToggleBox = obj[key];
						}
						break;
					case 'remoteloading':
						if (assert('remoteloading', 'boolean')) {
							enableRemoteLoading = obj[key];
						}
						break;
					case 'enablecache':
						if (assert('enablecache', 'boolean')) {
							enableCache = obj[key];
						}
						break;
					case 'enablereducedpatternset':
						if (assert('enablereducedpatternset', 'boolean')) {
							enableReducedPatternSet = obj[key];
						}
						break;
					case 'onhyphenationdonecallback':
						if (assert('onhyphenationdonecallback', 'function')) {
							onHyphenationDone = obj[key];
						}
						break;
					case 'onerrorhandler':
						if (assert('onerrorhandler', 'function')) {
							onError = obj[key];
						}
						break;
					case 'intermediatestate':
						if (assert('intermediatestate', 'string')) {
							intermediateState = obj[key];
						}
						break;
					case 'selectorfunction':
						if (assert('selectorfunction', 'function')) {
							selectorFunction = obj[key];
						}
						break;
					case 'safecopy':
						if (assert('safecopy', 'boolean')) {
							safeCopy = obj[key];
						}
						break;
					case 'doframes':
						if (assert('doframes', 'boolean')) {
							doFrames = obj[key];
						}
						break;
					case 'storagetype':
						if (assert('storagetype', 'string')) {
							storageType = obj[key];
						}						
						break;
					case 'orphancontrol':
						if (assert('orphancontrol', 'number')) {
							orphanControl = obj[key];
						}
						break;
					case 'dohyphenation':
						if (assert('dohyphenation', 'boolean')) {
							Hyphenator.doHyphenation = obj[key];
						}
						break;
					case 'persistentconfig':
						if (assert('persistentconfig', 'boolean')) {
							persistentConfig = obj[key];
						}
						break;
					case 'defaultlanguage':
						if (assert('defaultlanguage', 'string')) {
							defaultLanguage = obj[key];
						}
						break;
					default:
						onError(new Error('Hyphenator.config: property ' + key + ' not known.'));
					}
				}
			}
			if (storage && persistentConfig) {
				storeConfiguration();
			}
		},

		/**
		 * @name Hyphenator.run
			 * @description
		 * Bootstrap function that starts all hyphenation processes when called.
		 * @public
		 * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
         * &lt;script type = "text/javascript"&gt;
         *   Hyphenator.run();
         * &lt;/script&gt;
         */
		run: function () {
			documentCount = 0;
			var process = function () {
				try {
					if (contextWindow.document.getElementsByTagName('frameset').length > 0) {
						return; //we are in a frameset
					}
					documentCount++;
					autoSetMainLanguage(undefined);
					gatherDocumentInfos();
					//console.log('preparing for ' + contextWindow.location.href);
					prepare(hyphenateDocument);
					if (displayToggleBox) {
						toggleBox();
					}
				} catch (e) {
					onError(e);
				}
			}, i, haveAccess, fl = window.frames.length;
			
			if (!storage) {
				createStorage();
			}
			if (!documentLoaded && !isBookmarklet) {
				runOnContentLoaded(window, process);
			}
			if (isBookmarklet || documentLoaded) {
				if (doFrames && fl > 0) {
					for (i = 0; i < fl; i++) {
						haveAccess = undefined;
						//try catch isn't enough for webkit
						try {
							//opera throws only on document.toString-access
							haveAccess = window.frames[i].document.toString();
						} catch (e) {
							haveAccess = undefined;
						}
						if (!!haveAccess) {
							contextWindow = window.frames[i];
							process();
						}						
					}
				}
				contextWindow = window;
				process();
			}
		},
		
		/**
		 * @name Hyphenator.addExceptions
			 * @description
		 * Adds the exceptions from the string to the appropriate language in the 
		 * {@link Hyphenator-languages}-object
		 * @param {string} lang The language
		 * @param {string} words A comma separated string of hyphenated words WITH spaces.
		 * @public
		 * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
         * &lt;script type = "text/javascript"&gt;
         *   Hyphenator.addExceptions('de','ziem-lich, Wach-stube');
         *   Hyphenator.run();
         * &lt;/script&gt;
         */
		addExceptions: function (lang, words) {
			if (lang === '') {
				lang = 'global';
			}
			if (exceptions.hasOwnProperty(lang)) {
				exceptions[lang] += ", " + words;
			} else {
				exceptions[lang] = words;
			}
		},
		
		/**
		 * @name Hyphenator.hyphenate
			 * @public
		 * @description
		 * Hyphenates the target. The language patterns must be loaded.
		 * If the target is a string, the hyphenated string is returned,
		 * if it's an object, the values are hyphenated directly.
		 * @param {string|Object} target the target to be hyphenated
		 * @param {string} lang the language of the target
		 * @returns string
		 * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
		 * &lt;script src = "patterns/en.js" type = "text/javascript"&gt;&lt;/script&gt;
         * &lt;script type = "text/javascript"&gt;
		 * var t = Hyphenator.hyphenate('Hyphenation', 'en'); //Hy|phen|ation
		 * &lt;/script&gt;
		 */
		hyphenate: function (target, lang) {
			var hyphenate, n, i;
			if (Hyphenator.languages.hasOwnProperty(lang)) {
				if (!Hyphenator.languages[lang].prepared) {
					prepareLanguagesObj(lang);
				}
				hyphenate = function (word) {
					if (urlOrMailRE.test(word)) {
						return hyphenateURL(word);
					} else {
						return hyphenateWord(lang, word);
					}
				};
				if (typeof target === 'string' || target.constructor === String) {
					return target.replace(Hyphenator.languages[lang].genRegExp, hyphenate);
				} else if (typeof target === 'object') {
					i = 0;
					while (!!(n = target.childNodes[i++])) {
						if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate!
							n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate);
						} else if (n.nodeType === 1) {
							if (n.lang !== '') {
								Hyphenator.hyphenate(n, n.lang);
							} else {
								Hyphenator.hyphenate(n, lang);
							}
						}
					}
				}
			} else {
				onError(new Error('Language "' + lang + '" is not loaded.'));
			}
		},
		
		/**
		 * @name Hyphenator.getRedPatternSet
			 * @description
		 * Returns {@link Hyphenator-isBookmarklet}.
		 * @param {string} lang the language patterns are stored for
		 * @returns object {'patk': pat}
		 * @public
         */
		getRedPatternSet: function (lang) {
			return Hyphenator.languages[lang].redPatSet;
		},
		
		/**
		 * @name Hyphenator.isBookmarklet
			 * @description
		 * Returns {@link Hyphenator-isBookmarklet}.
		 * @returns boolean
		 * @public
         */
		isBookmarklet: function () {
			return isBookmarklet;
		},

		getConfigFromURI: function () {
			var loc = null, re = {}, jsArray = document.getElementsByTagName('script'), i, j, l, s, gp, option;
			for (i = 0, l = jsArray.length; i < l; i++) {
				if (!!jsArray[i].getAttribute('src')) {
					loc = jsArray[i].getAttribute('src');
				}
				if (!loc) {
					continue;
				} else {
					s = loc.indexOf('Hyphenator.js?');
					if (s === -1) {
						continue;
					}
					gp = loc.substring(s + 14).split('&');
					for (j = 0; j < gp.length; j++) {
						option = gp[j].split('=');
						if (option[0] === 'bm') {
							continue;
						}
						if (option[1] === 'true') {
							re[option[0]] = true;
							continue;
						}
						if (option[1] === 'false') {
							re[option[0]] = false;
							continue;
						}
						if (isFinite(option[1])) {
							re[option[0]] = parseInt(option[1], 10);
							continue;
						}
						if (option[0] === 'onhyphenationdonecallback') {
							re[option[0]] = new Function('', option[1]);
							continue;
						}
						re[option[0]] = option[1];
					}
					break;
				}
			}
			return re;
		},

		/**
		 * @name Hyphenator.toggleHyphenation
			 * @description
		 * Checks the current state of the ToggleBox and removes or does hyphenation.
		 * @public
         */
		toggleHyphenation: function () {
			if (Hyphenator.doHyphenation) {
				removeHyphenationFromDocument();
				Hyphenator.doHyphenation = false;
				storeConfiguration();
				toggleBox();
			} else {
				hyphenateDocument();
				Hyphenator.doHyphenation = true;
				storeConfiguration();
				toggleBox();
			}
		}
	};
}(window));

//Export properties/methods (for google closure compiler)
Hyphenator['languages'] = Hyphenator.languages;
Hyphenator['config'] = Hyphenator.config;
Hyphenator['run'] = Hyphenator.run;
Hyphenator['addExceptions'] = Hyphenator.addExceptions;
Hyphenator['hyphenate'] = Hyphenator.hyphenate;
Hyphenator['getRedPatternSet'] = Hyphenator.getRedPatternSet;
Hyphenator['isBookmarklet'] = Hyphenator.isBookmarklet;
Hyphenator['getConfigFromURI'] = Hyphenator.getConfigFromURI;
Hyphenator['toggleHyphenation'] = Hyphenator.toggleHyphenation;
window['Hyphenator'] = Hyphenator;

if (Hyphenator.isBookmarklet()) {
	Hyphenator.config({displaytogglebox: true, intermediatestate: 'visible', doframes: true});
	Hyphenator.config(Hyphenator.getConfigFromURI());
	Hyphenator.run();
}

// Swedish hyphenation patterns by Jan Michael Rynning, jmr@nada.kth.se
// Patterns modified for Hyphenator by Andreas Johansson, andreas@ibuypink.com
Hyphenator.languages['sv'] = {
	leftmin : 2,
	rightmin : 2,
	shortestPattern : 1,
	longestPattern : 8,
	specialChars : "åäöé",
	patterns : {
		2 : "c21df21hx12y",
		3 : "_b4_d4_f4_g2_k4_l2_m2_n4_p4_r2_s4_t4_v2_x2a2ba1ja1oa1t2aua5å1b23ba4bb3be3bib3k3bo3bub3v3by3bå3bä3böc3c1ci4ck4cr4cs1cy3da2db4dc2dd3di2dj3do4ds3du3dy4dz3dödé4e1a4eb4ece2de1ee1fe1ge1me1o2epe1v4eä3faf3d3fef5h3fi1fl1fo2ft3fu4fv5fy1fä3fö2gb2gd2gg2gh2gl4gw3gyh5c4hdh3gh2ih1k2hl2hm4hnh3ph1s2hth2öi1ai2di1gi3ii1ti1ö1ja2jb2jd1je4jh1ji4jk2jmj2o4jp2jt5jé2kb4kc4kjkl2k2o2kskv41le2lh1lil1n2lv3lé1ma2mb2mc2md1me2mh1mi1mo4ms1na2nd1ne2nh2nk1no4nsn5zo1ao2bo2do1eo1go1io1jo1ko5qox5oy2o3åo3ö1pa2pc2php2jp2l1po2pp2ps1pu3péqu41ra2rb1re2rh4rj2rk2rsr3w1sa4sbs2c1se2sh1si2sm1sos2t1su1så1sä1sö1ta2tc2th1tit2j2ts2tt2tv2tz5téu1au2bu2du1eu3ju1ou5uu5åu3ö1ve2vhv4i1vo2vs3vy1wawe2w2hxk2xs4y1ay2dy1ey1iy5wy5å1za1ze1zi1zo4zpz5s3zuå1aå1eå1få3iå1må3oå1på1vä1aä2b2äcä2dä3eä3i4äk4äs2ätö1aö2dö1eö1iö1vé3e",
		4 : "_a4b_ac3_a4d_e2s_ex3_ib4_ik4_o3o_o1u_sk4_st4_u3k_up2_y2a_y4ea5beab1la5buad3jad2sa5eda1gaa1geag1la4hjaib4a3iva3kaa5kea1kiak3na1koa1ku4aköa1laa4lja1loa1lua1lyam4iam1sa3möan3ca1nua5nya3nöa1pea1piap2sa5pya5pä2ara1arb2arha1ri4arla1ro4arp4arua3rya3rä2asaa1scas2has5la3suas3va1sya2söa5tea4tja2trau5b1avgav3rbbb4bb3l4b3dbe5ebe1kbe1sbe3u4bex2b3f2b5hb3je4b3m2b3n5bonbo1sboy54b3p3bry3brö4b3sb4spbst44b3tby5r5cap1c4e4ch_4chtcim2c3kac3kec3kick5jck1lck3nc3kock3rck5äck3öco2aco4m5da_2dak5dam4daxddd4d3djdd2s3d2ed4en5derde2sd4et4dex2d1f2d1gd3gl2d5hdi1o4d5l2d1m2d1nd2ol5dondo3y2d1pd2sed4sfd2sid2sjdsk2ds1ld2sod2suds1vd2sö2d3t4dupdu1s4dut2d1vd3vr2d3w5dåg2dås4dåt4dägdä2r4dög4döpe4ame2bre3che3coed3je3dåe2ede4eief4se3gae3geeg1legs3e5gåeig2e3ike1ine1joe3jue3jäe5jöe3kae1kie1klek3ne1koe1kue1kye1käe1lae1loel3p2enj2enye2ogeo4ie5ore1pee1pie1prep3se3påe1rie1roerp4e1rue3rye1räe1sc2esees2ke1sle1spes2ue1sye5tie1toet2se1tue1ty2etze1täeuk44eure4vjev3r3expfac44fav4f3b4feffe2l4fex2f1ffff4ff3lff3nf3foff3rffs4f3fäf3g22f3k4f3mfma44foffol24f3p2f3sfs2kf4slf4smf4snf4spf4stf4svf3taf3tif3toft5tft1vg4av4gaxge2a2gefg4emge2o2g1fg1gag1gegg5ggg1lg4gu1g2igi1o3givgi2ög2jog3jä4glj2g1m2g1ng2no1g2o3go_3gol2g1pg2r4g4rå2g2sg4sfgs1lgs1mgs3ngs3sgs1vgs1ä2g1tg3tr1g2u4gug4gup2gut2g1v1g2åg4älg2ärgä4s1g2ö4göghav24hirhi4th4leh2na4howh5ruhu2shä4shö2ghö4sia3gi3cai5coid1rid2si3dåi4dö2i1ei5fni1frig1li1kiik3ni1koik1vi3kyi3kåi3köi1lail5ki1loi3lui5läi1mui5måi3mäi5möi3niin5ji1nui1näi5oci1ogi3oki1oli5omion2i1opi1ori1osi1oti1pei1pii3rai1rii1roi1ruis2hi2skis3mis3nis5vi3syi4såit5ci4tj4i1ui1vai1viiv3riv2si1våix2tjd3rj4duje2a5jef2j1f4j3g4jinj4klj3kojk3v2j1l2j1n3job3jouj5pl2j3r2j1sj5saj4skjts42j2u4jur1k2a3ka_2kafka3i2kak2kap3kas4kau1k2e3ke_2kepke2s4kex2k1fkfö22kh44kif1kigk3jä2k3k2kle2k1m2k2nk4ny4koc1kom1kon1kor2k1pk2r4k2sok2su4k1tk2tr4kug3kusk2vek4vok1vå4kög3la_2laf2lak2lau2lav2lb44l1c2l2dl3dj3le_2lex2l1f2l1gl2gjlgs43lif3ligli1o2lip1ljul5jål1jä2l1kl3kel2kll2krlk3tl1lalld4ll3kll1ll1loll3pl1lull5vl5ly4l1m2loml1pel1pi4l3r2l1sl2scl2skl4sml2spls5sl2stl2sul2svl4så4l1tltu4lu5i2lunl1val1vil1vä2lå_4läc4löl4löm3lön1lösm4dim4domeu42mex2m1fm4fnmis22m1k2m3l2m1nm4odmo4i2m1pm2plm4på2m1rms2m2m1t4mud5mum3mur2m3v1mynmåg44mårmå1s4mägmäk31män1mäs1mät3möj3mös4möv3na_3nad2naf2nak2nb42n1cn2chn5de3ne_2nex2ng1n2gin2go1n2i4nid3ninni1o4nip2n1jn3jän1kin1kon1kun1kö2n1l2n1m2n1nnn3dn3nenn3k2n1p2n1rns2ins2k2n1t4nug3nui3num2nup2n1v4når4nä_4näc3näm3nät3nöj4nölnös4oby4o3däo4flo3fro4gjo4gäo4ilok3no2kvo1la1oljo1loo1luo1lyo1lä1omron3con3jo1nyon5åo1näo3nöoo4do3oro1peo1pio3på4orao1ri4orko1roo1ruo3ryo1räo1röo1too1tuo1tyo5tåo3täoun4oup44ourou4so1vao1viov3ro1väo3weo3än4pafpag43pappa3u2pb44pem4pex2p1f4p3g1pigpi1o3pipp3lj2p1m4p1np3ni5poa2poc2pofpo2i3pos4povp3pep1pipp3jpp1lpp1rp2pup5pypp3åp2r22pra3pro4prå4psop2sö2p1t4pug2p1v3päl4pör3que3ra_2rak3rarr4as2rav2r1c2r2dr3djr3dår3dä3re_re3b4recre3o4rex2r1f2r1g4ribri1or3jor5jur5jör1kirk3nr1kor1kur1kä2r1lrld22r1m2r1nrn1krn3tro3b2r1pr4pö4r1rrrd4rr1sr1spr1svr1sy2r1trt3t2rut5ruö2r1vry5o4rål4räm4räs2rögr3öi4röp3rör3sa_2safsa3i2sap2sau4s3dse2gsem22s1fsfö2s5hö5sie3sik3siosiu41s2j4sjn4sjts4ju3sjö4sk_4skhsk4i4skl4sknsk3s2skt2skv1skå2sl2s2lus3mjs4nå3soc2sod5soi2som3son3sots2p21spe4spls3ps3spö4s1r4s1sss2kss1lsss4s2sv2st_st3c2stj2stmst3t4stv1sty1stå1stä1stösu4b3sugsu3i3sum2sun2sup5suss2v24syk5syl3syn3syssyt25såg4såks4äds4äl2säp5säs3sät4söd2sög4söl4söp3ta_tat22tav3tax2tb43t2e5tec4tegte3i4tej5tib3tidt2il3tisti2ö4tje2t3l2t1m3tokt2opt4ov2t1pt2r42tra2tri5trét3sets2kt2sotss4t1stt2sut5syt1tot3tutt1vt3tyt3tä5tuöt1va4tve3typ5tys3tågtås44tåt4täm4tög4töpu4bou5clu5deud3ru4duu4dyu2esu1geugn4u5ieu1inu3isu5kiu4kluk3nu1kouk2su3kuuk3vu1lau1lou3luu1läu1löu1muu5nuu1peu1piu2plu3reu1riu1rou5ryu3seus3nu2spus3vu4såu4säu2sö1utbut3ju1tout3r2uttut1vu5ty2u1vu4vju4vä5vap4vau4vav2vb42v1c5vecve2k4vepves42v1f2v1gvi4c4vjo2v1l2v1m2vomvos42v1p2v2rv3ruv4scv2sov1stv2sö2v1t4vut2v1v3vägvä4l2vät3väx4vög4vöp3vörwhi2wi2ew4naxis4xli4xti2x4tåyb4sy4day4doyd3ryds4y4duy4döy1gay1gey1kiyk3ny1koy1lay3liyl5ky1loy3måy3ory5ouy1pey5poy1riy1roy1toyt5vy3vay3viy3väå3djå1gaå1geåg3lågå4å1kiå1laål3kå1läå2plå4pöå1riår5öås3nåss4ås4tåte2äd3rä1gaä1geäg1läg3rä5joä1kiäk3näk3rä1laä4noä3peä4prä1riä4såä3toä1vaä3viä5vuöd2sö4duö4döö1ga1ögdö1geögg4ög1lög2n1ögoö3joö1kiök3nök2sö1laöl2pö5läö3peö3piö4prörb4ör3gö1riör1uör3yör1äös3növe4ö2vj",
		5 : "_ab5i_ab3r_a3dr_ad3s_a5kl_a5le_a3lu_a5mu_an5s_ap1p_as2k_as4t_a5ta_at3t_bo2k_cis4_där3_ek1v_e4nä_es4t_e3tr_gus3_he2m_im3p_i2n1_i4na_in3d_ink2_in3t_i3so_ner1_no4n_ok3t_o3kv_o2ma_o2mo_o3mu_on4k_o5sc_o3sl_o3sv_o3tr_sa2k_si5o_sjö1_ta4k_ti3o_u4ra_ur3s_u2t1_u4ta_ut5s_vä2g_ång3_å3st_ä3ro_ö3roab4buabe2sab3laab4scab4ska5daga5deka5delad5epad3opa3dread3ruaf4fo3affäa2ge_ag1grag3roa4gurak3vea5kårak5åta2linal2kval4käal3låal3tral4tual4täalu5salv3sa4mafam4pram3åtanci5a4nefan3gian1graniu4ank3rano2ia4noka4nopan4sjan1stan4tja2pe_ap3seaps5laps3papu5s4arbi2arbo4arbrar3drar3kaar5kr4arn_a2robar2saar2sva4rura5rusasbe4a2skoa4skras3kuas3paas2skas2spas2stas3taas3toas4tra4sulas2uta2s5åati5öat4tjatt3saut5s2a1va2a1vi4a3väba4diba4dobak5lba4koba4kub4bakb4b3rbb4so4beldbe5lube3lybe3låbe5löbeng4be3nåbe1röbe3slbes5sbe5sube3trbe3tvbi3d44binvb5larb5latb5len3bles5blidbo4grbo2klbo1mubo4sc4brarb5scebs3chb4sofb4stjbång3båt2sbör2sceu4s3chau3chef5chocchäs3chör4ci4lucipp4ck4reckus2ck3vack3veck3väcle2acros24dadrdags35dakoda3lida3må4d1ap4darb4dartda4trdat5tdcen3ddi4sd4dosdd3radd3redd3rid3drädds3vde1k44deko4deldde3prder1kde2rode4rude3sede3spde3trdias4di5eldi2grdi3kadi5ku4dinf4dinr4dins4dintdi4oddi3scdi4sjdis1pd3jor3djur2d3k2do5lo4domr4dori4dortd5ost2d2r2d3rad3drejd3ren5dresd3retd4ric3drifd3rigd3rind5rocd3ror4drot5dränd3rätd5rödd3skids3klds5knds4mod4småds5nåds3plds3s4ds4tedu2scdu5södu4vudy4rodöds1d5öste2akeecis4edd4redi4ued1skedso4ee2k5e4en_e4ene3efteege2le5gruei5gnei5she1iskek4leek5roe1kve3eld_el3k4el3liell3sel3läe4lobel2siel5uge5luv2e1läe5mate5mise2naven4cee4nede4neken3knen5kren5käeno2men3siens2men2spen4såe5nus2e1näe3plaep5leep4trepu3ber1ak4eraser3d4erg4ler4gue5riberlä4er5nae3robe2romer3raer5scer3sler3sve5rume5råde2sales4hiesi4ues2mies3ples2skes2stes4tre3ståeta3beti3öe5träets1lets3met4svett3ret4vaet5vuetäc4e5um_e5up4ext4r4fans4farbfa3shfa4stfa4töfi2brfi3lifi2tifolk12f5omfo2nafra2mf4rerfre4sf4ri_5fritfrån5f4taff4takf4tapfte4rf4texf4tinf4t3rft2saft4sjfts4tfu5rufu3tufy4mafå3töfö2rafö2riför3kfört4för1öga5br3g2ag4gakt3g2alga5läga4no2garb4garmga2ro4gartga4stga4sugaus4g3d4rge5b42ge4jg2eligel5y3gelägen5g3genj4genm4genvge5ny3genä5gesege4toget5sg4gapg4gosggs4mgh4tegi5sn3gjor2g3k2g1larg2lasg4lidg4lög5glömg4nag4gont2gord4gorm4gortgo3sl3graf5gral4gras5grecg3rig5grip3grisg5roigro2v4grum5grå_grä4ngs1ang3selgsi4dg3sjugs4kigs3kng3skyg4smegs4nigs4nögs1orgs3plgs3pogs3pugs3tjg4suggs3vigs3vågs3ytguld34gulägu2magu5rugus4kg3utbgö5roha3blha5geha4liha5raha4scha4sphas3thavs3he4athe4frhe4lähets1h2nitho5nuhop3shos3phyg5rhys4thäll2hä4rihög5ria3fria4luia4skia3tri2b3li4ce_i5chaid4gei4domid3roids3vi4dunifes44igani2gebig5ejig3noi3kloik3rei3kuli3kumi2linil1jö3illuil2tji4lupim5smim4soi4nau1induin4gai4nif5inre1inri3inräin3slins4min3snin5te1intrint3si4nunin3ymio4krio5lii3onoions3ipos4ip5pii4resirk5liro3pi5sceisel4is3kuis3kyi2s3pis3sais3seiss5nistå4i4teii4texit4tui2t5åi2vaki4vinix5tu4jarbjas5pjo4kr4joljjo5löjs4mejs4tejuk3sjul3kjuss4jus4tjä5lojär5sjör2sjös4t3kad_ka4dr5kafäka5ju4kalf4kalg3kamp3kamr3kan_5kano3kapi3kar_ka3ra4karbka5ri4kark4karp4karvka4sk3kat_2k3d4kdom42ked_2kedake3drked4ske4er2kefu4keldkels4ke5nå3kernkes3s2k5g4kid3skik4skilt45kimå4kins2kintki4nuki4trkiv3s5kjol1klag2klat5klavk2lej2kligk2lim3klipk2lis3klos1klub4kluk1klädk4nal5knip3k4nuk5nykko5dek5odlkog3nko4gr4kola4kolj3komm5kompkom4s3konf3kontko3nu3korgko3ri2korrko3sl3kost4k3ou3kraf1krig4krivk3ryg4krälk3rätks3chk4serks2k4ks3klks5kvk3skäk3sköks2lik5slyks3plk1s4tk4texk2todk2tomkt3rekt2stkt5t4k4tugk2tutk4tälk5ugnku5la4kuld3kulö5kunnku4ro3kursk1vär3kyrkkäl4m5kämp5känn3käns3kärl5köp_kör4l2ladm4ladr5lagmlag3r5lakila5lo2larb1larnlar5s4lartlas3h4laskla4st1lat_la5trla5vuld3ral5dryle5igle2klle4kv3ler_ler5k3lernle5tåle3umle4vul3g2llg5stli5chli4golig3slik2llik3s2lind2lini5linj2lintlis3cli4volivs1l2jak4l1jol3jörl5kjul5kläll3drlle5bll2sell2soll3trll5unl5lödllör4l4mollm3stlo2af4lodllo4do2lolj4lord2lorglor4slo4vol4pakl5plalp5lölp4stl4sjol4själ3skilsk3nl3skyl3skål3skäl3sluls4mol3spels3pll3stals4tel3stol3styl3stål3stäl5stöl5surl4svil4tefl4tifl4tihl4tosl4trölt5sklung32lupplu4pu4lutb4lutsl4voslv3rilv3splväv4lyg3rlåg3s1långlå4skläg5rlä4splö4väma5frmag5nmag5sma5jumak3rma3limand4ma5nimash5mas4vmb4skm4datm3d4r2medsme4dume4klme4ko4meldmelo5me5lumen5kme5nume5nyme4somes4t2metam4fes2m1g4mid3smi4lu2mind4mink4minvmi3nömi5sfmi4spmi4tr2m1m2mme5dmm3s4m4mulm2namm4navmn5drmn3g4mn5stmn5tum2n3å2momrmo3namos3kmo2tamo4tumot3vm2pakmpos4mp5p4mps4kmp5spm4salm4skems3lämste2m1stom2strms5äp3musi1mål_5mån_mäns43märkmö4blnads3na5gr3nako3nakrn1akt2nalf4nalgnal3sna2lun5amb5namn4nanv2narb2nark4narm2nartn3chan3chen3chincis4n4dakn4davnd3d4nde3sn4dilnd3rind3snnd5åsne4di5nedlned3sne4döne2gr4nek_ne5ly4nenlne1ut2n1f4nfis3n4garn4getng3igngi4sng4lyng5omng3orn4gröngs1kn4gödni5ecni4kini5lin4jarn3junnju4sn3knynk3rin1kronk5slnk3spnnis42nodlno4kl2nolj2nomr2nord2norgno5sano5scno4tun1skin4socn1spins3plns3pons3s4n1svans3vin4trönts3cnt4sen4tutn3tvån5ugnnums5n3upp2nutbny5gr4nög4nö2janö5kro2ard5o4bjo4blioc3kuode4kodi4a1odlio3droods4kod2sto4gavog3gro5gloo5glyo4grio4gröog3seo4kliok3slok4suo5lakol5auolfö4ol3kaolk3rol4kuol4käol3läolm4soln3sol4saol4tåo4lugo4lurol5åro3menom5paom3pl4omraom1skom4trom3tvon5gion1gron1k4ons3cons3mont4soom5sop4plop4prop4puo3priop4sto3rako2rap1ordno4reh1orgaor4gror4gåor4möor4nuor4näor4plor5pror5teor2trosk4lo3somos4skos4tr4oti_4otie4otino5troot3svot5tiott2so5tunou3röova4nov4siov3slpaki3pa5lapals5pa5lä2parb4parmpar3s2paskpa2st3patr2p3d44peld5peng3penn3perspi4elpi5so3pjäs4p3k2p4lacp3lev3plex3plic1plik4plit1plomp3lop4poljpoly32porgpo4väp4paxpp3lapp5lupp3lypp3läpp3löpp5ocpp3ofpp3p4pp3rapp3ripp3rupp3rypp3räpp3tr5prax1presp3rigp3rik5prilpro3gp3ror3präs3prövp2salps2lip3snap3sodp1s4tp3tri5pung3punkpus3tpå3drpä5ro4radrra4du5ra1era3frra5isra2lora3plr4ar_4rarbr4are4rargr4ark4rarmr4arnr4ars4rartra5röras3hra2stra5yor4dafr4dosr4dulr4dös5recore5du4reft4reggre1kr4reldre3lurem5p3remsr4en_2reni2renk2renlre3nö3rer_3rern3reso3ret_4retyre5tårg3g23rial3rifi2rifr3rifu3rigtrik2sri4mo2rind2rinr2rins2rint3riotriv3sr4jisr4kekrkes3rk2ler4klörk4ner4kodrk3trr4kupr5körr5lavrlds3rl5spr4milrm5trrnal4rn3g4r2nomrns4krns4tro2kr2roljrom4aron4vro3plro4ra2rord2rorg3rornro4snros3vro5ter4plörra4nrres4r5ribrr5k4r4robr4romrrs2kr4rurr4sexr2sinr1skir2skur3skör4sler4slors4mors5när2splr2spors3s4rs4ter1storst4rr3stur2svär2tafrt4anr4tomr3trär4tutru3brruks13rum_runn24rupprus2hru4virv4sjrå5rarå3st4räkträs3sräv5sröd5rröd3srök3srör4srö4str1övr3sad_3sade4sadjsad5ssa5lo3s2amsa2ma4sang2sanl2sarb2sarm3sarn2sart4sarv4sass5sat_sa4tus3auk2s1av2sch_1scha4schb1schi4schk4schm4schp3schy3schösci3p3seglsek3r3sel_se5ly3sen_3set_2sexp4s3g2shi1ssid5s3s2ig4sinrsis4t2sjak5sjuk4sjur2ska_s4kags2kal1skap4skar4skass2kats4kav4ske_3skif5skin5skiv3skju1skol1skot1skris4krus3kups4kve1s2kys4kyns4kål4skår4sla_4slass1lats2levs4lic4sliss2lits5lors3lucs3luf4slus3slut3slå_s4läks5läms2läts2maks2mals2mids2mit5smug5smygsmå5gsmå3ksmå3s3smäd3smäl4smäs3smör2s2n43snabs3nams5ner3snib3snil3snits3niv3snut5snår5snäcs4när3snö_snö5g3snörsnö3s5sock2solj5sommso4pu3sor_2sord2sorg3sorn4sott4spas4sped2spen2sper3spirs1plaspli4s5plä4spre2spros3pry3språ1s4på3spån3spår5späns5sads5silss5klss2läss2löss3nass3vi4sta_5stacs4taf1stau4stea2stia2stib2stid2stil1stits5tju5stoc1stol4stom1stru2styp4ståg5stål3stäl5sun_5sunes5ung5supasu2pu2s1utsu4tosu4tr5svam4svap4svass3vat4svec3sven5sveps5ves4sviss5våds3väss3vätsyn3ks3yrksys4tsy5thsång34sätas5ögasö4kosör2sta1ch4tadi2taff3taga5tak_4talf4talv3tame3tami3tan_4tanl3tar_4tarb3tarntars44tart4tarv4task3tasttats32tatt4tavetav2st3chat3che2t3d4te4aste3b4tej2ste4kl4teld5tema4temote4mute4nä5ter_5term5terster3tte4ru5tes_5testtets34texa2texp2t1f42t3g4t4hen3tial5tici5tideti4du4tidöti4ed3tighti4goti2gr3tigttik3l3tiks5tilj5time2tind2tinr2tintti4od3tionti2os4tisc5tisk3tiva4tjob2tjou4tjäl4tjäm3tjän2t3k22t5n4tne4r4todl4tol_4tolj2tomr4toms4torm3torntos4kt4raf4trar4treg4tren2troct4rogt4rup1tryc4tråk5trä_3träd3träf3träg4träkt4ränt4rött4segts4ent4sext1skits3klts3nät3snöts3plts4tets3tjt3sudt3tact4taut4tedt4temtte2nttes4t4text4tiptt3jatt3rett3ritt4rytt4sett2sit4tugtt4våt3tör2tund5tunn2tupptu5re2tutbt3utvt3utötu4vut3vigt3vit3tvivt3våg3tvånt3vänty5da5tyg_ty3pi4t5äg4tärm3tävl4tö4dtö5detö4piub5alu3chau4dakuds4auf4fäuf4to4u1gaugg3sugns5ug3s4u2kebuk5laukos4ukt5suk4täul4diul4duul4döul2trum4fäum4soums4tu3mörund3run4dåung3r3unifunk3lunk3nun4krun1skun4tr1uppgupp3sup5utur5aku4robu4romu2sakusen3u2s1kus3kaus4kru5skyus4kåus5läu4ståu4stäu4taku4tefute3sutik2u5tiluti3öu3toputo5sut4ro1utruut3slutt4jut3övu2vak1vagnval3k5valv5vama4vanp2varb4varkvar2sva1ru5vavi2v3d4ve3ke4veldve3nyve5növer5g3verkve1st3veta3vetevid3svil4tvi2novi5ny3vis_vi5savis5hvi4stvi2tr2v3k22v1n44vok_4vord2vorg5vrakv1s2kvs4miv3snivs4tevs3våvu4d1v1und4v5up5våld3vård4vårivå3ru3vänl4värj5värky5danygg3ryg4gåygs4pyl4gjyl5läyl4trym2flyng3rynk5lyn4sayns4typ3riyre4syr4kuyrk5vyrs4kyr5styr5tuy1rå3ys2stys3tays3tiy2taky4te_y4teaytt3rze4roz4zinåds4låge2låg3stå2linål3stånd4rån4duåns4tåns4vå5plaår4doård2så4relå5rorår2svås4keåt3riå3trååt2sjått5säck5vädd3säd4duäde4säd5seäd3stäg4goäg4reäg3seäl2tuämp3länd3räng5ränn3säns1län4stän4sväpp3läp4stä4rapärg5lär4grärib4är4käär2nåär4nöär5obä5rolä3ropä5rorä5rosär2siär2soär4spär2svär2trärt3säs3paäs5piäs4skäs4späs3taäst3rä4stää5treät5teätt3rät4tuät4tvä2vakö4dakö4dalö4disöd3raöd3seög5akö5garö5gerögn3eög3siög3sköj4svök3slöl4kvöl4kööman4öm2klö4nalö2nomön4soö4pelöp5liö5plo1öppnö3rasö3resö3retö5rigör5irör5ivör3olör1orör3slör5teört5sör3vrörö4dö2sakös4sjös2skös4spös3taöst3vö2taköt4stöver1öv3raöv3riöv4sk",
		6 : "_ab5ol_a5gre_al4pr_am4br_amp3l_an5go_a3sti_au3st_a4val_av3s4_bak5s_ben5s_bort1_e3l4a_en5st_e2r3i_evan5_feb3r_fram3_fres5_för1a_gu4lä_hu5sa_in3s2_is5ka_ko5li_köp5s_lak5r_lu2st_me4re_mon2s_mån3s_må4st_nöd5r_oc1ku_om3s4_ord3s_o1s4k_re4gr_runs4_rym2d_röve5_seg3r_sta2m_sup3p_ta3bl_tak5l_tig3r_til4l_tre3s_trä5k_ult5r_ung2e_var4t_ved5s_väg3s_år4s5_åter1abel4sab3ortab5ricab3rioac4kesac4kisack3ska5dran1adresad3ril1af3riaf4toraga4raag5orda4kartak5ramakri5sak3robak4sta1aktigak3trial5admali2bra5lin_a3lineal3insalk3akall3stalms4kal5ortals5paana4boan3alfan3arkan5dakan4dunan4dänang4esan5sceans5kuans3lian4stoan4styan4treape4n3ap4lanapps4kap3ricap3rifa5prisa4ranna4rarvard5sta4rendarg5siar4nalarsk5lar4troarts5par4turar4vägasis5tas3kisas3pigass5upas5terasti5oas5töra4sundata5raa3tral4atrara4t3reat3riaa3tricat3riea5trika3trisa3t4roa4tro_at4ska1attacat2takat4tosa4tungau2t5a3automa4vartbad3s4bank5lbas4taba5stub4battbb4lerbe3d4rbe4stabe4stebis3kobi5skvble4mo5blera3blikr3bliksbor4tibort3rborts22b5raf3brik_b3rika3brike3briksb5riköbru4stb4slanbund4sbus2stcens3t3centrck5lisck3orgc4kortck3sla4dand_del2sade5lutden2tode5roldes3tidfö3ra2dinspdis3kodis1krdis5todi4tredjup5pdom2skdo4pak4d5ord3d4ragd3randd5rarbd5ratu4d5rik3d4riv3droppd3räkn3dräktd2s1ands5enhds3insd3skefds4kends4lotds3tald5statdste4ad5stigds3tinds5trodu4stedy4kaneb3rile4danse5draled2skoed3s2leg2lere4graneg5rateg3rinek3latek3orrek5visel1aktel4arbeleb3rel4fraeli5kuemon1sem5ortemp5leen5artene3röen5kloens5keens4teent4haen2t1rent3rient5ruepp2s3epps5ter4gåse4rinfers4leer4staer2steer3stres5alles3arme4skanes5kares3keres5kule5slagess5läe3stales3tine3struest4röe5tri_et3risets2adets3krets5paetu4rieu4se_eu5troe4varmfac5kefes5tafe3stoffö5refin5smfisk3rflo4dafor4mofost3rfram5p5frerifri5spf4tarmft4setft2s5ifts5väfäs5tifö2renför3smför3sugall3s5g2atig5avsn3gelisgel5stgel5änge4nap3g2enigenom5gen4sag4ense1g2ent1g2era3g2erigers5n5g2ettggs4lagg3s4tgg3s4vgi4stegis4trg4lans5glaseglas5k5glasögon3s4gra2m55grans5grett4g5rikgrus5t5gränsg5sattg5skafgs4kotgs4porgs5pregs3takgs3talgs4teng3stifg3stolgs3tragst4reg3stämg4s3vegul4dagytt3jgårds52g5åri2g5örthal4sohalv3åham4sthasp5lhets3thets3vhis2skhjäl3shos5tihust5rhys5tahälls1hälso3hä4varhö5genhörn5shöst5ri5brilick3u4iden3s3ifråni4kartik5läni5krobik5rofik5rosik5s2hik5u4til4danil5lakil4likill3s2il5läril2minim2b3rin4ge_ing5isin5kve1innehin4sem1inspein5sprin4ståin4trais5kepisk5nais4kuni5slamis3länis4priiss3täi1stalis4tesis3tigist5roit5rani5trini3trisit4t3r3jakt_jd4styje5staju4kosjus5krjus5tajäl4sa3kade_k3aktikal4lokall3s4kand_ka5plakap4prkaps5t3karnakarp5s4kart_4kartekas3ti3kats_4kensekfö3riking3r4kinnek2lamakla4mi3klass2k3läg3k4nap3k4nivkog4s3ko2linkol5tr5kolv_2k3omr3konstko5s4kko4str4krang5krerakrigs33kroppkråk5skrå4pakräk5lksaks5k2s5asks5kraks5tidkti5gek4tinnk2tinskt3rink5trodkt5rogkt3rolkt5rätkum5plkungs5ku4penkust3a3kvalik5vare3kvarnkvar3s3kvartk4vato1kvinn5kvire3kvällkydds3ky4linköks5tkör4sl1lade_3lagd_la4ginlan4dilder4slds4anle4ge_lem4sö2l5enlle5s2lli5kli5limerling5o4lingrli4stalk5lagl3k4rallok5vll4sanll3skall4svall4tigll5örtloc4kulod3stlo2ge_l5skotl3skrälskå4pls5nytls3poll4stakls5terl4stygls5vidlta2tul4tretluk4to4lull_5lust_l4varmlvers4ly4gatlyg3s23lyste5lystnly4strlång3slås5telå4stå1ländslä4sanlätt3s3lörermang2amani1k5ma3rimas3koma5skömas3time3stimet3roming4omin4krmiss3tmi4te_mitt3smnas3tmo4tinm4partmp3ladmp3latmp3linm3slagmulls3mult5rmun4komu3stamut4slmys4temäs5tamör4klna3kro5nalfl4nand_na4rapnast3rncyk3lnd5raknd5rasnd3ratn5driln3dropnd5rosnds3ornds5väne4d3rner5smnes3s4ne4stane3tren4gen_n4gendn4gensn4germng3radng4serngs3panings1nip4prni3t4rniv5skniv5stn4kartn4kis_nkrus4nk4tinnn3s4tnom3s4n4sintn4sis_n4sisens3kanns3korns5lasns5mitn3stapns4teln3stifns3tigns4transt5upn3s4tyns3värn4tarkn4tinfnt3radn3trahn3trakn5tramnt3repn3trernt3riant3rinnt3risn4trornt4strnufts4nös5keoc4k5rock3sko5dralods4tiod5stuoffs5tognos4og4s3toll4siolo5kvom4bräo4mordom4ste3omsätongs4lo4ninsonsi3son4treopp3leor4d5äor4spaort3reort3roo3s2fäo1skopos5pigos4s4tos3tigost5röos3tulot5runot4träotvin4o3ut3tovs4mepakis44pand_pan4trpa5skipent5rper4bl3perioper4slpe5tropi5stapi5sto5plan_p4lanep3larn3politp4partpp5askp4pinspp3linpp5lispp3lånpp3låtpres4t3princpring3p5riol3psalmp5s2hops4kenp4stakp4stävpul5trraci4t3rade_2raffär4anderand3s2ransvr3arta3rativra3trirda5grrd3ranrd3rat4reausre3d4r3regn_ress5kre1sti4retetret3ro2revigrfö3rir3ifrå3riktnrind3sring3rri5pleri2stäri4tutri4visrk3aktr3klasr5lakar4marbrm2s5jro4grorol4li5roman5ronau5rond_ropp2s2roriero4sinr4seldr4skidrsk3nars4kosr4s5lörs5natrs5takr5stekr4stonr3strörs4vagr4tinsr5tritrubb5lru4danruks3vrunns5ru5sha5rutigrut4rarydd5sråge5lrång3sräck5sräng3sräns5trä4sanrä5stiröd5elröns4tröst3r2sa3drsak5ri2s1aktsa2morsand3ss3anlä3s4ar_s5arm_2schau1schen1scher1schetse4at_2s3eggseg3rasek5lesek5trs5ersäs4fär_5s2hawsi4erisi4esksi2ettsikts35sill_silv3r2s1ind2s1inf3sinni2sin1ss1inst5sint_2sintrs3jaktsjäls3s2kado1skaft3skal_5skap_4skapiskaps1s4kara5skarv3sked_s4kene3skepp4skis_5skjorsk5laps3klas3s4ko_1s4kog3skolas4kolos4korp3skratsk4ret3skrev3skrifs3krig5skrin3skrips5kris3skrivs5kron5skrub3skruv5skräc3skulp2skyrk5skåp_5skänk3skärvs5lad_s3lands4lants3lar_3slev_slins3s3lustslu4to5s4lårs5länn3s4läp4s3lär3s2löj3smak_s3makts2met_3s4nacs5nares3nast1snittsol3s2son4stso5pras5ord_s4park5sparvs3passspa5tr3s4pek3s4pel5spets3spills3plans4plin5splits3pres3sprit5spränss3kunss3unn3stadi5stam_5stamm1stant1state3statl2s5te_5steg_s4tek_2stekn5stekts4tell3stem_3steme1stera3stick3stil_3stink3stisc3stjäl3stjär4stolkstor3s3strec3strejst3ren1strer2stria1stridst4rif3struks3tryc5stryk5stråk3strål3sträc4sträd5sträv3ström2st3s4s3tvis5svag_s3vagn4s3vaksvars33svart4s3ver4s3vils4vines5vitt3svåri3sväng2sålde2s5ägg2s3ört3tade_4tads5ta5kretak4totall5sta4nabt4ap3ltar4mita1strta4tan3tavlote2g1rte3grete4int5te5löten3g45tensiten3trte5nör5teriöter3k45ternates4tete5stu5tetiktifts5ti2gel5tikul3tillv3tilläti4van5torapt5ord_torm3stor1st4tort_t5ost_3trafit4rala5tralo3tralst4ralt3transt3ras_t3rat_t4rato4trer_4trern3tribu5tricktrids3t5rielt1ringt3rockt3rono5tross5trotnt4rump3truppträds4t3räkn5träni5tröjats5artt3s4att5slotts5läkts3ordts5tert3stolt4stont2strat4stryt4sturt5styrtte5g4t4tinstt3radtt3rattt4sta4t5ugn3tungatung3s3tvingtvär3s3tvätt3tyngdtäc4ko3törertörs3ttö4vasubb4leub3licud4retuf4tanu3itetuks5koulds2mull3änuls5tiun4domung5itungs4pu4pernu3pletup3lik3uppfaup4pin1uppla5uppläup4p3rupp5spur5arvur4stäus5anlu3schaus4klaus3penus5tatus3tigu3stikus5tinust5ro3utjämut4rerut5rop2utsid3utslä3utvecva5droval4lival4st4vand_van4stvan5trva4resva4ri_vart5rvas5ti5vattnve2s5pvet5savett5svild3s3vind_3vinklvis5kovis3tavi4varvmörk43vrerav2skrivs5tråv5stycvångs3vägg5s3värdevä4ril3världxan5d4y4brisyk5lonym4fory5schoyst3razo4nalåg3s4k5åklag1ålderåll4spål2s5eåman4sård4ra5årsavås4skräl4papäl4segäl4sluäl2t3räl4vinänd1stänni3säns5teän2t3rär2breär4nisärn3stär4skoät4s3kät4topö4darvöde4s5ö4karmöns3keönst3rö4raskör3d4rör1eniö3ringör3intör4kalör1k2lör5kliör4nisör1s2kör4släöts5ko5övere",
		7 : "_a5g4ra_a2n5es_ang4er_a3sket_a5sten_bild3s_e2l5in_e5skad_es3kal_es5kap_fågel3_för1en_in4ger_kans4k_kort5s_kring3_lek5tr_mas2ke_minis4_mörk5r_o3stra_papp5s_pa3ste_pa5sti_pi5sti_pres2s_re2ste_slut3s_sten3s_tes3ta_topp5s_tred2s_u5trerack3u4pa5kvariandel2sansis3tans3par1ansvarapo3str1apparaa4rigenark3lanar5skalas2s5opa5stardast5raka5stralast3rolbors5tebort3sl2b5ratic4kordndels5tidenti5öder5stidin3g4odis3tradrotts3dub3bleechiff5e3glerae5gleriekord5sek4ret_enning5ens4vinerings3erk4liners4kene4s3kenes5ten_esti2gees5tor_est5rerfib5rigfi3skalfros5tafru5strfurs5te4gerarbg3starkgs3tillhands4lhan5g2ahop5plohy3sterhård5s4ic4kordik5skorilufts5ind5skäind5stiing4es_in5glasings5tein3skrä3instruis3kopais4s3tri1stansist5attis5ten_i1stentis5tingis5tor_is5toreit2t5opjor4dinjord3s4jut4stajäl4p5rjärn3sk5kaptenk5arbet3klang_k5lock_5klocka3korres5kra3gek4retenkrid5s2kropps5k5rädd_k5slag_kstavs32kvente5lakan_3laktis3lande_5laste_lat4tisler3ste2linga_lings5tli3strölläggs5lt5ratilus2s5plycks5tman5g4omask3romer2skome5trinm5planemst3rin4mun3g45målet_mö4gen_nd5skalne5gresne5s4tinfalls5n4gentings5timngs3valnings3knings5vnist3ranslags5n3stansn2striknst5vilnter5s4n2t5ombn5tralant3ralints5koroförmå4ogno5stoll5släon5stelons4teron3traso5plineoran3g45organi3orientors5tigo5stillost5ronota2lanpek5tripekt3ropel3s4ipos4terpre3stapres5to3rande_3raste_rek5trirgs5toprhands5rs5kollrs5tendr5stenirs5tillr2taktirv2s5käsamman3san3slasilver33s2kada3skaffn5skapet4skogsgskor1sts5kran_3s2langslotts33smitta5spann_4spelsls3plats4s3prissse4linss2lag_3stalla2stalli5stark_5stenar3s4tene3stense5stensms4teriu3sterne5stetiss4tiken5storis3straff3strato5stride2striel1striktst5risk2strumm3strängs1under5svärm_sys5ter2taktig3tande_2t3anfa2tappar5tavla_3tavlan5teknik5tekniste5stik3tillst5tivite3t4ral_3t4ralet3rets_t3ring_t5ronik4tropi_trus5ta5tryck_5trygght5s4andt5skallt3skatttt3randuk3trisull3ste5underl1undervun5g2efurs5tin2v1aktivensk3äving3s45vinst_5vinsteväll4s3xem3play5klistys4tik_åk4sträård4s3tår5s2liäls5kogär4tandö3randeö4reströr5evigör2p5la",
		8 : "_and4rar_cy5klop_e5strad_krings2_mjölk5s_män5sko_skott3s_string4_vatten3ali5stikas5tikerelekt3riennings2ent4rat_ent3ratieri5stikgi5stralhandels35inspeln3instink5klist3r5korterakrings2kkru5stad2lapparallust3ral4skensv5längderni5sterinkrafts5n4tropinos5tikerpul2l5ov4ran4d3r5ringen_rreligi5rskotts3rslags4v5rullerasinne2s35stalgis5startad1steringstori4eu4strativ5tallise5tartavl5torietttran2s5atskotts5ts5tillf1undersöun3gerskun5tratiutlands35ventera4ändligh",
		9 : "_ma5skeri_pub3likad5rasseragi5st4rat"
	}
};Hyphenator.run();

