PageSourceSearch

https://www.wearelv.com/core/wp-content/themes/wearelv/js/hyphenator.js

js wearelv.com collected 2026-10-07 20:05:05 UTC 73,657 bytes, 2,399 lines download raw bytes

1var _____WB$wombat$assign$function_____=function(name){return (self._wb_wombat && self._wb_wombat.local_init && self._wb_wombat.local_init(name))||self[name];};if(!self.__WB_pmw){self.__WB_pmw=function(obj){this.__WB_source=obj;return this;}}{
2let window = _____WB$wombat$assign$function_____("window");
3let self = _____WB$wombat$assign$function_____("self");
4let document = _____WB$wombat$assign$function_____("document");
5let location = _____WB$wombat$assign$function_____("location");
6let top = _____WB$wombat$assign$function_____("top");
7let parent = _____WB$wombat$assign$function_____("parent");
8let frames = _____WB$wombat$assign$function_____("frames");
9let opens = _____WB$wombat$assign$function_____("opens");
10/** @license Hyphenator 4.0.0 - client side hyphenation for webbrowsers
11 *  Copyright (C) 2011  Mathias Nater, Zürich (mathias at mnn dot ch)
12 *  Project and Source hosted on http://code.google.com/p/hyphenator/
13 * 
14 *  This JavaScript code is free software: you can redistribute
15 *  it and/or modify it under the terms of the GNU Lesser
16 *  General Public License (GNU LGPL) as published by the Free Software
17 *  Foundation, either version 3 of the License, or (at your option)
18 *  any later version.  The code is distributed WITHOUT ANY WARRANTY;
19 *  without even the implied warranty of MERCHANTABILITY or FITNESS
20 *  FOR A PARTICULAR PURPOSE.  See the GNU GPL for more details.
21 *
22 *  As additional permission under GNU GPL version 3 section 7, you
23 *  may distribute non-source (e.g., minimized or compacted) forms of
24 *  that code without the copy of the GNU GPL normally required by
25 *  section 4, provided you include this license notice and a URL
26 *  through which recipients can access the Corresponding Source.
27 *
28 * 
29 *  Hyphenator.js contains code from Bram Steins hypher.js-Project:
30 *  https://github.com/bramstein/Hypher
31 *  
32 *  Code from this project is marked in the source and belongs 
33 *  to the following license:
34 *  
35 *  Copyright (c) 2011, Bram Stein
36 *  All rights reserved.
37 *  
38 *  Redistribution and use in source and binary forms, with or without 
39 *  modification, are permitted provided that the following conditions 
40 *  are met:
41 *   
42 *   1. Redistributions of source code must retain the above copyright
43 *      notice, this list of conditions and the following disclaimer. 
44 *   2. Redistributions in binary form must reproduce the above copyright 
45 *      notice, this list of conditions and the following disclaimer in the 
46 *      documentation and/or other materials provided with the distribution. 
47 *   3. The name of the author may not be used to endorse or promote products 
48 *      derived from this software without specific prior written permission. 
49 *  
50 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED 
51 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
52 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 
53 *  EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
54 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
55 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
56 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
57 *  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
58 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
59 *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 *  
61 */
62 
63/* 
64 *  Comments are jsdoctoolkit formatted. See http://code.google.com/p/jsdoc-toolkit/
65 */
66 
67/* The following comment is for JSLint: */
68/*global window, ActiveXObject, unescape */
69/*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 */
70
71
72/**
73 * @constructor
74 * @description Provides all functionality to do hyphenation, except the patterns that are loaded
75 * externally.
76 * @author Mathias Nater, <a href = "mailto:[email protected]">[email protected]</a>
77 * @version X.Y.Z
78 * @namespace Holds all methods and properties
79 * @example
80 * &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
81 * &lt;script type = "text/javascript"&gt;
82 *   Hyphenator.run();
83 * &lt;/script&gt;
84 */
85var Hyphenator = (function (window) {
86
87	var
88	/**
89	 * @name Hyphenator-supportedLang
90	 * @description
91	 * A key-value object that stores supported languages.
92	 * The key is the bcp47 code of the language and the value
93	 * is the (abbreviated) filename of the pattern file.
94	 * @type {Object.<string, string>}
95	 * @private
96	 * @example
97	 * Check if language lang is supported:
98	 * if (supportedLang.hasOwnProperty(lang))
99	 */
100	supportedLang = {
101		'be': 'be.js',
102		'ca': 'ca.js',
103		'cs': 'cs.js',
104		'da': 'da.js',
105		'bn': 'bn.js',
106		'de': 'de.js',
107		'el': 'el-monoton.js',
108		'el-monoton': 'el-monoton.js',
109		'el-polyton': 'el-polyton.js',
110		'en': 'en-us.js',
111		'en-gb': 'en-gb.js',
112		'en-us': 'en-us.js',
113		'es': 'es.js',
114		'fi': 'fi.js',
115		'fr': 'fr.js',
116		'grc': 'grc.js',
117		'gu': 'gu.js',
118		'hi': 'hi.js',
119		'hu': 'hu.js',
120		'hy': 'hy.js',
121		'it': 'it.js',
122		'kn': 'kn.js',
123		'la': 'la.js',
124		'lt': 'lt.js',
125		'lv': 'lv.js',
126		'ml': 'ml.js',
127		'nb': 'nb-no.js',
128		'no': 'nb-no.js',
129		'nb-no': 'nb-no.js',
130		'nl': 'nl.js',
131		'or': 'or.js',
132		'pa': 'pa.js',
133		'pl': 'pl.js',
134		'pt': 'pt.js',
135		'ru': 'ru.js',
136		'sk': 'sk.js',
137		'sl': 'sl.js',
138		'sv': 'sv.js',
139		'ta': 'ta.js',
140		'te': 'te.js',
141		'tr': 'tr.js',
142		'uk': 'uk.js'
143	},
144
145	/**
146	 * @name Hyphenator-languageHint
147	 * @description
148	 * An automatically generated string to be displayed in a prompt if the language can't be guessed.
149	 * The string is generated using the supportedLang-object.
150	 * @see Hyphenator-supportedLang
151	 * @type {string}
152	 * @private
153	 * @see Hyphenator-autoSetMainLanguage
154	 */
155
156	languageHint = (function () {
157		var k, r = '';
158		for (k in supportedLang) {
159			if (supportedLang.hasOwnProperty(k)) {
160				r += k + ', ';
161			}
162		}
163		r = r.substring(0, r.length - 2);
164		return r;
165	}()),
166	
167	/**
168	 * @name Hyphenator-prompterStrings
169	 * @description
170	 * A key-value object holding the strings to be displayed if the language can't be guessed
171	 * If you add hyphenation patterns change this string.
172	 * @type {Object.<string,string>}
173	 * @private
174	 * @see Hyphenator-autoSetMainLanguage
175	 */	
176	prompterStrings = {
177		'be': 'Мова гэтага сайта не можа быць вызначаны аўтаматычна. Калі ласка пакажыце мову:',
178		'cs': 'Jazyk této internetové stránky nebyl automaticky rozpoznán. Určete prosím její jazyk:',
179		'da': 'Denne websides sprog kunne ikke bestemmes. Angiv venligst sprog:',
180		'de': 'Die Sprache dieser Webseite konnte nicht automatisch bestimmt werden. Bitte Sprache angeben:',
181		'en': 'The language of this website could not be determined automatically. Please indicate the main language:',
182		'es': 'El idioma del sitio no pudo determinarse autom%E1ticamente. Por favor, indique el idioma principal:',
183		'fi': 'Sivun kielt%E4 ei tunnistettu automaattisesti. M%E4%E4rit%E4 sivun p%E4%E4kieli:',
184		'fr': 'La langue de ce site n%u2019a pas pu %EAtre d%E9termin%E9e automatiquement. Veuillez indiquer une langue, s.v.p.%A0:',
185		'hu': 'A weboldal nyelvét nem sikerült automatikusan megállapítani. Kérem adja meg a nyelvet:',
186		'hy': 'Չհաջողվեց հայտնաբերել այս կայքի լեզուն։ Խնդրում ենք նշեք հիմնական լեզուն՝',
187		'it': 'Lingua del sito sconosciuta. Indicare una lingua, per favore:',
188		'kn': 'ಜಾಲ ತಾಣದ ಭಾಷೆಯನ್ನು ನಿರ್ಧರಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ದಯವಿಟ್ಟು ಮುಖ್ಯ ಭಾಷೆಯನ್ನು ಸೂಚಿಸಿ:',
189		'lt': 'Nepavyko automatiškai nustatyti šios svetainės kalbos. Prašome įvesti kalbą:',
190		'lv': 'Šīs lapas valodu nevarēja noteikt automātiski. Lūdzu norādiet pamata valodu:',
191		'ml': 'ഈ വെ%u0D2C%u0D4D%u200Cസൈറ്റിന്റെ ഭാഷ കണ്ടുപിടിയ്ക്കാ%u0D28%u0D4D%u200D കഴിഞ്ഞില്ല. ഭാഷ ഏതാണെന്നു തിരഞ്ഞെടുക്കുക:',
192		'nl': 'De taal van deze website kan niet automatisch worden bepaald. Geef de hoofdtaal op:',
193		'no': 'Nettstedets språk kunne ikke finnes automatisk. Vennligst oppgi språk:',
194		'pt': 'A língua deste site não pôde ser determinada automaticamente. Por favor indique a língua principal:',
195		'ru': 'Язык этого сайта не может быть определен автоматически. Пожалуйста укажите язык:',
196		'sl': 'Jezika te spletne strani ni bilo mogoče samodejno določiti. Prosim navedite jezik:',
197		'sv': 'Spr%E5ket p%E5 den h%E4r webbplatsen kunde inte avg%F6ras automatiskt. V%E4nligen ange:',
198		'tr': 'Bu web sitesinin dili otomatik olarak tespit edilememiştir. Lütfen dökümanın dilini seçiniz%A0:',
199		'uk': 'Мова цього веб-сайту не може бути визначена автоматично. Будь ласка, вкажіть головну мову:'
200	},
201	
202	/**
203	 * @name Hyphenator-basePath
204	 * @description
205	 * A string storing the basepath from where Hyphenator.js was loaded.
206	 * This is used to load the patternfiles.
207	 * The basepath is determined dynamically by searching all script-tags for Hyphenator.js
208	 * If the path cannot be determined http://hyphenator.googlecode.com/svn/trunk/ is used as fallback.
209	 * @type {string}
210	 * @private
211	 * @see Hyphenator-loadPatterns
212	 */
213	basePath = (function () {
214		var s = document.getElementsByTagName('script'), i = 0, p, src, t;
215		while (!!(t = s[i++])) {
216			if (!t.src) {
217				continue;
218			}
219			src = t.src;
220			p = src.indexOf('Hyphenator.js');
221			if (p !== -1) {
222				return src.substring(0, p);
223			}
224		}
225		return 'http://hyphenator.googlecode.com/svn/trunk/';
226	}()),
227
228	/**
229	 * @name Hyphenator-isLocal
230	 * @description
231	 * isLocal is true, if Hyphenator is loaded from the same domain, as the webpage, but false, if
232	 * it's loaded from an external source (i.e. directly from google.code)
233	 */
234	isLocal = (function () {
235		var re = false;
236		if (window.location.href.indexOf(basePath) !== -1) {
237			re = true;
238		}
239		return re;
240	}()),
241	
242	/**
243	 * @name Hyphenator-documentLoaded
244	 * @description
245	 * documentLoaded is true, when the DOM has been loaded. This is set by runOnContentLoaded
246	 */
247	documentLoaded = false,
248	documentCount = 0,
249	
250	/**
251	 * @name Hyphenator-persistentConfig
252	 * @description
253	 * if persistentConfig is set to true (defaults to false), config options and the state of the 
254	 * toggleBox are stored in DOM-storage (according to the storage-setting). So they haven't to be
255	 * set for each page.
256	 */	
257	persistentConfig = false,	
258
259	/**
260	 * @name Hyphenator-contextWindow
261	 * @description
262	 * contextWindow stores the window for the document to be hyphenated.
263	 * If there are frames this will change.
264	 * So use contextWindow instead of window!
265	 */
266	contextWindow = window,
267
268	/**
269	 * @name Hyphenator-doFrames
270	 * @description
271	 * switch to control if frames/iframes should be hyphenated, too
272	 * defaults to false (frames are a bag of hurt!)
273	 */
274	doFrames = false,
275	
276	/**
277	 * @name Hyphenator-dontHyphenate
278	 * @description
279	 * A key-value object containing all html-tags whose content should not be hyphenated
280	 * @type {Object.<string,boolean>}
281	 * @private
282	 * @see Hyphenator-hyphenateElement
283	 */
284	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, 'math': true, 'svg': true},
285
286	/**
287	 * @name Hyphenator-enableCache
288	 * @description
289	 * A variable to set if caching is enabled or not
290	 * @type boolean
291	 * @default true
292	 * @private
293	 * @see Hyphenator.config
294	 * @see hyphenateWord
295	 */
296	enableCache = true,
297
298	/**
299	 * @name Hyphenator-storageType
300	 * @description
301	 * A variable to define what html5-DOM-Storage-Method is used ('none', 'local' or 'session')
302	 * @type {string}
303	 * @default 'none'
304	 * @private
305	 * @see Hyphenator.config
306	 */	
307	storageType = 'local',
308
309	/**
310	 * @name Hyphenator-storage
311	 * @description
312	 * An alias to the storage-Method defined in storageType.
313	 * Set by Hyphenator.run()
314	 * @type {Object|undefined}
315	 * @default null
316	 * @private
317	 * @see Hyphenator.run
318	 */	
319	storage,
320	
321	/**
322	 * @name Hyphenator-enableReducedPatternSet
323	 * @description
324	 * A variable to set if storing the used patterns is set
325	 * @type boolean
326	 * @default false
327	 * @private
328	 * @see Hyphenator.config
329	 * @see hyphenateWord
330	 * @see Hyphenator.getRedPatternSet
331	 */	
332	enableReducedPatternSet = false,
333	
334	/**
335	 * @name Hyphenator-enableRemoteLoading
336	 * @description
337	 * A variable to set if pattern files should be loaded remotely or not
338	 * @type boolean
339	 * @default true
340	 * @private
341	 * @see Hyphenator.config
342	 * @see Hyphenator-loadPatterns
343	 */
344	enableRemoteLoading = true,
345	
346	/**
347	 * @name Hyphenator-displayToggleBox
348	 * @description
349	 * A variable to set if the togglebox should be displayed or not
350	 * @type boolean
351	 * @default false
352	 * @private
353	 * @see Hyphenator.config
354	 * @see Hyphenator-toggleBox
355	 */
356	displayToggleBox = false,
357
358	/**
359	 * @name Hyphenator-css3
360	 * @description
361	 * A variable to set if css3 hyphenation should be used
362	 * @type boolean
363	 * @default false
364	 * @private
365	 * @see Hyphenator.config
366	 */
367	css3 = false,
368	/**
369	 * @name Hyphenator-css3_hsupport
370	 * @description
371	 * A generated object containing information for CSS3-hyphenation support
372	 * {
373	 *   support: boolean,
374	 *   property: <the property name to access hyphen-settings>,
375	 *   languages: <an object containing supported languages>
376	 * }
377	 * @type object
378	 * @default undefined
379	 * @private
380	 * @see Hyphenator-css3_gethsupport
381	 */
382	css3_h9n,
383	/**
384	 * @name Hyphenator-css3_gethsupport
385	 * @description
386	 * This function sets Hyphenator-css3_h9n for the current UA
387	 * @type function
388	 * @private
389	 * @see Hyphenator-css3_h9n
390	 */
391	css3_gethsupport = function () {
392		var s,
393		ua = navigator.userAgent,
394		r = {
395			support: false,
396			property: '',
397			languages: {}
398		};
399		if (window.getComputedStyle) {
400			s = window.getComputedStyle(window.document.getElementsByTagName('body')[0]);
401		} else {
402			//ancient Browser don't support CSS3 anyway
403			css3_h9n = r;
404			return;
405		}
406		if (ua.indexOf('Chrome') !== -1) {
407			//Chrome actually knows -webkit-hyphens but does no hyphenation
408			r.support = false;
409		} else if ((ua.indexOf('Safari') !== -1) && (s['-webkit-hyphens'] !== undefined)) {
410			r.support = true;
411			r.property = '-webkit-hyphens';
412			if (ua.indexOf('Mobile') !== -1) {
413				//iOS only hyphenates in systemlanguage
414				r.languages[navigator.language.split('-')[0]] = true;
415			} else {
416				//Desktop Safari only hyphenates some languages:
417				r.languages = {
418					de: true,
419					en: true,
420					es: true,
421					fr: true,
422					it: true,
423					nl: true,
424					ru: true,
425					zh: true
426				};
427			}
428		} else if ((ua.indexOf('Firefox') !== -1) && (s['MozHyphens'] !== undefined)) {
429			r.support = true;
430			r.property = 'MozHyphens';
431			r.languages = {
432				en: true
433			};
434		}
435		css3_h9n = r;
436	},
437	
438	/**
439	 * @name Hyphenator-hyphenateClass
440	 * @description
441	 * A string containing the css-class-name for the hyphenate class
442	 * @type {string}
443	 * @default 'hyphenate'
444	 * @private
445	 * @example
446	 * &lt;p class = "hyphenate"&gt;Text&lt;/p&gt;
447	 * @see Hyphenator.config
448	 */
449	hyphenateClass = 'hyphenate',
450
451	/**
452	 * @name Hyphenator-dontHyphenateClass
453	 * @description
454	 * A string containing the css-class-name for elements that should not be hyphenated
455	 * @type {string}
456	 * @default 'donthyphenate'
457	 * @private
458	 * @example
459	 * &lt;p class = "donthyphenate"&gt;Text&lt;/p&gt;
460	 * @see Hyphenator.config
461	 */
462	dontHyphenateClass = 'donthyphenate',
463	
464	/**
465	 * @name Hyphenator-min
466	 * @description
467	 * A number wich indicates the minimal length of words to hyphenate.
468	 * @type {number}
469	 * @default 6
470	 * @private
471	 * @see Hyphenator.config
472	 */	
473	min = 6,
474	
475	/**
476	 * @name Hyphenator-orphanControl
477	 * @description
478	 * Control how the last words of a line are handled:
479	 * level 1 (default): last word is hyphenated
480	 * level 2: last word is not hyphenated
481	 * level 3: last word is not hyphenated and last space is non breaking
482	 * @type {number}
483	 * @default 1
484	 * @private
485	 */
486	orphanControl = 1,
487	
488	/**
489	 * @name Hyphenator-isBookmarklet
490	 * @description
491	 * Indicates if Hyphanetor runs as bookmarklet or not.
492	 * @type boolean
493	 * @default false
494	 * @private
495	 */	
496	isBookmarklet = (function () {
497		var loc = null, re = false, jsArray = document.getElementsByTagName('script'), i, l;
498		for (i = 0, l = jsArray.length; i < l; i++) {
499			if (!!jsArray[i].getAttribute('src')) {
500				loc = jsArray[i].getAttribute('src');
501			}
502			if (!loc) {
503				continue;
504			} else if (loc.indexOf('Hyphenator.js?bm=true') !== -1) {
505				re = true;
506			}
507		}
508		return re;
509	}()),
510	
511	/**
512	 * @name Hyphenator-mainLanguage
513	 * @description
514	 * The general language of the document. In contrast to {@link Hyphenator-defaultLanguage},
515	 * mainLanguage is defined by the client (i.e. by the html or by a prompt).
516	 * @type {string|null}
517	 * @private
518	 * @see Hyphenator-autoSetMainLanguage
519	 */	
520	mainLanguage = null,
521
522	/**
523	 * @name Hyphenator-defaultLanguage
524	 * @description
525	 * The language defined by the developper. This language setting is defined by a config option.
526	 * It is overwritten by any html-lang-attribute and only taken in count, when no such attribute can
527	 * be found (i.e. just before the prompt).
528	 * @type {string|null}
529	 * @private
530	 * @see Hyphenator-autoSetMainLanguage
531	 */	
532	defaultLanguage = '',
533	
534
535	/**
536	 * @name Hyphenator-elements
537	 * @description
538	 * An array holding all elements that have to be hyphenated. This var is filled by
539	 * {@link Hyphenator-gatherDocumentInfos}
540	 * @type {Array}
541	 * @private
542	 */	
543	elements = (function () {
544		var Element = function (element, data) {
545			this.element = element;
546			this.hyphenated = false;
547			this.treated = false; //collected but not hyphenated (dohyphenation is off)
548			this.data = data;
549		},
550		ElementCollection = function () {
551			this.count = 0;
552			this.hyCount = 0;
553			this.list = {};
554		};
555		ElementCollection.prototype = {
556			add: function (el, lang, data) {
557				if (!this.list.hasOwnProperty(lang)) {
558					this.list[lang] = [];
559				}
560				this.list[lang].push(new Element(el, data));
561				this.count += 1;
562			},
563			each: function (fn) {
564				var k;
565				for (k in this.list) {
566					if (this.list.hasOwnProperty(k)) {
567						fn(k, this.list[k]);
568					}
569				}
570			}
571		};
572		return new ElementCollection();
573	}()),
574
575	
576	/**
577	 * @name Hyphenator-exceptions
578	 * @description
579	 * An object containing exceptions as comma separated strings for each language.
580	 * When the language-objects are loaded, their exceptions are processed, copied here and then deleted.
581	 * @see Hyphenator-prepareLanguagesObj
582	 * @type {Object}
583	 * @private
584	 */	
585	exceptions = {},
586	
587	/**
588	 * @name Hyphenator-docLanguages
589	 * @description
590	 * An object holding all languages used in the document. This is filled by
591	 * {@link Hyphenator-gatherDocumentInfos}
592	 * @type {Object}
593	 * @private
594	 */	
595	docLanguages = {},
596
597	/**
598	 * @name Hyphenator-state
599	 * @description
600	 * A number that inidcates the current state of the script
601	 * 0: not initialized
602	 * 1: loading patterns
603	 * 2: ready
604	 * 3: hyphenation done
605	 * 4: hyphenation removed
606	 * @type {number}
607	 * @private
608	 */	
609	state = 0,
610
611	/**
612	 * @name Hyphenator-url
613	 * @description
614	 * A string containing a RegularExpression to match URL's
615	 * @type {string}
616	 * @private
617	 */	
618	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#!:\\.?\\+=&%@!\\-]*)*',
619	//      protocoll     usr     pwd                    ip               or                          host                 tld        port               path
620	/**
621	 * @name Hyphenator-mail
622	 * @description
623	 * A string containing a RegularExpression to match mail-adresses
624	 * @type {string}
625	 * @private
626	 */	
627	mail = '[\\w-\\.]+@[\\w\\.]+',
628
629	/**
630	 * @name Hyphenator-urlRE
631	 * @description
632	 * A RegularExpressions-Object for url- and mail adress matching
633	 * @type {RegExp}
634	 * @private
635	 */		
636	urlOrMailRE = new RegExp('(' + url + ')|(' + mail + ')', 'i'),
637
638	/**
639	 * @name Hyphenator-zeroWidthSpace
640	 * @description
641	 * A string that holds a char.
642	 * Depending on the browser, this is the zero with space or an empty string.
643	 * zeroWidthSpace is used to break URLs
644	 * @type {string}
645	 * @private
646	 */		
647	zeroWidthSpace = (function () {
648		var zws, ua = navigator.userAgent.toLowerCase();
649		zws = String.fromCharCode(8203); //Unicode zero width space
650		if (ua.indexOf('msie 6') !== -1) {
651			zws = ''; //IE6 doesn't support zws
652		}
653		if (ua.indexOf('opera') !== -1 && ua.indexOf('version/10.00') !== -1) {
654			zws = ''; //opera 10 on XP doesn't support zws
655		}
656		return zws;
657	}()),
658	
659	/**
660	 * @name Hyphenator-createElem
661	 * @description
662	 * A function alias to document.createElementNS or document.createElement
663	 * @type {function(string, Object)}
664	 * @private
665	 */		
666	createElem = function (tagname, context) {
667		context = context || contextWindow;
668		if (document.createElementNS) {
669			return context.document.createElementNS('http://www.w3.org/1999/xhtml', tagname);
670		} else if (document.createElement) {
671			return context.document.createElement(tagname);
672		}
673	},
674	
675	/**
676	 * @name Hyphenator-onHyphenationDone
677	 * @description
678	 * A method to be called, when the last element has been hyphenated or the hyphenation has been
679	 * removed from the last element.
680	 * @see Hyphenator.config
681	 * @type {function()}
682	 * @private
683	 */		
684	onHyphenationDone = function () {},
685
686	/**
687	 * @name Hyphenator-onError
688	 * @description
689	 * A function that can be called upon an error.
690	 * @see Hyphenator.config
691	 * @type {function(Object)}
692	 * @private
693	 */		
694	onError = function (e) {
695		window.alert("Hyphenator.js says:\n\nAn Error ocurred:\n" + e.message);
696	},
697
698	/**
699	 * @name Hyphenator-selectorFunction
700	 * @description
701	 * A function that has to return a HTMLNodeList of Elements to be hyphenated.
702	 * By default it uses the classname ('hyphenate') to select the elements.
703	 * @see Hyphenator.config
704	 * @type {function()}
705	 * @private
706	 */		
707	selectorFunction = function () {
708		var tmp, el = [], i, l;
709		if (document.getElementsByClassName) {
710			el = contextWindow.document.getElementsByClassName(hyphenateClass);
711		} else {
712			tmp = contextWindow.document.getElementsByTagName('*');
713			l = tmp.length;
714			for (i = 0; i < l; i++)
715			{
716				if (tmp[i].className.indexOf(hyphenateClass) !== -1 && tmp[i].className.indexOf(dontHyphenateClass) === -1) {
717					el.push(tmp[i]);
718				}
719			}
720		}
721		return el;
722	},
723
724	/**
725	 * @name Hyphenator-intermediateState
726	 * @description
727	 * The value of style.visibility of the text while it is hyphenated.
728	 * @see Hyphenator.config
729	 * @type {string}
730	 * @private
731	 */		
732	intermediateState = 'hidden',
733	
734	/**
735	 * @name Hyphenator-unhide
736	 * @description
737	 * How hidden elements unhide: either simultaneous (default: 'wait') or progressively.
738	 * 'wait' makes Hyphenator.js to wait until all elements are hyphenated (one redraw)
739	 * With 'progressiv' Hyphenator.js unhides elements as soon as they are hyphenated.
740	 * @see Hyphenator.config
741	 * @type {string}
742	 * @private
743	 */		
744	unhide = 'wait',
745	
746	/**
747	 * @name Hyphenator-hyphen
748	 * @description
749	 * A string containing the character for in-word-hyphenation
750	 * @type {string}
751	 * @default the soft hyphen
752	 * @private
753	 * @see Hyphenator.config
754	 */
755	hyphen = String.fromCharCode(173),
756	
757	/**
758	 * @name Hyphenator-urlhyphen
759	 * @description
760	 * A string containing the character for url/mail-hyphenation
761	 * @type {string}
762	 * @default the zero width space
763	 * @private
764	 * @see Hyphenator.config
765	 * @see Hyphenator-zeroWidthSpace
766	 */
767	urlhyphen = zeroWidthSpace,
768
769	/**
770	 * @name Hyphenator-safeCopy
771	 * @description
772	 * Defines wether work-around for copy issues is active or not
773	 * Not supported by Opera (no onCopy handler)
774	 * @type boolean
775	 * @default true
776	 * @private
777	 * @see Hyphenator.config
778	 * @see Hyphenator-registerOnCopy
779	 */
780	safeCopy = true,
781	
782		
783	/*
784	 * runOnContentLoaded is based od jQuery.bindReady()
785	 * see
786	 * jQuery JavaScript Library v1.3.2
787	 * http://jquery.com/
788	 *
789	 * Copyright (c) 2009 John Resig
790	 * Dual licensed under the MIT and GPL licenses.
791	 * http://docs.jquery.com/License
792	 *
793	 * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
794	 * Revision: 6246
795	 */
796	/**
797	 * @name Hyphenator-runOnContentLoaded
798	 * @description
799	 * A crossbrowser solution for the DOMContentLoaded-Event based on jQuery
800	 * <a href = "http://jquery.com/</a>
801	 * I added some functionality: e.g. support for frames and iframes…
802	 * @param {Object} w the window-object
803	 * @param {function()} f the function to call onDOMContentLoaded
804	 * @private
805	 */
806	runOnContentLoaded = function (w, f) {
807		var DOMContentLoaded = function () {}, toplevel, hyphRunForThis = {};
808		if (documentLoaded && !hyphRunForThis[w.location.href]) {
809			f();
810			hyphRunForThis[w.location.href] = true;
811			return;
812		}
813		function init(context) {
814			contextWindow = context || window;
815			if (!hyphRunForThis[contextWindow.location.href] && (!documentLoaded || contextWindow != window.parent)) {
816				documentLoaded = true;
817				f();
818				hyphRunForThis[contextWindow.location.href] = true;
819			}
820		}
821		
822		function doScrollCheck() {
823			try {
824				// If IE is used, use the trick by Diego Perini
825				// http://javascript.nwbox.com/IEContentLoaded/
826				document.documentElement.doScroll("left");
827			} catch (error) {
828				setTimeout(doScrollCheck, 1);
829				return;
830			}
831		
832			// and execute any waiting functions
833			init(window);
834		}
835
836		function doOnLoad() {
837			var i, haveAccess, fl = window.frames.length;
838			if (doFrames && fl > 0) {
839				for (i = 0; i < fl; i++) {
840					haveAccess = undefined;
841					//try catch isn't enough for webkit
842					try {
843						//opera throws only on document.toString-access
844						haveAccess = window.frames[i].document.toString();
845					} catch (e) {
846						haveAccess = undefined;
847					}
848					if (!!haveAccess) {
849						init(window.frames[i]);
850					}
851				}
852				contextWindow = window;
853				f();
854				hyphRunForThis[window.location.href] = true;
855			} else {
856				init(window);
857			}
858		}
859		
860		// Cleanup functions for the document ready method
861		if (document.addEventListener) {
862			DOMContentLoaded = function () {
863				document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
864				if (doFrames && window.frames.length > 0) {
865					//we are in a frameset, so do nothing but wait for onload to fire
866					return;
867				} else {
868					init(window);
869				}
870			};
871		
872		} else if (document.attachEvent) {
873			DOMContentLoaded = function () {
874				// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
875				if (document.readyState === "complete") {
876					document.detachEvent("onreadystatechange", DOMContentLoaded);
877					if (doFrames && window.frames.length > 0) {
878						//we are in a frameset, so do nothing but wait for onload to fire
879						return;
880					} else {
881						init(window);
882					}
883				}
884			};
885		}
886
887		// Mozilla, Opera and webkit nightlies currently support this event
888		if (document.addEventListener) {
889			// Use the handy event callback
890			document.addEventListener("DOMContentLoaded", DOMContentLoaded, false);
891			
892			// A fallback to window.onload, that will always work
893			window.addEventListener("load", doOnLoad, false);
894
895		// If IE event model is used
896		} else if (document.attachEvent) {
897			// ensure firing before onload,
898			// maybe late but safe also for iframes
899			document.attachEvent("onreadystatechange", DOMContentLoaded);
900			
901			// A fallback to window.onload, that will always work
902			window.attachEvent("onload", doOnLoad);
903
904			// If IE and not a frame
905			// continually check to see if the document is ready
906			toplevel = false;
907			try {
908				toplevel = window.frameElement === null;
909			} catch (e) {}
910
911			if (document.documentElement.doScroll && toplevel) {
912				doScrollCheck();
913			}
914		}
915
916	},
917
918
919
920	/**
921	 * @name Hyphenator-getLang
922	 * @description
923	 * Gets the language of an element. If no language is set, it may use the {@link Hyphenator-mainLanguage}.
924	 * @param {Object} el The first parameter is an DOM-Element-Object
925	 * @param {boolean} fallback The second parameter is a boolean to tell if the function should return the {@link Hyphenator-mainLanguage}
926	 * if there's no language found for the element.
927	 * @private
928	 */
929	getLang = function (el, fallback) {
930		if (!!el.getAttribute('lang')) {
931			return el.getAttribute('lang').toLowerCase();
932		}
933		// The following doesn't work in IE due to a bug when getAttribute('xml:lang') in a table
934		/*if (!!el.getAttribute('xml:lang')) {
935			return el.getAttribute('xml:lang').substring(0, 2);
936		}*/
937		//instead, we have to do this (thanks to borgzor):
938		try {
939			if (!!el.getAttribute('xml:lang')) {
940				return el.getAttribute('xml:lang').toLowerCase();
941			}
942		} catch (ex) {}
943		if (el.tagName !== 'HTML') {
944			return getLang(el.parentNode, true);
945		}
946		if (fallback) {
947			return mainLanguage;
948		}
949		return null;
950	},
951	
952	/**
953	 * @name Hyphenator-autoSetMainLanguage
954	 * @description
955	 * Retrieves the language of the document from the DOM.
956	 * The function looks in the following places:
957	 * <ul>
958	 * <li>lang-attribute in the html-tag</li>
959	 * <li>&lt;meta http-equiv = "content-language" content = "xy" /&gt;</li>
960	 * <li>&lt;meta name = "DC.Language" content = "xy" /&gt;</li>
961	 * <li>&lt;meta name = "language" content = "xy" /&gt;</li>
962	 * </li>
963	 * If nothing can be found a prompt using {@link Hyphenator-languageHint} and {@link Hyphenator-prompterStrings} is displayed.
964	 * If the retrieved language is in the object {@link Hyphenator-supportedLang} it is copied to {@link Hyphenator-mainLanguage}
965	 * @private
966	 */		
967	autoSetMainLanguage = function (w) {
968		w = w || contextWindow;
969		var el = w.document.getElementsByTagName('html')[0],
970			m = w.document.getElementsByTagName('meta'),
971			i, text, e, ul;
972		mainLanguage = getLang(el, false);
973		if (!mainLanguage) {
974			for (i = 0; i < m.length; i++) {
975				//<meta http-equiv = "content-language" content="xy">	
976				if (!!m[i].getAttribute('http-equiv') && (m[i].getAttribute('http-equiv').toLowerCase() === 'content-language')) {
977					mainLanguage = m[i].getAttribute('content').toLowerCase();
978				}
979				//<meta name = "DC.Language" content="xy">
980				if (!!m[i].getAttribute('name') && (m[i].getAttribute('name').toLowerCase() === 'dc.language')) {
981					mainLanguage = m[i].getAttribute('content').toLowerCase();
982				}			
983				//<meta name = "language" content = "xy">
984				if (!!m[i].getAttribute('name') && (m[i].getAttribute('name').toLowerCase() === 'language')) {
985					mainLanguage = m[i].getAttribute('content').toLowerCase();
986				}
987			}
988		}
989		//get lang for frame from enclosing document
990		if (!mainLanguage && doFrames && contextWindow != window.parent) {
991			autoSetMainLanguage(window.parent);
992		}
993		//fallback to defaultLang if set
994		if (!mainLanguage && defaultLanguage !== '') {
995			mainLanguage = defaultLanguage;
996		}
997		//ask user for lang
998		if (!mainLanguage) {
999			text = '';
1000			ul = navigator.language ? navigator.language : navigator.userLanguage;
1001			ul = ul.substring(0, 2);
1002			if (prompterStrings.hasOwnProperty(ul)) {
1003				text = prompterStrings[ul];
1004			} else {
1005				text = prompterStrings.en;
1006			}
1007			text += ' (ISO 639-1)\n\n' + languageHint;
1008			mainLanguage = window.prompt(unescape(text), ul).toLowerCase();
1009		}
1010		if (!supportedLang.hasOwnProperty(mainLanguage)) {
1011			if (supportedLang.hasOwnProperty(mainLanguage.split('-')[0])) { //try subtag
1012				mainLanguage = mainLanguage.split('-')[0];
1013			} else {
1014				e = new Error('The language "' + mainLanguage + '" is not yet supported.');
1015				throw e;
1016			}
1017		}
1018	},
1019    
1020	/**
1021	 * @name Hyphenator-gatherDocumentInfos
1022	 * @description
1023	 * This method runs through the DOM and executes the process()-function on:
1024	 * - every node returned by the {@link Hyphenator-selectorFunction}.
1025	 * The process()-function copies the element to the elements-variable, sets its visibility
1026	 * to intermediateState, retrieves its language and recursivly desce
1026nds the DOM-tree until
1027	 * the child-Nodes aren't of type 1
1028	 * @private
1029	 */		
1030	gatherDocumentInfos = function () {
1031		var elToProcess, tmp, i = 0,
1032		process = function (el, hide, lang) {
1033			var n, i = 0, hyphenatorSettings = {};
1034
1035			if (el.lang && typeof(el.lang) === 'string') {
1036				lang = el.lang.toLowerCase(); //copy attribute-lang to internal lang
1037			} else if (lang) {
1038				lang = lang.toLowerCase();
1039			} else {
1040				lang = getLang(el, true);
1041			}
1042			
1043			//if css3-hyphenation is supported: use it!
1044			if (css3 && css3_h9n.support && !!css3_h9n.languages[lang]) {
1045				el.style[css3_h9n.property] = "auto";
1046				el.style['-webkit-locale'] = "'" + lang + "'";
1047			} else {
1048				if (intermediateState === 'hidden') {
1049					if (!!el.getAttribute('style')) {
1050						hyphenatorSettings.hasOwnStyle = true;
1051					} else {
1052						hyphenatorSettings.hasOwnStyle = false;					
1053					}
1054					hyphenatorSettings.isHidden = true;
1055					el.style.visibility = 'hidden';
1056				}
1057				if (supportedLang[lang]) {
1058					docLanguages[lang] = true;
1059				} else {
1060					if (supportedLang.hasOwnProperty(lang.split('-')[0])) { //try subtag
1061						lang = lang.split('-')[0];
1062						hyphenatorSettings.language = lang;
1063					} else if (!isBookmarklet) {
1064						onError(new Error('Language ' + lang + ' is not yet supported.'));
1065					}
1066				}				
1067				elements.add(el, lang, hyphenatorSettings);
1068			}
1069			while (!!(n = el.childNodes[i++])) {
1070				if (n.nodeType === 1 && !dontHyphenate[n.nodeName.toLowerCase()] &&
1071					n.className.indexOf(dontHyphenateClass) === -1 && !(n in elToProcess)) {
1072					process(n, false, lang);
1073				}
1074			}
1075		};
1076		if (css3) {
1077			css3_gethsupport();
1078		}
1079		if (isBookmarklet) {
1080			elToProcess = contextWindow.document.getElementsByTagName('body')[0];
1081			process(elToProcess, false, mainLanguage);
1082		} else {
1083			elToProcess = selectorFunction();
1084			while (!!(tmp = elToProcess[i++]))
1085			{
1086				process(tmp, true, '');
1087			}			
1088		}
1089		if (elements.count === 0) {
1090			//nothing to hyphenate or all hyphenated b css3
1091			state = 3;
1092			onHyphenationDone();
1093		}
1094	},
1095		 
1096	
1097	/**
1098	 * @name Hyphenator-createTrie
1099	 * @description
1100	 * converts patterns of the given language in a trie
1101	 * @private
1102	 * @param {string} lang the language whose patterns shall be converted
1103	 */		
1104	convertPatterns = function (lang) {
1105		/** @license BSD licenced code
1106		 * The following code is based on code from hypher.js and adapted for Hyphenator.js
1107		 * Copyright (c) 2011, Bram Stein
1108		 */
1109		var size = 0,
1110			tree = {
1111				tpoints: []
1112			},
1113			patterns, pattern, i, j, k,
1114			patternObject = Hyphenator.languages[lang].patterns,
1115			c, chars, points, t, p, codePoint,
1116			getPoints = (function () {
1117				//IE<9 doesn't act like other browsers
1118				if ('in3se'.split(/\D/).length === 1) {
1119					return function (pattern) {
1120						var chars = pattern.split(''), c, i, r = [],
1121						numb3rs = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}, lastWasNum = false;
1122						i = 0;
1123						while (!!(c = chars[i])) {
1124							if (numb3rs.hasOwnProperty(c)) {
1125								r.push(c);
1126								i += 2;
1127								lastWasNum = true;
1128							} else {
1129								r.push('');
1130								i += 1;
1131								lastWasNum = false;
1132							}
1133						}
1134						if (!lastWasNum) {
1135							r.push('');
1136						}
1137						return r;
1138					};
1139				} else {
1140					return function (pattern) {
1141						return pattern.split(/\D/);
1142					};
1143				}
1144			}());
1145	
1146		for (size in patternObject) {
1147			if (patternObject.hasOwnProperty(size)) {
1148				patterns = patternObject[size].match(new RegExp('.{1,' + (+size) + '}', 'g'));
1149				i = 0;
1150				while (!!(pattern = patterns[i++])) {
1151					chars = pattern.replace(/[\d]/g, '').split('');
1152					points = getPoints(pattern);
1153					t = tree;
1154
1155					j = 0;
1156					while (!!(c = chars[j++])) {
1157						codePoint = c.charCodeAt(0);
1158						
1159						if (!t[codePoint]) {
1160							t[codePoint] = {};
1161						}
1162						t = t[codePoint];
1163					}
1164
1165					t.tpoints = [];
1166					for (k = 0; k < points.length; k++) {
1167						p = points[k];
1168						t.tpoints.push((p == "") ? 0 : p);
1169					}
1170				}
1171			}
1172		}
1173		Hyphenator.languages[lang].patterns = tree;
1174		/**
1175		 * end of BSD licenced code from hypher.js
1176		 */
1177	},
1178
1179	recreatePattern = function (pattern, nodePoints) {
1180		var r = [], c = pattern.split(''), i;
1181		for (i = 0; i < nodePoints.length; i++) {
1182			if (nodePoints[i] !== 0) {
1183				r.push(nodePoints[i]);
1184			}
1185			if (c[i]) {
1186				r.push(c[i]);
1187			}
1188		}
1189		return r.join('');
1190	},
1191	
1192	/**
1193	 * @name Hyphenator-convertExceptionsToObject
1194	 * @description
1195	 * Converts a list of comma seprated exceptions to an object:
1196	 * 'Fortran,Hy-phen-a-tion' -> {'Fortran':'Fortran','Hyphenation':'Hy-phen-a-tion'}
1197	 * @private
1198	 * @param {string} exc a comma separated string of exceptions (without spaces)
1199	 */		
1200	convertExceptionsToObject = function (exc) {
1201		var w = exc.split(', '),
1202			r = {},
1203			i, l, key;
1204		for (i = 0, l = w.length; i < l; i++) {
1205			key = w[i].replace(/-/g, '');
1206			if (!r.hasOwnProperty(key)) {
1207				r[key] = w[i];
1208			}
1209		}
1210		return r;
1211	},
1212	
1213	/**
1214	 * @name Hyphenator-loadPatterns
1215	 * @description
1216	 * Adds a &lt;script&gt;-Tag to the DOM to load an externeal .js-file containing patterns and settings for the given language.
1217	 * If the given language is not in the {@link Hyphenator-supportedLang}-Object it returns.
1218	 * One may ask why we are not using AJAX to load the patterns. The XMLHttpRequest-Object 
1219	 * has a same-origin-policy. This makes the isBookmarklet-functionality impossible.
1220	 * @param {string} lang The language to load the patterns for
1221	 * @private
1222	 * @see Hyphenator-basePath
1223	 */
1224	loadPatterns = function (lang) {
1225		var url, xhr, head, script;
1226		if (supportedLang[lang] && !Hyphenator.languages[lang]) {
1227	        url = basePath + 'patterns/' + supportedLang[lang];
1228		} else {
1229			return;
1230		}
1231		if (isLocal && !isBookmarklet) {
1232			//check if 'url' is available:
1233			xhr = null;
1234			if (typeof XMLHttpRequest !== 'undefined') {
1235				xhr = new XMLHttpRequest();
1236			}
1237			if (!xhr) {
1238				try {
1239					xhr  = new ActiveXObject("Msxml2.XMLHTTP");
1240				} catch (e) {
1241					xhr  = null;
1242				}
1243			}
1244			if (xhr) {
1245				xhr.open('HEAD', url, false);
1246				xhr.setRequestHeader('Cache-Control', 'no-cache');
1247				xhr.send(null);
1248				if (xhr.status === 404) {
1249					onError(new Error('Could not load\n' + url));
1250					delete docLanguages[lang];
1251					return;
1252				}
1253			}
1254		}
1255		if (createElem) {
1256			head = window.document.getElementsByTagName('head').item(0);
1257			script = createElem('script', window);
1258			script.src = url;
1259			script.type = 'text/javascript';
1260			head.appendChild(script);
1261		}
1262	},
1263	
1264	/**
1265	 * @name Hyphenator-prepareLanguagesObj
1266	 * @description
1267	 * Adds a cache to each language and converts the exceptions-list to an object.
1268	 * If storage is active the object is stored there.
1269	 * @private
1270	 * @param {string} lang the language ob the lang-obj
1271	 */		
1272	prepareLanguagesObj = function (lang) {
1273		var lo = Hyphenator.languages[lang], wrd;
1274		if (!lo.prepared) {	
1275			if (enableCache) {
1276				lo.cache = {};
1277				//Export
1278				lo['cache'] = lo.cache;
1279			}
1280			if (enableReducedPatternSet) {
1281				lo.redPatSet = {};
1282			}
1283			//add exceptions from the pattern file to the local 'exceptions'-obj
1284			if (lo.hasOwnProperty('exceptions')) {
1285				Hyphenator.addExceptions(lang, lo.exceptions);
1286				delete lo.exceptions;
1287			}
1288			//copy global exceptions to the language specific exceptions
1289			if (exceptions.hasOwnProperty('global')) {
1290				if (exceptions.hasOwnProperty(lang)) {
1291					exceptions[lang] += ', ' + exceptions.global;
1292				} else {
1293					exceptions[lang] = exceptions.global;
1294				}
1295			}
1296			//move exceptions from the the local 'exceptions'-obj to the 'language'-object
1297			if (exceptions.hasOwnProperty(lang)) {
1298				lo.exceptions = convertExceptionsToObject(exceptions[lang]);
1299				delete exceptions[lang];
1300			} else {
1301				lo.exceptions = {};
1302			}
1303			convertPatterns(lang);
1304			wrd = '[\\w' + lo.specialChars + '@' + String.fromCharCode(173) + String.fromCharCode(8204) + '-]{' + min + ',}';
1305			lo.genRegExp = new RegExp('(' + url + ')|(' + mail + ')|(' + wrd + ')', 'gi');
1306			lo.prepared = true;
1307		}
1308		if (!!storage) {
1309			try {
1310				storage.setItem('Hyphenator_' + lang, window.JSON.stringify(lo));
1311			} catch (e) {
1312				//onError(e);
1313			}
1314		}
1315		
1316	},
1317	
1318	/**
1319	 * @name Hyphenator-prepare
1320	 * @description
1321	 * This funtion prepares the Hyphenator-Object: If RemoteLoading is turned off, it assumes
1322	 * that the patternfiles are loaded, all conversions are made and the callback is called.
1323	 * If storage is active the object is retrieved there.
1324	 * If RemoteLoading is on (default), it loads the pattern files and waits until they are loaded,
1325	 * by repeatedly checking Hyphenator.languages. If a patterfile is loaded the patterns are
1326	 * converted to their object style and the lang-object extended.
1327	 * Finally the callback is called.
1328	 * @private
1329	 */
1330	prepare = function (callback) {
1331		var lang, interval, tmp1, tmp2;
1332		if (!enableRemoteLoading) {
1333			for (lang in Hyphenator.languages) {
1334				if (Hyphenator.languages.hasOwnProperty(lang)) {
1335					prepareLanguagesObj(lang);
1336				}
1337			}
1338			state = 2;
1339			callback('*');
1340			return;
1341		}
1342		// get all languages that are used and preload the patterns
1343		state = 1;
1344		for (lang in docLanguages) {
1345			if (docLanguages.hasOwnProperty(lang)) {
1346				if (!!storage && storage.getItem('Hyphenator_' + lang)) {
1347					Hyphenator.languages[lang] = window.JSON.parse(storage.getItem('Hyphenator_' + lang));
1348					if (exceptions.hasOwnProperty('global')) {
1349						tmp1 = convertExceptionsToObject(exceptions.global);
1350						for (tmp2 in tmp1) {
1351							if (tmp1.hasOwnProperty(tmp2)) {
1352								Hyphenator.languages[lang].exceptions[tmp2] = tmp1[tmp2];
1353							}
1354						}
1355					}
1356					//Replace exceptions since they may have been changed:
1357					if (exceptions.hasOwnProperty(lang)) {
1358						tmp1 = convertExceptionsToObject(exceptions[lang]);
1359						for (tmp2 in tmp1) {
1360							if (tmp1.hasOwnProperty(tmp2)) {
1361								Hyphenator.languages[lang].exceptions[tmp2] = tmp1[tmp2];
1362							}
1363						}
1364						delete exceptions[lang];
1365					}
1366					//Replace genRegExp since it may have been changed:
1367					tmp1 = '[\\w' + Hyphenator.languages[lang].specialChars + '@' + String.fromCharCode(173) + String.fromCharCode(8204) + '-]{' + min + ',}';
1368					Hyphenator.languages[lang].genRegExp = new RegExp('(' + url + ')|(' + mail + ')|(' + tmp1 + ')', 'gi');
1369					
1370					delete docLanguages[lang];
1371					callback(lang);
1372					continue;
1373				} else {
1374					loadPatterns(lang);
1375				}
1376			}
1377		}
1378		// else async wait until patterns are loaded, then hyphenate
1379		interval = window.setInterval(function () {
1380			var finishedLoading = true, lang;
1381			for (lang in docLanguages) {
1382				if (docLanguages.hasOwnProperty(lang)) {
1383					finishedLoading = false;
1384					if (!!Hyphenator.languages[lang]) {
1385						delete docLanguages[lang];
1386						//do conversion while other patterns are loading:
1387						prepareLanguagesObj(lang);
1388						callback(lang);
1389					}
1390				}
1391			}
1392			if (finishedLoading) {
1393				//console.log('callig callback for ' + contextWindow.location.href);
1394				window.clearInterval(interval);
1395				state = 2;
1396			}
1397		}, 100);
1398	},
1399
1400	/**
1401	 * @name Hyphenator-switchToggleBox
1402	 * @description
1403	 * Creates or hides the toggleBox: a small button to turn off/on hyphenation on a page.
1404	 * @see Hyphenator.config
1405	 * @private
1406	 */		
1407	toggleBox = function () {
1408		var myBox, bdy, myIdAttribute, myTextNode, myClassAttribute,
1409		text = (Hyphenator.doHyphenation ? 'Hy-phen-a-tion' : 'Hyphenation');
1410		if (!!(myBox = contextWindow.document.getElementById('HyphenatorToggleBox'))) {
1411			myBox.firstChild.data = text;
1412		} else {
1413			bdy = contextWindow.document.getElementsByTagName('body')[0];
1414			myBox = createElem('div', contextWindow);
1415			myIdAttribute = contextWindow.document.createAttribute('id');
1416			myIdAttribute.nodeValue = 'HyphenatorToggleBox';
1417			myClassAttribute = contextWindow.document.createAttribute('class');
1418			myClassAttribute.nodeValue = dontHyphenateClass;
1419			myTextNode = contextWindow.document.createTextNode(text);
1420			myBox.appendChild(myTextNode);
1421			myBox.setAttributeNode(myIdAttribute);
1422			myBox.setAttributeNode(myClassAttribute);
1423			myBox.onclick =  Hyphenator.toggleHyphenation;
1424			myBox.style.position = 'absolute';
1425			myBox.style.top = '0px';
1426			myBox.style.right = '0px';
1427			myBox.style.margin = '0';
1428			myBox.style.backgroundColor = '#AAAAAA';
1429			myBox.style.color = '#FFFFFF';
1430			myBox.style.font = '6pt Arial';
1431			myBox.style.letterSpacing = '0.2em';
1432			myBox.style.padding = '3px';
1433			myBox.style.cursor = 'pointer';
1434			myBox.style.WebkitBorderBottomLeftRadius = '4px';
1435			myBox.style.MozBorderRadiusBottomleft = '4px';
1436			bdy.appendChild(myBox);
1437		}
1438	},
1439
1440
1441	/**
1442	 * @name Hyphenator-hyphenateWord
1443	 * @description
1444	 * This function is the heart of Hyphenator.js. It returns a hyphenated word.
1445	 *
1446	 * If there's already a {@link Hyphenator-hypen} in the word, the word is returned as it is.
1447	 * If the word is in the exceptions list or in the cache, it is retrieved from it.
1448	 * If there's a '-' put a zeroWidthSpace after the '-' and hyphenate the parts.
1449	 * @param {string} lang The language of the word
1450	 * @param {string} word The word
1451	 * @returns string The hyphenated word
1452	 * @public
1453	 */	
1454	hyphenateWord = function (lang, word) {
1455		var lo = Hyphenator.languages[lang], parts, l, subst,
1456			w, characters, originalCharacters, wordLength, i, j, k, node, points = [],
1457			characterPoints = [], nodePoints, nodePointsLength, m = Math.max, trie,
1458			result = [''], pattern;
1459		if (word === '') {
1460			return '';
1461		}
1462		if (word.indexOf(hyphen) !== -1) {
1463			//word already contains shy; -> leave at it is!
1464			return word;
1465		}
1466		if (enableCache && lo.cache.hasOwnProperty(word)) { //the word is in the cache
1467			return lo.cache[word];
1468		}
1469		if (lo.exceptions.hasOwnProperty(word)) { //the word is in the exceptions list
1470			return lo.exceptions[word].replace(/-/g, hyphen);
1471		}
1472		if (word.indexOf('-') !== -1) {
1473			//word contains '-' -> hyphenate the parts separated with '-'
1474			parts = word.split('-');
1475			for (i = 0, l = parts.length; i < l; i++) {
1476				parts[i] = hyphenateWord(lang, parts[i]);
1477			}
1478			return parts.join('-');
1479		}
1480		w = word = '_' + word + '_';
1481		if (!!lo.charSubstitution) {
1482			for (subst in lo.charSubstitution) {
1483				if (lo.charSubstitution.hasOwnProperty(subst)) {
1484					w = w.replace(new RegExp(subst, 'g'), lo.charSubstitution[subst]);
1485				}
1486			}
1487		}
1488		if (word.indexOf("'") !== -1) {
1489			w = w.replace("'", "’");
1489 //replace APOSTROPHE with RIGHT SINGLE QUOTATION MARK (since the latter is used in the patterns)
1490		}
1491		/** @license BSD licenced code
1492		 * The following code is based on code from hypher.js
1493		 * Copyright (c) 2011, Bram Stein
1494		 */
1495		characters = w.toLowerCase().split('');
1496		originalCharacters = word.split('');
1497		wordLength = characters.length;
1498		trie = lo.patterns;
1499		for (i = 0; i < wordLength; i += 1) {
1500			points[i] = 0;
1501			characterPoints[i] = characters[i].charCodeAt(0);
1502		}
1503		for (i = 0; i < wordLength; i += 1) {
1504			pattern = '';
1505			node = trie;
1506			for (j = i; j < wordLength; j += 1) {
1507				node = node[characterPoints[j]];
1508				if (node) {
1509					if (enableReducedPatternSet) {
1510						pattern += String.fromCharCode(characterPoints[j]);
1511					}
1512					nodePoints = node.tpoints;
1513					if (nodePoints) {
1514						if (enableReducedPatternSet) {
1515							if (!lo.redPatSet) {
1516								lo.redPatSet = {};
1517							}
1518							lo.redPatSet[pattern] = recreatePattern(pattern, nodePoints);
1519						}
1520						for (k = 0, nodePointsLength = nodePoints.length; k < nodePointsLength; k += 1) {
1521							points[i + k] = m(points[i + k], nodePoints[k]);
1522						}
1523					}
1524				} else {
1525					break;
1526				}
1527			}
1528		}
1529		for (i = 1; i < wordLength - 1; i += 1) {
1530			if (i > lo.leftmin && i < (wordLength - lo.rightmin) && points[i] % 2) {
1531				result.push(originalCharacters[i]);
1532			} else {
1533				result[result.length - 1] += originalCharacters[i];
1534			}
1535		}
1536		return result.join(hyphen);
1537		/**
1538		 * end of BSD licenced code from hypher.js
1539		 */
1540	},
1541		
1542	/**
1543	 * @name Hyphenator-hyphenateURL
1544	 * @description
1545	 * Puts {@link Hyphenator-urlhyphen} after each no-alphanumeric char that my be in a URL.
1546	 * @param {string} url to hyphenate
1547	 * @returns string the hyphenated URL
1548	 * @public
1549	 */
1550	hyphenateURL = function (url) {
1551		return url.replace(/([:\/\.\?#&_,;!@]+)/gi, '$&' + urlhyphen);
1552	},
1553
1554	/**
1555	 * @name Hyphenator-removeHyphenationFromElement
1556	 * @description
1557	 * Removes all hyphens from the element. If there are other elements, the function is
1558	 * called recursively.
1559	 * Removing hyphens is usefull if you like to copy text. Some browsers are buggy when the copy hyphenated texts.
1560	 * @param {Object} el The element where to remove hyphenation.
1561	 * @public
1562	 */
1563	removeHyphenationFromElement = function (el) {
1564		var h, i = 0, n;
1565		switch (hyphen) {
1566		case '|':
1567			h = '\\|';
1568			break;
1569		case '+':
1570			h = '\\+';
1571			break;
1572		case '*':
1573			h = '\\*';
1574			break;
1575		default:
1576			h = hyphen;
1577		}
1578		while (!!(n = el.childNodes[i++])) {
1579			if (n.nodeType === 3) {
1580				n.data = n.data.replace(new RegExp(h, 'g'), '');
1581				n.data = n.data.replace(new RegExp(zeroWidthSpace, 'g'), '');
1582			} else if (n.nodeType === 1) {
1583				removeHyphenationFromElement(n);
1584			}
1585		}
1586	},
1587	
1588	
1589	/**
1590	 * @name Hyphenator-registerOnCopy
1591	 * @description
1592	 * Huge work-around for browser-inconsistency when it comes to
1593	 * copying of hyphenated text.
1594	 * The idea behind this code has been provided by http://github.com/aristus/sweet-justice
1595	 * sweet-justice is under BSD-License
1596	 * @private
1597	 */
1598	registerOnCopy = function (el) {
1599		var body = el.ownerDocument.getElementsByTagName('body')[0],
1600		shadow,
1601		selection,
1602		range,
1603		rangeShadow,
1604		restore,
1605		oncopyHandler = function (e) {
1606			e = e || window.event;
1607			var target = e.target || e.srcElement,
1608			currDoc = target.ownerDocument,
1609			body = currDoc.getElementsByTagName('body')[0],
1610			targetWindow = 'defaultView' in currDoc ? currDoc.defaultView : currDoc.parentWindow;
1611			if (target.tagName && dontHyphenate[target.tagName.toLowerCase()]) {
1612				//Safari needs this
1613				return;
1614			}
1615			//create a hidden shadow element
1616			shadow = currDoc.createElement('div');
1617			//Moving the element out of the screen doesn't work for IE9 (https://connect.microsoft.com/IE/feedback/details/663981/)
1618			//shadow.style.overflow = 'hidden';
1619			//shadow.style.position = 'absolute';
1620			//shadow.style.top = '-5000px';
1621			//shadow.style.height = '1px';
1622			//doing this instead:
1623			shadow.style.color = window.getComputedStyle ? targetWindow.getComputedStyle(body).backgroundColor : '#FFFFFF';
1624			shadow.style.fontSize = '0px';
1625			body.appendChild(shadow);
1626			if (!!window.getSelection) {
1627				//FF3, Webkit, IE9
1628				e.stopPropagation();
1629				selection = targetWindow.getSelection();
1630				range = selection.getRangeAt(0);
1631				shadow.appendChild(range.cloneContents());
1632				removeHyphenationFromElement(shadow);
1633				selection.selectAllChildren(shadow);
1634				restore = function () {
1635					shadow.parentNode.removeChild(shadow);
1636					selection.removeAllRanges(); //IE9 needs that
1637					selection.addRange(range);
1638				};
1639			} else {
1640				// IE<9
1641				e.cancelBubble = true;
1642				selection = targetWindow.document.selection;
1643				range = selection.createRange();
1644				shadow.innerHTML = range.htmlText;
1645				removeHyphenationFromElement(shadow);
1646				rangeShadow = body.createTextRange();
1647				rangeShadow.moveToElementText(shadow);
1648				rangeShadow.select();
1649				restore = function () {
1650					shadow.parentNode.removeChild(shadow);
1651					if (range.text !== "") {
1652						range.select();
1653					}
1654				};
1655			}
1656			window.setTimeout(restore, 0);
1657		};
1658		if (!body) {
1659			return;
1660		}
1661		el = el || body;
1662		if (window.addEventListener) {
1663			el.addEventListener("copy", oncopyHandler, true);
1664		} else {
1665			el.attachEvent("oncopy", oncopyHandler);
1666		}
1667	},
1668	
1669	/**
1670	 * @name Hyphenator-unhideElement
1671	 * @description
1672	 * Unhides an element and removes the visibility attr if set by hyphenator
1673	 * @param Object The Element object from ElementCollection
1674	 * @private
1675	 */	
1676	unhideElement = function (elo) {
1677		var el = elo.element,
1678		hyphenatorSettings = elo.data;
1679		el.style.visibility = 'visible';
1680		elo.data.isHidden = false;
1681		if (!hyphenatorSettings.hasOwnStyle) {
1682			el.setAttribute('style', ''); // without this, removeAttribute doesn't work in Safari (thanks to molily)
1683			el.removeAttribute('style');
1684		} else {
1685			if (el.style.removeProperty) {
1686				el.style.removeProperty('visibility');
1687			} else if (el.style.removeAttribute) { // IE
1688				el.style.removeAttribute('visibility');
1689			}  
1690		}
1691	},
1692
1693	/**
1694	 * @name Hyphenator-checkIfAllDone
1695	 * @description
1696	 * Checks if all Elements are hyphenated, unhides them and fires onHyphenationDone()
1697	 * @private
1698	 */		
1699	checkIfAllDone = function () {
1700		var allDone = true;
1701		elements.each(function (lang, list) {
1702			var i, l = list.length;
1703			for (i = 0; i < l; i++) {
1704				allDone = allDone && list[i].hyphenated;
1705				if (intermediateState === 'hidden' && unhide === 'wait') {
1706					unhideElement(list[i]);
1707				}
1708			}
1709		});
1710		if (allDone) {
1711			state = 3;
1712			onHyphenationDone();
1713		}
1714	},
1715
1716
1717	/**
1718	 * @name Hyphenator-hyphenateElement
1719	 * @description
1720	 * Takes the content of the given element and - if there's text - replaces the words
1721	 * by hyphenated words. If there's another element, the function is called recursively.
1722	 * When all words are hyphenated, the visibility of the element is set to 'visible'.
1723	 * @param {Object} el The element to hyphenate
1724	 * @private
1725	 */
1726	hyphenateElement = function (lang, elo) {
1727		var hyphenatorSettings = elo.data,
1728			el = elo.element,
1729			hyphenate, n, i,
1730			controlOrphans = function (part) {
1731				var h, r;
1732				switch (hyphen) {
1733				case '|':
1734					h = '\\|';
1735					break;
1736				case '+':
1737					h = '\\+';
1738					break;
1739				case '*':
1740					h = '\\*';
1741					break;
1742				default:
1743					h = hyphen;
1744				}
1745				if (orphanControl >= 2) {
1746					//remove hyphen points from last word
1747					r = part.split(' ');
1748					r[1] = r[1].replace(new RegExp(h, 'g'), '');
1749					r[1] = r[1].replace(new RegExp(zeroWidthSpace, 'g'), '');
1750					r = r.join(' ');
1751				}
1752				if (orphanControl === 3) {
1753					//replace spaces by non breaking spaces
1754					r = r.replace(/[ ]+/g, String.fromCharCode(160));
1755				}
1756				return r;
1757			};
1758		if (Hyphenator.languages.hasOwnProperty(lang)) {
1759			hyphenate = function (word) {
1760				if (!Hyphenator.doHyphenation) {
1761					return word;
1762				} else if (urlOrMailRE.test(word)) {
1763					return hyphenateURL(word);
1764				} else {
1765					return hyphenateWord(lang, word);
1766				}
1767			};
1768			if (safeCopy && (el.tagName.toLowerCase() !== 'body')) {
1769				registerOnCopy(el);
1770			}
1771			i = 0;
1772			while (!!(n = el.childNodes[i++])) {
1773				if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate!
1774					n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate);
1775					if (orphanControl !== 1) {
1776						n.data = n.data.replace(/[\S]+ [\S]+$/, controlOrphans);
1777					}
1778				}
1779			}
1780		}
1781		if (hyphenatorSettings.isHidden && intermediateState === 'hidden' && unhide === 'progressive') {
1782			unhideElement(elo);
1783		}
1784		elo.hyphenated = true;
1785		elements.hyCount += 1;
1786		if (elements.count <= elements.hyCount) {
1787			checkIfAllDone();
1788		}
1789	},
1790	
1791
1792	/**
1793	 * @name Hyphenator-hyphenateLanguageElements
1794	 * @description
1795	 * Calls hyphenateElement() for all elements of the specified language.
1796	 * If the language is '*' then all elements are hyphenated.
1797	 * This is done with a setTimout
1798	 * to prevent a "long running Script"-alert when hyphenating large pages.
1799	 * Therefore a tricky bind()-function was necessary.
1800	 * @private
1801	 */
1802	hyphenateLanguageElements = function (lang) {
1803		function bind(fun, arg1, arg2) {
1804			return function () {
1805				return fun(arg1, arg2);
1806			};
1807		}
1808		var el, i, l;
1809		if (lang === '*') {
1810			elements.each(function (lang, langels) {
1811				var i, l = langels.length;
1812				for (i = 0; i < l; i++) {
1813					window.setTimeout(bind(hyphenateElement, lang, langels[i]), 0);
1814				}
1815			});
1816		} else {
1817			if (elements.list.hasOwnProperty(lang)) {
1818				l = elements.list[lang].length;
1819				for (i = 0; i < l; i++) {
1820					window.setTimeout(bind(hyphenateElement, lang, elements.list[lang][i]), 0);
1821				}
1822			}
1823		}
1824	},
1825	
1826	/**
1827	 * @name Hyphenator-removeHyphenationFromDocument
1828	 * @description
1829	 * Does what it says ;-)
1830	 * @private
1831	 */
1832	removeHyphenationFromDocument = function () {
1833		elements.each(function (lang, elo) {
1834			var i, l = elo.length, el;
1835			for (i = 0; i < l; i++) {
1836				removeHyphenationFromElement(elo[i].element);
1837				elo[i].hyphenated = false;
1838			}
1839		});
1840		state = 4;
1841	},
1842		
1843	/**
1844	 * @name Hyphenator-createStorage
1845	 * @description
1846	 * inits the private var storage depending of the setting in storageType
1847	 * and the supported features of the system.
1848	 * @private
1849	 */
1850	createStorage = function () {
1851		try {
1852			if (storageType !== 'none' &&
1853				typeof(window.localStorage) !== 'undefined' &&
1854				typeof(window.sessionStorage) !== 'undefined' &&
1855				typeof(window.JSON.stringify) !== 'undefined' &&
1856				typeof(window.JSON.parse) !== 'undefined') {
1857				switch (storageType) {
1858				case 'session':
1859					storage = window.sessionStorage;
1860					break;
1861				case 'local':
1862					storage = window.localStorage;
1863					break;
1864				default:
1865					storage = undefined;
1866					break;
1867				}
1868			}
1869		} catch (f) {
1870			//FF throws an error if DOM.storage.enabled is set to false
1871		}
1872	},
1873	
1874	/**
1875	 * @name Hyphenator-storeConfiguration
1876	 * @description
1877	 * Stores the current config-options in DOM-Storage
1878	 * @private
1879	 */
1880	storeConfiguration = function () {
1881		if (!storage) {
1882			return;
1883		}
1884		var settings = {
1885			'STORED': true,
1886			'classname': hyphenateClass,
1887			'donthyphenateclassname': dontHyphenateClass,
1888			'minwordlength': min,
1889			'hyphenchar': hyphen,
1890			'urlhyphenchar': urlhyphen,
1891			'togglebox': toggleBox,
1892			'displaytogglebox': displayToggleBox,
1893			'remoteloading': enableRemoteLoading,
1894			'enablecache': enableCache,
1895			'onhyphenationdonecallback': onHyphenationDone,
1896			'onerrorhandler': onError,
1897			'intermediatestate': intermediateState,
1898			'selectorfunction': selectorFunction,
1899			'safecopy': safeCopy,
1900			'doframes': doFrames,
1901			'storagetype': storageType,
1902			'orphancontrol': orphanControl,
1903			'dohyphenation': Hyphenator.doHyphenation,
1904			'persistentconfig': persistentConfig,
1905			'defaultlanguage': defaultLanguage
1906		};
1907		storage.setItem('Hyphenator_config', window.JSON.stringify(settings));
1908	},
1909	
1910	/**
1911	 * @name Hyphenator-restoreConfiguration
1912	 * @description
1913	 * Retrieves config-options from DOM-Storage and does configuration accordingly
1914	 * @private
1915	 */
1916	restoreConfiguration = function () {
1917		var settings;
1918		if (storage.getItem('Hyphenator_config')) {
1919			settings = window.JSON.parse(storage.getItem('Hyphenator_config'));
1920			Hyphenator.config(settings);
1921		}
1922	};
1923
1924	return {
1925		
1926		/**
1927		 * @name Hyphenator.version
1928		 * @memberOf Hyphenator
1929		 * @description
1930		 * String containing the actual version of Hyphenator.js
1931		 * [major release].[minor releas].[bugfix release]
1932		 * major release: new API, new Features, big changes
1933		 * minor release: new languages, improvements
1934		 * @public
1935         */		
1936		version: '4.0.0',
1937
1938		/**
1939		 * @name Hyphenator.doHyphenation
1940		 * @description
1941		 * If doHyphenation is set to false (defaults to true), hyphenateDocument() isn't called.
1942		 * All other actions are performed.
1943		 */		
1944		doHyphenation: true,
1945		
1946		/**
1947		 * @name Hyphenator.languages
1948		 * @memberOf Hyphenator
1949		 * @description
1950		 * Objects that holds key-value pairs, where key is the language and the value is the
1951		 * language-object loaded from (and set by) the pattern file.
1952		 * The language object holds the following members:
1953		 * <table>
1954		 * <tr><th>key</th><th>desc></th></tr>
1955		 * <tr><td>leftmin</td><td>The minimum of chars to remain on the old line</td></tr>
1956		 * <tr><td>rightmin</td><td>The minimum of chars to go on the new line</td></tr>
1957		 * <tr><td>shortestPattern</td><td>The shortes pattern (numbers don't count!)</td></tr>
1958		 * <tr><td>longestPattern</td><td>The longest pattern (numbers don't count!)</td></tr>
1959		 * <tr><td>specialChars</td><td>Non-ASCII chars in the alphabet.</td></tr>
1960		 * <tr><td>patterns</td><td>the patterns</td></tr>
1961		 * </table>
1962		 * And optionally (or after prepareLanguagesObj() has been called):
1963		 * <table>
1964		 * <tr><td>exceptions</td><td>Excpetions for the secified language</td></tr>
1965		 * </table>
1966		 * @public
1967         */		
1968		languages: {},
1969		
1970
1971		/**
1972		 * @name Hyphenator.config
1973			 * @description
1974		 * Config function that takes an object as an argument. The object contains key-value-pairs
1975		 * containig Hyphenator-settings. This is a shortcut for calling Hyphenator.set...-Methods.
1976		 * @param {Object} obj <table>
1977		 * <tr><th>key</th><th>values</th><th>default</th></tr>
1978		 * <tr><td>classname</td><td>string</td><td>'hyphenate'</td></tr>
1979		 * <tr><td>donthyphenateclassname</td><td>string</td><td>''</td></tr>
1980		 * <tr><td>minwordlength</td><td>integer</td><td>6</td></tr>
1981		 * <tr><td>
1981hyphenchar</td><td>string</td><td>'&amp;shy;'</td></tr>
1982		 * <tr><td>urlhyphenchar</td><td>string</td><td>'zero with space'</td></tr>
1983		 * <tr><td>togglebox</td><td>function</td><td>see code</td></tr>
1984		 * <tr><td>displaytogglebox</td><td>boolean</td><td>false</td></tr>
1985		 * <tr><td>remoteloading</td><td>boolean</td><td>true</td></tr>
1986		 * <tr><td>enablecache</td><td>boolean</td><td>true</td></tr>
1987		 * <tr><td>enablereducedpatternset</td><td>boolean</td><td>false</td></tr>
1988		 * <tr><td>onhyphenationdonecallback</td><td>function</td><td>empty function</td></tr>
1989		 * <tr><td>onerrorhandler</td><td>function</td><td>alert(onError)</td></tr>
1990		 * <tr><td>intermediatestate</td><td>string</td><td>'hidden'</td></tr>
1991		 * <tr><td>selectorfunction</td><td>function</td><td>[…]</td></tr>
1992		 * <tr><td>safecopy</td><td>boolean</td><td>true</td></tr>
1993		 * <tr><td>doframes</td><td>boolean</td><td>false</td></tr>
1994		 * <tr><td>storagetype</td><td>string</td><td>'none'</td></tr>
1995		 * </table>
1996		 * @public
1997		 * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
1998         * &lt;script type = "text/javascript"&gt;
1999         *     Hyphenator.config({'minwordlength':4,'hyphenchar':'|'});
2000         *     Hyphenator.run();
2001         * &lt;/script&gt;
2002         */
2003		config: function (obj) {
2004			var assert = function (name, type) {
2005					if (typeof obj[name] === type) {
2006						return true;
2007					} else {
2008						onError(new Error('Config onError: ' + name + ' must be of type ' + type));
2009						return false;
2010					}
2011				},
2012				key;
2013
2014			if (obj.hasOwnProperty('storagetype')) {
2015				if (assert('storagetype', 'string')) {
2016					storageType = obj.storagetype;
2017				}
2018				if (!storage) {
2019					createStorage();
2020				}			
2021			}
2022			if (!obj.hasOwnProperty('STORED') && storage && obj.hasOwnProperty('persistentconfig') && obj.persistentconfig === true) {
2023				restoreConfiguration();
2024			}
2025			
2026			for (key in obj) {
2027				if (obj.hasOwnProperty(key)) {
2028					switch (key) {
2029					case 'STORED':
2030						break;
2031					case 'classname':
2032						if (assert('classname', 'string')) {
2033							hyphenateClass = obj[key];
2034						}
2035						break;
2036					case 'donthyphenateclassname':
2037						if (assert('donthyphenateclassname', 'string')) {
2038							dontHyphenateClass = obj[key];
2039						}						
2040						break;
2041					case 'minwordlength':
2042						if (assert('minwordlength', 'number')) {
2043							min = obj[key];
2044						}
2045						break;
2046					case 'hyphenchar':
2047						if (assert('hyphenchar', 'string')) {
2048							if (obj.hyphenchar === '&shy;') {
2049								obj.hyphenchar = String.fromCharCode(173);
2050							}
2051							hyphen = obj[key];
2052						}
2053						break;
2054					case 'urlhyphenchar':
2055						if (obj.hasOwnProperty('urlhyphenchar')) {
2056							if (assert('urlhyphenchar', 'string')) {
2057								urlhyphen = obj[key];
2058							}
2059						}
2060						break;
2061					case 'togglebox':
2062						if (assert('togglebox', 'function')) {
2063							toggleBox = obj[key];
2064						}
2065						break;
2066					case 'displaytogglebox':
2067						if (assert('displaytogglebox', 'boolean')) {
2068							displayToggleBox = obj[key];
2069						}
2070						break;
2071					case 'remoteloading':
2072						if (assert('remoteloading', 'boolean')) {
2073							enableRemoteLoading = obj[key];
2074						}
2075						break;
2076					case 'enablecache':
2077						if (assert('enablecache', 'boolean')) {
2078							enableCache = obj[key];
2079						}
2080						break;
2081					case 'enablereducedpatternset':
2082						if (assert('enablereducedpatternset', 'boolean')) {
2083							enableReducedPatternSet = obj[key];
2084						}
2085						break;
2086					case 'onhyphenationdonecallback':
2087						if (assert('onhyphenationdonecallback', 'function')) {
2088							onHyphenationDone = obj[key];
2089						}
2090						break;
2091					case 'onerrorhandler':
2092						if (assert('onerrorhandler', 'function')) {
2093							onError = obj[key];
2094						}
2095						break;
2096					case 'intermediatestate':
2097						if (assert('intermediatestate', 'string')) {
2098							intermediateState = obj[key];
2099						}
2100						break;
2101					case 'selectorfunction':
2102						if (assert('selectorfunction', 'function')) {
2103							selectorFunction = obj[key];
2104						}
2105						break;
2106					case 'safecopy':
2107						if (assert('safecopy', 'boolean')) {
2108							safeCopy = obj[key];
2109						}
2110						break;
2111					case 'doframes':
2112						if (assert('doframes', 'boolean')) {
2113							doFrames = obj[key];
2114						}
2115						break;
2116					case 'storagetype':
2117						if (assert('storagetype', 'string')) {
2118							storageType = obj[key];
2119						}						
2120						break;
2121					case 'orphancontrol':
2122						if (assert('orphancontrol', 'number')) {
2123							orphanControl = obj[key];
2124						}
2125						break;
2126					case 'dohyphenation':
2127						if (assert('dohyphenation', 'boolean')) {
2128							Hyphenator.doHyphenation = obj[key];
2129						}
2130						break;
2131					case 'persistentconfig':
2132						if (assert('persistentconfig', 'boolean')) {
2133							persistentConfig = obj[key];
2134						}
2135						break;
2136					case 'defaultlanguage':
2137						if (assert('defaultlanguage', 'string')) {
2138							defaultLanguage = obj[key];
2139						}
2140						break;
2141					case 'useCSS3hyphenation':
2142						if (assert('useCSS3hyphenation', 'boolean')) {
2143							css3 = obj[key];
2144						}
2145						break;
2146					case 'unhide':
2147						if (assert('unhide', 'string')) {
2148							unhide = obj[key];
2149						}
2150						break;
2151					default:
2152						onError(new Error('Hyphenator.config: property ' + key + ' not known.'));
2153					}
2154				}
2155			}
2156			if (storage && persistentConfig) {
2157				storeConfiguration();
2158			}
2159		},
2160
2161		/**
2162		 * @name Hyphenator.run
2163			 * @description
2164		 * Bootstrap function that starts all hyphenation processes when called.
2165		 * @public
2166		 * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
2167         * &lt;script type = "text/javascript"&gt;
2168         *   Hyphenator.run();
2169         * &lt;/script&gt;
2170         */
2171		run: function () {
2172			documentCount = 0;
2173			var process = function () {
2174				try {
2175					if (contextWindow.document.getElementsByTagName('frameset').length > 0) {
2176						return; //we are in a frameset
2177					}
2178					documentCount++;
2179					autoSetMainLanguage(undefined);
2180					gatherDocumentInfos();
2181					//console.log('preparing for ' + contextWindow.location.href);
2182					prepare(hyphenateLanguageElements);
2183					if (displayToggleBox) {
2184						toggleBox();
2185					}
2186				} catch (e) {
2187					onError(e);
2188				}
2189			}, i, haveAccess, fl = window.frames.length;
2190			
2191			if (!storage) {
2192				createStorage();
2193			}
2194			if (!documentLoaded && !isBookmarklet) {
2195				runOnContentLoaded(window, process);
2196			}
2197			if (isBookmarklet || documentLoaded) {
2198				if (doFrames && fl > 0) {
2199					for (i = 0; i < fl; i++) {
2200						haveAccess = undefined;
2201						//try catch isn't enough for webkit
2202						try {
2203							//opera throws only on document.toString-access
2204							haveAccess = window.frames[i].document.toString();
2205						} catch (e) {
2206							haveAccess = undefined;
2207						}
2208						if (!!haveAccess) {
2209							contextWindow = window.frames[i];
2210							process();
2211						}						
2212					}
2213				}
2214				contextWindow = window;
2215				process();
2216			}
2217		},
2218		
2219		/**
2220		 * @name Hyphenator.addExceptions
2221			 * @description
2222		 * Adds the exceptions from the string to the appropriate language in the 
2223		 * {@link Hyphenator-languages}-object
2224		 * @param {string} lang The language
2225		 * @param {string} words A comma separated string of hyphenated words WITH spaces.
2226		 * @public
2227		 * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
2228         * &lt;script type = "text/javascript"&gt;
2229         *   Hyphenator.addExceptions('de','ziem-lich, Wach-stube');
2230         *   Hyphenator.run();
2231         * &lt;/script&gt;
2232         */
2233		addExceptions: function (lang, words) {
2234			if (lang === '') {
2235				lang = 'global';
2236			}
2237			if (exceptions.hasOwnProperty(lang)) {
2238				exceptions[lang] += ", " + words;
2239			} else {
2240				exceptions[lang] = words;
2241			}
2242		},
2243		
2244		/**
2245		 * @name Hyphenator.hyphenate
2246			 * @public
2247		 * @description
2248		 * Hyphenates the target. The language patterns must be loaded.
2249		 * If the target is a string, the hyphenated string is returned,
2250		 * if it's an object, the values are hyphenated directly.
2251		 * @param {string|Object} target the target to be hyphenated
2252		 * @param {string} lang the language of the target
2253		 * @returns string
2254		 * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
2255		 * &lt;script src = "patterns/en.js" type = "text/javascript"&gt;&lt;/script&gt;
2256         * &lt;script type = "text/javascript"&gt;
2257		 * var t = Hyphenator.hyphenate('Hyphenation', 'en'); //Hy|phen|ation
2258		 * &lt;/script&gt;
2259		 */
2260		hyphenate: function (target, lang) {
2261			var hyphenate, n, i;
2262			if (Hyphenator.languages.hasOwnProperty(lang)) {
2263				if (!Hyphenator.languages[lang].prepared) {
2264					prepareLanguagesObj(lang);
2265				}
2266				hyphenate = function (word) {
2267					if (urlOrMailRE.test(word)) {
2268						return hyphenateURL(word);
2269					} else {
2270						return hyphenateWord(lang, word);
2271					}
2272				};
2273				if (typeof target === 'string' || target.constructor === String) {
2274					return target.replace(Hyphenator.languages[lang].genRegExp, hyphenate);
2275				} else if (typeof target === 'object') {
2276					i = 0;
2277					while (!!(n = target.childNodes[i++])) {
2278						if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate!
2279							n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate);
2280						} else if (n.nodeType === 1) {
2281							if (n.lang !== '') {
2282								Hyphenator.hyphenate(n, n.lang);
2283							} else {
2284								Hyphenator.hyphenate(n, lang);
2285							}
2286						}
2287					}
2288				}
2289			} else {
2290				onError(new Error('Language "' + lang + '" is not loaded.'));
2291			}
2292		},
2293		
2294		/**
2295		 * @name Hyphenator.getRedPatternSet
2296			 * @description
2297		 * Returns {@link Hyphenator-isBookmarklet}.
2298		 * @param {string} lang the language patterns are stored for
2299		 * @returns object {'patk': pat}
2300		 * @public
2301         */
2302		getRedPatternSet: function (lang) {
2303			return Hyphenator.languages[lang].redPatSet;
2304		},
2305		
2306		/**
2307		 * @name Hyphenator.isBookmarklet
2308			 * @description
2309		 * Returns {@link Hyphenator-isBookmarklet}.
2310		 * @returns boolean
2311		 * @public
2312         */
2313		isBookmarklet: function () {
2314			return isBookmarklet;
2315		},
2316
2317		getConfigFromURI: function () {
2318			var loc = null, re = {}, jsArray = document.getElementsByTagName('script'), i, j, l, s, gp, option;
2319			for (i = 0, l = jsArray.length; i < l; i++) {
2320				if (!!jsArray[i].getAttribute('src')) {
2321					loc = jsArray[i].getAttribute('src');
2322				}
2323				if (!loc) {
2324					continue;
2325				} else {
2326					s = loc.indexOf('Hyphenator.js?');
2327					if (s === -1) {
2328						continue;
2329					}
2330					gp = loc.substring(s + 14).split('&');
2331					for (j = 0; j < gp.length; j++) {
2332						option = gp[j].split('=');
2333						if (option[0] === 'bm') {
2334							continue;
2335						}
2336						if (option[1] === 'true') {
2337							re[option[0]] = true;
2338							continue;
2339						}
2340						if (option[1] === 'false') {
2341							re[option[0]] = false;
2342							continue;
2343						}
2344						if (isFinite(option[1])) {
2345							re[option[0]] = parseInt(option[1], 10);
2346							continue;
2347						}
2348						if (option[0] === 'onhyphenationdonecallback') {
2349							re[option[0]] = new Function('', option[1]);
2350							continue;
2351						}
2352						re[option[0]] = option[1];
2353					}
2354					break;
2355				}
2356			}
2357			return re;
2358		},
2359
2360		/**
2361		 * @name Hyphenator.toggleHyphenation
2362			 * @description
2363		 * Checks the current state of the ToggleBox and removes or does hyphenation.
2364		 * @public
2365         */
2366		toggleHyphenation: function () {
2367			if (Hyphenator.doHyphenation) {
2368				removeHyphenationFromDocument();
2369				Hyphenator.doHyphenation = false;
2370				storeConfiguration();
2371				toggleBox();
2372			} else {
2373				hyphenateLanguageElements('*');
2374				Hyphenator.doHyphenation = true;
2375				storeConfiguration();
2376				toggleBox();
2377			}
2378		}
2379	};
2380}(window));
2381
2382//Export properties/methods (for google closure compiler)
2383Hyphenator['languages'] = Hyphenator.languages;
2384Hyphenator['config'] = Hyphenator.config;
2385Hyphenator['run'] = Hyphenator.run;
2386Hyphenator['addExceptions'] = Hyphenator.addExceptions;
2387Hyphenator['hyphenate'] = Hyphenator.hyphenate;
2388Hyphenator['getRedPatternSet'] = Hyphenator.getRedPatternSet;
2389Hyphenator['isBookmarklet'] = Hyphenator.isBookmarklet;
2390Hyphenator['getConfigFromURI'] = Hyphenator.getConfigFromURI;
2391Hyphenator['toggleHyphenation'] = Hyphenator.toggleHyphenation;
2392window['Hyphenator'] = Hyphenator;
2393
2394if (Hyphenator.isBookmarklet()) {
2395	Hyphenator.config({displaytogglebox: true, intermediatestate: 'visible', doframes: true});
2396	Hyphenator.config(Hyphenator.getConfigFromURI());
2397	Hyphenator.run();
2398}
2399}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.