PageSourceSearch

https://www.geoparcjbelbani.com/geoeco/js/jspdf.debug.js

js geoparcjbelbani.com collected 2026-10-02 23:02:21 UTC 321,642 bytes, 9,358 lines download raw bytes

1/** @preserve
2 * jsPDF - PDF Document creation from JavaScript
3 * Version 1.0.272-git Built on 2014-09-29T15:09
4 *                           CommitID d4770725ca
5 *
6 * Copyright (c) 2010-2014 James Hall, https://github.com/MrRio/jsPDF
7 *               2010 Aaron Spike, https://github.com/acspike
8 *               2012 Willow Systems Corporation, willow-systems.com
9 *               2012 Pablo Hess, https://github.com/pablohess
10 *               2012 Florian Jenett, https://github.com/fjenett
11 *               2013 Warren Weckesser, https://github.com/warrenweckesser
12 *               2013 Youssef Beddad, https://github.com/lifof
13 *               2013 Lee Driscoll, https://github.com/lsdriscoll
14 *               2013 Stefan Slonevskiy, https://github.com/stefslon
15 *               2013 Jeremy Morel, https://github.com/jmorel
16 *               2013 Christoph Hartmann, https://github.com/chris-rock
17 *               2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
18 *               2014 James Makes, https://github.com/dollaruw
19 *               2014 Diego Casorran, https://github.com/diegocr
20 *
21 * Permission is hereby granted, free of charge, to any person obtaining
22 * a copy of this software and associated documentation files (the
23 * "Software"), to deal in the Software without restriction, including
24 * without limitation the rights to use, copy, modify, merge, publish,
25 * distribute, sublicense, and/or sell copies of the Software, and to
26 * permit persons to whom the Software is furnished to do so, subject to
27 * the following conditions:
28 *
29 * The above copyright notice and this permission notice shall be
30 * included in all copies or substantial portions of the Software.
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
36 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
37 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
38 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 *
40 * Contributor(s):
41 *    siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,
42 *    kim3er, mfo, alnorth,
43 */
44
45/**
46 * Creates new jsPDF document object instance.
47 *
48 * @class
49 * @param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l")
50 * @param unit        Measurement unit to be used when coordinates are specified.
51 *                    One of "pt" (points), "mm" (Default), "cm", "in"
52 * @param format      One of 'pageFormats' as shown below, default: a4
53 * @returns {jsPDF}
54 * @name jsPDF
55 */
56var jsPDF = (function(global) {
57	'use strict';
58	var pdfVersion = '1.3',
59		pageFormats = { // Size in pt of various paper formats
60			'a0'  : [2383.94, 3370.39], 'a1'  : [1683.78, 2383.94],
61			'a2'  : [1190.55, 1683.78], 'a3'  : [ 841.89, 1190.55],
62			'a4'  : [ 595.28,  841.89], 'a5'  : [ 419.53,  595.28],
63			'a6'  : [ 297.64,  419.53], 'a7'  : [ 209.76,  297.64],
64			'a8'  : [ 147.40,  209.76], 'a9'  : [ 104.88,  147.40],
65			'a10' : [  73.70,  104.88], 'b0'  : [2834.65, 4008.19],
66			'b1'  : [2004.09, 2834.65], 'b2'  : [1417.32, 2004.09],
67			'b3'  : [1000.63, 1417.32], 'b4'  : [ 708.66, 1000.63],
68			'b5'  : [ 498.90,  708.66], 'b6'  : [ 354.33,  498.90],
69			'b7'  : [ 249.45,  354.33], 'b8'  : [ 175.75,  249.45],
70			'b9'  : [ 124.72,  175.75], 'b10' : [  87.87,  124.72],
71			'c0'  : [2599.37, 3676.54], 'c1'  : [1836.85, 2599.37],
72			'c2'  : [1298.27, 1836.85], 'c3'  : [ 918.43, 1298.27],
73			'c4'  : [ 649.13,  918.43], 'c5'  : [ 459.21,  649.13],
74			'c6'  : [ 323.15,  459.21], 'c7'  : [ 229.61,  323.15],
75			'c8'  : [ 161.57,  229.61], 'c9'  : [ 113.39,  161.57],
76			'c10' : [  79.37,  113.39], 'dl'  : [ 311.81,  623.62],
77			'letter'            : [612,   792],
78			'government-letter' : [576,   756],
79			'legal'             : [612,  1008],
80			'junior-legal'      : [576,   360],
81			'ledger'            : [1224,  792],
82			'tabloid'           : [792,  1224],
83			'credit-card'       : [153,   243]
84		};
85
86	/**
87	 * jsPDF's Internal PubSub Implementation.
88	 * See mrrio.github.io/jsPDF/doc/symbols/PubSub.html
89	 * Backward compatible rewritten on 2014 by
90	 * Diego Casorran, https://github.com/diegocr
91	 *
92	 * @class
93	 * @name PubSub
94	 */
95	function PubSub(context) {
96		var topics = {};
97
98		this.subscribe = function(topic, callback, once) {
99			if(typeof callback !== 'function') {
100				return false;
101			}
102
103			if(!topics.hasOwnProperty(topic)) {
104				topics[topic] = {};
105			}
106
107			var id = Math.random().toString(35);
108			topics[topic][id] = [callback,!!once];
109
110			return id;
111		};
112
113		this.unsubscribe = function(token) {
114			for(var topic in topics) {
115				if(topics[topic][token]) {
116					delete topics[topic][token];
117					return true;
118				}
119			}
120			return false;
121		};
122
123		this.publish = function(topic) {
124			if(topics.hasOwnProperty(topic)) {
125				var args = Array.prototype.slice.call(arguments, 1), idr = [];
126
127				for(var id in topics[topic]) {
128					var sub = topics[topic][id];
129					try {
130						sub[0].apply(context, args);
131					} catch(ex) {
132						if(global.console) {
133							console.error('jsPDF PubSub Error', ex.message, ex);
134						}
135					}
136					if(sub[1]) idr.push(id);
137				}
138				if(idr.length) idr.forEach(this.unsubscribe);
139			}
140		};
141	}
142
143	/**
144	 * @constructor
145	 * @private
146	 */
147	function jsPDF(orientation, unit, format, compressPdf) {
148		var options = {};
149
150		if (typeof orientation === 'object') {
151			options = orientation;
152
153			orientation = options.orientation;
154			unit = options.unit || unit;
155			format = options.format || format;
156			compressPdf = options.compress || options.compressPdf || compressPdf;
157		}
158
159		// Default options
160		unit        = unit || 'mm';
161		format      = format || 'a4';
162		orientation = ('' + (orientation || 'P')).toLowerCase();
163
164		var format_as_string = ('' + format).toLowerCase(),
165			compress = !!compressPdf && typeof Uint8Array === 'function',
166			textColor            = options.textColor  || '0 g',
167			drawColor            = options.drawColor  || '0 G',
168			activeFontSize       = options.fontSize   || 16,
169			lineHeightProportion = options.lineHeight || 1.15,
170			lineWidth            = options.lineWidth  || 0.200025, // 2mm
171			objectNumber =  2,  // 'n' Current object number
172			outToPages   = !1,  // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content
173			offsets      = [],  // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes.
174			fonts        = {},  // collection of font objects, where key is fontKey - a dynamically created label for a given font.
175			fontmap      = {},  // mapping structure fontName > fontStyle > font key - performance layer. See addFont()
176			activeFontKey,      // will be string representing the KEY of the font as combination of fontName + fontStyle
177			k,                  // Scale factor
178			tmp,
179			page = 0,
180			currentPage,
181			pages = [],
182			pagedim = {},
183			content = [],
184			lineCapID = 0,
185			lineJoinID = 0,
186			content_length = 0,
187			pageWidth,
188			pageHeight,
189			pageMode,
190			zoomMode,
191			layoutMode,
192			documentProperties = {
193				'title'    : '',
194				'subject'  : '',
195				'author'   : '',
196				'keywords' : '',
197				'creator'  : ''
198			},
199			API = {},
200			events = new PubSub(API),
201
202		/////////////////////
203		// Private functions
204		/////////////////////
205		f2 = function(number) {
206			return number.toFixed(2); // Ie, %.2f
207		},
208		f3 = function(number) {
209			return number.toFixed(3); // Ie, %.3f
210		},
211		padd2 = function(number) {
212			return ('0' + parseInt(number)).slice(-2);
213		},
214		out = function(string) {
215			if (outToPages) {
216				/* set by beginPage */
217				pages[currentPage].push(string);
218			} else {
219				// +1 for '\n' that will be used to join 'content'
220				content_length += string.length + 1;
221				content.push(string);
222			}
223		},
224		newObject = function() {
225			// Begin a new object
226			objectNumber++;
227			offsets[objectNumber] = content_length;
228			out(objectNumber + ' 0 obj');
229			return objectNumber;
230		},
231		putStream = function(str) {
232			out('stream');
233			out(str);
234			out('endstream');
235		},
236		putPages = function() {
237			var n,p,arr,i,deflater,adler32,adler32cs,wPt,hPt;
238
239			adler32cs = global.adler32cs || jsPDF.adler32cs;
240			if (compress && typeof adler32cs === 'undefined') {
241				compress = false;
242			}
243
244			// outToPages = false as set in endDocument(). out() writes to content.
245
246			for (n = 1; n <= page; n++) {
247				newObject();
248				wPt = (pageWidth = pagedim[n].width) * k;
249				hPt = (pageHeight = pagedim[n].height) * k;
250				out('<</Type /Page');
251				out('/Parent 1 0 R');
252				out('/Resources 2 0 R');
253				out('/MediaBox [0 0 ' + f2(wPt) + ' ' + f2(hPt) + ']');
254				out('/Contents ' + (objectNumber + 1) + ' 0 R>>');
255				out('endobj');
256
257				// Page content
258				p = pages[n].join('\n');
259				newObject();
260				if (compress) {
261					arr = [];
262					i = p.length;
263					while(i--) {
264						arr[i] = p.charCodeAt(i);
265					}
266					adler32 = adler32cs.from(p);
267					deflater = new Deflater(6);
268					deflater.append(new Uint8Array(arr));
269					p = deflater.flush();
270					arr = new Uint8Array(p.length + 6);
271					arr.set(new Uint8Array([120, 156])),
272					arr.set(p, 2);
273					arr.set(new Uint8Array([adler32 & 0xFF, (adler32 >> 8) & 0xFF, (adler32 >> 16) & 0xFF, (adler32 >> 24) & 0xFF]), p.length+2);
274					p = String.fromCharCode.apply(null, arr);
275					out('<</Length ' + p.length + ' /Filter [/FlateDecode]>>');
276				} else {
277					out('<</Length ' + p.length + '>>');
278				}
279				putStream(p);
280				out('endobj');
281			}
282			offsets[1] = content_length;
283			out('1 0 obj');
284			out('<</Type /Pages');
285			var kids = '/Kids [';
286			for (i = 0; i < page; i++) {
287				kids += (3 + 2 * i) + ' 0 R ';
288			}
289			out(kids + ']');
290			out('/Count ' + page);
291			out('>>');
292			out('endobj');
293		},
294		putFont = function(font) {
295			font.objectNumber = newObject();
296			out('<</BaseFont/' + font.PostScriptName + '/Type/Font');
297			if (typeof font.encoding === 'string') {
298				out('/Encoding/' + font.encoding);
299			}
300			out('/Subtype/Type1>>');
301			out('endobj');
302		},
303		putFonts = function() {
304			for (var fontKey in fonts) {
305				if (fonts.hasOwnProperty(fontKey)) {
306					putFont(fonts[fontKey]);
307				}
308			}
309		},
310		putXobjectDict = function() {
311			// Loop through images, or other data objects
312			events.publish('putXobjectDict');
313		},
314		putResourceDictionary = function() {
315			out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
316			out('/Font <<');
317
318			// Do this for each font, the '1' bit is the index of the font
319			for (var fontKey in fonts) {
320				if (fonts.hasOwnProperty(fontKey)) {
321					out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R');
322				}
323			}
324			out('>>');
325			out('/XObject <<');
326			putXobjectDict();
327			out('>>');
328		},
329		putResources = function() {
330			putFonts();
331			events.publish('putResources');
332			// Resource dictionary
333			offsets[2] = content_length;
334			out('2 0 obj');
335			out('<<');
336			putResourceDictionary();
337			out('>>');
338			out('endobj');
339			events.publish('postPutResources');
340		},
341		addToFontDictionary = function(fontKey, fontName, fontStyle) {
342			// this is mapping structure for quick font key lookup.
343			// returns the KEY of the font (ex: "F1") for a given
344			// pair of font name and type (ex: "Arial". "Italic")
345			if (!fontmap.hasOwnProperty(fontName)) {
346				fontmap[fontName] = {};
347			}
348			fontmap[fontName][fontStyle] = fontKey;
349		},
350		/**
351		 * FontObject describes a particular font as member of an instnace of jsPDF
352		 *
353		 * It's a collection of properties like 'id' (to be used in PDF stream),
354		 * 'fontName' (font's family name), 'fontStyle' (font's style variant label)
355		 *
356		 * @class
357		 * @public
358		 * @property id {String} PDF-document-instance-specific label assinged to the font.
359		 * @property PostScriptName {String} PDF specification full name for the font
360		 * @property encoding {Object} Encoding_name-to-Font_metrics_object mapping.
361		 * @name FontObject
362		 */
363		addFont = function(PostScriptName, fontName, fontStyle, encoding) {
364			var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10),
365			// This is FontObject
366			font = fonts[fontKey] = {
367				'id'             : fontKey,
368				'PostScriptName' : PostScriptName,
369				'fontName'       : fontName,
370				'fontStyle'      : fontStyle,
371				'encoding'       : encoding,
372				'metadata'       : {}
373			};
374			addToFontDictionary(fontKey, fontName, fontStyle);
375			events.publish('addFont', font);
376
377			return fontKey;
378		},
379		addFonts = function() {
380
381			var HELVETICA     = "helvetica",
382				TIMES         = "times",
383				COURIER       = "courier",
384				NORMAL        = "normal",
385				BOLD          = "bold",
386				ITALIC        = "italic",
387				BOLD_ITALIC   = "bolditalic",
388				encoding      = 'StandardEncoding',
389				standardFonts = [
390					['Helvetica', HELVETICA, NORMAL],
391					['Helvetica-Bold', HELVETICA, BOLD],
392					['Helvetica-Oblique', HELVETICA, ITALIC],
393					['Helvetica-BoldOblique', HELVETICA, BOLD_ITALIC],
394					['Courier', COURIER, NORMAL],
395					['Courier-Bold', COURIER, BOLD],
396					['Courier-Oblique', COURIER, ITALIC],
397					['Courier-BoldOblique', COURIER, BOLD_ITALIC],
398					['Times-Roman', TIMES, NORMAL],
399					['Times-Bold', TIMES, BOLD],
400					['Times-Italic', TIMES, ITALIC],
401					['Times-BoldItalic', TIMES, BOLD_ITALIC]
402				];
403
404			for (var i = 0, l = standardFonts.length; i < l; i++) {
405				var fontKey = addFont(
406						standardFonts[i][0],
407						standardFonts[i][1],
408						standardFonts[i][2],
409						encoding);
410
411				// adding aliases for standard fonts, this time matching the capitalization
412				var parts = standardFonts[i][0].split('-');
413				addToFontDictionary(fontKey, parts[0], parts[1] || '');
414			}
415			events.publish('addFonts', { fonts : fonts, dictionary : fontmap });
416		},
417		SAFE = function __safeCall(fn) {
418			fn.foo = function __safeCallWrapper() {
419				try {
420					return fn.apply(this, arguments);
421				} catch (e) {
422					var stack = e.stack || '';
423					if(~stack.indexOf(' at ')) stack = stack.split(" at ")[1];
424					var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message;
425					if(global.console) {
426						global.console.error(m, e);
427						if(global.alert) alert(m);
428					} else {
429						throw new Error(m);
430					}
431				}
432			};
433			fn.foo.bar = fn;
434			return fn.foo;
435		},
436		to8bitStream = function(text, flags) {
437		/**
438		 * PDF 1.3 spec:
439		 * "For text strings encoded in Unicode, the first two bytes must be 254 followed by
440		 * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts
441		 * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely
442		 * to be a meaningful beginning of a word or phrase.) The remainder of the
443		 * string consists of Unicode character codes, according to the UTF-16 encoding
444		 * specified in the Unicode standard, version 2.0. Commonly used Unicode values
445		 * are represented as 2 bytes per character, with the high-order byte appearing first
446		 * in the string."
447		 *
448		 * In other words, if there are chars in a string with char code above 255, we
449		 * recode the string to UCS2 BE - string doubles in length and BOM is prepended.
450		 *
451		 * HOWEVER!
452		 * Actual *content* (body) text (as opposed to strings used in document properties etc)
453		 * does NOT expect BOM. There, it is treated as a literal GID (Glyph ID)
454		 *
455		 * Because of Adobe's focus on "you subset your fonts!" you are not supposed to have
456		 * a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could
457		 * fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode
458		 * code page. There, however, all characters in the stream are treated as GIDs,
459		 * including BOM, which is the reason we need to skip BOM in content text (i.e. that
460		 * that is tied to a font).
461		 *
462		 * To signal this "special" PDFEscape / to8bitStream handling mode,
463		 * API.text() function sets (unless you overwrite it with manual values
464		 * given to API.text(.., flags) )
465		 * flags.autoencode = true
466		 * flags.noBOM = true
467		 *
468		 * ===================================================================================
469		 * `flags` properties relied upon:
470		 *   .sourceEncoding = string with encoding label.
471		 *                     "Unicode" by default. = encoding of the incoming text.
472		 *                     pass some non-existing encoding name
473		 *                     (ex: 'Do not touch my strings! I know what I am doing.')
474		 *                     to make encoding code skip the encoding step.
475		 *   .outputEncoding = Either valid PDF encoding name
476		 *                     (must be supported by jsPDF font metrics, otherwise no encoding)
477		 *                     or a JS object, where key = sourceCharCode, value = outputCharCode
478		 *                     missing keys will be treated as: sourceCharCode === outputCharCode
479		 *   .noBOM
480		 *       See comment higher above for explanation for why this is important
481		 *   .autoencode
482		 *       See comment higher above for explanation for why this is important
483		 */
484
485			var i,l,sourceEncoding,encodingBlock,outputEncoding,newtext,isUnicode,ch,bch;
486
487			flags = flags || {};
488			sourceEncoding = flags.sourceEncoding || 'Unicode';
489			outputEncoding = flags.outputEncoding;
490
491			// This 'encoding' section relies on font metrics format
492			// attached to font objects by, among others,
493			// "Willow Systems' standard_font_metrics plugin"
494			// see jspdf.plugin.standard_font_metrics.js for format
495			// of the font.metadata.encoding Object.
496			// It should be something like
497			//   .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}}
498			//   .widths = {0:width, code:width, ..., 'fof':divisor}
499			//   .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...}
500			if ((flags.autoencode || outputEncoding) &&
501				fonts[activeFontKey].metadata &&
502				fonts[activeFontKey].metadata[sourceEncoding] &&
503				fonts[activeFontKey].metadata[sourceEncoding].encoding) {
504				encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding;
505
506				// each font has default encoding. Some have it clearly defined.
507				if (!outputEncoding && fonts[activeFontKey].encoding) {
508					outputEncoding = fonts[activeFontKey].encoding;
509				}
510
511				// Hmmm, the above did not work? Let's try again, in different place.
512				if (!outputEncoding && encodingBlock.codePages) {
513					outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default
514				}
515
516				if (typeof outputEncoding === 'string') {
517					outputEncoding = encodingBlock[outputEncoding];
518				}
519				// we want output encoding to be a JS Object, where
520				// key = sourceEncoding's character code and
521				// value = outputEncoding's character code.
522				if (outputEncoding) {
523					isUnicode = false;
524					newtext = [];
525					for (i = 0, l = text.length; i < l; i++) {
526						ch = outputEncoding[text.charCodeAt(i)];
527						if (ch) {
528							newtext.push(
529								String.fromCharCode(ch));
530						} else {
531							newtext.push(
532								text[i]);
533						}
534
535						// since we are looping over chars anyway, might as well
536						// check for residual unicodeness
537						if (newtext[i].charCodeAt(0) >> 8) {
538							/* more than 255 */
539							isUnicode = true;
540						}
541					}
542					text = newtext.join('');
543				}
544			}
545
546			i = text.length;
547			// isUnicode may be set to false above. Hence the triple-equal to undefined
548			while (isUnicode === undefined && i !== 0) {
549				if (text.charCodeAt(i - 1) >> 8) {
550					/* more than 255 */
551					isUnicode = true;
552				}
553				i--;
554			}
555			if (!isUnicode) {
556				return text;
557			}
558
559			newtext = flags.noBOM ? [] : [254, 255];
560			for (i = 0, l = text.length; i < l; i++) {
561				ch = text.charCodeAt(i);
562				bch = ch >> 8; // divide by 256
563				if (bch >> 8) {
564					/* something left after dividing by 256 second time */
565					throw new Error("Character at position " + i + " of string '"
566						+ text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE");
567				}
568				newtext.push(bch);
569				newtext.push(ch - (bch << 8));
570			}
571			return String.fromCharCode.apply(undefined, newtext);
572		},
573		pdfEscape = function(text, flags) {
574			/**
575			 * Replace '/', '(', and ')' with pdf-safe versions
576			 *
577			 * Doing to8bitStream does NOT make this PDF display unicode text. For that
578			 * we also need to reference a unicode font and embed it - royal pain in the rear.
579			 *
580			 * There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars,
581			 * which JavaScript Strings are happy to provide. So, while we still cannot display
582			 * 2-byte characters property, at least CONDITIONALLY converting (entire string containing)
583			 * 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF
584			 * is still parseable.
585			 * This will allow immediate support for unicode in document properties strings.
586			 */
587			return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
588		},
589		putInfo = function() {
590			out('/Producer (jsPDF ' + jsPDF.version + ')');
591			for(var key in documentProperties) {
592				if(documentProperties.hasOwnProperty(key) && documentProperties[key]) {
593					out('/'+key.substr(0,1).toUpperCase() + key.substr(1)
594						+' (' + pdfEscape(documentProperties[key]) + ')');
595				}
596			}
597			var created  = new Date(),
598				tzoffset = created.getTimezoneOffset(),
599				tzsign   = tzoffset < 0 ? '+' : '-',
600				tzhour   = Math.floor(Math.abs(tzoffset / 60)),
601				tzmin    = Math.abs(tzoffset % 60),
602				tzstr    = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join('');
603			out(['/CreationDate (D:',
604					created.getFullYear(),
605					padd2(created.getMonth() + 1),
606					padd2(created.getDate()),
607					padd2(created.getHours()),
608					padd2(created.getMinutes()),
609					padd2(created.getSeconds()), tzstr, ')'].join(''));
610		},
611		putCatalog = function() {
612			out('/Type /Catalog');
613			out('/Pages 1 0 R');
614			// PDF13ref Section 7.2.1
615			if (!zoomMode) zoomMode = 'fullwidth';
616			switch(zoomMode) {
617				case 'fullwidth'  : out('/OpenAction [3 0 R /FitH null]');       break;
618				case 'fullheight' : out('/OpenAction [3 0 R /FitV null]');       break;
619				case 'fullpage'   : out('/OpenAction [3 0 R /Fit]');             break;
620				case 'original'   : out('/OpenAction [3 0 R /XYZ null null 1]'); break;
621				default:
622					var pcn = '' + zoomMode;
623					if (pcn.substr(pcn.length-1) === '%')
624						zoomMode = parseInt(zoomMode) / 100;
625					if (typeof zoomMode === 'number') {
626						out('/OpenAction [3 0 R /XYZ null null '+f2(zoomMode)+']');
627					}
628			}
629			if (!layoutMode) layoutMode = 'continuous';
630			switch(layoutMode) {
631				case 'continuous' : out('/PageLayout /OneColumn');      break;
632				case 'single'     : out('/PageLayout /SinglePage');     break;
633				case 'two':
634				case 'twoleft'    : out('/PageLayout /TwoColumnLeft');  break;
635				case 'tworight'   : out('/PageLayout /TwoColumnRight'); break;
636			}
637			if (pageMode) {
638				/**
639				 * A name object specifying how the document should be displayed when opened:
640				 * UseNone      : Neither document outline nor thumbnail images visible -- DEFAULT
641				 * UseOutlines  : Document outline visible
642				 * UseThumbs    : Thumbnail images visible
643				 * FullScreen   : Full-screen mode, with no menu bar, window controls, or any other window visible
644				 */
645				out('/PageMode /' + pageMode);
646			}
647			events.publish('putCatalog');
648		},
649		putTrailer = function() {
650			out('/Size ' + (objectNumber + 1));
651			out('/Root ' + objectNumber + ' 0 R');
652			out('/Info ' + (objectNumber - 1) + ' 0 R');
653		},
654		beginPage = function(width,height) {
655			// Dimensions are stored as user units and converted to points on output
656			var orientation = typeof height === 'string' && height.toLowerCase();
657			if (typeof width === 'string') {
658				var format = width.toLowerCase();
659				if (pageFormats.hasOwnProperty(format)) {
660					width  = pageFormats[format][0] / k;
661					height = pageFormats[format][1] / k;
662				}
663			}
664			if (Array.isArray(width)) {
665				height = width[1];
666				width = width[0];
667			}
668			if (orientation) {
669				switch(orientation.substr(0,1)) {
670					case 'l': if (height > width ) orientation = 's'; break;
671					case 'p': if (width > height ) orientation = 's'; break;
672				}
673				if (orientation === 's') { tmp = width; width = height; height = tmp; }
674			}
675			outToPages = true;
676			pages[++page] = [];
677			pagedim[page] = {
678				width  : Number(width)  || pageWidth,
679				height : Number(height) || pageHeight
680			};
681			_setPage(page);
682		},
683		_addPage = function() {
684			beginPage.apply(this, arguments);
685			// Set line width
686			out(f2(lineWidth * k) + ' w');
687			// Set draw color
688			out(drawColor);
689			// resurrecting non-default line caps, joins
690			if (lineCapID !== 0) {
691				out(lineCapID + ' J');
692			}
693			if (lineJoinID !== 0) {
694				out(lineJoinID + ' j');
695			}
696			events.publish('addPage', { pageNumber : page });
697		},
698		_setPage = function(n) {
699			if (n > 0 && n <= page) {
700				currentPage = n;
701				pageWidth = pagedim[n].width;
702				pageHeight = pagedim[n].height;
703			}
704		},
705		/**
706		 * Returns a document-specific font key - a label assigned to a
707		 * font name + font type combination at the time the font was added
708		 * to the font inventory.
709		 *
710		 * Font key is used as label for the desired font for a block of text
711		 * to be added to the PDF document stream.
712		 * @private
713		 * @function
714		 * @param fontName {String} can be undefined on "falthy" to indicate "use current"
715		 * @param fontStyle {String} can be undefined on "falthy" to indicate "use current"
716		 * @returns {String} Font key.
717		 */
718		getFont = function(fontName, fontStyle) {
719			var key;
720
721			fontName  = fontName  !== undefined ? fontName  : fonts[activeFontKey].fontName;
722			fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle;
723
724			try {
725			 // get a string like 'F3' - the KEY corresponding tot he font + type combination.
726				key = fontmap[fontName][fontStyle];
727			} catch (e) {}
728
729			if (!key) {
730				throw new Error("Unable to look up font label for font '" + fontName + "', '"
731					+ fontStyle + "'. Refer to getFontList() for available fonts.");
732			}
733			return key;
734		},
735		buildDocument = function() {
736
737			outToPages = false; // switches out() to content
738			objectNumber = 2;
739			content = [];
740			offsets = [];
741
742			// putHeader()
743			out('%PDF-' + pdfVersion);
744
745			putPages();
746
747			putResources();
748
749			// Info
750			newObject();
751			out('<<');
752			putInfo();
753			out('>>');
754			out('endobj');
755
756			// Catalog
757			newObject();
758			out('<<');
759			putCatalog();
760			out('>>');
761			out('endobj');
762
763			// Cross-ref
764			var o = content_length, i, p = "0000000000";
765			out('xref');
766			out('0 ' + (objectNumber + 1));
767			out(p+' 65535 f ');
768			for (i = 1; i <= objectNumber; i++) {
769				out((p + offsets[i]).slice(-10) + ' 00000 n ');
770			}
771			// Trailer
772			out('trailer');
773			out('<<');
774			putTrailer();
775			out('>>');
776			out('startxref');
777			out(o);
778			out('%%EOF');
779
780			outToPages = true;
781
782			return content.join('\n');
783		},
784		getStyle = function(style) {
785			// see path-painting operators in PDF spec
786			var op = 'S'; // stroke
787			if (style === 'F') {
788				op = 'f'; // fill
789			} else if (style === 'FD' || style === 'DF') {
790				op = 'B'; // both
791			} else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') {
792				/*
793				Allow direct use of these PDF path-painting operators:
794				- f	fill using nonzero winding number rule
795				- f*	fill using even-odd rule
796				- B	fill then stroke with fill using non-zero winding number rule
797				- B*	fill then stroke with fill using even-odd rule
798				*/
799				op = style;
800			}
801			return op;
802		},
803		getArrayBuffer = function() {
804			var data = buildDocument(), len = data.length,
805				ab = new ArrayBuffer(len), u8 = new Uint8Array(ab);
806
807			while(len--) u8[len] = data.charCodeAt(len);
808			return ab;
809		},
810		getBlob = function() {
811			return new Blob([getArrayBuffer()], { type : "application/pdf" });
812		},
813		/**
814		 * Generates the PDF document.
815		 *
816		 * If `type` argument is undefined, output is raw body of resulting PDF returned as a string.
817		 *
818		 * @param {String} type A string identifying one of the possible output types.
819		 * @param {Object} options An object providing some additional signalling to PDF generator.
820		 * @function
821		 * @returns {jsPDF}
822		 * @methodOf jsPDF#
823		 * @name output
824		 */
825		output = SAFE(function(type, options) {
826			var datauri = ('' + type).substr(0,6) === 'dataur'
827				? 'data:application/pdf;base64,'+btoa(buildDocument()):0;
828
829			switch (type) {
830				case undefined:
831					return buildDocument();
832				case 'save':
833					if (navigator.getUserMedia) {
834						if (global.URL === undefined
835						|| global.URL.createObjectURL === undefined) {
836							return API.output('dataurlnewwindow');
837						}
838					}
839					saveAs(getBlob(), options);
840					if(typeof saveAs.unload === 'function') {
841						if(global.setTimeout) {
842							setTimeout(saveAs.unload,911);
843						}
844					}
845					break;
846				case 'arraybuffer':
847					return getArrayBuffer();
848				case 'blob':
849					return getBlob();
850				case 'bloburi':
851				case 'bloburl':
852					// User is responsible of calling revokeObjectURL
853					return global.URL && global.URL.createObjectURL(getBlob()) || void 0;
854				case 'datauristring':
855				case 'dataurlstring':
856					return datauri;
857				case 'dataurlnewwindow':
858					var nW = global.open(datauri);
859					if (nW || typeof safari === "undefined") return nW;
860					/* pass through */
861				case 'datauri':
862				case 'dataurl':
863					return global.document.location.href = datauri;
864				default:
865					throw new Error('Output type "' + type + '" is not supported.');
866			}
867			// @TODO: Add different output options
868		});
869
870		switch (unit) {
871			case 'pt':  k = 1;          break;
872			case 'mm':  k = 72 / 25.4;  break;
873			case 'cm':  k = 72 / 2.54;  break;
874			case 'in':  k = 72;         break;
875			case 'px':  k = 96 / 72;    break;
876			case 'pc':  k = 12;         break;
877			case 'em':  k = 12;         break;
878			case 'ex':  k = 6;          break;
879			default:
880				throw ('Invalid unit: ' + unit);
881		}
882
883		//---------------------------------------
884		// Public API
885
886		/**
887		 * Object exposing internal API to plugins
888		 * @public
889		 */
890		API.internal = {
891			'pdfEscape' : pdfEscape,
892			'getStyle' : getStyle,
893			/**
894			 * Returns {FontObject} describing a particular font.
895			 * @public
896			 * @function
897			 * @param fontName {String} (Optional) Font's family name
898			 * @param fontStyle {String} (Optional) Font's style variation name (Example:"Italic")
899			 * @returns {FontObject}
900			 */
901			'getFont' : function() {
902				return fonts[getFont.apply(API, arguments)];
903			},
904			'getFontSize' : function() {
905				return activeFontSize;
906			},
907			'getLineHeight' : function() {
908				return activeFontSize * lineHeightProportion;
909			},
910			'write' : function(string1 /*, string2, string3, etc */) {
911				out(arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' '));
912			},
913			'getCoordinateString' : function(value) {
914				return f2(value * k);
915			},
916			'getVerticalCoordinateString' : function(value) {
917				return f2((pageHeight - value) * k);
918			},
919			'collections' : {},
920			'newObject' : newObject,
921			'putStream' : putStream,
922			'events' : events,
923			// ratio that you use in multiplication of a given "size" number to arrive to 'point'
924			// units of measurement.
925			// scaleFactor is set at initialization of the document and calculated against the stated
926			// default measurement units for the document.
927			// If default is "mm", k is the number that will turn number in 'mm' into 'points' number.
928			// through multiplication.
929			'scaleFactor' : k,
930			'pageSize' : {
931				get width() {
932					return pageWidth
933				},
934				get height() {
935					return pageHeight
936				}
937			},
938			'output' : function(type, options) {
939				return output(type, options);
940			},
941			'getNumberOfPages' : function() {
942				return pages.length - 1;
943			},
944			'pages' : pages
945		};
946
947		/**
948		 * Adds (and transfers the focus to) new page to the PDF document.
949		 * @function
950		 * @returns {jsPDF}
951		 *
952		 * @methodOf jsPDF#
953		 * @name addPage
954		 */
955		API.addPage = function() {
956			_addPage.apply(this, arguments);
957			return this;
958		};
959		API.setPage = function() {
960			_setPage.apply(this, arguments);
961			return this;
962		};
963		API.setDisplayMode = function(zoom, layout, pmode) {
964			zoomMode   = zoom;
965			layoutMode = layout;
966			pageMode   = pmode;
967			return this;
968		},
969
970		/**
971		 * Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings.
972		 *
973		 * @function
974		 * @param {String|Array} text String or array of strings to be added to the page. Each line is shifted one line down per font, spacing settings declared before this call.
975		 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
976		 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
977		 * @param {Object} flags Collection of settings signalling how the text must be encoded. Defaults are sane. If you think you want to pass some flags, you likely can read the source.
978		 * @returns {jsPDF}
979		 * @methodOf jsPDF#
980		 * @name text
981		 */
982		API.text = function(text, x, y, flags, angle) {
983			/**
984			 * Inserts something like this into PDF
985			 *   BT
986			 *    /F1 16 Tf  % Font name + size
987			 *    16 TL % How many units down for next line in multiline text
988			 *    0 g % color
989			 *    28.35 813.54 Td % position
990			 *    (line one) Tj
991			 *    T* (line two) Tj
992			 *    T* (line three) Tj
993			 *   ET
994			 */
995			function ESC(s) {
996				s = s.split("\t").join(Array(options.TabLen||9).join(" "));
997				return pdfEscape(s, flags);
998			}
999
1000			// Pre-August-2012 the order of arguments was function(x, y, text, flags)
1001			// in effort to make all calls have similar signature like
1002			//   function(data, coordinates... , miscellaneous)
1003			// this method had its args flipped.
1004			// code below allows backward compatibility with old arg order.
1005			if (typeof text === 'number') {
1006				tmp = y;
1007				y = x;
1008				x = text;
1009				text = tmp;
1010			}
1011
1012			// If there are any newlines in text, we assume
1013			// the user wanted to print multiple lines, so break the
1014			// text up into an array.  If the text is already an array,
1015			// we assume the user knows what they are doing.
1016			if (typeof text === 'string' && text.match(/[\n\r]/)) {
1017				text = text.split(/\r\n|\r|\n/g);
1018			}
1019			if (typeof flags === 'number') {
1020				angle = flags;
1021				flags = null;
1022			}
1023			var xtra = '',mode = 'Td', todo;
1024			if (angle) {
1025				angle *= (Math.PI / 180);
1026				var c = Math.cos(angle),
1027				s = Math.sin(angle);
1028				xtra = [f2(c), f2(s), f2(s * -1), f2(c), ''].join(" ");
1029				mode = 'Tm';
1030			}
1031			flags = flags || {};
1032			if (!('noBOM' in flags))
1033				flags.noBOM = true;
1034			if (!('autoencode' in flags))
1035				flags.autoencode = true;
1036
1037			if (typeof text === 'string') {
1038				text = ESC(text);
1039			} else if (text instanceof Array) {
1040				// we don't want to destroy  original text array, so cloning it
1041				var sa = text.concat(), da = [], len = sa.length;
1042				// we do array.join('text that must not be PDFescaped")
1043				// thus, pdfEscape each component separately
1044				while (len--) {
1045					da.push(ESC(sa.shift()));
1046				}
1047				var linesLeft = Math.ceil((pageHeight - y) * k / (activeFontSize * lineHeightProportion));
1048				if (0 <= linesLeft && linesLeft < da.length + 1) {
1049					todo = da.splice(linesLeft-1);
1050				}
1051				text = da.join(") Tj\nT* (");
1052			} else {
1053				throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.');
1054			}
1055			// Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates
1056
1057			// BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET
1058			// if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations)
1059			// Thus, there is NO useful, *reliable* concept of "default" font for a page.
1060			// The fact that "default" (reuse font used before) font worked before in basic cases is an accident
1061			// - readers dealing smartly with brokenness of jsPDF's markup.
1062			out(
1063				'BT\n/' +
1064				activeFontKey + ' ' + activeFontSize + ' Tf\n' +     // font face, style, size
1065				(activeFontSize * lineHeightProportion) + ' TL\n' +  // line spacing
1066				textColor +
1067				'\n' + xtra + f2(x * k) + ' ' + f2((pageHeight - y) * k) + ' ' + mode + '\n(' +
1068				text +
1069				') Tj\nET');
1070
1071			if (todo) {
1072				this.addPage();
1073				this.text( todo, x, activeFontSize * 1.7 / k);
1074			}
1075
1076			return this;
1077		};
1078
1079		API.lstext = function(text, x, y, spacing) {
1080			for (var i = 0, len = text.length ; i < len; i++, x += spacing) this.text(text[i], x, y);
1081		};
1082
1083		API.line = function(x1, y1, x2, y2) {
1084			return this.lines([[x2 - x1, y2 - y1]], x1, y1);
1085		};
1086
1087		API.clip = function() {
1088			// By patrick-roberts, github.com/MrRio/jsPDF/issues/328
1089			// Call .clip() after calling .rect() with a style argument of null
1090			out('W') // clip
1091			out('S') // stroke path; necessary for clip to work
1092		};
1093
1094		/**
1095		 * Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates.
1096		 * All data points in `lines` are relative to last line origin.
1097		 * `x`, `y` become x1,y1 for first line / curve in the set.
1098		 * For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point.
1099		 * For bezier curves you need to specify [x2,y2,x3,y3,x4,y4] - vectors to control points 1, 2, ending point. All vectors are against the start of the curve - x1,y1.
1100		 *
1101		 * @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line
1102		 * @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves).
1103		 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1104		 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1105		 * @param {Number} scale (Defaults to [1.0,1.0]) x,y Scaling factor for all vectors. Elements can be any floating number Sub-one makes drawing smaller. Over-one grows the drawing. Negative flips the direction.
1106		 * @param {String} style A string specifying the painting style or null.  Valid styles include: 'S' [default] - stroke, 'F' - fill,  and 'DF' (or 'FD') -  fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
1107		 * @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point.
1108		 * @function
1109		 * @returns {jsPDF}
1110		 * @methodOf jsPDF#
1111		 * @name lines
1112		 */
1113		API.lines = function(lines, x, y, scale, style, closed) {
1114			var scalex,scaley,i,l,leg,x2,y2,x3,y3,x4,y4;
1115
1116			// Pre-August-2012 the order of arguments was function(x, y, lines, scale, style)
1117			// in effort to make all calls have similar signature like
1118			//   function(content, coordinateX, coordinateY , miscellaneous)
1119			// this method had its args flipped.
1120			// code below allows backward compatibility with old arg order.
1121			if (typeof lines === 'number') {
1122				tmp = y;
1123				y = x;
1124				x = lines;
1125				lines = tmp;
1126			}
1127
1128			scale = scale || [1, 1];
1129
1130			// starting point
1131			out(f3(x * k) + ' ' + f3((pageHeight - y) * k) + ' m ');
1132
1133			scalex = scale[0];
1134			scaley = scale[1];
1135			l = lines.length;
1136			//, x2, y2 // bezier only. In page default measurement "units", *after* scaling
1137			//, x3, y3 // bezier only. In page default measurement "units", *after* scaling
1138			// ending point for all, lines and bezier. . In page default measurement "units", *after* scaling
1139			x4 = x; // last / ending point = starting point for first item.
1140			y4 = y; // last / ending point = starting point for first item.
1141
1142			for (i = 0; i < l; i++) {
1143				leg = lines[i];
1144				if (leg.length === 2) {
1145					// simple line
1146					x4 = leg[0] * scalex + x4; // here last x4 was prior ending point
1147					y4 = leg[1] * scaley + y4; // here last y4 was prior ending point
1148					out(f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' l');
1149				} else {
1150					// bezier curve
1151					x2 = leg[0] * scalex + x4; // here last x4 is prior ending point
1152					y2 = leg[1] * scaley + y4; // here last y4 is prior ending point
1153					x3 = leg[2] * scalex + x4; // here last x4 is prior ending point
1154					y3 = leg[3] * scaley + y4; // here last y4 is prior ending point
1155					x4 = leg[4] * scalex + x4; // here last x4 was prior ending point
1156					y4 = leg[5] * scaley + y4; // here last y4 was prior ending point
1157					out(
1158						f3(x2 * k) + ' ' +
1159						f3((pageHeight - y2) * k) + ' ' +
1160						f3(x3 * k) + ' ' +
1161						f3((pageHeight - y3) * k) + ' ' +
1162						f3(x4 * k) + ' ' +
1163						f3((pageHeight - y4) * k) + ' c');
1164				}
1165			}
1166
1167			if (closed) {
1168				out(' h');
1169			}
1170
1171			// stroking / filling / both the path
1172			if (style !== null) {
1173				out(getStyle(style));
1174			}
1175			return this;
1176		};
1177
1178		/**
1179		 * Adds a rectangle to PDF
1180		 *
1181		 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1182		 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1183		 * @param {Number} w Width (in units declared at inception of PDF document)
1184		 * @param {Number} h Height (in units declared at inception of PDF document)
1185		 * @param {String} style A string specifying the painting style or null.  Valid styles include: 'S' [default] - stroke, 'F' - fill,  and 'DF' (or 'FD') -  fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
1186		 * @function
1187		 * @returns {jsPDF}
1188		 * @methodOf jsPDF#
1189		 * @name rect
1190		 */
1191		API.rect = function(x, y, w, h, style) {
1192			var op = getStyle(style);
1193			out([
1194					f2(x * k),
1195					f2((pageHeight - y) * k),
1196					f2(w * k),
1197					f2(-h * k),
1198					're'
1199				].join(' '));
1200
1201			if (style !== null) {
1202				out(getStyle(style));
1203			}
1204
1205			return this;
1206		};
1207
1208		/**
1209		 * Adds a triangle to PDF
1210		 *
1211		 * @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page
1212		 * @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1213		 * @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page
1214		 * @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1215		 * @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page
1216		 * @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1217		 * @param {String} style A string specifying the painting style or null.  Valid styles include: 'S' [default] - stroke, 'F' - fill,  and 'DF' (or 'FD') -  fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
1218		 * @function
1219		 * @returns {jsPDF}
1220		 * @methodOf jsPDF#
1221		 * @name triangle
1222		 */
1223		API.triangle = function(x1, y1, x2, y2, x3, y3, style) {
1224			this.lines(
1225				[
1226					[x2 - x1, y2 - y1], // vector to point 2
1227					[x3 - x2, y3 - y2], // vector to point 3
1228					[x1 - x3, y1 - y3]// closing vector back to point 1
1229				],
1230				x1,
1231				y1, // start of path
1232				[1, 1],
1233				style,
1234				true);
1235			return this;
1236		};
1237
1238		/**
1239		 * Adds a rectangle with rounded corners to PDF
1240		 *
1241		 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1242		 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1243		 * @param {Number} w Width (in units declared at inception of PDF document)
1244		 * @param {Number} h Height (in units declared at inception of PDF document)
1245		 * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
1246		 * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
1247		 * @param {String} style A string specifying the painting style or null.  Valid styles include: 'S' [default] - stroke, 'F' - fill,  and 'DF' (or 'FD') -  fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
1248		 * @function
1249		 * @returns {jsPDF}
1250		 * @methodOf jsPDF#
1251		 * @name roundedRect
1252		 */
1253		API.roundedRect = function(x, y, w, h, rx, ry, style) {
1254			var MyArc = 4 / 3 * (Math.SQRT2 - 1);
1255			this.lines(
1256				[
1257					[(w - 2 * rx), 0],
1258					[(rx * MyArc), 0, rx, ry - (ry * MyArc), rx, ry],
1259					[0, (h - 2 * ry)],
1260					[0, (ry * MyArc),  - (rx * MyArc), ry, -rx, ry],
1261					[(-w + 2 * rx), 0],
1262					[ - (rx * MyArc), 0, -rx,  - (ry * MyArc), -rx, -ry],
1263					[0, (-h + 2 * ry)],
1264					[0,  - (ry * MyArc), (rx * MyArc), -ry, rx, -ry]
1265				],
1266				x + rx,
1267				y, // start of path
1268				[1, 1],
1269				style);
1270			return this;
1271		};
1272
1273		/**
1274		 * Adds an ellipse to PDF
1275		 *
1276		 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1277		 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1278		 * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
1279		 * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
1280		 * @param {String} style A string specifying the painting style or null.  Valid styles include: 'S' [default] - stroke, 'F' - fill,  and 'DF' (or 'FD') -  fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
1281		 * @function
1282		 * @returns {jsPDF}
1283		 * @methodOf jsPDF#
1284		 * @name ellipse
1285		 */
1286		API.ellipse = function(x, y, rx, ry, style) {
1287			var lx = 4 / 3 * (Math.SQRT2 - 1) * rx,
1288				ly = 4 / 3 * (Math.SQRT2 - 1) * ry;
1289
1290			out([
1291					f2((x + rx) * k),
1292					f2((pageHeight - y) * k),
1293					'm',
1294					f2((x + rx) * k),
1295					f2((pageHeight - (y - ly)) * k),
1296					f2((x + lx) * k),
1297					f2((pageHeight - (y - ry)) * k),
1298					f2(x * k),
1299					f2((pageHeight - (y - ry)) * k),
1300					'c'
1301				].join(' '));
1302			out([
1303					f2((x - lx) * k),
1304					f2((pageHeight - (y - ry)) * k),
1305					f2((x - rx) * k),
1306					f2((pageHeight - (y - ly)) * k),
1307					f2((x - rx) * k),
1308					f2((pageHeight - y) * k),
1309					'c'
1310				].join(' '));
1311			out([
1312					f2((x - rx) * k),
1313					f2((pageHeight - (y + ly)) * k),
1314					f2((x - lx) * k),
1315					f2((pageHeight - (y + ry)) * k),
1316					f2(x * k),
1317					f2((pageHeight - (y + ry)) * k),
1318					'c'
1319				].join(' '));
1320			out([
1321					f2((x + lx) * k),
1322					f2((pageHeight - (y + ry)) * k),
1323					f2((x + rx) * k),
1324					f2((pageHeight - (y + ly)) * k),
1325					f2((x + rx) * k),
1326					f2((pageHeight - y) * k),
1327					'c'
1328				].join(' '));
1329
1330			if (style !== null) {
1331				out(getStyle(style));
1332			}
1333
1334			return this;
1335		};
1336
1337		/**
1338		 * Adds an circle to PDF
1339		 *
1340		 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1341		 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1342		 * @param {Number} r Radius (in units declared at inception of PDF document)
1343		 * @param {String} style A string specifying the painting style or null.  Valid styles include: 'S' [default] - stroke, 'F' - fill,  and 'DF' (or 'FD') -  fill then stroke. A null value postpones setting the style so that a shape may be composed using multiple method calls. The last drawing method call used to define the shape should not have a null style argument.
1344		 * @function
1345		 * @returns {jsPDF}
1346		 * @methodOf jsPDF#
1347		 * @name circle
1348		 */
1349		API.circle = function(x, y, r, style) {
1350			return this.ellipse(x, y, r, r, style);
1351		};
1352
1353		/**
1354		 * Adds a properties to the PDF document
1355		 *
1356		 * @param {Object} A property_name-to-property_value object structure.
1357		 * @function
1358		 * @returns {jsPDF}
1359		 * @methodOf jsPDF#
1360		 * @name setProperties
1361		 */
1362		API.setProperties = function(properties) {
1363			// copying only those properties we can render.
1364			for (var property in documentProperties) {
1365				if (documentProperties.hasOwnProperty(property) && properties[property]) {
1366					documentProperties[property] = properties[property];
1367				}
1368			}
1369			return this;
1370		};
1371
1372		/**
1373		 * Sets font size for upcoming text elements.
1374		 *
1375		 * @param {Number} size Font size in points.
1376		 * @function
1377		 * @returns {jsPDF}
1378		 * @methodOf jsPDF#
1379		 * @name setFontSize
1380		 */
1381		API.setFontSize = function(size) {
1382			activeFontSize = size;
1383			return this;
1384		};
1385
1386		/**
1387		 * Sets text font face, variant for upcoming text elements.
1388		 * See output of jsPDF.getFontList() for possible font names, styles.
1389		 *
1390		 * @param {String} fontName Font name or family. Example: "times"
1391		 * @param {String} fontStyle Font style or variant. Example: "italic"
1392		 * @function
1393		 * @returns {jsPDF}
1394		 * @methodOf jsPDF#
1395		 * @name setFont
1396		 */
1397		API.setFont = function(fontName, fontStyle) {
1398			activeFontKey = getFont(fontName, fontStyle);
1399			// if font is not found, the above line blows up and we never go further
1400			return this;
1401		};
1402
1403		/**
1404		 * Switches font style or variant for upcoming text elements,
1405		 * while keeping the font face or family same.
1406		 * See output of jsPDF.getFontList() for possible font names, styles.
1407		 *
1408		 * @param {String} style Font style or variant. Example: "italic"
1409		 * @function
1410		 * @returns {jsPDF}
1411		 * @methodOf jsPDF#
1412		 * @name setFontStyle
1413		 */
1414		API.setFontStyle = API.setFontType = function(style) {
1415			activeFontKey = getFont(undefined, style);
1416			// if font is not found, the above line blows up and we never go further
1417			return this;
1418		};
1419
1420		/**
1421		 * Returns an object - a tree of fontName to fontStyle relationships available to
1422		 * active PDF document.
1423		 *
1424		 * @public
1425		 * @function
1426		 * @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... }
1427		 * @methodOf jsPDF#
1428		 * @name getFontList
1429		 */
1430		API.getFontList = function() {
1431			// TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added.
1432			var list = {},fontName,fontStyle,tmp;
1433
1434			for (fontName in fontmap) {
1435				if (fontmap.hasOwnProperty(fontName)) {
1436					list[fontName] = tmp = [];
1437					for (fontStyle in fontmap[fontName]) {
1438						if (fontmap[fontName].hasOwnProperty(fontStyle)) {
1439							tmp.push(fontStyle);
1440						}
1441					}
1442				}
1443			}
1444
1445			return list;
1446		};
1447
1448		/**
1449		 * Sets line width for upcoming lines.
1450		 *
1451		 * @param {Number} width Line width (in units declared at inception of PDF document)
1452		 * @function
1453		 * @returns {jsPDF}
1454		 * @methodOf jsPDF#
1455		 * @name setLineWidth
1456		 */
1457		API.setLineWidth = function(width) {
1458			out((width * k).toFixed(2) + ' w');
1459			return this;
1460		};
1461
1462		/**
1463		 * Sets the stroke color for upcoming elements.
1464		 *
1465		 * Depending on the number of arguments given, Gray, RGB, or CMYK
1466		 * color space is implied.
1467		 *
1468		 * When only ch1 is given, "Gray" color space is implied and it
1469		 * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
1470		 * if values are communicated as String types, or in range from 0 (black)
1471		 * to 255 (white) if communicated as Number type.
1472		 * The RGB-like 0-255 range is provided for backward compatibility.
1473		 *
1474		 * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
1475		 * value must be in the range from 0.00 (minimum intensity) to to 1.00
1476		 * (max intensity) if values are communicated as String types, or
1477		 * from 0 (min intensity) to to 255 (max intensity) if values are communicated
1478		 * as Number types.
1479		 * The RGB-like 0-255 range is provided for backward compatibility.
1480		 *
1481		 * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
1482		 * value must be a in the range from 0.00 (0% concentration) to to
1483		 * 1.00 (100% concentration)
1484		 *
1485		 * Because JavaScript treats fixed point numbers badly (rounds to
1486		 * floating point nearest to binary representation) it is highly advised to
1487		 * communicate the fractional numbers as String types, not JavaScript Number type.
1488		 *
1489		 * @param {Number|String} ch1 Color channel value
1490		 * @param {Number|String} ch2 Color channel value
1491		 * @param {Number|String} ch3 Color channel value
1492		 * @param {Number|String} ch4 Color channel value
1493		 *
1494		 * @function
1495		 * @returns {jsPDF}
1496		 * @methodOf jsPDF#
1497		 * @name setDrawColor
1498		 */
1499		API.setDrawColor = function(ch1, ch2, ch3, ch4) {
1500			var color;
1501			if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) {
1502				// Gray color space.
1503				if (typeof ch1 === 'string') {
1504					color = ch1 + ' G';
1505				} else {
1506					color = f2(ch1 / 255) + ' G';
1507				}
1508			} else if (ch4 === undefined) {
1509				// RGB
1510				if (typeof ch1 === 'string') {
1511					color = [ch1, ch2, ch3, 'RG'].join(' ');
1512				} else {
1513					color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' ');
1514				}
1515			} else {
1516				// CMYK
1517				if (typeof ch1 === 'string') {
1518					color = [ch1, ch2, ch3, ch4, 'K'].join(' ');
1519				} else {
1520					color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' ');
1521				}
1522			}
1523
1524			out(color);
1525			return this;
1526		};
1527
1528		/**
1529		 * Sets the fill color for upcoming elements.
1530		 *
1531		 * Depending on the number of arguments given, Gray, RGB, or CMYK
1532		 * color space is implied.
1533		 *
1534		 * When only ch1 is given, "Gray" color space is implied and it
1535		 * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
1536		 * if values are communicated as String types, or in range from 0 (black)
1537		 * to 255 (white) if communicated as Number type.
1538		 * The RGB-like 0-255 range is provided for backward compatibility.
1539		 *
1540		 * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
1541		 * value must be in the range from 0.00 (minimum intensity) to to 1.00
1542		 * (max intensity) if values are communicated as String types, or
1543		 * from 0 (min intensity) to to 255 (max intensity) if values are communicated
1544		 * as Number types.
1545		 * The RGB-like 0-255 range is provided for backward compatibility.
1546		 *
1547		 * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
1548		 * value must be a in the range from 0.00 (0% concentration) to to
1549		 * 1.00 (100% concentration)
1550		 *
1551		 * Because JavaScript treats fixed point numbers badly (rounds to
1552		 * floating point nearest to binary representation) it is highly advised to
1553		 * communicate the fractional numbers as String types, not JavaScript Number type.
1554		 *
1555		 * @param {Number|String} ch1 Color channel value
1556		 * @param {Number|String} ch2 Color channel value
1557		 * @param {Number|String} ch3 Color channel value
1558		 * @param {Number|String} ch4 Color channel value
1559		 *
1560		 * @function
1561		 * @returns {jsPDF}
1562		 * @methodOf jsPDF#
1563		 * @name setFillColor
1564		 */
1565		API.setFillColor = function(ch1, ch2, ch3, ch4) {
1566			var color;
1567
1568			if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) {
1569				// Gray color space.
1570				if (typeof ch1 === 'string') {
1571					color = ch1 + ' g';
1572				} else {
1573					color = f2(ch1 / 255) + ' g';
1574				}
1575			} else if (ch4 === undefined) {
1576				// RGB
1577				if (typeof ch1 === 'string') {
1578					color = [ch1, ch2, ch3, 'rg'].join(' ');
1579				} else {
1580					color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' ');
1581				}
1582			} else {
1583				// CMYK
1584				if (typeof ch1 === 'string') {
1585					color = [ch1, ch2, ch3, ch4, 'k'].join(' ');
1586				} else {
1587					color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' ');
1588				}
1589			}
1590
1591			out(color);
1592			return this;
1593		};
1594
1595		/**
1596		 * Sets the text color for upcoming elements.
1597		 * If only one, first argument is given,
1598		 * treats the value as gray-scale color value.
1599		 *
1600		 * @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF'
1601		 * @param {Number} g Green channel color value in range 0-255
1602		 * @param {Number} b Blue channel color value in range 0-255
1603		 * @function
1604		 * @returns {jsPDF}
1605		 * @methodOf jsPDF#
1606		 * @name setTextColor
1607		 */
1608		API.setTextColor = function(r, g, b) {
1609			if ((typeof r === 'string') && /^#[0-9A-Fa-f]{6}$/.test(r)) {
1610				var hex = parseInt(r.substr(1), 16);
1611				r = (hex >> 16) & 255;
1612				g = (hex >> 8) & 255;
1613				b = (hex & 255);
1614			}
1615
1616			if ((r === 0 && g === 0 && b === 0) || (typeof g === 'undefined')) {
1617				textColor = f3(r / 255) + ' g';
1618			} else {
1619				textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' ');
1620			}
1621			return this;
1622		};
1623
1624		/**
1625		 * Is an Object providing a mapping from human-readable to
1626		 * integer flag values designating the varieties of line cap
1627		 * and join styles.
1628		 *
1629		 * @returns {Object}
1630		 * @fieldOf jsPDF#
1631		 * @name CapJoinStyles
1632		 */
1633		API.CapJoinStyles = {
1634			0 : 0,
1635			'butt' : 0,
1636			'but' : 0,
1637			'miter' : 0,
1638			1 : 1,
1639			'round' : 1,
1640			'rounded' : 1,
1641			'circle' : 1,
1642			2 : 2,
1643			'projecting' : 2,
1644			'project' : 2,
1645			'square' : 2,
1646			'bevel' : 2
1647		};
1648
1649		/**
1650		 * Sets the line cap styles
1651		 * See {jsPDF.CapJoinStyles} for variants
1652		 *
1653		 * @param {String|Number} style A string or number identifying the type of line cap
1654		 * @function
1655		 * @returns {jsPDF}
1656		 * @methodOf jsPDF#
1657		 * @name setLineCap
1658		 */
1659		API.setLineCap = function(style) {
1660			var id = this.CapJoinStyles[style];
1661			if (id === undefined) {
1662				throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
1663			}
1664			lineCapID = id;
1665			out(id + ' J');
1666
1667			return this;
1668		};
1669
1670		/**
1671		 * Sets the line join styles
1672		 * See {jsPDF.CapJoinStyles} for variants
1673		 *
1674		 * @param {String|Number} style A string or number identifying the type of line join
1675		 * @function
1676		 * @returns {jsPDF}
1677		 * @methodOf jsPDF#
1678		 * @name setLineJoin
1679		 */
1680		API.setLineJoin = function(style) {
1681			var id = this.CapJoinStyles[style];
1682			if (id === undefined) {
1683				throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
1684			}
1685			lineJoinID = id;
1686			out(id + ' j');
1687
1688			return this;
1689		};
1690
1691		// Output is both an internal (for plugins) and external function
1692		API.output = output;
1693
1694		/**
1695		 * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf')
1696		 * @param  {String} filename The filename including extension.
1697		 *
1698		 * @function
1699		 * @returns {jsPDF}
1700		 * @methodOf jsPDF#
1701		 * @name save
1702		 */
1703		API.save = function(filename) {
1704			API.output('save', filename);
1705		};
1706
1707		// applying plugins (more methods) ON TOP of built-in API.
1708		// this is intentional as we allow plugins to override
1709		// built-ins
1710		for (var plugin in jsPDF.API) {
1711			if (jsPDF.API.hasOwnProperty(plugin)) {
1712				if (plugin === 'events' && jsPDF.API.events.length) {
1713					(function(events, newEvents) {
1714
1715						// jsPDF.API.events is a JS Array of Arrays
1716						// where each Array is a pair of event name, handler
1717						// Events were added by plugins to the jsPDF instantiator.
1718						// These are always added to the new instance and some ran
1719						// during instantiation.
1720						var eventname,handler_and_args,i;
1721
1722						for (i = newEvents.length - 1; i !== -1; i--) {
1723							// subscribe takes 3 args: 'topic', function, runonce_flag
1724							// if undefined, runonce is false.
1725							// users can attach callback directly,
1726							// or they can attach an array with [callback, runonce_flag]
1727							// that's what the "apply" magic is for below.
1728							eventname = newEvents[i][0];
1729							handler_and_args = newEvents[i][1];
1730							events.subscribe.apply(
1731								events,
1732								[eventname].concat(
1733									typeof handler_and_args === 'function' ?
1734										[handler_and_args] : handler_and_args));
1735						}
1736					}(events, jsPDF.API.events));
1737				} else {
1738					API[plugin] = jsPDF.API[plugin];
1739				}
1740			}
1741		}
1742
1743		//////////////////////////////////////////////////////
1744		// continuing initialization of jsPDF Document object
1745		//////////////////////////////////////////////////////
1746		// Add the first page automatically
1747		addFonts();
1748		activeFontKey = 'F1';
1749		_addPage(format, orientation);
1750
1751		events.publish('initialized');
1752		return API;
1753	}
1754
1755	/**
1756	 * jsPDF.API is a STATIC property of jsPDF class.
1757	 * jsPDF.API is an object you can add methods and properties to.
1758	 * The methods / properties you add will show up in new jsPDF objects.
1759	 *
1760	 * One property is prepopulated. It is the 'events' Object. Plugin authors can add topics,
1761	 * callbacks to this object. These will be reassigned to all new instances of jsPDF.
1762	 * Examples:
1763	 * jsPDF.API.events['initialized'] = function(){ 'this' is API object }
1764	 * jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object }
1765	 *
1766	 * @static
1767	 * @public
1768	 * @memberOf jsPDF
1769	 * @name API
1770	 *
1771	 * @example
1772	 * jsPDF.API.mymethod = function(){
1773	 *   // 'this' will be ref to internal API object. see jsPDF source
1774	 *   // , so you can refer to built-in methods like so:
1775	 *   //     this.line(....)
1776	 *   //     this.text(....)
1777	 * }
1778	 * var pdfdoc = new jsPDF()
1779	 * pdfdoc.mymethod() // <- !!!!!!
1780	 */
1781	jsPDF.API = {events:[]};
1782	jsPDF.version = "1.0.272-debug 2014-09-29T15:09:diegocr";
1783
1784	if (typeof define === 'function' && define.amd) {
1785		define('jsPDF', function() {
1786			return jsPDF;
1787		});
1788	} else {
1789		global.jsPDF = jsPDF;
1790	}
1791	return jsPDF;
1792}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this));
1793/**
1794 * jsPDF addHTML PlugIn
1795 * Copyright (c) 2014 Diego Casorran
1796 *
1797 * Licensed under the MIT License.
1798 * http://opensource.org/licenses/mit-license
1799 */
1800
1801(function (jsPDFAPI) {
1802	'use strict';
1803
1804	/**
1805	 * Renders an HTML element to canvas object which added as an image to the PDF
1806	 *
1807	 * This PlugIn requires html2canvas: https://github.com/niklasvh/html2canvas
1808	 *            OR rasterizeHTML: https://github.com/cburgmer/rasterizeHTML.js
1809	 *
1810	 * @public
1811	 * @function
1812	 * @param element {Mixed} HTML Element, or anything supported by html2canvas.
1813	 * @param x {Number} starting X coordinate in jsPDF instance's declared units.
1814	 * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
1815	 * @param options {Object} Additional options, check the code below.
1816	 * @param callback {Function} to call when the rendering has finished.
1817	 *
1818	 * NOTE: Every parameter is optional except 'element' and 'callback', in such
1819	 *       case the image is positioned at 0x0 covering the whole PDF document
1820	 *       size. Ie, to easily take screenshoots of webpages saving them to PDF.
1821	 */
1822	jsPDFAPI.addHTML = function (element, x, y, options, callback) {
1823		'use strict';
1824
1825		if(typeof html2canvas === 'undefined' && typeof rasterizeHTML === 'undefined')
1826			throw new Error('You need either '
1827				+'https://github.com/niklasvh/html2canvas'
1828				+' or https://github.com/cburgmer/rasterizeHTML.js');
1829
1830		if(typeof x !== 'number') {
1831			options = x;
1832			callback = y;
1833		}
1834
1835		if(typeof options === 'function') {
1836			callback = options;
1837			options = null;
1838		}
1839
1840		var I = this.internal, K = I.scaleFactor, W = I.pageSize.width, H = I.pageSize.height;
1841
1842		options = options || {};
1843		options.onrendered = function(obj) {
1844			x = parseInt(x) || 0;
1845			y = parseInt(y) || 0;
1846			var dim = options.dim || {};
1847			var h = dim.h || 0;
1848			var w = dim.w || Math.min(W,obj.width/K) - x;
1849
1850			var format = 'JPEG';
1851			if(options.format)
1852				format = options.format;
1853
1854			if(obj.height > H && options.pagesplit) {
1855				var crop = function() {
1856					var cy = 0;
1857					while(1) {
1858						var canvas = document.createElement('canvas');
1859						canvas.width = Math.min(W*K,obj.width);
1860						canvas.height = Math.min(H*K,obj.height-cy);
1861						var ctx = canvas.getContext('2d');
1862						ctx.drawImage(obj,0,cy,obj.width,canvas.height,0,0,canvas.width,canvas.height);
1863						var args = [canvas, x,cy?0:y,canvas.width/K,canvas.height/K, format,null,'SLOW'];
1864						this.addImage.apply(this, args);
1865						cy += canvas.height;
1866						if(cy >= obj.height) break;
1867						this.addPage();
1868					}
1869					callback(w,cy,null,args);
1870				}.bind(this);
1871				if(obj.nodeName === 'CANVAS') {
1872					var img = new Image();
1873					img.onload = crop;
1874					img.src = obj.toDataURL("image/png");
1875					obj = img;
1876				} else {
1877					crop();
1878				}
1879			} else {
1880				var alias = Math.random().toString(35);
1881				var args = [obj, x,y,w,h, format,alias,'SLOW'];
1882
1883				this.addImage.apply(this, args);
1884
1885				callback(w,h,alias,args);
1886			}
1887		}.bind(this);
1888
1889		if(typeof html2canvas !== 'undefined' && !options.rstz) {
1890			return html2canvas(element, options);
1891		}
1892
1893		if(typeof rasterizeHTML !== 'undefined') {
1894			var meth = 'drawDocument';
1895			if(typeof element === 'string') {
1896				meth = /^http/.test(element) ? 'drawURL' : 'drawHTML';
1897			}
1898			options.width = options.width || (W*K);
1899			return rasterizeHTML[meth](element, void 0, options).then(function(r) {
1900				options.onrendered(r.image);
1901			}, function(e) {
1902				callback(null,e);
1903			});
1904		}
1905
1906		return null;
1907	};
1908})(jsPDF.API);
1909/** @preserve
1910 * jsPDF addImage plugin
1911 * Copyright (c) 2012 Jason Siefken, https://github.com/siefkenj/
1912 *               2013 Chris Dowling, https://github.com/gingerchris
1913 *               2013 Trinh Ho, https://github.com/ineedfat
1914 *               2013 Edwin Alejandro Perez, https://github.com/eaparango
1915 *               2013 Norah Smith, https://github.com/burnburnrocket
1916 *               2014 Diego Casorran, https://github.com/diegocr
1917 *               2014 James Robb, https://github.com/jamesbrobb
1918 *
1919 * Permission is hereby granted, free of charge, to any person obtaining
1920 * a copy of this software and associated documentation files (the
1921 * "Software"), to deal in the Software without restriction, including
1922 * without limitation the rights to use, copy, modify, merge, publish,
1923 * distribute, sublicense, and/or sell copies of the Software, and to
1924 * permit persons to whom the Software is furnished to do so, subject to
1925 * the following conditions:
1926 *
1927 * The above copyright notice and this permission notice shall be
1928 * included in all copies or substantial portions of the Software.
1929 *
1930 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1931 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1932 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1933 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
1934 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1935 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1936 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1937 */
1938
1939;(function(jsPDFAPI) {
1940	'use strict'
1941
1942	var namespace = 'addImage_',
1943		supported_image_types = ['jpeg', 'jpg', 'png'];
1944
1945	// Image functionality ported from pdf.js
1946	var putImage = function(img) {
1947
1948		var objectNumber = this.internal.newObject()
1949		, out = this.internal.write
1950		, putStream = this.internal.putStream
1951
1952		img['n'] = objectNumber
1953
1954		out('<</Type /XObject')
1955		out('/Subtype /Image')
1956		out('/Width ' + img['w'])
1957		out('/Height ' + img['h'])
1958		if (img['cs'] === this.color_spaces.INDEXED) {
1959			out('/ColorSpace [/Indexed /DeviceRGB '
1960					// if an indexed png defines more than one colour with transparency, we've created a smask
1961					+ (img['pal'].length / 3 - 1) + ' ' + ('smask' in img ? objectNumber + 2 : objectNumber + 1)
1962					+ ' 0 R]');
1963		} else {
1964			out('/ColorSpace /' + img['cs']);
1965			if (img['cs'] === this.color_spaces.DEVICE_CMYK) {
1966				out('/Decode [1 0 1 0 1 0 1 0]');
1967			}
1968		}
1969		out('/BitsPerComponent ' + img['bpc']);
1970		if ('f' in img) {
1971			out('/Filter /' + img['f']);
1972		}
1973		if ('dp' in img) {
1974			out('/DecodeParms <<' + img['dp'] + '>>');
1975		}
1976		if ('trns' in img && img['trns'].constructor == Array) {
1977			var trns = '',
1978				i = 0,
1979				len = img['trns'].length;
1980			for (; i < len; i++)
1981				trns += (img['trns'][i] + ' ' + img['trns'][i] + ' ');
1982			out('/Mask [' + trns + ']');
1983		}
1984		if ('smask' in img) {
1985			out('/SMask ' + (objectNumber + 1) + ' 0 R');
1986		}
1987		out('/Length ' + img['data'].length + '>>');
1988
1989		putStream(img['data']);
1990
1991		out('endobj');
1992
1993		// Soft mask
1994		if ('smask' in img) {
1995			var dp = '/Predictor 15 /Colors 1 /BitsPerComponent ' + img['bpc'] + ' /Columns ' + img['w'];
1996			var smask = {'w': img['w'], 'h': img['h'], 'cs': 'DeviceGray', 'bpc': img['bpc'], 'dp': dp, 'data': img['smask']};
1997			if ('f' in img)
1998				smask.f = img['f'];
1999			putImage.call(this, smask);
2000		}
2001
2002	    //Palette
2003		if (img['cs'] === this.color_spaces.INDEXED) {
2004
2005			this.internal.newObject();
2006			//out('<< /Filter / ' + img['f'] +' /Length ' + img['pal'].length + '>>');
2007			//putStream(zlib.compress(img['pal']));
2008			out('<< /Length ' + img['pal'].length + '>>');
2009			putStream(this.arrayBufferToBinaryString(new Uint8Array(img['pal'])));
2010			out('endobj');
2011		}
2012	}
2013	, putResourcesCallback = function() {
2014		var images = this.internal.collections[namespace + 'images']
2015		for ( var i in images ) {
2016			putImage.call(this, images[i])
2017		}
2018	}
2019	, putXObjectsDictCallback = function(){
2020		var images = this.internal.collections[namespace + 'images']
2021		, out = this.internal.write
2022		, image
2023		for (var i in images) {
2024			image = images[i]
2025			out(
2026				'/I' + image['i']
2027				, image['n']
2028				, '0'
2029				, 'R'
2030			)
2031		}
2032	}
2033	, checkCompressValue = function(value) {
2034		if(value && typeof value === 'string')
2035			value = value.toUpperCase();
2036		return value in jsPDFAPI.image_compression ? value : jsPDFAPI.image_compression.NONE;
2037	}
2038	, getImages = function() {
2039		var images = this.internal.collections[namespace + 'images'];
2040		//first run, so initialise stuff
2041		if(!images) {
2042			this.internal.collections[namespace + 'images'] = images = {};
2043			this.internal.events.subscribe('putResources', putResourcesCallback);
2044			this.internal.events.subscribe('putXobjectDict', putXObjectsDictCallback);
2045		}
2046
2047		return images;
2048	}
2049	, getImageIndex = function(images) {
2050		var imageIndex = 0;
2051
2052		if (images){
2053			// this is NOT the first time this method is ran on this instance of jsPDF object.
2054			imageIndex = Object.keys ?
2055			Object.keys(images).length :
2056			(function(o){
2057				var i = 0
2058				for (var e in o){if(o.hasOwnProperty(e)){ i++ }}
2059				return i
2060			})(images)
2061		}
2062
2063		return imageIndex;
2064	}
2065	, notDefined = function(value) {
2066		return typeof value === 'undefined' || value === null;
2067	}
2068	, generateAliasFromData = function(data) {
2069		return typeof data === 'string' && jsPDFAPI.sHashCode(data);
2070	}
2071	, doesNotSupportImageType = function(type) {
2072		return supported_image_types.indexOf(type) === -1;
2073	}
2074	, processMethodNotEnabled = function(type) {
2075		return typeof jsPDFAPI['process' + type.toUpperCase()] !== 'function';
2076	}
2077	, isDOMElement = function(object) {
2078		return typeof object === 'object' && object.nodeType === 1;
2079	}
2080	, createDataURIFromElement = function(element, format, angle) {
2081
2082		//if element is an image which uses data url defintion, just return the dataurl
2083		if (element.nodeName === 'IMG' && element.hasAttribute('src')) {
2084			var src = ''+element.getAttribute('src');
2085			if (!angle && src.indexOf('data:image/') === 0) return src;
2086
2087			// only if the user doesn't care about a format
2088			if (!format && /\.png(?:[?#].*)?$/i.test(src)) format = 'png';
2089		}
2090
2091		if(element.nodeName === 'CANVAS') {
2092			var canvas = element;
2093		} else {
2094			var canvas = document.createElement('canvas');
2095			canvas.width = element.clientWidth || element.width;
2096			canvas.height = element.clientHeight || element.height;
2097
2098			var ctx = canvas.getContext('2d');
2099			if (!ctx) {
2100				throw ('addImage requires canvas to be supported by browser.');
2101			}
2102			if (angle) {
2103				var x, y, b, c, s, w, h, to_radians = Math.PI/180, angleInRadians;
2104
2105				if (typeof angle === 'object') {
2106					x = angle.x;
2107					y = angle.y;
2108					b = angle.bg;
2109					angle = angle.angle;
2110				}
2111				angleInRadians = angle*to_radians;
2112				c = Math.abs(Math.cos(angleInRadians));
2113				s = Math.abs(Math.sin(angleInRadians));
2114				w = canvas.width;
2115				h = canvas.height;
2116				canvas.width = h * s + w * c;
2117				canvas.height = h * c + w * s;
2118
2119				if (isNaN(x)) x = canvas.width / 2;
2120				if (isNaN(y)) y = canvas.height / 2;
2121
2122				ctx.clearRect(0,0,canvas.width, canvas.height);
2123				ctx.fillStyle = b || 'white';
2124				ctx.fillRect(0, 0, canvas.width, canvas.height);
2125				ctx.save();
2126				ctx.translate(x, y);
2127				ctx.rotate(angleInRadians);
2128				ctx.drawImage(element, -(w/2), -(h/2));
2129				ctx.rotate(-angleInRadians);
2130				ctx.translate(-x, -y);
2131				ctx.restore();
2132			} else {
2133				ctx.drawImage(element, 0, 0, canvas.width, canvas.height);
2134			}
2135		}
2136		return canvas.toDataURL((''+format).toLowerCase() == 'png' ? 'image/png' : 'image/jpeg');
2137	}
2138	,checkImagesForAlias = function(alias, images) {
2139		var cached_info;
2140		if(images) {
2141			for(var e in images) {
2142				if(alias === images[e].alias) {
2143					cached_info = images[e];
2144					break;
2145				}
2146			}
2147		}
2148		return cached_info;
2149	}
2150	,determineWidthAndHeight = function(w, h, info) {
2151		if (!w && !h) {
2152			w = -96;
2153			h = -96;
2154		}
2155		if (w < 0) {
2156			w = (-1) * info['w'] * 72 / w / this.internal.scaleFactor;
2157		}
2158		if (h < 0) {
2159			h = (-1) * info['h'] * 72 / h / this.internal.scaleFactor;
2160		}
2161		if (w === 0) {
2162			w = h * info['w'] / info['h'];
2163		}
2164		if (h === 0) {
2165			h = w * info['h'] / info['w'];
2166		}
2167
2168		return [w, h];
2169	}
2170	, writeImageToPDF = function(x, y, w, h, info, index, images) {
2171		var dims = determineWidthAndHeight.call(this, w, h, info),
2172			coord = this.internal.getCoordinateString,
2173			vcoord = this.internal.getVerticalCoordinateString;
2174
2175		w = dims[0];
2176		h = dims[1];
2177
2178		images[index] = info;
2179
2180		this.internal.write(
2181			'q'
2182			, coord(w)
2183			, '0 0'
2184			, coord(h) // TODO: check if this should be shifted by vcoord
2185			, coord(x)
2186			, vcoord(y + h)
2187			, 'cm /I'+info['i']
2188			, 'Do Q'
2189		)
2190	};
2191
2192	/**
2193	 * COLOR SPACES
2194	 */
2195	jsPDFAPI.color_spaces = {
2196		DEVICE_RGB:'DeviceRGB',
2197		DEVICE_GRAY:'DeviceGray',
2198		DEVICE_CMYK:'DeviceCMYK',
2199		CAL_GREY:'CalGray',
2200		CAL_RGB:'CalRGB',
2201		LAB:'Lab',
2202		ICC_BASED:'ICCBased',
2203		INDEXED:'Indexed',
2204		PATTERN:'Pattern',
2205		SEPERATION:'Seperation',
2206		DEVICE_N:'DeviceN'
2207	};
2208
2209	/**
2210	 * DECODE METHODS
2211	 */
2212	jsPDFAPI.decode = {
2213		DCT_DECODE:'DCTDecode',
2214		FLATE_DECODE:'FlateDecode',
2215		LZW_DECODE:'LZWDecode',
2216		JPX_DECODE:'JPXDecode',
2217		JBIG2_DECODE:'JBIG2Decode',
2218		ASCII85_DECODE:'ASCII85Decode',
2219		ASCII_HEX_DECODE:'ASCIIHexDecode',
2220		RUN_LENGTH_DECODE:'RunLengthDecode',
2221		CCITT_FAX_DECODE:'CCITTFaxDecode'
2222	};
2223
2224	/**
2225	 * IMAGE COMPRESSION TYPES
2226	 */
2227	jsPDFAPI.image_compression = {
2228		NONE: 'NONE',
2229		FAST: 'FAST',
2230		MEDIUM: 'MEDIUM',
2231		SLOW: 'SLOW'
2232	};
2233
2234	jsPDFAPI.sHashCode = function(str) {
2235		return Array.prototype.reduce && str.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);
2236	};
2237
2238	jsPDFAPI.isString = function(object) {
2239		return typeof object === 'string';
2240	};
2241
2242	/**
2243	 * Strips out and returns info from a valid base64 data URI
2244	 * @param {String[dataURI]} a valid data URI of format 'data:[<MIME-type>][;base64],<data>'
2245	 * @returns an Array containing the following
2246	 * [0] the complete data URI
2247	 * [1] <MIME-type>
2248	 * [2] format - the second part of the mime-type i.e 'png' in 'image/png'
2249	 * [4] <data>
2250	 */
2251	jsPDFAPI.extractInfoFromBase64DataURI = function(dataURI) {
2252		return /^data:([\w]+?\/([\w]+?));base64,(.+?)$/g.exec(dataURI);
2253	};
2254
2255	/**
2256	 * Check to see if ArrayBuffer is supported
2257	 */
2258	jsPDFAPI.supportsArrayBuffer = function() {
2259		return typeof ArrayBuffer !== 'undefined' && typeof Uint8Array !== 'undefined';
2260	};
2261
2262	/**
2263	 * Tests supplied object to determine if ArrayBuffer
2264	 * @param {Object[object]}
2265	 */
2266	jsPDFAPI.isArrayBuffer = function(object) {
2267		if(!this.supportsArrayBuffer())
2268	        return false;
2269		return object instanceof ArrayBuffer;
2270	};
2271
2272	/**
2273	 * Tests supplied object to determine if it implements the ArrayBufferView (TypedArray) interface
2274	 * @param {Object[object]}
2275	 */
2276	jsPDFAPI.isArrayBufferView = function(object) {
2277		if(!this.supportsArrayBuffer())
2278	        return false;
2279		if(typeof Uint32Array === 'undefined')
2280			return false;
2281		return (object instanceof Int8Array ||
2282				object instanceof Uint8Array ||
2283				(typeof Uint8ClampedArray !== 'undefined' && object instanceof Uint8ClampedArray) ||
2284				object instanceof Int16Array ||
2285				object instanceof Uint16Array ||
2286				object instanceof Int32Array ||
2287				object instanceof Uint32Array ||
2288				object instanceof Float32Array ||
2289				object instanceof Float64Array );
2290	};
2291
2292	/**
2293	 * Exactly what it says on the tin
2294	 */
2295	jsPDFAPI.binaryStringToUint8Array = function(binary_string) {
2296		/*
2297		 * not sure how efficient this will be will bigger files. Is there a native method?
2298		 */
2299		var len = binary_string.length;
2300	    var bytes = new Uint8Array( len );
2301	    for (var i = 0; i < len; i++) {
2302	        bytes[i] = binary_string.charCodeAt(i);
2303	    }
2304	    return bytes;
2305	};
2306
2307	/**
2308	 * @see this discussion
2309	 * http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers
2310	 *
2311	 * As stated, i imagine the method below is highly inefficent for large files.
2312	 *
2313	 * Also of note from Mozilla,
2314	 *
2315	 * "However, this is slow and error-prone, due to the need for multiple conversions (especially if the binary data is not actually byte-format data, but, for example, 32-bit integers or floats)."
2316	 *
2317	 * https://developer.mozilla.org/en-US/Add-ons/Code_snippets/StringView
2318	 *
2319	 * Although i'm strugglig to see how StringView solves this issue? Doesn't appear to be a direct method for conversion?
2320	 *
2321	 * Async method using Blob and FileReader could be best, but i'm not sure how to fit it into the flow?
2322	 */
2323	jsPDFAPI.arrayBufferToBinaryString = function(buffer) {
2324		if(this.isArrayBuffer(buffer))
2325			buffer = new Uint8Array(buffer);
2326
2327	    var binary_string = '';
2328	    var len = buffer.byteLength;
2329	    for (var i = 0; i < len; i++) {
2330	        binary_string += String.fromCharCode(buffer[i]);
2331	    }
2332	    return binary_string;
2333	    /*
2334	     * Another solution is the method below - convert array buffer straight to base64 and then use atob
2335	     */
2336		//return atob(this.arrayBufferToBase64(buffer));
2337	};
2338
2339	/**
2340	 * Converts an ArrayBuffer directly to base64
2341	 *
2342	 * Taken from here
2343	 *
2344	 * http://jsperf.com/encoding-xhr-image-data/31
2345	 *
2346	 * Need to test if this is a better solution for larger files
2347	 *
2348	 */
2349	jsPDFAPI.arrayBufferToBase64 = function(arrayBuffer) {
2350		var base64    = ''
2351		var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
2352
2353		var bytes         = new Uint8Array(arrayBuffer)
2354		var byteLength    = bytes.byteLength
2355		var byteRemainder = byteLength % 3
2356		var mainLength    = byteLength - byteRemainder
2357
2358		var a, b, c, d
2359		var chunk
2360
2361		// Main loop deals with bytes in chunks of 3
2362		for (var i = 0; i < mainLength; i = i + 3) {
2363			// Combine the three bytes into a single integer
2364			chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
2365
2366			// Use bitmasks to extract 6-bit segments from the triplet
2367			a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
2368			b = (chunk & 258048)   >> 12 // 258048   = (2^6 - 1) << 12
2369			c = (chunk & 4032)     >>  6 // 4032     = (2^6 - 1) << 6
2370			d = chunk & 63               // 63       = 2^6 - 1
2371
2372			// Convert the raw binary segments to the appropriate ASCII encoding
2373			base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
2374		}
2375
2376		// Deal with the remaining bytes and padding
2377		if (byteRemainder == 1) {
2378			chunk = bytes[mainLength]
2379
2380			a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
2381
2382			// Set the 4 least significant bits to zero
2383			b = (chunk & 3)   << 4 // 3   = 2^2 - 1
2384
2385			base64 += encodings[a] + encodings[b] + '=='
2386		} else if (byteRemainder == 2) {
2387			chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
2388
2389			a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
2390			b = (chunk & 1008)  >>  4 // 1008  = (2^6 - 1) << 4
2391
2392			// Set the 2 least significant bits to zero
2393			c = (chunk & 15)    <<  2 // 15    = 2^4 - 1
2394
2395			base64 += encodings[a] + encodings[b] + encodings[c] + '='
2396		}
2397
2398		return base64
2399	};
2400
2401	jsPDFAPI.createImageInfo = function(data, wd, ht, cs, bpc, f, imageIndex, alias, dp, trns, pal, smask) {
2402		var info = {
2403				alias:alias,
2404				w : wd,
2405				h : ht,
2406				cs : cs,
2407				bpc : bpc,
2408				i : imageIndex,
2409				data : data
2410				// n: objectNumber will be added by putImage code
2411			};
2412
2413		if(f) info.f = f;
2414		if(dp) info.dp = dp;
2415		if(trns) info.trns = trns;
2416		if(pal) info.pal = pal;
2417		if(smask) info.smask = smask;
2418
2419		return info;
2420	};
2421
2422	jsPDFAPI.addImage = function(imageData, format, x, y, w, h, alias, compression, rotation) {
2423		'use strict'
2424
2425		if(typeof format !== 'string') {
2426			var tmp = h;
2427			h = w;
2428			w = y;
2429			y = x;
2430			x = format;
2431			format = tmp;
2432		}
2433
2434		if (typeof imageData === 'object' && !isDOMElement(imageData) && "imageData" in imageData) {
2435			var options = imageData;
2436
2437			imageData = options.imageData;
2438			format = options.format || format;
2439			x = options.x || x || 0;
2440			y = options.y || y || 0;
2441			w = options.w || w;
2442			h = options.h || h;
2443			alias = options.alias || alias;
2444			compression = options.compression || compression;
2445			rotation = options.rotation || options.angle || rotation;
2446		}
2447
2448		if (isNaN(x) || isNaN(y))
2449		{
2450			console.error('jsPDF.addImage: Invalid coordinates', arguments);
2451			throw new Error('Invalid coordinates passed to jsPDF.addImage');
2452		}
2453
2454		var images = getImages.call(this), info;
2455
2456		if (!(info = checkImagesForAlias(imageData, images))) {
2457			var dataAsBinaryString;
2458
2459			if(isDOMElement(imageData))
2460				imageData = createDataURIFromElement(imageData, format, rotation);
2461
2462			if(notDefined(alias))
2463				alias = generateAliasFromData(imageData);
2464
2465			if (!(info = checkImagesForAlias(alias, images))) {
2466
2467				if(this.isString(imageData)) {
2468
2469					var base64Info = this.extractInfoFromBase64DataURI(imageData);
2470
2471					if(base64Info) {
2472
2473						format = base64Info[2];
2474						imageData = atob(base64Info[3]);//convert to binary string
2475
2476					} else {
2477
2478						if (imageData.charCodeAt(0) === 0x89 &&
2479							imageData.charCodeAt(1) === 0x50 &&
2480							imageData.charCodeAt(2) === 0x4e &&
2481							imageData.charCodeAt(3) === 0x47  )  format = 'png';
2482					}
2483				}
2484				format = (format || 'JPEG').toLowerCase();
2485
2486				if(doesNotSupportImageType(format))
2487					throw new Error('addImage currently only supports formats ' + supported_image_types + ', not \''+format+'\'');
2488
2489				if(processMethodNotEnabled(format))
2490					throw new Error('please ensure that the plugin for \''+format+'\' support is added');
2491
2492				/**
2493				 * need to test if it's more efficent to convert all binary strings
2494				 * to TypedArray - or should we just leave and process as string?
2495				 */
2496				if(this.supportsArrayBuffer()) {
2497					dataAsBinaryString = imageData;
2498					imageData = this.binaryStringToUint8Array(imageData);
2499				}
2500
2501				info = this['process' + format.toUpperCase()](
2502					imageData,
2503					getImageIndex(images),
2504					alias,
2505					checkCompressValue(compression),
2506					dataAsBinaryString
2507				);
2508
2509				if(!info)
2510					throw new Error('An unkwown error occurred whilst processing the image');
2511			}
2512		}
2513
2514		writeImageToPDF.call(this, x, y, w, h, info, info.i, images);
2515
2516		return this
2517	};
2518
2519	/**
2520	 * JPEG SUPPORT
2521	 **/
2522
2523	//takes a string imgData containing the raw bytes of
2524	//a jpeg image and returns [width, height]
2525	//Algorithm from: http://www.64lines.com/jpeg-width-height
2526	var getJpegSize = function(imgData) {
2527		'use strict'
2528		var width, height, numcomponents;
2529		// Verify we have a valid jpeg header 0xff,0xd8,0xff,0xe0,?,?,'J','F','I','F',0x00
2530		if (!imgData.charCodeAt(0) === 0xff ||
2531			!imgData.charCodeAt(1) === 0xd8 ||
2532			!imgData.charCodeAt(2) === 0xff ||
2533			!imgData.charCodeAt(3) === 0xe0 ||
2534			!imgData.charCodeAt(6) === 'J'.charCodeAt(0) ||
2535			!imgData.charCodeAt(7) === 'F'.charCodeAt(0) ||
2536			!imgData.charCodeAt(8) === 'I'.charCodeAt(0) ||
2537			!imgData.charCodeAt(9) === 'F'.charCodeAt(0) ||
2538			!imgData.charCodeAt(10) === 0x00) {
2539				throw new Error('getJpegSize requires a binary string jpeg file')
2540		}
2541		var blockLength = imgData.charCodeAt(4)*256 + imgData.charCodeAt(5);
2542		var i = 4, len = imgData.length;
2543		while ( i < len ) {
2544			i += blockLength;
2545			if (imgData.charCodeAt(i) !== 0xff) {
2546				throw new Error('getJpegSize could not find the size of the image');
2547			}
2548			if (imgData.charCodeAt(i+1) === 0xc0 || //(SOF) Huffman  - Baseline DCT
2549			    imgData.charCodeAt(i+1) === 0xc1 || //(SOF) Huffman  - Extended sequential DCT
2550			    imgData.charCodeAt(i+1) === 0xc2 || // Progressive DCT (SOF2)
2551			    imgData.charCodeAt(i+1) === 0xc3 || // Spatial (sequential) lossless (SOF3)
2552			    imgData.charCodeAt(i+1) === 0xc4 || // Differential sequential DCT (SOF5)
2553			    imgData.charCodeAt(i+1) === 0xc5 || // Differential progressive DCT (SOF6)
2554			    imgData.charCodeAt(i+1) === 0xc6 || // Differential spatial (SOF7)
2555			    imgData.charCodeAt(i+1) === 0xc7) {
2556				height = imgData.charCodeAt(i+5)*256 + imgData.charCodeAt(i+6);
2557				width = imgData.charCodeAt(i+7)*256 + imgData.charCodeAt(i+8);
2558                numcomponents = imgData.charCodeAt(i+9);
2559				return [width, height, numcomponents];
2560			} else {
2561				i += 2;
2562				blockLength = imgData.charCodeAt(i)*256 + imgData.charCodeAt(i+1)
2563			}
2564		}
2565	}
2566	, getJpegSizeFromBytes = function(data) {
2567
2568		var hdr = (data[0] << 8) | data[1];
2569
2570		if(hdr !== 0xFFD8)
2571			throw new Error('Supplied data is not a JPEG');
2572
2573		var len = data.length,
2574			block = (data[4] << 8) + data[5],
2575			pos = 4,
2576			bytes, width, height, numcomponents;
2577
2578		while(pos < len) {
2579			pos += block;
2580			bytes = readBytes(data, pos);
2581			block = (bytes[2] << 8) + bytes[3];
2582			if((bytes[1] === 0xC0 || bytes[1] === 0xC2) && bytes[0] === 0xFF && block > 7) {
2583				bytes = readBytes(data, pos + 5);
2584				width = (bytes[2] << 8) + bytes[3];
2585				height = (bytes[0] << 8) + bytes[1];
2586                numcomponents = bytes[4];
2587				return {width:width, height:height, numcomponents: numcomponents};
2588			}
2589
2590			pos+=2;
2591		}
2592
2593		throw new Error('getJpegSizeFromBytes could not find the size of the image');
2594	}
2595	, readBytes = function(data, offset) {
2596		return data.subarray(offset, offset+ 5);
2597	};
2598
2599	jsPDFAPI.processJPEG = function(data, index, alias, compression, dataAsBinaryString) {
2600		'use strict'
2601		var colorSpace = this.color_spaces.DEVICE_RGB,
2602			filter = this.decode.DCT_DECODE,
2603			bpc = 8,
2604			dims;
2605
2606		if(this.isString(data)) {
2607			dims = getJpegSize(data);
2608			return this.createImageInfo(data, dims[0], dims[1], dims[3] == 1 ? this.color_spaces.DEVICE_GRAY:colorSpace, bpc, filter, index, alias);
2609		}
2610
2611		if(this.isArrayBuffer(data))
2612			data = new Uint8Array(data);
2613
2614		if(this.isArrayBufferView(data)) {
2615
2616			dims = getJpegSizeFromBytes(data);
2617
2618			// if we already have a stored binary string rep use that
2619			data = dataAsBinaryString || this.arrayBufferToBinaryString(data);
2620
2621			return this.createImageInfo(data, dims.width, dims.height, dims.numcomponents == 1 ? this.color_spaces.DEVICE_GRAY:colorSpace, bpc, filter, index, alias);
2622		}
2623
2624		return null;
2625	};
2626
2627	jsPDFAPI.processJPG = function(/*data, index, alias, compression, dataAsBinaryString*/) {
2628		return this.processJPEG.apply(this, arguments);
2629	}
2630
2631})(jsPDF.API);
2632(function (jsPDFAPI) {
2633	'use strict';
2634
2635	jsPDFAPI.autoPrint = function () {
2636		'use strict'
2637		var refAutoPrintTag;
2638
2639		this.internal.events.subscribe('postPutResources', function () {
2640			refAutoPrintTag = this.internal.newObject()
2641				this.internal.write("<< /S/Named /Type/Action /N/Print >>", "endobj");
2642		});
2643
2644		this.internal.events.subscribe("putCatalog", function () {
2645			this.internal.write("/OpenAction " + refAutoPrintTag + " 0" + " R");
2646		});
2647		return this;
2648	};
2649})(jsPDF.API);
2650/** ====================================================================
2651 * jsPDF Cell plugin
2652 * Copyright (c) 2013 Youssef Beddad, [email protected]
2653 *               2013 Eduardo Menezes de Morais, [email protected]
2654 *               2013 Lee Driscoll, https://github.com/lsdriscoll
2655 *               2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
2656 *               2014 James Hall, [email protected]
2657 *               2014 Diego Casorran, https://github.com/diegocr
2658 *
2659 * Permission is hereby granted, free of charge, to any person obtaining
2660 * a copy of this software and associated documentation files (the
2661 * "Software"), to deal in the Software without restriction, including
2662 * without limitation the rights to use, copy, modify, merge, publish,
2663 * distribute, sublicense, and/or sell copies of the Software, and to
2664 * permit persons to whom the Software is furnished to do so, subject to
2665 * the following conditions:
2666 *
2667 * The above copyright notice and this permission notice shall be
2668 * included in all copies or substantial portions of the Software.
2669 *
2670 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2671 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2672 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2673 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2674 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2675 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2676 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2677 * ====================================================================
2678 */
2679
2680(function (jsPDFAPI) {
2681    'use strict';
2682    /*jslint browser:true */
2683    /*global document: false, jsPDF */
2684
2685    var fontName,
2686        fontSize,
2687        fontStyle,
2688        padding = 3,
2689        margin = 13,
2690        headerFunction,
2691        lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined },
2692        pages = 1,
2693        setLastCellPosition = function (x, y, w, h, ln) {
2694            lastCellPos = { 'x': x, 'y': y, 'w': w, 'h': h, 'ln': ln };
2695        },
2696        getLastCellPosition = function () {
2697            return lastCellPos;
2698        },
2699        NO_MARGINS = {left:0, top:0, bottom: 0};
2700
2701    jsPDFAPI.setHeaderFunction = function (func) {
2702        headerFunction = func;
2703    };
2704
2705    jsPDFAPI.getTextDimensions = function (txt) {
2706        fontName = this.internal.getFont().fontName;
2707        fontSize = this.table_font_size || this.internal.getFontSize();
2708        fontStyle = this.internal.getFont().fontStyle;
2709        // 1 pixel = 0.264583 mm and 1 mm = 72/25.4 point
2710        var px2pt = 0.264583 * 72 / 25.4,
2711            dimensions,
2712            text;
2713
2714        text = document.createElement('font');
2715        text.id = "jsPDFCell";
2716        text.style.fontStyle = fontStyle;
2717        text.style.fontName = fontName;
2718        text.style.fontSize = fontSize + 'pt';
2719        text.textContent = txt;
2720
2721        document.body.appendChild(text);
2722
2723        dimensions = { w: (text.offsetWidth + 1) * px2pt, h: (text.offsetHeight + 1) * px2pt};
2724
2725        document.body.removeChild(text);
2726
2727        return dimensions;
2728    };
2729
2730    jsPDFAPI.cellAddPage = function () {
2731        var margins = this.margins || NO_MARGINS;
2732
2733        this.addPage();
2734
2735        setLastCellPosition(margins.left, margins.top, undefined, undefined);
2736        //setLastCellPosition(undefined, undefined, undefined, undefined, undefined);
2737        pages += 1;
2738    };
2739
2740    jsPDFAPI.cellInitialize = function () {
2741        lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined };
2742        pages = 1;
2743    };
2744
2745    jsPDFAPI.cell = function (x, y, w, h, txt, ln, align) {
2746        var curCell = getLastCellPosition();
2747
2748        // If this is not the first cell, we must change its position
2749        if (curCell.ln !== undefined) {
2750            if (curCell.ln === ln) {
2751                //Same line
2752                x = curCell.x + curCell.w;
2753                y = curCell.y;
2754            } else {
2755                //New line
2756                var margins = this.margins || NO_MARGINS;
2757                if ((curCell.y + curCell.h + h + margin) >= this.internal.pageSize.height - margins.bottom) {
2758                    this.cellAddPage();
2759                    if (this.printHeaders && this.tableHeaderRow) {
2760                        this.printHeaderRow(ln, true);
2761                    }
2762                }
2763                //We ignore the passed y: the lines may have diferent heights
2764                y = (getLastCellPosition().y + getLastCellPosition().h);
2765
2766            }
2767        }
2768
2769        if (txt[0] !== undefined) {
2770            if (this.printingHeaderRow) {
2771                this.rect(x, y, w, h, 'FD');
2772            } else {
2773                this.rect(x, y, w, h);
2774            }
2775            if (align === 'right') {
2776                if (txt instanceof Array) {
2777                    for(var i = 0; i<txt.length; i++) {
2778                        var currentLine = txt[i];
2779                        var textSize = this.getStringUnitWidth(currentLine) * this.internal.getFontSize();
2780                        this.text(currentLine, x + w - textSize - padding, y + this.internal.getLineHeight()*(i+1));
2781                    }
2782                }
2783            } else {
2784                this.text(txt, x + padding, y + this.internal.getLineHeight());
2785            }
2786        }
2787        setLastCellPosition(x, y, w, h, ln);
2788        return this;
2789    };
2790
2791    /**
2792     * Return the maximum value from an array
2793     * @param array
2794     * @param comparisonFn
2795     * @returns {*}
2796     */
2797    jsPDFAPI.arrayMax = function (array, comparisonFn) {
2798        var max = array[0],
2799            i,
2800            ln,
2801            item;
2802
2803        for (i = 0, ln = array.length; i < ln; i += 1) {
2804            item = array[i];
2805
2806            if (comparisonFn) {
2807                if (comparisonFn(max, item) === -1) {
2808                    max = item;
2809                }
2810            } else {
2811                if (item > max) {
2812                    max = item;
2813                }
2814            }
2815        }
2816
2817        return max;
2818    };
2819
2820    /**
2821     * Create a table from a set of data.
2822     * @param {Integer} [x] : left-position for top-left corner of table
2823     * @param {Integer} [y] top-position for top-left corner of table
2824     * @param {Object[]} [data] As array of objects containing key-value pairs corresponding to a row of data.
2825     * @param {String[]} [headers] Omit or null to auto-generate headers at a performance cost
2826
2827     * @param {Object} [config.printHeaders] True to print column headers at the top of every page
2828     * @param {Object} [config.autoSize] True to dynamically set the column widths to match the widest cell value
2829     * @param {Object} [config.margins] margin values for left, top, bottom, and width
2830     * @param {Object} [config.fontSize] Integer fontSize to use (optional)
2831     */
2832
2833    jsPDFAPI.table = function (x,y, data, headers, config) {
2834        if (!data) {
2835            throw 'No data for PDF table';
2836        }
2837
2838        var headerNames = [],
2839            headerPrompts = [],
2840            header,
2841            i,
2842            ln,
2843            cln,
2844            columnMatrix = {},
2845            columnWidths = {},
2846            columnData,
2847            column,
2848            columnMinWidths = [],
2849            j,
2850            tableHeaderConfigs = [],
2851            model,
2852            jln,
2853            func,
2854
2855        //set up defaults. If a value is provided in config, defaults will be overwritten:
2856           autoSize        = false,
2857           printHeaders    = true,
2858           fontSize        = 12,
2859           margins         = NO_MARGINS;
2860
2861           margins.width = this.internal.pageSize.width;
2862
2863        if (config) {
2864        //override config defaults if the user has specified non-default behavior:
2865            if(config.autoSize === true) {
2866                autoSize = true;
2867            }
2868            if(config.printHeaders === false) {
2869                printHeaders = false;
2870            }
2871            if(config.fontSize){
2872                fontSize = config.fontSize;
2873            }
2874            if(config.margins){
2875                margins = config.margins;
2876            }
2877        }
2878
2879        /**
2880         * @property {Number} lnMod
2881         * Keep track of the current line number modifier used when creating cells
2882         */
2883        this.lnMod = 0;
2884        lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined },
2885        pages = 1;
2886
2887        this.printHeaders = printHeaders;
2888        this.margins = margins;
2889        this.setFontSize(fontSize);
2890        this.table_font_size = fontSize;
2891
2892        // Set header values
2893        if (headers === undefined || (headers === null)) {
2894            // No headers defined so we derive from data
2895            headerNames = Object.keys(data[0]);
2896
2897        } else if (headers[0] && (typeof headers[0] !== 'string')) {
2898            var px2pt = 0.264583 * 72 / 25.4;
2899
2900            // Split header configs into names and prompts
2901            for (i = 0, ln = headers.length; i < ln; i += 1) {
2902                header = headers[i];
2903                headerNames.push(header.name);
2904                headerPrompts.push(header.prompt);
2905                columnWidths[header.name] = header.width *px2pt;
2906            }
2907
2908        } else {
2909            headerNames = headers;
2910        }
2911
2912        if (autoSize) {
2913            // Create a matrix of columns e.g., {column_title: [row1_Record, row2_Record]}
2914            func = function (rec) {
2915                return rec[header];
2916            };
2917
2918            for (i = 0, ln = headerNames.length; i < ln; i += 1) {
2919                header = headerNames[i];
2920
2921                columnMatrix[header] = data.map(
2922                    func
2923                );
2924
2925                // get header width
2926                columnMinWidths.push(this.getTextDimensions(headerPrompts[i] || header).w);
2927                column = columnMatrix[header];
2928
2929                // get cell widths
2930                for (j = 0, cln = column.length; j < cln; j += 1) {
2931                    columnData = column[j];
2932                    columnMinWidths.push(this.getTextDimensions(columnData).w);
2933                }
2934
2935                // get final column width
2936                columnWidths[header] = jsPDFAPI.arrayMax(columnMinWidths);
2937            }
2938        }
2939
2940        // -- Construct the table
2941
2942        if (printHeaders) {
2943            var lineHeight = this.calculateLineHeight(headerNames, columnWidths, headerPrompts.length?headerPrompts:headerNames);
2944
2945            // Construct the header row
2946            for (i = 0, ln = headerNames.length; i < ln; i += 1) {
2947                header = headerNames[i];
2948                tableHeaderConfigs.push([x, y, columnWidths[header], lineHeight, String(headerPrompts.length ? headerPrompts[i] : header)]);
2949            }
2950
2951            // Store the table header config
2952            this.setTableHeaderRow(tableHeaderConfigs);
2953
2954            // Print the header for the start of the table
2955            this.printHeaderRow(1, false);
2956        }
2957
2958        // Construct the data rows
2959        for (i = 0, ln = data.length; i < ln; i += 1) {
2960            var lineHeight;
2961            model = data[i];
2962            lineHeight = this.calculateLineHeight(headerNames, columnWidths, model);
2963
2964            for (j = 0, jln = headerNames.length; j < jln; j += 1) {
2965                header = headerNames[j];
2966                this.cell(x, y, columnWidths[header], lineHeight, model[header], i + 2, header.align);
2967            }
2968        }
2969        this.lastCellPos = lastCellPos;
2970        this.table_x = x;
2971        this.table_y = y;
2972        return this;
2973    };
2974    /**
2975     * Calculate the height for containing the highest column
2976     * @param {String[]} headerNames is the header, used as keys to the data
2977     * @param {Integer[]} columnWidths is size of each column
2978     * @param {Object[]} model is the line of data we want to calculate the height of
2979     */
2980    jsPDFAPI.calculateLineHeight = function (headerNames, columnWidths, model) {
2981        var header, lineHeight = 0;
2982        for (var j = 0; j < headerNames.length; j++) {
2983            header = headerNames[j];
2984            model[header] = this.splitTextToSize(String(model[header]), columnWidths[header] - padding);
2985            var h = this.internal.getLineHeight() * model[header].length + padding;
2986            if (h > lineHeight)
2987                lineHeight = h;
2988        }
2989        return lineHeight;
2990    };
2991
2992    /**
2993     * Store the config for outputting a table header
2994     * @param {Object[]} config
2995     * An array of cell configs that would define a header row: Each config matches the config used by jsPDFAPI.
2995cell
2996     * except the ln parameter is excluded
2997     */
2998    jsPDFAPI.setTableHeaderRow = function (config) {
2999        this.tableHeaderRow = config;
3000    };
3001
3002    /**
3003     * Output the store header row
3004     * @param lineNumber The line number to output the header at
3005     */
3006    jsPDFAPI.printHeaderRow = function (lineNumber, new_page) {
3007        if (!this.tableHeaderRow) {
3008            throw 'Property tableHeaderRow does not exist.';
3009        }
3010
3011        var tableHeaderCell,
3012            tmpArray,
3013            i,
3014            ln;
3015
3016        this.printingHeaderRow = true;
3017        if (headerFunction !== undefined) {
3018            var position = headerFunction(this, pages);
3019            setLastCellPosition(position[0], position[1], position[2], position[3], -1);
3020        }
3021        this.setFontStyle('bold');
3022        var tempHeaderConf = [];
3023        for (i = 0, ln = this.tableHeaderRow.length; i < ln; i += 1) {
3024            this.setFillColor(200,200,200);
3025
3026            tableHeaderCell = this.tableHeaderRow[i];
3027            if (new_page) {
3028                tableHeaderCell[1] = this.margins && this.margins.top || 0;
3029                tempHeaderConf.push(tableHeaderCell);
3030            }
3031            tmpArray = [].concat(tableHeaderCell);
3032            this.cell.apply(this, tmpArray.concat(lineNumber));
3033        }
3034        if (tempHeaderConf.length > 0){
3035            this.setTableHeaderRow(tempHeaderConf);
3036        }
3037        this.setFontStyle('normal');
3038        this.printingHeaderRow = false;
3039    };
3040
3041})(jsPDF.API);
3042/** @preserve
3043 * jsPDF fromHTML plugin. BETA stage. API subject to change. Needs browser
3044 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
3045 *               2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
3046 *               2014 Diego Casorran, https://github.com/diegocr
3047 *               2014 Daniel Husar, https://github.com/danielhusar
3048 *               2014 Wolfgang Gassler, https://github.com/woolfg
3049 *
3050 * Permission is hereby granted, free of charge, to any person obtaining
3051 * a copy of this software and associated documentation files (the
3052 * "Software"), to deal in the Software without restriction, including
3053 * without limitation the rights to use, copy, modify, merge, publish,
3054 * distribute, sublicense, and/or sell copies of the Software, and to
3055 * permit persons to whom the Software is furnished to do so, subject to
3056 * the following conditions:
3057 *
3058 * The above copyright notice and this permission notice shall be
3059 * included in all copies or substantial portions of the Software.
3060 *
3061 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3062 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
3063 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
3064 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
3065 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
3066 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
3067 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3068 * ====================================================================
3069 */
3070
3071(function (jsPDFAPI) {
3072	var clone,
3073	DrillForContent,
3074	FontNameDB,
3075	FontStyleMap,
3076	FontWeightMap,
3077	FloatMap,
3078	ClearMap,
3079	GetCSS,
3080	PurgeWhiteSpace,
3081	Renderer,
3082	ResolveFont,
3083	ResolveUnitedNumber,
3084	UnitedNumberMap,
3085	elementHandledElsewhere,
3086	images,
3087	loadImgs,
3088	checkForFooter,
3089	process,
3090	tableToJson;
3091	clone = (function () {
3092		return function (obj) {
3093			Clone.prototype = obj;
3094			return new Clone()
3095		};
3096		function Clone() {}
3097	})();
3098	PurgeWhiteSpace = function (array) {
3099		var fragment,
3100		i,
3101		l,
3102		lTrimmed,
3103		r,
3104		rTrimmed,
3105		trailingSpace;
3106		i = 0;
3107		l = array.length;
3108		fragment = void 0;
3109		lTrimmed = false;
3110		rTrimmed = false;
3111		while (!lTrimmed && i !== l) {
3112			fragment = array[i] = array[i].trimLeft();
3113			if (fragment) {
3114				lTrimmed = true;
3115			}
3116			i++;
3117		}
3118		i = l - 1;
3119		while (l && !rTrimmed && i !== -1) {
3120			fragment = array[i] = array[i].trimRight();
3121			if (fragment) {
3122				rTrimmed = true;
3123			}
3124			i--;
3125		}
3126		r = /\s+$/g;
3127		trailingSpace = true;
3128		i = 0;
3129		while (i !== l) {
3130			fragment = array[i].replace(/\s+/g, " ");
3131			if (trailingSpace) {
3132				fragment = fragment.trimLeft();
3133			}
3134			if (fragment) {
3135				trailingSpace = r.test(fragment);
3136			}
3137			array[i] = fragment;
3138			i++;
3139		}
3140		return array;
3141	};
3142	Renderer = function (pdf, x, y, settings) {
3143		this.pdf = pdf;
3144		this.x = x;
3145		this.y = y;
3146		this.settings = settings;
3147		//list of functions which are called after each element-rendering process
3148		this.watchFunctions = [];
3149		this.init();
3150		return this;
3151	};
3152	ResolveFont = function (css_font_family_string) {
3153		var name,
3154		part,
3155		parts;
3156		name = void 0;
3157		parts = css_font_family_string.split(",");
3158		part = parts.shift();
3159		while (!name && part) {
3160			name = FontNameDB[part.trim().toLowerCase()];
3161			part = parts.shift();
3162		}
3163		return name;
3164	};
3165	ResolveUnitedNumber = function (css_line_height_string) {
3166
3167		//IE8 issues
3168		css_line_height_string = css_line_height_string === "auto" ? "0px" : css_line_height_string;
3169		if (css_line_height_string.indexOf("em") > -1 && !isNaN(Number(css_line_height_string.replace("em", "")))) {
3170			css_line_height_string = Number(css_line_height_string.replace("em", "")) * 18.719 + "px";
3171		}
3172		if (css_line_height_string.indexOf("pt") > -1 && !isNaN(Number(css_line_height_string.replace("pt", "")))) {
3173			css_line_height_string = Number(css_line_height_string.replace("pt", "")) * 1.333 + "px";
3174		}
3175
3176		var normal,
3177		undef,
3178		value;
3179		undef = void 0;
3180		normal = 16.00;
3181		value = UnitedNumberMap[css_line_height_string];
3182		if (value) {
3183			return value;
3184		}
3185		value = {
3186			"xx-small"  :  9,
3187			"x-small"   : 11,
3188			small       : 13,
3189			medium      : 16,
3190			large       : 19,
3191			"x-large"   : 23,
3192			"xx-large"  : 28,
3193			auto        :  0
3194		}[{ css_line_height_string : css_line_height_string }];
3195
3196		if (value !== undef) {
3197			return UnitedNumberMap[css_line_height_string] = value / normal;
3198		}
3199		if (value = parseFloat(css_line_height_string)) {
3200			return UnitedNumberMap[css_line_height_string] = value / normal;
3201		}
3202		value = css_line_height_string.match(/([\d\.]+)(px)/);
3203		if (value.length === 3) {
3204			return UnitedNumberMap[css_line_height_string] = parseFloat(value[1]) / normal;
3205		}
3206		return UnitedNumberMap[css_line_height_string] = 1;
3207	};
3208	GetCSS = function (element) {
3209		var css,tmp,computedCSSElement;
3210		computedCSSElement = (function (el) {
3211			var compCSS;
3212			compCSS = (function (el) {
3213				if (document.defaultView && document.defaultView.getComputedStyle) {
3214					return document.defaultView.getComputedStyle(el, null);
3215				} else if (el.currentStyle) {
3216					return el.currentStyle;
3217				} else {
3218					return el.style;
3219				}
3220			})(el);
3221			return function (prop) {
3222				prop = prop.replace(/-\D/g, function (match) {
3223					return match.charAt(1).toUpperCase();
3224				});
3225				return compCSS[prop];
3226			};
3227		})(element);
3228		css = {};
3229		tmp = void 0;
3230		css["font-family"] = ResolveFont(computedCSSElement("font-family")) || "times";
3231		css["font-style"] = FontStyleMap[computedCSSElement("font-style")] || "normal";
3232		css["text-align"] = TextAlignMap[computedCSSElement("text-align")] || "left";
3233		tmp = FontWeightMap[computedCSSElement("font-weight")] || "normal";
3234		if (tmp === "bold") {
3235			if (css["font-style"] === "normal") {
3236				css["font-style"] = tmp;
3237			} else {
3238				css["font-style"] = tmp + css["font-style"];
3239			}
3240		}
3241		css["font-size"] = ResolveUnitedNumber(computedCSSElement("font-size")) || 1;
3242		css["line-height"] = ResolveUnitedNumber(computedCSSElement("line-height")) || 1;
3243		css["display"] = (computedCSSElement("display") === "inline" ? "inline" : "block");
3244
3245		tmp = (css["display"] === "block");
3246		css["margin-top"]     = tmp && ResolveUnitedNumber(computedCSSElement("margin-top"))     || 0;
3247		css["margin-bottom"]  = tmp && ResolveUnitedNumber(computedCSSElement("margin-bottom"))  || 0;
3248		css["padding-top"]    = tmp && ResolveUnitedNumber(computedCSSElement("padding-top"))    || 0;
3249		css["padding-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-bottom")) || 0;
3250		css["margin-left"]    = tmp && ResolveUnitedNumber(computedCSSElement("margin-left"))    || 0;
3251		css["margin-right"]   = tmp && ResolveUnitedNumber(computedCSSElement("margin-right"))   || 0;
3252		css["padding-left"]   = tmp && ResolveUnitedNumber(computedCSSElement("padding-left"))   || 0;
3253		css["padding-right"]  = tmp && ResolveUnitedNumber(computedCSSElement("padding-right"))  || 0;
3254
3255		//float and clearing of floats
3256		css["float"] = FloatMap[computedCSSElement("cssFloat")] || "none";
3257		css["clear"] = ClearMap[computedCSSElement("clear")] || "none";
3258		return css;
3259	};
3260	elementHandledElsewhere = function (element, renderer, elementHandlers) {
3261		var handlers,
3262		i,
3263		isHandledElsewhere,
3264		l,
3265		t;
3266		isHandledElsewhere = false;
3267		i = void 0;
3268		l = void 0;
3269		t = void 0;
3270		handlers = elementHandlers["#" + element.id];
3271		if (handlers) {
3272			if (typeof handlers === "function") {
3273				isHandledElsewhere = handlers(element, renderer);
3274			} else {
3275				i = 0;
3276				l = handlers.length;
3277				while (!isHandledElsewhere && i !== l) {
3278					isHandledElsewhere = handlers[i](element, renderer);
3279					i++;
3280				}
3281			}
3282		}
3283		handlers = elementHandlers[element.nodeName];
3284		if (!isHandledElsewhere && handlers) {
3285			if (typeof handlers === "function") {
3286				isHandledElsewhere = handlers(element, renderer);
3287			} else {
3288				i = 0;
3289				l = handlers.length;
3290				while (!isHandledElsewhere && i !== l) {
3291					isHandledElsewhere = handlers[i](element, renderer);
3292					i++;
3293				}
3294			}
3295		}
3296		return isHandledElsewhere;
3297	};
3298	tableToJson = function (table, renderer) {
3299		var data,
3300		headers,
3301		i,
3302		j,
3303		rowData,
3304		tableRow,
3305		table_obj,
3306		table_with,
3307		cell,
3308		l;
3309		data = [];
3310		headers = [];
3311		i = 0;
3312		l = table.rows[0].cells.length;
3313		table_with = table.clientWidth;
3314		while (i < l) {
3315			cell = table.rows[0].cells[i];
3316			headers[i] = {
3317				name : cell.textContent.toLowerCase().replace(/\s+/g, ''),
3318				prompt : cell.textContent.replace(/\r?\n/g, ''),
3319				width : (cell.clientWidth / table_with) * renderer.pdf.internal.pageSize.width
3320			};
3321			i++;
3322		}
3323		i = 1;
3324		while (i < table.rows.length) {
3325			tableRow = table.rows[i];
3326			rowData = {};
3327			j = 0;
3328			while (j < tableRow.cells.length) {
3329				rowData[headers[j].name] = tableRow.cells[j].textContent.replace(/\r?\n/g, '');
3330				j++;
3331			}
3332			data.push(rowData);
3333			i++;
3334		}
3335		return table_obj = {
3336			rows : data,
3337			headers : headers
3338		};
3339	};
3340	var SkipNode = {
3341		SCRIPT   : 1,
3342		STYLE    : 1,
3343		NOSCRIPT : 1,
3344		OBJECT   : 1,
3345		EMBED    : 1,
3346		SELECT   : 1
3347	};
3348	var listCount = 1;
3349	DrillForContent = function (element, renderer, elementHandlers) {
3350		var cn,
3351		cns,
3352		fragmentCSS,
3353		i,
3354		isBlock,
3355		l,
3356		px2pt,
3357		table2json,
3358		cb;
3359		cns = element.childNodes;
3360		cn = void 0;
3361		fragmentCSS = GetCSS(element);
3362		isBlock = fragmentCSS.display === "block";
3363		if (isBlock) {
3364			renderer.setBlockBoundary();
3365			renderer.setBlockStyle(fragmentCSS);
3366		}
3367		px2pt = 0.264583 * 72 / 25.4;
3368		i = 0;
3369		l = cns.length;
3370		while (i < l) {
3371			cn = cns[i];
3372			if (typeof cn === "object") {
3373
3374				//execute all watcher functions to e.g. reset floating
3375				renderer.executeWatchFunctions(cn);
3376
3377				/*** HEADER rendering **/
3378				if (cn.nodeType === 1 && cn.nodeName === 'HEADER') {
3379					var header = cn;
3380					//store old top margin
3381					var oldMarginTop = renderer.pdf.margins_doc.top;
3382					//subscribe for new page event and render header first on every page
3383					renderer.pdf.internal.events.subscribe('addPage', function (pageInfo) {
3384						//set current y position to old margin
3385						renderer.y = oldMarginTop;
3386						//render all child nodes of the header element
3387						DrillForContent(header, renderer, elementHandlers);
3388						//set margin to old margin + rendered header + 10 space to prevent overlapping
3389						//important for other plugins (e.g. table) to start rendering at correct position after header
3390						renderer.pdf.margins_doc.top = renderer.y + 10;
3391						renderer.y += 10;
3392					}, false);
3393				}
3394
3395				if (cn.nodeType === 8 && cn.nodeName === "#comment") {
3396					if (~cn.textContent.indexOf("ADD_PAGE")) {
3397						renderer.pdf.addPage();
3398						renderer.y = renderer.pdf.margins_doc.top;
3399					}
3400
3401				} else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) {
3402					/*** IMAGE RENDERING ***/
3403					var cached_image;
3404					if (cn.nodeName === "IMG") {
3405						var url = cn.getAttribute("src");
3406						cached_image = images[renderer.pdf.sHashCode(url) || url];
3407					}
3408					if (cached_image) {
3409						if ((renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom < renderer.y + cn.height) && (renderer.y > renderer.pdf.margins_doc.top)) {
3410							renderer.pdf.addPage();
3411							renderer.y = renderer.pdf.margins_doc.top;
3412							//check if we have to set back some values due to e.g. header rendering for new page
3413							renderer.executeWatchFunctions(cn);
3414						}
3415
3416						var imagesCSS = GetCSS(cn);
3417						var imageX = renderer.x;
3418						var fontToUnitRatio = 12 / renderer.pdf.internal.scaleFactor;
3419
3420						//define additional paddings, margins which have to be taken into account for margin calculations
3421						var additionalSpaceLeft = (imagesCSS["margin-left"] + imagesCSS["padding-left"])*fontToUnitRatio;
3422						var additionalSpaceRight = (imagesCSS["margin-right"] + imagesCSS["padding-right"])*fontToUnitRatio;
3423						var additionalSpaceTop = (imagesCSS["margin-top"] + imagesCSS["padding-top"])*fontToUnitRatio;
3424						var additionalSpaceBottom = (imagesCSS["margin-bottom"] + imagesCSS["padding-bottom"])*fontToUnitRatio;
3425
3426						//if float is set to right, move the image to the right border
3427						//add space if margin is set
3428						if (imagesCSS['float'] !== undefined && imagesCSS['float'] === 'right') {
3429							imageX += renderer.settings.width - cn.width - additionalSpaceRight;
3430						} else {
3431							imageX +=  additionalSpaceLeft;
3432						}
3433
3434						renderer.pdf.addImage(cached_image, imageX, renderer.y + additionalSpaceTop, cn.width, cn.height);
3435						cached_image = undefined;
3436						//if the float prop is specified we have to float the text around the image
3437						if (imagesCSS['float'] === 'right' || imagesCSS['float'] === 'left') {
3438							//add functiont to set back coordinates after image rendering
3439							renderer.watchFunctions.push((function(diffX , thresholdY, diffWidth, el) {
3440								//undo drawing box adaptions which were set by floating
3441								if (renderer.y >= thresholdY) {
3442									renderer.x += diffX;
3443									renderer.settings.width += diffWidth;
3444									return true;
3445								} else if(el && el.nodeType === 1 && !SkipNode[el.nodeName] && renderer.x+el.width > (renderer.pdf.margins_doc.left + renderer.pdf.margins_doc.width)) {
3446									renderer.x += diffX;
3447									renderer.y = thresholdY;
3448									renderer.settings.width += diffWidth;
3449									return true;
3450								} else {
3451									return false;
3452								}
3453							}).bind(this, (imagesCSS['float'] === 'left') ? -cn.width-additionalSpaceLeft-additionalSpaceRight : 0, renderer.y+cn.height+additionalSpaceTop+additionalSpaceBottom, cn.width));
3454							//reset floating by clear:both divs
3455							//just set cursorY after the floating element
3456							renderer.watchFunctions.push((function(yPositionAfterFloating, pages, el) {
3457								if (renderer.y < yPositionAfterFloating && pages === renderer.pdf.internal.getNumberOfPages()) {
3458									if (el.nodeType === 1 && GetCSS(el).clear === 'both') {
3459										renderer.y = yPositionAfterFloating;
3460										return true;
3461									} else {
3462										return false;
3463									}
3464								} else {
3465									return true;
3466								}
3467							}).bind(this, renderer.y+cn.height, renderer.pdf.internal.getNumberOfPages()));
3468
3469							//if floating is set we decrease the available width by the image width
3470							renderer.settings.width -= cn.width+additionalSpaceLeft+additionalSpaceRight;
3471							//if left just add the image width to the X coordinate
3472							if (imagesCSS['float'] === 'left') {
3473								renderer.x += cn.width+additionalSpaceLeft+additionalSpaceRight;
3474							}
3475						} else {
3476						//if no floating is set, move the rendering cursor after the image height
3477							renderer.y += cn.height + additionalSpaceBottom;
3478						}
3479
3480					/*** TABLE RENDERING ***/
3481					} else if (cn.nodeName === "TABLE") {
3482						table2json = tableToJson(cn, renderer);
3483						renderer.y += 10;
3484						renderer.pdf.table(renderer.x, renderer.y, table2json.rows, table2json.headers, {
3485							autoSize : false,
3486							printHeaders : true,
3487							margins : renderer.pdf.margins_doc
3488						});
3489						renderer.y = renderer.pdf.lastCellPos.y + renderer.pdf.lastCellPos.h + 20;
3490					} else if (cn.nodeName === "OL" || cn.nodeName === "UL") {
3491						listCount = 1;
3492						if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
3493							DrillForContent(cn, renderer, elementHandlers);
3494						}
3495						renderer.y += 10;
3496					} else if (cn.nodeName === "LI") {
3497						var temp = renderer.x;
3498						renderer.x += cn.parentNode.nodeName === "UL" ? 22 : 10;
3499						renderer.y += 3;
3500						if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
3501							DrillForContent(cn, renderer, elementHandlers);
3502						}
3503						renderer.x = temp;
3504					} else if (cn.nodeName === "BR") {
3505						renderer.y += fragmentCSS["font-size"] * renderer.pdf.internal.scaleFactor;
3506					} else {
3507						if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
3508							DrillForContent(cn, renderer, elementHandlers);
3509						}
3510					}
3511				} else if (cn.nodeType === 3) {
3512					var value = cn.nodeValue;
3513					if (cn.nodeValue && cn.parentNode.nodeName === "LI") {
3514						if (cn.parentNode.parentNode.nodeName === "OL") {
3515							value = listCount++ + '. ' + value;
3516						} else {
3517							var fontPx = fragmentCSS["font-size"] * 16;
3518							var radius = 2;
3519							if (fontPx > 20) {
3520								radius = 3;
3521							}
3522							cb = function (x, y) {
3523								this.pdf.circle(x, y, radius, 'FD');
3524							};
3525						}
3526					}
3527					renderer.addText(value, fragmentCSS);
3528				} else if (typeof cn === "string") {
3529					renderer.addText(cn, fragmentCSS);
3530				}
3531			}
3532			i++;
3533		}
3534
3535		if (isBlock) {
3536			return renderer.setBlockBoundary(cb);
3537		}
3538	};
3539	images = {};
3540	loadImgs = function (element, renderer, elementHandlers, cb) {
3541		var imgs = element.getElementsByTagName('img'),
3542		l = imgs.length, found_images,
3543		x = 0;
3544		function done() {
3545			renderer.pdf.internal.events.publish('imagesLoaded');
3546			cb(found_images);
3547		}
3548		function loadImage(url, width, height) {
3549			if (!url)
3550				return;
3551			var img = new Image();
3552			found_images = ++x;
3553			img.crossOrigin = '';
3554			img.onerror = img.onload = function () {
3555				if(img.complete) {
3556					//to support data urls in images, set width and height
3557					//as those values are not recognized automatically
3558					if (img.src.indexOf('data:image/') === 0) {
3559						img.width = width || img.width || 0;
3560						img.height = height || img.height || 0;
3561					}
3562					//if valid image add to known images array
3563					if (img.width + img.height) {
3564						var hash = renderer.pdf.sHashCode(url) || url;
3565						images[hash] = images[hash] || img;
3566					}
3567				}
3568				if(!--x) {
3569					done();
3570				}
3571			};
3572			img.src = url;
3573		}
3574		while (l--)
3575			loadImage(imgs[l].getAttribute("src"),imgs[l].width,imgs[l].height);
3576		return x || done();
3577	};
3578	checkForFooter = function (elem, renderer, elementHandlers) {
3579		//check if we can found a <footer> element
3580		var footer = elem.getElementsByTagName("footer");
3581		if (footer.length > 0) {
3582
3583			footer = footer[0];
3584
3585			//bad hack to get height of footer
3586			//creat dummy out and check new y after fake rendering
3587			var oldOut = renderer.pdf.internal.write;
3588			var oldY = renderer.y;
3589			renderer.pdf.internal.write = function () {};
3590			DrillForContent(footer, renderer, elementHandlers);
3591			var footerHeight = Math.ceil(renderer.y - oldY) + 5;
3592			renderer.y = oldY;
3593			renderer.pdf.internal.write = oldOut;
3594
3595			//add 20% to prevent overlapping
3596			renderer.pdf.margins_doc.bottom += footerHeight;
3597
3598			//Create function render header on every page
3599			var renderFooter = function (pageInfo) {
3600				var pageNumber = pageInfo !== undefined ? pageInfo.pageNumber : 1;
3601				//set current y position to old margin
3602				var oldPosition = renderer.y;
3603				//render all child nodes of the header element
3604				renderer.y = renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom;
3605				renderer.pdf.margins_doc.bottom -= footerHeight;
3606
3607				//check if we have to add page numbers
3608				var spans = footer.getElementsByTagName('span');
3609				for (var i = 0; i < spans.length; ++i) {
3610					//if we find some span element with class pageCounter, set the page
3611					if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" pageCounter ") > -1) {
3612						spans[i].innerHTML = pageNumber;
3613					}
3614					//if we find some span element with class totalPages, set a variable which is replaced after rendering of all pages
3615					if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) {
3616						spans[i].innerHTML = '###jsPDFVarTotalPages###';
3617					}
3618				}
3619
3620				//render footer content
3621				DrillForContent(footer, renderer, elementHandlers);
3622				//set bottom margin to previous height including the footer height
3623				renderer.pdf.margins_doc.bottom += footerHeight;
3624				//important for other plugins (e.g. table) to start rendering at correct position after header
3625				renderer.y = oldPosition;
3626			};
3627
3628			//check if footer contains totalPages which shoudl be replace at the disoposal of the document
3629			var spans = footer.getElementsByTagName('span');
3630			for (var i = 0; i < spans.length; ++i) {
3631				if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) {
3632					renderer.pdf.internal.events.subscribe('htmlRenderingFinished', renderer.pdf.putTotalPages.bind(renderer.pdf, '###jsPDFVarTotalPages###'), true);
3633				}
3634			}
3635
3636			//register event to render footer on every new page
3637			renderer.pdf.internal.events.subscribe('addPage', renderFooter, false);
3638			//render footer on first page
3639			renderFooter();
3640
3641			//prevent footer rendering
3642			SkipNode['FOOTER'] = 1;
3643		}
3644	};
3645	process = function (pdf, element, x, y, settings, callback) {
3646		if (!element)
3647			return false;
3648		if (typeof element !== "string" && !element.parentNode)
3649			element = '' + element.innerHTML;
3650		if (typeof element === "string") {
3651			element = (function (element) {
3652				var $frame,
3653				$hiddendiv,
3654				framename,
3655				visuallyhidden;
3656				framename = "jsPDFhtmlText" + Date.now().toString() + (Math.random() * 1000).toFixed(0);
3657				visuallyhidden = "position: absolute !important;" + "clip: rect(1px 1px 1px 1px); /* IE6, IE7 */" + "clip: rect(1px, 1px, 1px, 1px);" + "padding:0 !important;" + "border:0 !important;" + "height: 1px !important;" + "width: 1px !important; " + "top:auto;" + "left:-100px;" + "overflow: hidden;";
3658				$hiddendiv = document.createElement('div');
3659				$hiddendiv.style.cssText = visuallyhidden;
3660				$hiddendiv.innerHTML = "<iframe style=\"height:1px;width:1px\" name=\"" + framename + "\" />";
3661				document.body.appendChild($hiddendiv);
3662				$frame = window.frames[framename];
3663				$frame.document.body.innerHTML = element;
3664				return $frame.document.body;
3665			})(element.replace(/<\/?script[^>]*?>/gi, ''));
3666		}
3667		var r = new Renderer(pdf, x, y, settings), out;
3668
3669		// 1. load images
3670		// 2. prepare optional footer elements
3671		// 3. render content
3672		loadImgs.call(this, element, r, settings.elementHandlers, function (found_images) {
3673			checkForFooter( element, r, settings.elementHandlers);
3674			DrillForContent(element, r, settings.elementHandlers);
3675			//send event dispose for final taks (e.g. footer totalpage replacement)
3676			r.pdf.internal.events.publish('htmlRenderingFinished');
3677			out = r.dispose();
3678			if (typeof callback === 'function') callback(out);
3679			else if (found_images) console.error('jsPDF Warning: rendering issues? provide a callback to fromHTML!');
3680		});
3681		return out || {x: r.x, y:r.y};
3682	};
3683	Renderer.prototype.init = function () {
3684		this.paragraph = {
3685			text : [],
3686			style : []
3687		};
3688		return this.pdf.internal.write("q");
3689	};
3690	Renderer.prototype.dispose = function () {
3691		this.pdf.internal.write("Q");
3692		return {
3693			x : this.x,
3694			y : this.y,
3695			ready:true
3696		};
3697	};
3698
3699	//Checks if we have to execute some watcher functions
3700	//e.g. to end text floating around an image
3701	Renderer.prototype.executeWatchFunctions = function(el) {
3702		var ret = false;
3703		var narray = [];
3704		if (this.watchFunctions.length > 0) {
3705			for(var i=0; i< this.watchFunctions.length; ++i) {
3706				if (this.watchFunctions[i](el) === true) {
3707					ret = true;
3708				} else {
3709					narray.push(this.watchFunctions[i]);
3710				}
3711			}
3712			this.watchFunctions = narray;
3713		}
3714		return ret;
3715	};
3716
3717	Renderer.prototype.splitFragmentsIntoLines = function (fragments, styles) {
3718		var currentLineLength,
3719		defaultFontSize,
3720		ff,
3721		fontMetrics,
3722		fontMetricsCache,
3723		fragment,
3724		fragmentChopped,
3725		fragmentLength,
3726		fragmentSpecificMetrics,
3727		fs,
3728		k,
3729		line,
3730		lines,
3731		maxLineLength,
3732		style;
3733		defaultFontSize = 12;
3734		k = this.pdf.internal.scaleFactor;
3735		fontMetricsCache = {};
3736		ff = void 0;
3737		fs = void 0;
3738		fontMetrics = void 0;
3739		fragment = void 0;
3740		style = void 0;
3741		fragmentSpecificMetrics = void 0;
3742		fragmentLength = void 0;
3743		fragmentChopped = void 0;
3744		line = [];
3745		lines = [line];
3746		currentLineLength = 0;
3747		maxLineLength = this.settings.width;
3748		while (fragments.length) {
3749			fragment = fragments.shift();
3750			style = styles.shift();
3751			if (fragment) {
3752				ff = style["font-family"];
3753				fs = style["font-style"];
3754				fontMetrics = fontMetricsCache[ff + fs];
3755				if (!fontMetrics) {
3756					fontMetrics = this.pdf.internal.getFont(ff, fs).metadata.Unicode;
3757					fontMetricsCache[ff + fs] = fontMetrics;
3758				}
3759				fragmentSpecificMetrics = {
3760					widths : fontMetrics.widths,
3761					kerning : fontMetrics.kerning,
3762					fontSize : style["font-size"] * defaultFontSize,
3763					textIndent : currentLineLength
3764				};
3765				fragmentLength = this.pdf.getStringUnitWidth(fragment, fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
3766				if (currentLineLength + fragmentLength > maxLineLength) {
3767					fragmentChopped = this.pdf.splitTextToSize(fragment, maxLineLength, fragmentSpecificMetrics);
3768					line.push([fragmentChopped.shift(), style]);
3769					while (fragmentChopped.length) {
3770						line = [[fragmentChopped.shift(), style]];
3771						lines.push(line);
3772					}
3773					currentLineLength = this.pdf.getStringUnitWidth(line[0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
3774				} else {
3775					line.push([fragment, style]);
3776					currentLineLength += fragmentLength;
3777				}
3778			}
3779		}
3780
3781		//if text alignment was set, set margin/indent of each line
3782		if (style['text-align'] !== undefined && (style['text-align'] === 'center' || style['text-align'] === 'right' || style['text-align'] === 'justify')) {
3783			for (var i = 0; i < lines.length; ++i) {
3784				var length = this.pdf.getStringUnitWidth(lines[i][0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
3785				//if there is more than on line we have to clone the style object as all lines hold a reference on this object
3786				if (i > 0) {
3787					lines[i][0][1] = clone(lines[i][0][1]);
3788				}
3789				var space = (maxLineLength - length);
3790
3791				if (style['text-align'] === 'right') {
3792					lines[i][0][1]['margin-left'] = space;
3793					//if alignment is not right, it has to be center so split the space to the left and the right
3794				} else if (style['text-align'] === 'center') {
3795					lines[i][0][1]['margin-left'] = space / 2;
3796					//if justify was set, calculate the word spacing and define in by using the css property
3797				} else if (style['text-align'] === 'justify') {
3798					var countSpaces = lines[i][0][0].split(' ').length - 1;
3799					lines[i][0][1]['word-spacing'] = space / countSpaces;
3800					//ignore the last line in justify mode
3801					if (i === (lines.length - 1)) {
3802						lines[i][0][1]['word-spacing'] = 0;
3803					}
3804				}
3805			}
3806		}
3807
3808		return lines;
3809	};
3810	Renderer.prototype.RenderTextFragment = function (text, style) {
3811		var defaultFontSize,
3812		font,
3813		maxLineHeight;
3814
3815		maxLineHeight = 0;
3816		defaultFontSize = 12;
3817
3818		if (this.pdf.internal.pageSize.height - this.pdf.margins_doc.bottom < this.y + this.pdf.internal.getFontSize()) {
3819			this.pdf.internal.write("ET", "Q");
3820			this.pdf.addPage();
3821			this.y = this.pdf.margins_doc.top;
3822			this.pdf.internal.write("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
3823			//move cursor by one line on new page
3824			maxLineHeight = Math.max(maxLineHeight, style["line-height"], style["font-size"]);
3825			this.pdf.internal.write(0, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td");
3826		}
3827
3828		font = this.pdf.internal.getFont(style["font-family"], style["font-style"]);
3829
3830		//set the word spacing for e.g. justify style
3831		if (style['word-spacing'] !== undefined && style['word-spacing'] > 0) {
3832			this.pdf.internal.write(style['word-spacing'].toFixed(2), "Tw");
3833		}
3834
3835		this.pdf.internal.write("/" + font.id, (defaultFontSize * style["font-size"]).toFixed(2), "Tf", "(" + this.pdf.internal.pdfEscape(text) + ") Tj");
3836
3837		//set the word spacing back to neutral => 0
3838		if (style['word-spacing'] !== undefined) {
3839			this.pdf.internal.write(0, "Tw");
3840		}
3841	};
3842	Renderer.prototype.renderParagraph = function (cb) {
3843		var blockstyle,
3844		defaultFontSize,
3845		fontToUnitRatio,
3846		fragments,
3847		i,
3848		l,
3849		line,
3850		lines,
3851		maxLineHeight,
3852		out,
3853		paragraphspacing_after,
3854		paragraphspacing_before,
3855		priorblockstype,
3856		styles,
3857		fontSize;
3858		fragments = PurgeWhiteSpace(this.paragraph.text);
3859		styles = this.paragraph.style;
3860		blockstyle = this.paragraph.blockstyle;
3861		priorblockstype = this.paragraph.blockstyle || {};
3862		this.paragraph = {
3863			text : [],
3864			style : [],
3865			blockstyle : {},
3866			priorblockstyle : blockstyle
3867		};
3868		if (!fragments.join("").trim()) {
3869			return;
3870		}
3871		lines = this.splitFragmentsIntoLines(fragments, styles);
3872		line = void 0;
3873		maxLineHeight = void 0;
3874		defaultFontSize = 12;
3875		fontToUnitRatio = defaultFontSize / this.pdf.internal.scaleFactor;
3876		paragraphspacing_before = (Math.max((blockstyle["margin-top"] || 0) - (priorblockstype["margin-bottom"] || 0), 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio;
3877		paragraphspacing_after = ((blockstyle["margin-bottom"] || 0) + (blockstyle["padding-bottom"] || 0)) * fontToUnitRatio;
3878		out = this.pdf.internal.write;
3879		i = void 0;
3880		l = void 0;
3881		this.y += paragraphspacing_before;
3882		out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
3883
3884		//stores the current indent of cursor position
3885		var currentIndent = 0;
3886
3887		while (lines.length) {
3888			line = lines.shift();
3889			maxLineHeight = 0;
3890			i = 0;
3891			l = line.length;
3892			while (i !== l) {
3893				if (line[i][0].trim()) {
3894					maxLineHeight = Math.max(maxLineHeight, line[i][1]["line-height"], line[i][1]["font-size"]);
3895					fontSize = line[i][1]["font-size"] * 7;
3896				}
3897				i++;
3898			}
3899			//if we have to move the cursor to adapt the indent
3900			var indentMove = 0;
3901			//if a margin was added (by e.g. a text-alignment), move the cursor
3902			if (line[0][1]["margin-left"] !== undefined && line[0][1]["margin-left"] > 0) {
3903				wantedIndent = this.pdf.internal.getCoordinateString(line[0][1]["margin-left"]);
3904				indentMove = wantedIndent - currentIndent;
3905				currentIndent = wantedIndent;
3906			}
3907			//move the cursor
3908			out(indentMove, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td");
3909			i = 0;
3910			l = line.length;
3911			while (i !== l) {
3912				if (line[i][0]) {
3913					this.RenderTextFragment(line[i][0], line[i][1]);
3914				}
3915				i++;
3916			}
3917			this.y += maxLineHeight * fontToUnitRatio;
3918
3919			//if some watcher function was executed sucessful, so e.g. margin and widths were changed,
3920			//reset line drawing and calculate position and lines again
3921			//e.g. to stop text floating around an image
3922			if (this.executeWatchFunctions(line[0][1]) && lines.length > 0) {
3923				var localFragments = [];
3924				var localStyles = [];
3925				//create fragement array of
3926				lines.forEach(function(localLine) {
3927					var i = 0;
3928					var l = localLine.length;
3929					while (i !== l) {
3930						if (localLine[i][0]) {
3931							localFragments.push(localLine[i][0]+' ');
3932							localStyles.push(localLine[i][1]);
3933						}
3934						++i;
3935					}
3936				});
3937				//split lines again due to possible coordinate changes
3938				lines = this.splitFragmentsIntoLines(PurgeWhiteSpace(localFragments), localStyles);
3939				//reposition the current cursor
3940				out("ET", "Q");
3941				out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
3942			}
3943
3944		}
3945		if (cb && typeof cb === "function") {
3946			cb.call(this, this.x - 9, this.y - fontSize / 2);
3947		}
3948		out("ET", "Q");
3949		return this.y += paragraphspacing_after;
3950	};
3951	Renderer.prototype.setBlockBoundary = function (cb) {
3952		return this.renderParagraph(cb);
3953	};
3954	Renderer.prototype.setBlockStyle = function (css) {
3955		return this.paragraph.blockstyle = css;
3956	};
3957	Renderer.prototype.addText = function (text, css) {
3958		this.paragraph.text.push(text);
3959		return this.paragraph.style.push(css);
3960	};
3961	FontNameDB = {
3962		helvetica         : "helvetica",
3963		"sans-serif"      : "helvetica",
3964		"times new roman" : "times",
3965		serif             : "times",
3966		times             : "times",
3967		monospace         : "courier",
3968		courier           : "courier"
3969	};
3970	FontWeightMap = {
3971		100 : "normal",
3972		200 : "normal",
3973		300 : "normal",
3974		400 : "normal",
3975		500 : "bold",
3976		600 : "bold",
3977		700 : "bold",
3978		800 : "bold",
3979		900 : "bold",
3980		normal  : "normal",
3981		bold    : "bold",
3982		bolder  : "bold",
3983		lighter : "normal"
3984	};
3985	FontStyleMap = {
3986		normal  : "normal",
3987		italic  : "italic",
3988		oblique : "italic"
3989	};
3990	TextAlignMap = {
3991		left    : "left",
3992		right   : "right",
3993		center  : "center",
3994		justify : "justify"
3995	};
3996	FloatMap = {
3997		none : 'none',
3998		right: 'right',
3999		left: 'left'
4000	};
4001	ClearMap = {
4002	  none : 'none',
4003	  both : 'both'
4004	};
4005	UnitedNumberMap = {
4006		normal : 1
4007	};
4008	/**
4009	 * Converts HTML-formatted text into formatted PDF text.
4010	 *
4011	 * Notes:
4012	 * 2012-07-18
4013	 * Plugin relies on having browser, DOM around. The HTML is pushed into dom and traversed.
4014	 * Plugin relies on jQuery for CSS extraction.
4015	 * Targeting HTML output from Markdown templating, which is a very simple
4016	 * markup - div, span, em, strong, p. No br-based paragraph separation supported explicitly (but still may work.)
4017	 * Images, tables are NOT supported.
4018	 *
4019	 * @public
4020	 * @function
4021	 * @param HTML {String or DOM Element} HTML-formatted text, or pointer to DOM element that is to be rendered into PDF.
4022	 * @param x {Number} starting X coordinate in jsPDF instance's declared units.
4023	 * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
4024	 * @param settings {Object} Additional / optional variables controlling parsing, rendering.
4025	 * @returns {Object} jsPDF instance
4026	 */
4027	jsPDFAPI.fromHTML = function (HTML, x, y, settings, callback, margins) {
4028		"use strict";
4029
4030		this.margins_doc = margins || {
4031			top : 0,
4032			bottom : 0
4033		};
4034		if (!settings)
4035			settings = {};
4036		if (!settings.elementHandlers)
4037			settings.elementHandlers = {};
4038
4039		return process(this, HTML, isNaN(x) ? 4 : x, isNaN(y) ? 4 : y, settings, callback);
4040	};
4041})(jsPDF.API);
4042/** ==================================================================== 
4043 * jsPDF JavaScript plugin
4044 * Copyright (c) 2013 Youssef Beddad, [email protected]
4045 * 
4046 * Permission is hereby granted, free of charge, to any person obtaining
4047 * a copy of this software and associated documentation files (the
4048 * "Software"), to deal in the Software without restriction, including
4049 * without limitation the rights to use, copy, modify, merge, publish,
4050 * distribute, sublicense, and/or sell copies of the Software, and to
4051 * permit persons to whom the Software is furnished to do so, subject to
4052 * the following conditions:
4053 * 
4054 * The above copyright notice and this permission notice shall be
4055 * included in all copies or substantial portions of the Software.
4056 * 
4057 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4058 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4059 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
4060 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
4061 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
4062 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4063 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4064 * ====================================================================
4065 */
4066
4067/*global jsPDF */
4068
4069(function (jsPDFAPI) {
4070    'use strict';
4071    var jsNamesObj, jsJsObj, text;
4072    jsPDFAPI.addJS = function (txt) {
4073        text = txt;
4074        this.internal.events.subscribe(
4075            'postPutResources',
4076            function (txt) {
4077                jsNamesObj = this.internal.newObject();
4078                this.internal.write('<< /Names [(EmbeddedJS) ' + (jsNamesObj + 1) + ' 0 R] >>', 'endobj');
4079                jsJsObj = this.internal.newObject();
4080                this.internal.write('<< /S /JavaScript /JS (', text, ') >>', 'endobj');
4081            }
4082        );
4083        this.internal.events.subscribe(
4084            'putCatalog',
4085            function () {
4086                if (jsNamesObj !== undefined && jsJsObj !== undefined) {
4087                    this.internal.write('/Names <</JavaScript ' + jsNamesObj + ' 0 R>>');
4088                }
4089            }
4090        );
4091        return this;
4092    };
4093}(jsPDF.API));
4094/**@preserve
4095 *  ==================================================================== 
4096 * jsPDF PNG PlugIn
4097 * Copyright (c) 2014 James Robb, https://github.com/jamesbrobb
4098 * 
4099 * Permission is hereby granted, free of charge, to any person obtaining
4100 * a copy of this software and associated documentation files (the
4101 * "Software"), to deal in the Software without restriction, including
4102 * without limitation the rights to use, copy, modify, merge, publish,
4103 * distribute, sublicense, and/or sell copies of the Software, and to
4104 * permit persons to whom the Software is furnished to do so, subject to
4105 * the following conditions:
4106 * 
4107 * The above copyright notice and this permission notice shall be
4108 * included in all copies or substantial portions of the Software.
4109 * 
4110 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4111 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4112 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
4113 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
4114 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
4115 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4116 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4117 * ====================================================================
4118 */
4119
4120(function(jsPDFAPI) {
4121'use strict'
4122	
4123	/*
4124	 * @see http://www.w3.org/TR/PNG-Chunks.html
4125	 * 
4126	 Color    Allowed      Interpretation
4127	 Type     Bit Depths
4128	   
4129	   0       1,2,4,8,16  Each pixel is a grayscale sample.
4130	   
4131	   2       8,16        Each pixel is an R,G,B triple.
4132	   
4133	   3       1,2,4,8     Each pixel is a palette index;
4134	                       a PLTE chunk must appear.
4135	   
4136	   4       8,16        Each pixel is a grayscale sample,
4137	                       followed by an alpha sample.
4138	   
4139	   6       8,16        Each pixel is an R,G,B triple,
4140	                       followed by an alpha sample.
4141	*/
4142	
4143	/*
4144	 * PNG filter method types
4145	 * 
4146	 * @see http://www.w3.org/TR/PNG-Filters.html
4147	 * @see http://www.libpng.org/pub/png/book/chapter09.html
4148	 * 
4149	 * This is what the value 'Predictor' in decode params relates to
4150	 * 
4151	 * 15 is "optimal prediction", which means the prediction algorithm can change from line to line.
4152	 * In that case, you actually have to read the first byte off each line for the prediction algorthim (which should be 0-4, corresponding to PDF 10-14) and select the appropriate unprediction algorithm based on that byte.
4153	 *
4154	   0       None
4155	   1       Sub
4156	   2       Up
4157	   3       Average
4158	   4       Paeth
4159	 */
4160	
4161	var doesNotHavePngJS = function() {
4162		return typeof PNG !== 'function' || typeof FlateStream !== 'function';
4163	}
4164	, canCompress = function(value) {
4165		return value !== jsPDFAPI.image_compression.NONE && hasCompressionJS();
4166	}
4167	, hasCompressionJS = function() {
4168		var inst = typeof Deflater === 'function';
4169		if(!inst)
4170			throw new Error("requires deflate.js for compression")
4171		return inst;
4172	}
4173	, compressBytes = function(bytes, lineLength, colorsPerPixel, compression) {
4174		
4175		var level = 5,
4176			filter_method = filterUp;
4177		
4178		switch(compression) {
4179		
4180			case jsPDFAPI.image_compression.FAST:
4181				
4182				level = 3;
4183				filter_method = filterSub;
4184				break;
4185				
4186			case jsPDFAPI.image_compression.MEDIUM:
4187				
4188				level = 6;
4189				filter_method = filterAverage;
4190				break;
4191				
4192			case jsPDFAPI.image_compression.SLOW:
4193				
4194				level = 9;
4195				filter_method = filterPaeth;//uses to sum to choose best filter for each line
4196				break;
4197		}
4198		
4199		bytes = applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method);
4200		
4201		var header = new Uint8Array(createZlibHeader(level));
4202		var checksum = adler32(bytes);
4203		
4204		var deflate = new Deflater(level);
4205		var a = deflate.append(bytes);
4206		var cBytes = deflate.flush();
4207		
4208		var len = header.length + a.length + cBytes.length;
4209		
4210		var cmpd = new Uint8Array(len + 4);
4211		cmpd.set(header);
4212		cmpd.set(a, header.length);
4213		cmpd.set(cBytes, header.length + a.length);
4214		
4215		cmpd[len++] = (checksum >>> 24) & 0xff;
4216		cmpd[len++] = (checksum >>> 16) & 0xff;
4217		cmpd[len++] = (checksum >>> 8) & 0xff;
4218		cmpd[len++] = checksum & 0xff;
4219		
4220		return jsPDFAPI.arrayBufferToBinaryString(cmpd);
4221	}
4222	, createZlibHeader = function(bytes, level){
4223		/*
4224		 * @see http://www.ietf.org/rfc/rfc1950.txt for zlib header 
4225		 */
4226		var cm = 8;
4227        var cinfo = Math.LOG2E * Math.log(0x8000) - 8;
4228        var cmf = (cinfo << 4) | cm;
4229        
4230        var hdr = cmf << 8;
4231        var flevel = Math.min(3, ((level - 1) & 0xff) >> 1);
4232        
4233        hdr |= (flevel << 6);
4234        hdr |= 0;//FDICT
4235        hdr += 31 - (hdr % 31);
4236        
4237        return [cmf, (hdr & 0xff) & 0xff];
4238	}
4239	, adler32 = function(array, param) {
4240		var adler = 1;
4241	    var s1 = adler & 0xffff,
4242	        s2 = (adler >>> 16) & 0xffff;
4243	    var len = array.length;
4244	    var tlen;
4245	    var i = 0;
4246
4247	    while (len > 0) {
4248	      tlen = len > param ? param : len;
4249	      len -= tlen;
4250	      do {
4251	        s1 += array[i++];
4252	        s2 += s1;
4253	      } while (--tlen);
4254
4255	      s1 %= 65521;
4256	      s2 %= 65521;
4257	    }
4258
4259	    return ((s2 << 16) | s1) >>> 0;
4260	}
4261	, applyPngFilterMethod = function(bytes, lineLength, colorsPerPixel, filter_method) {
4262		var lines = bytes.length / lineLength,
4263			result = new Uint8Array(bytes.length + lines),
4264			filter_methods = getFilterMethods(),
4265			i = 0, line, prevLine, offset;
4266		
4267		for(; i < lines; i++) {
4268			offset = i * lineLength;
4269			line = bytes.subarray(offset, offset + lineLength);
4270			
4271			if(filter_method) {
4272				result.set(filter_method(line, colorsPerPixel, prevLine), offset + i);
4273				
4274			}else{
4275			
4276				var j = 0,
4277					len = filter_methods.length,
4278					results = [];
4279				
4280				for(; j < len; j++)
4281					results[j] = filter_methods[j](line, colorsPerPixel, prevLine);
4282				
4283				var ind = getIndexOfSmallestSum(results.concat());
4284				
4285				result.set(results[ind], offset + i);
4286			}
4287			
4288			prevLine = line;
4289		}
4290		
4291		return result;
4292	}
4293	, filterNone = function(line, colorsPerPixel, prevLine) {
4294		/*var result = new Uint8Array(line.length + 1);
4295		result[0] = 0;
4296		result.set(line, 1);*/
4297		
4298		var result = Array.apply([], line);
4299		result.unshift(0);
4300
4301		return result;
4302	}
4303	, filterSub = function(line, colorsPerPixel, prevLine) {
4304		var result = [],
4305			i = 0,
4306			len = line.length,
4307			left;
4308		
4309		result[0] = 1;
4310		
4311		for(; i < len; i++) {
4312			left = line[i - colorsPerPixel] || 0;
4313			result[i + 1] = (line[i] - left + 0x0100) & 0xff;
4314		}
4315		
4316		return result;
4317	}
4318	, filterUp = function(line, colorsPerPixel, prevLine) {
4319		var result = [],
4320			i = 0,
4321			len = line.length,
4322			up;
4323		
4324		result[0] = 2;
4325		
4326		for(; i < len; i++) {
4327			up = prevLine && prevLine[i] || 0;
4328			result[i + 1] = (line[i] - up + 0x0100) & 0xff;
4329		}
4330		
4331		return result;
4332	}
4333	, filterAverage = function(line, colorsPerPixel, prevLine) {
4334		var result = [],
4335			i = 0,
4336			len = line.length,
4337			left,
4338			up;
4339	
4340		result[0] = 3;
4341		
4342		for(; i < len; i++) {
4343			left = line[i - colorsPerPixel] || 0;
4344			up = prevLine && prevLine[i] || 0;
4345			result[i + 1] = (line[i] + 0x0100 - ((left + up) >>> 1)) & 0xff;
4346		}
4347		
4348		return result;
4349	}
4350	, filterPaeth = function(line, colorsPerPixel, prevLine) {
4351		var result = [],
4352			i = 0,
4353			len = line.length,
4354			left,
4355			up,
4356			upLeft,
4357			paeth;
4358		
4359		result[0] = 4;
4360		
4361		for(; i < len; i++) {
4362			left = line[i - colorsPerPixel] || 0;
4363			up = prevLine && prevLine[i] || 0;
4364			upLeft = prevLine && prevLine[i - colorsPerPixel] || 0;
4365			paeth = paethPredictor(left, up, upLeft);
4366			result[i + 1] = (line[i] - paeth + 0x0100) & 0xff;
4367		}
4368		
4369		return result;
4370	}
4371	,paethPredictor = function(left, up, upLeft) {
4372
4373		var p = left + up - upLeft,
4374	        pLeft = Math.abs(p - left),
4375	        pUp = Math.abs(p - up),
4376	        pUpLeft = Math.abs(p - upLeft);
4377		
4378		return (pLeft <= pUp && pLeft <= pUpLeft) ? left : (pUp <= pUpLeft) ? up : upLeft;
4379	}
4380	, getFilterMethods = function() {
4381		return [filterNone, filterSub, filterUp, filterAverage, filterPaeth];
4382	}
4383	,getIndexOfSmallestSum = function(arrays) {
4384		var i = 0,
4385			len = arrays.length,
4386			sum, min, ind;
4387		
4388		while(i < len) {
4389			sum = absSum(arrays[i].slice(1));
4390			
4391			if(sum < min || !min) {
4392				min = sum;
4393				ind = i;
4394			}
4395			
4396			i++;
4397		}
4398		
4399		return ind;
4400	}
4401	, absSum = function(array) {
4402		var i = 0,
4403			len = array.length,
4404			sum = 0;
4405	
4406		while(i < len)
4407			sum += Math.abs(array[i++]);
4408			
4409		return sum;
4410	}
4411	, logImg = function(img) {
4412		console.log("width: " + img.width);
4413		console.log("height: " + img.height);
4414		console.log("bits: " + img.bits);
4415		console.log("colorType: " + img.colorType);
4416		console.log("transparency:");
4417		console.log(img.transparency);
4418		console.log("text:");
4419		console.log(img.text);
4420		console.log("compressionMethod: " + img.compressionMethod);
4421		console.log("filterMethod: " + img.filterMethod);
4422		console.log("interlaceMethod: " + img.interlaceMethod);
4423		console.log("imgData:");
4424		console.log(img.imgData);
4425		console.log("palette:");
4426		console.log(img.palette);
4427		console.log("colors: " + img.colors);
4428		console.log("colorSpace: " + img.colorSpace);
4429		console.log("pixelBitlength: " + img.pixelBitlength);
4430		console.log("hasAlphaChannel: " + img.hasAlphaChannel);
4431	};
4432	
4433	
4434	
4435	
4436	jsPDFAPI.processPNG = function(imageData, imageIndex, alias, compression, dataAsBinaryString) {
4437		'use strict'
4438		
4439		var colorSpace = this.color_spaces.DEVICE_RGB,
4440			decode = this.decode.FLATE_DECODE,
4441			bpc = 8,
4442			img, dp, trns,
4443			colors, pal, smask;
4444		
4445	/*	if(this.isString(imageData)) {
4446			
4447		}*/
4448		
4449		if(this.isArrayBuffer(imageData))
4450			imageData = new Uint8Array(imageData);
4451		
4452		if(this.isArrayBufferView(imageData)) {
4453			
4454			if(doesNotHavePngJS())
4455				throw new Error("PNG support requires png.js and zlib.js");
4456				
4457			img = new PNG(imageData);
4458			imageData = img.imgData;
4459			bpc = img.bits;
4460			colorSpace = img.colorSpace;
4461			colors = img.colors;
4462			
4463			//logImg(img);
4464			
4465			/*
4466			 * colorType 6 - Each pixel is an R,G,B triple, followed by an alpha sample.
4467			 * 
4468			 * colorType 4 - Each pixel is a grayscale sample, followed by an alpha sample.
4469			 * 
4470			 * Extract alpha to create two separate images, using the alpha as a sMask
4471			 */
4472			if([4,6].indexOf(img.colorType) !== -1) {
4473				
4474				/*
4475				 * processes 8 bit RGBA and grayscale + alpha images
4476				 */
4477				if(img.bits === 8) {
4478				
4479				        var pixels = img.pixelBitlength == 32 ? new Uint32Array(img.decodePixels().buffer) : img.pixelBitlength == 16 ? new Uint16Array(img.decodePixels().buffer) : new Uint8Array(img.decodePixels().buffer),
4480						len = pixels.length,
4481						imgData = new Uint8Array(len * img.colors),
4482						alphaData = new Uint8Array(len),
4483						pDiff = img.pixelBitlength - img.bits,
4484						i = 0, n = 0, pixel, pbl;
4485				
4486					for(; i < len; i++) {
4487						pixel = pixels[i];
4488						pbl = 0;
4489						
4490						while(pbl < pDiff) {
4491							
4492							imgData[n++] = ( pixel >>> pbl ) & 0xff;
4493							pbl = pbl + img.bits;
4494						}
4495						
4496						alphaData[i] = ( pixel >>> pbl ) & 0xff;
4497					}
4498				}
4499				
4500				/*
4501				 * processes 16 bit RGBA and grayscale + alpha images
4502				 */
4503				if(img.bits === 16) {
4504					
4505					var pixels = new Uint32Array(img.decodePixels().buffer),
4506						len = pixels.length,
4507						imgData = new Uint8Array((len * (32 / img.pixelBitlength) ) * img.colors),
4508						alphaData = new Uint8Array(len * (32 / img.pixelBitlength) ),
4509						hasColors = img.colors > 1,
4510						i = 0, n = 0, a = 0, pixel;
4511					
4512					while(i < len) {
4513						pixel = pixels[i++];
4514						
4515						imgData[n++] = (pixel >>> 0) & 0xFF;
4516						
4517						if(hasColors) {
4518							imgData[n++] = (pixel >>> 16) & 0xFF;
4519							
4520							pixel = pixels[i++];
4521							imgData[n++] = (pixel >>> 0) & 0xFF;
4522						}
4523						
4524						alphaData[a++] = (pixel >>> 16) & 0xFF;
4525					}
4526					
4527					bpc = 8;
4528				}
4529				
4530				if(canCompress(compression)) {
4531										
4532					imageData = compressBytes(imgData, img.width * img.colors, img.colors, compression);
4533					smask = compressBytes(alphaData, img.width, 1, compression);
4534					
4535				}else{
4536					
4537					imageData = imgData;
4538					smask = alphaData;
4539					decode = null;
4540				}
4541			}
4542			
4543			/*
4544			 * Indexed png. Each pixel is a palette index.
4545			 */
4546			if(img.colorType === 3) {
4547				
4548				colorSpace = this.color_spaces.INDEXED;
4549				pal = img.palette;
4550				
4551				if(img.transparency.indexed) {
4552					
4553					var trans = img.transparency.indexed;
4554					
4555					var total = 0,
4556						i = 0,
4557						len = trans.length;
4558
4559					for(; i<len; ++i)
4560					    total += trans[i];
4561					
4562					total = total / 255;
4563					
4564					/*
4565					 * a single color is specified as 100% transparent (0),
4566					 * so we set trns to use a /Mask with that index
4567					 */
4568					if(total === len - 1 && trans.indexOf(0) !== -1) {
4569						trns = [trans.indexOf(0)];
4570					
4571					/*
4572					 * there's more than one colour within the palette that specifies
4573					 * a transparency value less than 255, so we unroll the pixels to create an image sMask
4574					 */
4575					}else if(total !== len){
4576						
4577						var pixels = img.decodePixels(),
4578							alphaData = new Uint8Array(pixels.length),
4579							i = 0,
4580							len = pixels.length;
4581						
4582						for(; i < len; i++)
4583							alphaData[i] = trans[pixels[i]];
4584						
4585						smask = compressBytes(alphaData, img.width, 1);
4586					}
4587				}
4588			}
4589			
4590			if(decode === this.decode.FLATE_DECODE)
4591				dp = '/Predictor 15 /Colors '+ colors +' /BitsPerComponent '+ bpc +' /Columns '+ img.width;
4592			else
4593				//remove 'Predictor' as it applies to the type of png filter applied to its IDAT - we only apply with compression
4594				dp = '/Colors '+ colors +' /BitsPerComponent '+ bpc +' /Columns '+ img.width;
4595			
4596			if(this.isArrayBuffer(imageData) || this.isArrayBufferView(imageData))
4597				imageData = this.arrayBufferToBinaryString(imageData);
4598			
4599			if(smask && this.isArrayBuffer(smask) || this.isArrayBufferView(smask))
4600				smask = this.arrayBufferToBinaryString(smask);
4601			
4602			return this.createImageInfo(imageData, img.width, img.height, colorSpace,
4603										bpc, decode, imageIndex, alias, dp, trns, pal, smask);
4604		}
4605		
4606		throw new Error("Unsupported PNG image data, try using JPEG instead.");
4607	}
4608
4609})(jsPDF.API)
4610/** @preserve
4611jsPDF Silly SVG plugin
4612Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
4613*/
4614/**
4615 * Permission is hereby granted, free of charge, to any person obtaining
4616 * a copy of this software and associated documentation files (the
4617 * "Software"), to deal in the Software without restriction, including
4618 * without limitation the rights to use, copy, modify, merge, publish,
4619 * distribute, sublicense, and/or sell copies of the Software, and to
4620 * permit persons to whom the Software is furnished to do so, subject to
4621 * the following conditions:
4622 * 
4623 * The above copyright notice and this permission notice shall be
4624 * included in all copies or substantial portions of the Software.
4625 * 
4626 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4627 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4628 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
4629 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
4630 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
4631 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4632 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4633 * ====================================================================
4634 */
4635
4636;(function(jsPDFAPI) {
4637'use strict'
4638
4639/**
4640Parses SVG XML and converts only some of the SVG elements into
4641PDF elements.
4642
4643Supports:
4644 paths
4645
4646@public
4647@function
4648@param
4649@returns {Type}
4650*/
4651jsPDFAPI.addSVG = function(svgtext, x, y, w, h) {
4652	// 'this' is _jsPDF object returned when jsPDF is inited (new jsPDF())
4653
4654	var undef
4655
4656	if (x === undef || y === undef) {
4657		throw new Error("addSVG needs values for 'x' and 'y'");
4658	}
4659
4660    function InjectCSS(cssbody, document) {
4661        var styletag = document.createElement('style');
4662        styletag.type = 'text/css';
4663        if (styletag.styleSheet) {
4664        	// ie
4665            styletag.styleSheet.cssText = cssbody;
4666        } else {
4667        	// others
4668            styletag.appendChild(document.createTextNode(cssbody));
4669        }
4670        document.getElementsByTagName("head")[0].appendChild(styletag);
4671    }
4672
4673	function createWorkerNode(document){
4674
4675		var frameID = 'childframe' // Date.now().toString() + '_' + (Math.random() * 100).toString()
4676		, frame = document.createElement('iframe')
4677
4678		InjectCSS(
4679			'.jsPDF_sillysvg_iframe {display:none;position:absolute;}'
4680			, document
4681		)
4682
4683		frame.name = frameID
4684		frame.setAttribute("width", 0)
4685		frame.setAttribute("height", 0)
4686		frame.setAttribute("frameborder", "0")
4687		frame.setAttribute("scrolling", "no")
4688		frame.setAttribute("seamless", "seamless")
4689		frame.setAttribute("class", "jsPDF_sillysvg_iframe")
4690		
4691		document.body.appendChild(frame)
4692
4693		return frame
4694	}
4695
4696	function attachSVGToWorkerNode(svgtext, frame){
4697		var framedoc = ( frame.contentWindow || frame.contentDocument ).document
4698		framedoc.write(svgtext)
4699		framedoc.close()
4700		return framedoc.getElementsByTagName('svg')[0]
4701	}
4702
4703	function convertPathToPDFLinesArgs(path){
4704		'use strict'
4705		// we will use 'lines' method call. it needs:
4706		// - starting coordinate pair
4707		// - array of arrays of vector shifts (2-len for line, 6 len for bezier)
4708		// - scale array [horizontal, vertical] ratios
4709		// - style (stroke, fill, both)
4710
4711		var x = parseFloat(path[1])
4712		, y = parseFloat(path[2])
4713		, vectors = []
4714		, position = 3
4715		, len = path.length
4716
4717		while (position < len){
4718			if (path[position] === 'c'){
4719				vectors.push([
4720					parseFloat(path[position + 1])
4721					, parseFloat(path[position + 2])
4722					, parseFloat(path[position + 3])
4723					, parseFloat(path[position + 4])
4724					, parseFloat(path[position + 5])
4725					, parseFloat(path[position + 6])
4726				])
4727				position += 7
4728			} else if (path[position] === 'l') {
4729				vectors.push([
4730					parseFloat(path[position + 1])
4731					, parseFloat(path[position + 2])
4732				])
4733				position += 3
4734			} else {
4735				position += 1
4736			}
4737		}
4738		return [x,y,vectors]
4739	}
4740
4741	var workernode = createWorkerNode(document)
4742	, svgnode = attachSVGToWorkerNode(svgtext, workernode)
4743	, scale = [1,1]
4744	, svgw = parseFloat(svgnode.getAttribute('width'))
4745	, svgh = parseFloat(svgnode.getAttribute('height'))
4746
4747	if (svgw && svgh) {
4748		// setting both w and h makes image stretch to size.
4749		// this may distort the image, but fits your demanded size
4750		if (w && h) {
4751			scale = [w / svgw, h / svgh]
4752		} 
4753		// if only one is set, that value is set as max and SVG 
4754		// is scaled proportionately.
4755		else if (w) {
4756			scale = [w / svgw, w / svgw]
4757		} else if (h) {
4758			scale = [h / svgh, h / svgh]
4759		}
4760	}
4761
4762	var i, l, tmp
4763	, linesargs
4764	, items = svgnode.childNodes
4765	for (i = 0, l = items.length; i < l; i++) {
4766		tmp = items[i]
4767		if (tmp.tagName && tmp.tagName.toUpperCase() === 'PATH') {
4768			linesargs = convertPathToPDFLinesArgs( tmp.getAttribute("d").split(' ') )
4769			// path start x coordinate
4770			linesargs[0] = linesargs[0] * scale[0] + x // where x is upper left X of image
4771			// path start y coordinate
4772			linesargs[1] = linesargs[1] * scale[1] + y // where y is upper left Y of image
4773			// the rest of lines are vectors. these will adjust with scale value auto.
4774			this.lines.call(
4775				this
4776				, linesargs[2] // lines
4777				, linesargs[0] // starting x
4778				, linesargs[1] // starting y
4779				, scale
4780			)
4781		}
4782	}
4783
4784	// clean up
4785	// workernode.parentNode.removeChild(workernode)
4786
4787	return this
4788}
4789
4790})(jsPDF.API);
4791/** @preserve
4792 * jsPDF split_text_to_size plugin - MIT license.
4793 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
4794 *               2014 Diego Casorran, https://github.com/diegocr
4795 */
4796/**
4797 * Permission is hereby granted, free of charge, to any person obtaining
4798 * a copy of this software and associated documentation files (the
4799 * "Software"), to deal in the Software without restriction, including
4800 * without limitation the rights to use, copy, modify, merge, publish,
4801 * distribute, sublicense, and/or sell copies of the Software, and to
4802 * permit persons to whom the Software is furnished to do so, subject to
4803 * the following conditions:
4804 *
4805 * The above copyright notice and this permission notice shall be
4806 * included in all copies or substantial portions of the Software.
4807 *
4808 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4809 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4810 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
4811 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
4812 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
4813 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
4814 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4815 * ====================================================================
4816 */
4817
4818;(function(API) {
4819'use strict'
4820
4821/**
4822Returns an array of length matching length of the 'word' string, with each
4823cell ocupied by the width of the char in that position.
4824
4825@function
4826@param word {String}
4827@param widths {Object}
4828@param kerning {Object}
4829@returns {Array}
4830*/
4831var getCharWidthsArray = API.getCharWidthsArray = function(text, options){
4832
4833	if (!options) {
4834		options = {}
4835	}
4836
4837	var widths = options.widths ? options.widths : this.internal.getFont().metadata.Unicode.widths
4838	, widthsFractionOf = widths.fof ? widths.fof : 1
4839	, kerning = options.kerning ? options.kerning : this.internal.getFont().metadata.Unicode.kerning
4840	, kerningFractionOf = kerning.fof ? kerning.fof : 1
4841
4842	// console.log("widths, kergnings", widths, kerning)
4843
4844	var i, l
4845	, char_code
4846	, prior_char_code = 0 // for kerning
4847	, default_char_width = widths[0] || widthsFractionOf
4848	, output = []
4849
4850	for (i = 0, l = text.length; i < l; i++) {
4851		char_code = text.charCodeAt(i)
4852		output.push(
4853			( widths[char_code] || default_char_width ) / widthsFractionOf +
4854			( kerning[char_code] && kerning[char_code][prior_char_code] || 0 ) / kerningFractionOf
4855		)
4856		prior_char_code = char_code
4857	}
4858
4859	return output
4860}
4861var getArraySum = function(array){
4862	var i = array.length
4863	, output = 0
4864	while(i){
4865		;i--;
4866		output += array[i]
4867	}
4868	return output
4869}
4870/**
4871Returns a widths of string in a given font, if the font size is set as 1 point.
4872
4873In other words, this is "proportional" value. For 1 unit of font size, the length
4874of the string will be that much.
4875
4876Multiply by font size to get actual width in *points*
4877Then divide by 72 to get inches or divide by (72/25.6) to get 'mm' etc.
4878
4879@public
4880@function
4881@param
4882@returns {Type}
4883*/
4884var getStringUnitWidth = API.getStringUnitWidth = function(text, options) {
4885	return getArraySum(getCharWidthsArray.call(this, text, options))
4886}
4887
4888/**
4889returns array of lines
4890*/
4891var splitLongWord = function(word, widths_array, firstLineMaxLen, maxLen){
4892	var answer = []
4893
4894	// 1st, chop off the piece that can fit on the hanging line.
4895	var i = 0
4896	, l = word.length
4897	, workingLen = 0
4898	while (i !== l && workingLen + widths_array[i] < firstLineMaxLen){
4899		workingLen += widths_array[i]
4900		;i++;
4901	}
4902	// this is first line.
4903	answer.push(word.slice(0, i))
4904
4905	// 2nd. Split the rest into maxLen pieces.
4906	var startOfLine = i
4907	workingLen = 0
4908	while (i !== l){
4909		if (workingLen + widths_array[i] > maxLen) {
4910			answer.push(word.slice(startOfLine, i))
4911			workingLen = 0
4912			startOfLine = i
4913		}
4914		workingLen += widths_array[i]
4915		;i++;
4916	}
4917	if (startOfLine !== i) {
4918		answer.push(word.slice(startOfLine, i))
4919	}
4920
4921	return answer
4922}
4923
4924// Note, all sizing inputs for this function must be in "font measurement units"
4925// By default, for PDF, it's "point".
4926var splitParagraphIntoLines = function(text, maxlen, options){
4927	// at this time works only on Western scripts, ones with space char
4928	// separating the words. Feel free to expand.
4929
4930	if (!options) {
4931		options = {}
4932	}
4933
4934	var line = []
4935	, lines = [line]
4936	, line_length = options.textIndent || 0
4937	, separator_length = 0
4938	, current_word_length = 0
4939	, word
4940	, widths_array
4941	, words = text.split(' ')
4942	, spaceCharWidth = getCharWidthsArray(' ', options)[0]
4943	, i, l, tmp, lineIndent
4944
4945	if(options.lineIndent === -1) {
4946		lineIndent = words[0].length +2;
4947	} else {
4948		lineIndent = options.lineIndent || 0;
4949	}
4950	if(lineIndent) {
4951		var pad = Array(lineIndent).join(" "), wrds = [];
4952		words.map(function(wrd) {
4953			wrd = wrd.split(/\s*\n/);
4954			if(wrd.length > 1) {
4955				wrds = wrds.concat(wrd.map(function(wrd, idx) {
4956					return (idx && wrd.length ? "\n":"") + wrd;
4957				}));
4958			} else {
4959				wrds.push(wrd[0]);
4960			}
4961		});
4962		words = wrds;
4963		lineIndent = getStringUnitWidth(pad, options);
4964	}
4965
4966	for (i = 0, l = words.length; i < l; i++) {
4967		var force = 0;
4968
4969		word = words[i]
4970		if(lineIndent && word[0] == "\n") {
4971			word = word.substr(1);
4972			force = 1;
4973		}
4974		widths_array = getCharWidthsArray(word, options)
4975		current_word_length = getArraySum(widths_array)
4976
4977		if (line_length + separator_length + current_word_length > maxlen || force) {
4978			if (current_word_length > maxlen) {
4979				// this happens when you have space-less long URLs for example.
4980				// we just chop these to size. We do NOT insert hiphens
4981				tmp = splitLongWord(word, widths_array, maxlen - (line_length + separator_length), maxlen)
4982				// first line we add to existing line object
4983				line.push(tmp.shift()) // it's ok to have extra space indicator there
4984				// last line we make into new line object
4985				line = [tmp.pop()]
4986				// lines in the middle we apped to lines object as whole lines
4987				while(tmp.length){
4988					lines.push([tmp.shift()]) // single fragment occupies whole line
4989				}
4990				current_word_length = getArraySum( widths_array.slice(word.length - line[0].length) )
4991			} else {
4992				// just put it on a new line
4993				line = [word]
4994			}
4995
4996			// now we attach new line to lines
4997			lines.push(line)
4998			line_length = current_word_length + lineIndent
4999			separator_length = spaceCharWidth
5000
5001		} else {
5002			line.push(word)
5003
5004			line_length += separator_length + current_word_length
5005			separator_length = spaceCharWidth
5006		}
5007	}
5008
5009	if(lineIndent) {
5010		var postProcess = function(ln, idx) {
5011			return (idx ? pad : '') + ln.join(" ");
5012		};
5013	} else {
5014		var postProcess = function(ln) { return ln.join(" ")};
5015	}
5016
5017	return lines.map(postProcess);
5018}
5019
5020/**
5021Splits a given string into an array of strings. Uses 'size' value
5022(in measurement units declared as default for the jsPDF instance)
5023and the font's "widths" and "Kerning" tables, where availabe, to
5024determine display length of a given string for a given font.
5025
5026We use character's 100% of unit size (height) as width when Width
5027table or other default width is not available.
5028
5029@public
5030@function
5031@param text {String} Unencoded, regular JavaScript (Unicode, UTF-16 / UCS-2) string.
5032@param size {Number} Nominal number, measured in units default to this instance of jsPDF.
5033@param options {Object} Optional flags needed for chopper to do the right thing.
5034@returns {Array} with strings chopped to size.
5035*/
5036API.splitTextToSize = function(text, maxlen, options) {
5037	'use strict'
5038
5039	if (!options) {
5040		options = {}
5041	}
5042
5043	var fsize = options.fontSize || this.internal.getFontSize()
5044	, newOptions = (function(options){
5045		var widths = {0:1}
5046		, kerning = {}
5047
5048		if (!options.widths || !options.kerning) {
5049			var f = this.internal.getFont(options.fontName, options.fontStyle)
5050			, encoding = 'Unicode'
5051			// NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE
5052			// Actual JavaScript-native String's 16bit char codes used.
5053			// no multi-byte logic here
5054
5055			if (f.metadata[encoding]) {
5056				return {
5057					widths: f.metadata[encoding].widths || widths
5058					, kerning: f.metadata[encoding].kerning || kerning
5059				}
5060			}
5061		} else {
5062			return 	{
5063				widths: options.widths
5064				, kerning: options.kerning
5065			}
5066		}
5067
5068		// then use default values
5069		return 	{
5070			widths: widths
5071			, kerning: kerning
5072		}
5073	}).call(this, options)
5074
5075	// first we split on end-of-line chars
5076	var paragraphs
5077	if(Array.isArray(text)) {
5078		paragraphs = text;
5079	} else {
5080		paragraphs = text.split(/\r?\n/);
5081	}
5082
5083	// now we convert size (max length of line) into "font size units"
5084	// at present time, the "font size unit" is always 'point'
5085	// 'proportional' means, "in proportion to font size"
5086	var fontUnit_maxLen = 1.0 * this.internal.scaleFactor * maxlen / fsize
5087	// at this time, fsize is always in "points" regardless of the default measurement unit of the doc.
5088	// this may change in the future?
5089	// until then, proportional_maxlen is likely to be in 'points'
5090
5091	// If first line is to be indented (shorter or longer) than maxLen
5092	// we indicate that by using CSS-style "text-indent" option.
5093	// here it's in font units too (which is likely 'points')
5094	// it can be negative (which makes the first line longer than maxLen)
5095	newOptions.textIndent = options.textIndent ?
5096		options.textIndent * 1.0 * this.internal.scaleFactor / fsize :
5097		0
5098	newOptions.lineIndent = options.lineIndent;
5099
5100	var i, l
5101	, output = []
5102	for (i = 0, l = paragraphs.length; i < l; i++) {
5103		output = output.concat(
5104			splitParagraphIntoLines(
5105				paragraphs[i]
5106				, fontUnit_maxLen
5107				, newOptions
5108			)
5109		)
5110	}
5111
5112	return output
5113}
5114
5115})(jsPDF.API);
5116/** @preserve 
5117jsPDF standard_fonts_metrics plugin
5118Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
5119MIT license.
5120*/
5121/**
5122 * Permission is hereby granted, free of charge, to any person obtaining
5123 * a copy of this software and associated documentation files (the
5124 * "Software"), to deal in the Software without restriction, including
5125 * without limitation the rights to use, copy, modify, merge, publish,
5126 * distribute, sublicense, and/or sell copies of the Software, and to
5127 * permit persons to whom the Software is furnished to do so, subject to
5128 * the following conditions:
5129 * 
5130 * The above copyright notice and this permission notice shall be
5131 * included in all copies or substantial portions of the Software.
5132 * 
5133 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
5134 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
5135 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
5136 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
5137 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
5138 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
5139 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5140 * ====================================================================
5141 */
5142
5143;(function(API) {
5144'use strict'
5145
5146/*
5147# reference (Python) versions of 'compress' and 'uncompress'
5148# only 'uncompress' function is featured lower as JavaScript
5149# if you want to unit test "roundtrip", just transcribe the reference
5150# 'compress' function from Python into JavaScript
5151
5152def compress(data):
5153
5154	keys =   '0123456789abcdef'
5155	values = 'klmnopqrstuvwxyz'
5156	mapping = dict(zip(keys, values))
5157	vals = []
5158	for key in data.keys():
5159		value = data[key]
5160		try:
5161			keystring = hex(key)[2:]
5162			keystring = keystring[:-1] + mapping[keystring[-1:]]
5163		except:
5164			keystring = key.join(["'","'"])
5165			#print('Keystring is %s' % keystring)
5166
5167		try:
5168			if value < 0:
5169				valuestring = hex(value)[3:]
5170				numberprefix = '-'
5171			else:
5172				valuestring = hex(value)[2:]
5173				numberprefix = ''
5174			valuestring = numberprefix + valuestring[:-1] + mapping[valuestring[-1:]]
5175		except:
5176			if type(value) == dict:
5177				valuestring = compress(value)
5178			else:
5179				raise Exception("Don't know what to do with value type %s" % type(value))
5180
5181		vals.append(keystring+valuestring)
5182	
5183	return '{' + ''.join(vals) + '}'
5184
5185def uncompress(data):
5186
5187	decoded = '0123456789abcdef'
5188	encoded = 'klmnopqrstuvwxyz'
5189	mapping = dict(zip(encoded, decoded))
5190
5191	sign = +1
5192	stringmode = False
5193	stringparts = []
5194
5195	output = {}
5196
5197	activeobject = output
5198	parentchain = []
5199
5200	keyparts = ''
5201	valueparts = ''
5202
5203	key = None
5204
5205	ending = set(encoded)
5206
5207	i = 1
5208	l = len(data) - 1 # stripping starting, ending {}
5209	while i != l: # stripping {}
5210		# -, {, }, ' are special.
5211
5212		ch = data[i]
5213		i += 1
5214
5215		if ch == "'":
5216			if stringmode:
5217				# end of string mode
5218				stringmode = False
5219				key = ''.join(stringparts)
5220			else:
5221				# start of string mode
5222				stringmode = True
5223				stringparts = []
5224		elif stringmode == True:
5225			#print("Adding %s to stringpart" % ch)
5226			stringparts.append(ch)
5227
5228		elif ch == '{':
5229			# start of object
5230			parentchain.append( [activeobject, key] )
5231			activeobject = {}
5232			key = None
5233			#DEBUG = True
5234		elif ch == '}':
5235			# end of object
5236			parent, key = parentchain.pop()
5237			parent[key] = activeobject
5238			key = None
5239			activeobject = parent
5240			#DEBUG = False
5241
5242		elif ch == '-':
5243			sign = -1
5244		else:
5245			# must be number
5246			if key == None:
5247				#debug("In Key. It is '%s', ch is '%s'" % (keyparts, ch))
5248				if ch in ending:
5249					#debug("End of key")
5250					keyparts += mapping[ch]
5251					key = int(keyparts, 16) * sign
5252					sign = +1
5253					keyparts = ''
5254				else:
5255					keyparts += ch
5256			else:
5257				#debug("In value. It is '%s', ch is '%s'" % (valueparts, ch))
5258				if ch in ending:
5259					#debug("End of value")
5260					valueparts += mapping[ch]
5261					activeobject[key] = int(valueparts, 16) * sign
5262					sign = +1
5263					key = None
5264					valueparts = ''
5265				else:
5266					valueparts += ch
5267
5268			#debug(activeobject)
5269
5270	return output
5271
5272*/
5273
5274/**
5275Uncompresses data compressed into custom, base16-like format. 
5276@public
5277@function
5278@param
5279@returns {Type}
5280*/
5281var uncompress = function(data){
5282
5283	var decoded = '0123456789abcdef'
5284	, encoded = 'klmnopqrstuvwxyz'
5285	, mapping = {}
5286
5287	for (var i = 0; i < encoded.length; i++){
5288		mapping[encoded[i]] = decoded[i]
5289	}
5290
5291	var undef
5292	, output = {}
5293	, sign = 1
5294	, stringparts // undef. will be [] in string mode
5295	
5296	, activeobject = output
5297	, parentchain = []
5298	, parent_key_pair
5299	, keyparts = ''
5300	, valueparts = ''
5301	, key // undef. will be Truthy when Key is resolved.
5302	, datalen = data.length - 1 // stripping ending }
5303	, ch
5304
5305	i = 1 // stripping starting {
5306	
5307	while (i != datalen){
5308		// - { } ' are special.
5309
5310		ch = data[i]
5311		i += 1
5312
5313		if (ch == "'"){
5314			if (stringparts){
5315				// end of string mode
5316				key = stringparts.join('')
5317				stringparts = undef				
5318			} else {
5319				// start of string mode
5320				stringparts = []				
5321			}
5322		} else if (stringparts){
5323			stringparts.push(ch)
5324		} else if (ch == '{'){
5325			// start of object
5326			parentchain.push( [activeobject, key] )
5327			activeobject = {}
5328			key = undef
5329		} else if (ch == '}'){
5330			// end of object
5331			parent_key_pair = parentchain.pop()
5332			parent_key_pair[0][parent_key_pair[1]] = activeobject
5333			key = undef
5334			activeobject = parent_key_pair[0]
5335		} else if (ch == '-'){
5336			sign = -1
5337		} else {
5338			// must be number
5339			if (key === undef) {
5340				if (mapping.hasOwnProperty(ch)){
5341					keyparts += mapping[ch]
5342					key = parseInt(keyparts, 16) * sign
5343					sign = +1
5344					keyparts = ''
5345				} else {
5346					keyparts += ch
5347				}
5348			} else {
5349				if (mapping.hasOwnProperty(ch)){
5350					valueparts += mapping[ch]
5351					activeobject[key] = parseInt(valueparts, 16) * sign
5352					sign = +1
5353					key = undef
5354					valueparts = ''
5355				} else {
5356					valueparts += ch					
5357				}
5358			}
5359		}
5360	} // end while
5361
5362	return output
5363}
5364
5365// encoding = 'Unicode' 
5366// NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE. NO clever BOM behavior
5367// Actual 16bit char codes used.
5368// no multi-byte logic here
5369
5370// Unicode characters to WinAnsiEncoding:
5371// {402: 131, 8211: 150, 8212: 151, 8216: 145, 8217: 146, 8218: 130, 8220: 147, 8221: 148, 8222: 132, 8224: 134, 8225: 135, 8226: 149, 8230: 133, 8364: 128, 8240:137, 8249: 139, 8250: 155, 710: 136, 8482: 153, 338: 140, 339: 156, 732: 152, 352: 138, 353: 154, 376: 159, 381: 142, 382: 158}
5372// as you can see, all Unicode chars are outside of 0-255 range. No char code conflicts.
5373// this means that you can give Win cp1252 encoded strings to jsPDF for rendering directly
5374// as well as give strings with some (supported by these fonts) Unicode characters and 
5375// these will be mapped to win cp1252 
5376// for example, you can send char code (cp1252) 0x80 or (unicode) 0x20AC, getting "Euro" glyph displayed in both cases.
5377
5378var encodingBlock = {
5379	'codePages': ['WinAnsiEncoding']
5380	, 'WinAnsiEncoding': uncompress("{19m8n201n9q201o9r201s9l201t9m201u8m201w9n201x9o201y8o202k8q202l8r202m9p202q8p20aw8k203k8t203t8v203u9v2cq8s212m9t15m8w15n9w2dw9s16k8u16l9u17s9z17x8y17y9y}")
5381}
5382, encodings = {'Unicode':{
5383	'Courier': encodingBlock
5384	, 'Courier-Bold': encodingBlock
5385	, 'Courier-BoldOblique': encodingBlock
5386	, 'Courier-Oblique': encodingBlock
5387	, 'Helvetica': encodingBlock
5388	, 'Helvetica-Bold': encodingBlock
5389	, 'Helvetica-BoldOblique': encodingBlock
5390	, 'Helvetica-Oblique': encodingBlock
5391	, 'Times-Roman': encodingBlock
5392	, 'Times-Bold': encodingBlock
5393	, 'Times-BoldItalic': encodingBlock
5394	, 'Times-Italic': encodingBlock
5395//	, 'Symbol'
5396//	, 'ZapfDingbats'
5397}}
5398/** 
5399Resources:
5400Font metrics data is reprocessed derivative of contents of
5401"Font Metrics for PDF Core 14 Fonts" package, which exhibits the following copyright and license:
5402
5403Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
5404
5405This file and the 14 PostScript(R) AFM files it accompanies may be used,
5406copied, and distributed for any purpose and without charge, with or without
5407modification, provided that all copyright notices are retained; that the AFM
5408files are not distributed without this file; that all modifications to this
5409file or any of the AFM files are prominently noted in the modified file(s);
5410and that this paragraph is not modified. Adobe Systems has no responsibility
5411or obligation to support the use of the AFM files.
5412
5413*/
5414, fontMetrics = {'Unicode':{
5415	// all sizing numbers are n/fontMetricsFractionOf = one font size unit
5416	// this means that if fontMetricsFractionOf = 1000, and letter A's width is 476, it's
5417	// width is 476/1000 or 47.6% of its height (regardless of font size)
5418	// At this time this value applies to "widths" and "kerning" numbers.
5419
5420	// char code 0 represents "default" (average) width - use it for chars missing in this table.
5421	// key 'fof' represents the "fontMetricsFractionOf" value
5422
5423	'Courier-Oblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}")
5424	, 'Times-BoldItalic': uncompress("{'widths'{k3o2q4ycx2r201n3m201o6o201s2l201t2l201u2l201w3m201x3m201y3m2k1t2l2r202m2n2n3m2o3m2p5n202q6o2r1w2s2l2t2l2u3m2v3t2w1t2x2l2y1t2z1w3k3m3l3m3m3m3n3m3o3m3p3m3q3m3r3m3s3m203t2l203u2l3v2l3w3t3x3t3y3t3z3m4k5n4l4m4m4m4n4m4o4s4p4m4q4m4r4s4s4y4t2r4u3m4v4m4w3x4x5t4y4s4z4s5k3x5l4s5m4m5n3r5o3x5p4s5q4m5r5t5s4m5t3x5u3x5v2l5w1w5x2l5y3t5z3m6k2l6l3m6m3m6n2w6o3m6p2w6q2l6r3m6s3r6t1w6u1w6v3m6w1w6x4y6y3r6z3m7k3m7l3m7m2r7n2r7o1w7p3r7q2w7r4m7s3m7t2w7u2r7v2n7w1q7x2n7y3t202l3mcl4mal2ram3man3mao3map3mar3mas2lat4uau1uav3maw3way4uaz2lbk2sbl3t'fof'6obo2lbp3tbq3mbr1tbs2lbu1ybv3mbz3mck4m202k3mcm4mcn4mco4mcp4mcq5ycr4mcs4mct4mcu4mcv4mcw2r2m3rcy2rcz2rdl4sdm4sdn4sdo4sdp4sdq4sds4sdt4sdu4sdv4sdw4sdz3mek3mel3mem3men3meo3mep3meq4ser2wes2wet2weu2wev2wew1wex1wey1wez1wfl3rfm3mfn3mfo3mfp3mfq3mfr3tfs3mft3rfu3rfv3rfw3rfz2w203k6o212m6o2dw2l2cq2l3t3m3u2l17s3x19m3m}'kerning'{cl{4qu5kt5qt5rs17ss5ts}201s{201ss}201t{cks4lscmscnscoscpscls2wu2yu201ts}201x{2wu2yu}2k{201ts}2w{4qx5kx5ou5qx5rs17su5tu}2x{17su5tu5ou}2y{4qx5kx5ou5qx5rs17ss5ts}'fof'-6ofn{17sw5tw5ou5qw5rs}7t{cksclscmscnscoscps4ls}3u{17su5tu5os5qs}3v{17su5tu5os5qs}7p{17su5tu}ck{4qu5kt5qt5rs17ss5ts}4l{4qu5kt5qt5rs17ss5ts}cm{4qu5kt5qt5rs17ss5ts}cn{4qu5kt5qt5rs17ss5ts}co{4qu5kt5qt5rs17ss5ts}cp{4qu5kt5qt5rs17ss5ts}6l{4qu5ou5qw5rt17su5tu}5q{ckuclucmucnucoucpu4lu}5r{ckuclucmucnucoucpu4lu}7q{cksclscmscnscoscps4ls}6p{4qu5ou5qw5rt17sw5tw}ek{4qu5ou5qw5rt17su5tu}el{4qu5ou5qw5rt17su5tu}em{4qu5ou5qw5rt17su5tu}en{4qu5ou5qw5rt17su5tu}eo{4qu5ou5qw5rt17su5tu}ep{4qu5ou5qw5rt17su5tu}es{17ss5ts5qs4qu}et{4qu5ou5qw5rt17sw5tw}eu{4qu5ou5qw5rt17ss5ts}ev{17ss5ts5qs4qu}6z{17sw5tw5ou5qw5rs}fm{17sw5tw5ou5qw5rs}7n{201ts}fo{17sw5tw5ou5qw5rs}fp{17sw5tw5ou5qw5rs}fq{17sw5tw5ou5qw5rs}7r{cksclscmscnscoscps4ls}fs{17sw5tw5ou5qw5rs}ft{17su5tu}fu{17su5tu}fv{17su5tu}fw{17su5tu}fz{cksclscmscnscoscps4ls}}}")
5425	, 'Helvetica-Bold': uncompress("{'widths'{k3s2q4scx1w201n3r201o6o201s1w201t1w201u1w201w3m201x3m201y3m2k1w2l2l202m2n2n3r2o3r2p5t202q6o2r1s2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v2l3w3u3x3u3y3u3z3x4k6l4l4s4m4s4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3r4v4s4w3x4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v2l5w1w5x2l5y3u5z3r6k2l6l3r6m3x6n3r6o3x6p3r6q2l6r3x6s3x6t1w6u1w6v3r6w1w6x5t6y3x6z3x7k3x7l3x7m2r7n3r7o2l7p3x7q3r7r4y7s3r7t3r7u3m7v2r7w1w7x2r7y3u202l3rcl4sal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3xbq3rbr1wbs2lbu2obv3rbz3xck4s202k3rcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw1w2m2zcy1wcz1wdl4sdm4y
5425dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3res3ret3reu3rev3rew1wex1wey1wez1wfl3xfm3xfn3xfo3xfp3xfq3xfr3ufs3xft3xfu3xfv3xfw3xfz3r203k6o212m6o2dw2l2cq2l3t3r3u2l17s4m19m3r}'kerning'{cl{4qs5ku5ot5qs17sv5tv}201t{2ww4wy2yw}201w{2ks}201x{2ww4wy2yw}2k{201ts201xs}2w{7qs4qu5kw5os5qw5rs17su5tu7tsfzs}2x{5ow5qs}2y{7qs4qu5kw5os5qw5rs17su5tu7tsfzs}'fof'-6o7p{17su5tu5ot}ck{4qs5ku5ot5qs17sv5tv}4l{4qs5ku5ot5qs17sv5tv}cm{4qs5ku5ot5qs17sv5tv}cn{4qs5ku5ot5qs17sv5tv}co{4qs5ku5ot5qs17sv5tv}cp{4qs5ku5ot5qs17sv5tv}6l{17st5tt5os}17s{2kwclvcmvcnvcovcpv4lv4wwckv}5o{2kucltcmtcntcotcpt4lt4wtckt}5q{2ksclscmscnscoscps4ls4wvcks}5r{2ks4ws}5t{2kwclvcmvcnvcovcpv4lv4wwckv}eo{17st5tt5os}fu{17su5tu5ot}6p{17ss5ts}ek{17st5tt5os}el{17st5tt5os}em{17st5tt5os}en{17st5tt5os}6o{201ts}ep{17st5tt5os}es{17ss5ts}et{17ss5ts}eu{17ss5ts}ev{17ss5ts}6z{17su5tu5os5qt}fm{17su5tu5os5qt}fn{17su5tu5os5qt}fo{17su5tu5os5qt}fp{17su5tu5os5qt}fq{17su5tu5os5qt}fs{17su5tu5os5qt}ft{17su5tu5ot}7m{5os}fv{17su5tu5ot}fw{17su5tu5ot}}}")
5426	, 'Courier': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}")
5427	, 'Courier-BoldOblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}")
5428	, 'Times-Bold': uncompress("{'widths'{k3q2q5ncx2r201n3m201o6o201s2l201t2l201u2l201w3m201x3m201y3m2k1t2l2l202m2n2n3m2o3m2p6o202q6o2r1w2s2l2t2l2u3m2v3t2w1t2x2l2y1t2z1w3k3m3l3m3m3m3n3m3o3m3p3m3q3m3r3m3s3m203t2l203u2l3v2l3w3t3x3t3y3t3z3m4k5x4l4s4m4m4n4s4o4s4p4m4q3x4r4y4s4y4t2r4u3m4v4y4w4m4x5y4y4s4z4y5k3x5l4y5m4s5n3r5o4m5p4s5q4s5r6o5s4s5t4s5u4m5v2l5w1w5x2l5y3u5z3m6k2l6l3m6m3r6n2w6o3r6p2w6q2l6r3m6s3r6t1w6u2l6v3r6w1w6x5n6y3r6z3m7k3r7l3r7m2w7n2r7o2l7p3r7q3m7r4s7s3m7t3m7u2w7v2r7w1q7x2r7y3o202l3mcl4sal2lam3man3mao3map3mar3mas2lat4uau1yav3maw3tay4uaz2lbk2sbl3t'fof'6obo2lbp3rbr1tbs2lbu2lbv3mbz3mck4s202k3mcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw2r2m3rcy2rcz2rdl4sdm4ydn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3rek3mel3mem3men3meo3mep3meq4ser2wes2wet2weu2wev2wew1wex1wey1wez1wfl3rfm3mfn3mfo3mfp3mfq3mfr3tfs3mft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3m3u2l17s4s19m3m}'kerning'{cl{4qt5ks5ot5qy5rw17sv5tv}201t{cks4lscmscnscoscpscls4wv}2k{201ts}2w{4qu5ku7mu5os5qx5ru17su5tu}2x{17su5tu5ou5qs}2y{4qv5kv7mu5ot5qz5ru17su5tu}'fof'-6o7t{cksclscmscnscoscps4ls}3u{17su5tu5os5qu}3v{17su5tu5os5qu}fu{17su5tu5ou5qu}7p{17su5tu5ou5qu}ck{4qt5ks5ot5qy5rw17sv5tv}4l{4qt5ks5ot5qy5rw17sv5tv}cm{4qt5ks5ot5qy5rw17sv5tv}cn{4qt5ks5ot5qy5rw17sv5tv}co{4qt5ks5ot5qy5rw17sv5tv}cp{4qt5ks5ot5qy5rw17sv5tv}6l{17st5tt5ou5qu}17s{ckuclucmucnucoucpu4lu4wu}5o{ckuclucmucnucoucpu4lu4wu}5q{ckzclzcmzcnzcozcpz4lz4wu}5r{ckxclxcmxcnxcoxcpx4lx4wu}5t{ckuclucmucnucoucpu4lu4wu}7q{ckuclucmucnucoucpu4lu}6p{17sw5tw5ou5qu}ek{17st5tt5qu}el{17st5tt5ou5qu}em{17st5tt5qu}en{17st5tt5qu}eo{17st5tt5qu}ep{17st5tt5ou5qu}es{17ss5ts5qu}et{17sw5tw5ou5qu}eu{17sw5tw5ou5qu}ev{17ss5ts5qu}6z{17sw5tw5ou5qu5rs}fm{17sw5tw5ou5qu5rs}fn{17sw5tw5ou5qu5rs}fo{17sw5tw5ou5qu5rs}fp{17sw5tw5ou5qu5rs}fq{17sw5tw5ou5qu5rs}7r{cktcltcmtcntcotcpt4lt5os}fs{17sw5tw5ou5qu5rs}ft{17su5tu5ou5qu}7m{5os}fv{17su5tu5ou5qu}fw{17su5tu5ou5qu}fz{cksclscmscnscoscps4ls}}}")
5429	//, 'Symbol': uncompress("{'widths'{k3uaw4r19m3m2k1t2l2l202m2y2n3m2p5n202q6o3k3m2s2l2t2l2v3r2w1t3m3m2y1t2z1wbk2sbl3r'fof'6o3n3m3o3m3p3m3q3m3r3m3s3m3t3m3u1w3v1w3w3r3x3r3y3r3z2wbp3t3l3m5v2l5x2l5z3m2q4yfr3r7v3k7w1o7x3k}'kerning'{'fof'-6o}}")
5430	, 'Helvetica': uncompress("{'widths'{k3p2q4mcx1w201n3r201o6o201s1q201t1q201u1q201w2l201x2l201y2l2k1w2l1w202m2n2n3r2o3r2p5t202q6o2r1n2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v1w3w3u3x3u3y3u3z3r4k6p4l4m4m4m4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3m4v4m4w3r4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v1w5w1w5x1w5y2z5z3r6k2l6l3r6m3r6n3m6o3r6p3r6q1w6r3r6s3r6t1q6u1q6v3m6w1q6x5n6y3r6z3r7k3r7l3r7m2l7n3m7o1w7p3r7q3m7r4s7s3m7t3m7u3m7v2l7w1u7x2l7y3u202l3rcl4mal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3rbr1wbs2lbu2obv3rbz3xck4m202k3rcm4mcn4mco4mcp4mcq6ocr4scs4mct4mcu4mcv4mcw1w2m2ncy1wcz1wdl4sdm4y
5430dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3mes3ret3reu3rev3rew1wex1wey1wez1wfl3rfm3rfn3rfo3rfp3rfq3rfr3ufs3xft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3r3u1w17s4m19m3r}'kerning'{5q{4wv}cl{4qs5kw5ow5qs17sv5tv}201t{2wu4w1k2yu}201x{2wu4wy2yu}17s{2ktclucmucnu4otcpu4lu4wycoucku}2w{7qs4qz5k1m17sy5ow5qx5rsfsu5ty7tufzu}2x{17sy5ty5oy5qs}2y{7qs4qz5k1m17sy5ow5qx5rsfsu5ty7tufzu}'fof'-6o7p{17sv5tv5ow}ck{4qs5kw5ow5qs17sv5tv}4l{4qs5kw5ow5qs17sv5tv}cm{4qs5kw5ow5qs17sv5tv}cn{4qs5kw5ow5qs17sv5tv}co{4qs5kw5ow5qs17sv5tv}cp{4qs5kw5ow5qs17sv5tv}6l{17sy5ty5ow}do{17st5tt}4z{17st5tt}7s{fst}dm{17st5tt}dn{17st5tt}5o{ckwclwcmwcnwcowcpw4lw4wv}dp{17st5tt}dq{17st5tt}7t{5ow}ds{17st5tt}5t{2ktclucmucnu4otcpu4lu4wycoucku}fu{17sv5tv5ow}6p{17sy5ty5ow5qs}ek{17sy5ty5ow}el{17sy5ty5ow}em{17sy5ty5ow}en{5ty}eo{17sy5ty5ow}ep{17sy5ty5ow}es{17sy5ty5qs}et{17sy5ty5ow5qs}eu{17sy5ty5ow5qs}ev{17sy5ty5ow5qs}6z{17sy5ty5ow5qs}fm{17sy5ty5ow5qs}fn{17sy5ty5ow5qs}fo{17sy5ty5ow5qs}fp{17sy5ty5qs}fq{17sy5ty5ow5qs}7r{5ow}fs{17sy5ty5ow5qs}ft{17sv5tv5ow}7m{5ow}fv{17sv5tv5ow}fw{17sv5tv5ow}}}")
5431	, 'Helvetica-BoldOblique': uncompress("{'widths'{k3s2q4scx1w201n3r201o6o201s1w201t1w201u1w201w3m201x3m201y3m2k1w2l2l202m2n2n3r2o3r2p5t202q6o2r1s2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v2l3w3u3x3u3y3u3z3x4k6l4l4s4m4s4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3r4v4s4w3x4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v2l5w1w5x2l5y3u5z3r6k2l6l3r6m3x6n3r6o3x6p3r6q2l6r3x6s3x6t1w6u1w6v3r6w1w6x5t6y3x6z3x7k3x7l3x7m2r7n3r7o2l7p3x7q3r7r4y7s3r7t3r7u3m7v2r7w1w7x2r7y3u202l3rcl4sal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3xbq3rbr1wbs2lbu2obv3rbz3xck4s202k3rcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw1w2m2zcy1wcz1wdl4sdm4y
5431dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3res3ret3reu3rev3rew1wex1wey1wez1wfl3xfm3xfn3xfo3xfp3xfq3xfr3ufs3xft3xfu3xfv3xfw3xfz3r203k6o212m6o2dw2l2cq2l3t3r3u2l17s4m19m3r}'kerning'{cl{4qs5ku5ot5qs17sv5tv}201t{2ww4wy2yw}201w{2ks}201x{2ww4wy2yw}2k{201ts201xs}2w{7qs4qu5kw5os5qw5rs17su5tu7tsfzs}2x{5ow5qs}2y{7qs4qu5kw5os5qw5rs17su5tu7tsfzs}'fof'-6o7p{17su5tu5ot}ck{4qs5ku5ot5qs17sv5tv}4l{4qs5ku5ot5qs17sv5tv}cm{4qs5ku5ot5qs17sv5tv}cn{4qs5ku5ot5qs17sv5tv}co{4qs5ku5ot5qs17sv5tv}cp{4qs5ku5ot5qs17sv5tv}6l{17st5tt5os}17s{2kwclvcmvcnvcovcpv4lv4wwckv}5o{2kucltcmtcntcotcpt4lt4wtckt}5q{2ksclscmscnscoscps4ls4wvcks}5r{2ks4ws}5t{2kwclvcmvcnvcovcpv4lv4wwckv}eo{17st5tt5os}fu{17su5tu5ot}6p{17ss5ts}ek{17st5tt5os}el{17st5tt5os}em{17st5tt5os}en{17st5tt5os}6o{201ts}ep{17st5tt5os}es{17ss5ts}et{17ss5ts}eu{17ss5ts}ev{17ss5ts}6z{17su5tu5os5qt}fm{17su5tu5os5qt}fn{17su5tu5os5qt}fo{17su5tu5os5qt}fp{17su5tu5os5qt}fq{17su5tu5os5qt}fs{17su5tu5os5qt}ft{17su5tu5ot}7m{5os}fv{17su5tu5ot}fw{17su5tu5ot}}}")
5432	//, 'ZapfDingbats': uncompress("{'widths'{k4u2k1w'fof'6o}'kerning'{'fof'-6o}}")
5433	, 'Courier-Bold': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}")
5434	, 'Times-Italic': uncompress("{'widths'{k3n2q4ycx2l201n3m201o5t201s2l201t2l201u2l201w3r201x3r201y3r2k1t2l2l202m2n2n3m2o3m2p5n202q5t2r1p2s2l2t2l2u3m2v4n2w1t2x2l2y1t2z1w3k3m3l3m3m3m3n3m3o3m3p3m3q3m3r3m3s3m203t2l203u2l3v2l3w4n3x4n3y4n3z3m4k5w4l3x4m3x4n4m4o4s4p3x4q3x4r4s4s4s4t2l4u2w4v4m4w3r4x5n4y4m4z4s5k3x5l4s5m3x5n3m5o3r5p4s5q3x5r5n5s3x5t3r5u3r5v2r5w1w5x2r5y2u5z3m6k2l6l3m6m3m6n2w6o3m6p2w6q1w6r3m6s3m6t1w6u1w6v2w6w1w6x4s6y3m6z3m7k3m7l3m7m2r7n2r7o1w7p3m7q2w7r4m7s2w7t2w7u2r7v2s7w1v7x2s7y3q202l3mcl3xal2ram3man3mao3map3mar3mas2lat4wau1vav3maw4nay4waz2lbk2sbl4n'fof'6obo2lbp3mbq3obr1tbs2lbu1zbv3mbz3mck3x202k3mcm3xcn3xco3xcp3xcq5tcr4mcs3xct3xcu3xcv3xcw2l2m2ucy2lcz2ldl4mdm4sdn4sdo4sdp4sdq4sds4sdt4sdu4sdv4sdw4sdz3mek3mel3mem3men3meo3mep3meq4mer2wes2wet2weu2wev2wew1wex1wey1wez1wfl3mfm3mfn3mfo3mfp3mfq3mfr4nfs3mft3mfu3mfv3mfw3mfz2w203k6o212m6m2dw2l2cq2l3t3m3u2l17s3r19m3m}'kerning'{cl{5kt4qw}201s{201sw}201t{201tw2wy2yy6q-t}201x{2wy2yy}2k{201tw}2w{7qs4qy7rs5ky7mw5os5qx5ru17su5tu}2x{17ss5ts5os}2y{7qs4qy7rs5ky7mw5os5qx5ru17su5tu}'fof'-6o6t{17ss5ts5qs}7t{5os}3v{5qs}7p{17su5tu5qs}ck{5kt4qw}4l{5kt4qw}cm{5kt4qw}cn{5kt4qw}co{5kt4qw}cp{5kt4qw}6l{4qs5ks5ou5qw5ru17su5tu}17s{2ks}5q{ckvclvcmvcnvcovcpv4lv}5r{ckuclucmucnucoucpu4lu}5t{2ks}6p{4qs5ks5ou5qw5ru17su5tu}ek{4qs5ks5ou5qw5ru17su5tu}el{4qs5ks5ou5qw5ru17su5tu}em{4qs5ks5ou5qw5ru17su5tu}en{4qs5ks5ou5qw5ru17su5tu}eo{4qs5ks5ou5qw5ru17su5tu}ep{4qs5ks5ou5qw5ru17su5tu}es{5ks5qs4qs}et{4qs5ks5ou5qw5ru17su5tu}eu{4qs5ks5qw5ru17su5tu}ev{5ks5qs4qs}ex{17ss5ts5qs}6z{4qv5ks5ou5qw5ru17su5tu}fm{4qv5ks5ou5qw5ru17su5tu}fn{4qv5ks5ou5qw5ru17su5tu}fo{4qv5ks5ou5qw5ru17su5tu}fp{4qv5ks5ou5qw5ru17su5tu}fq{4qv5ks5ou5qw5ru17su5tu}7r{5os}fs{4qv5ks5ou5qw5ru17su5tu}ft{17su5tu5qs}fu{17su5tu5qs}
5434fv{17su5tu5qs}fw{17su5tu5qs}}}")
5435	, 'Times-Roman': uncompress("{'widths'{k3n2q4ycx2l201n3m201o6o201s2l201t2l201u2l201w2w201x2w201y2w2k1t2l2l202m2n2n3m2o3m2p5n202q6o2r1m2s2l2t2l2u3m2v3s2w1t2x2l2y1t2z1w3k3m3l3m3m3m3n3m3o3m3p3m3q3m3r3m3s3m203t2l203u2l3v1w3w3s3x3s3y3s3z2w4k5w4l4s4m4m4n4m4o4s4p3x4q3r4r4s4s4s4t2l4u2r4v4s4w3x4x5t4y4s4z4s5k3r5l4s5m4m5n3r5o3x5p4s5q4s5r5y5s4s5t4s5u3x5v2l5w1w5x2l5y2z5z3m6k2l6l2w6m3m6n2w6o3m6p2w6q2l6r3m6s3m6t1w6u1w6v3m6w1w6x4y6y3m6z3m7k3m7l3m7m2l7n2r7o1w7p3m7q3m7r4s7s3m7t3m7u2w7v3k7w1o7x3k7y3q202l3mcl4sal2lam3man3mao3map3mar3mas2lat4wau1vav3maw3say4waz2lbk2sbl3s'fof'6obo2lbp3mbq2xbr1tbs2lbu1zbv3mbz2wck4s202k3mcm4scn4sco4scp4scq5tcr4mcs3xct3xcu3xcv3xcw2l2m2tcy2lcz2ldl4sdm4sdn4sdo4sdp4sdq4sds4sdt4sdu4sdv4sdw4sdz3mek2wel2wem2wen2weo2wep2weq4mer2wes2wet2weu2wev2wew1wex1wey1wez1wfl3mfm3mfn3mfo3mfp3mfq3mfr3sfs3mft3mfu3mfv3mfw3mfz3m203k6o212m6m2dw2l2cq2l3t3m3u1w17s4s19m3m}'kerning'{cl{4qs5ku17sw5ou5qy5rw201ss5tw201ws}201s{201ss}201t{ckw4lwcmwcnwcowcpwclw4wu201ts}2k{201ts}2w{4qs5kw5os5qx5ru17sx5tx}2x{17sw5tw5ou5qu}2y{4qs5kw5os5qx5ru17sx5tx}'fof'-6o7t{ckuclucmucnucoucpu4lu5os5rs}3u{17su5tu5qs}3v{17su5tu5qs}7p{17sw5tw5qs}ck{4qs5ku17sw5ou5qy5rw201ss5tw201ws}4l{4qs5ku17sw5ou5qy5rw201ss5tw201ws}cm{4qs5ku17sw5ou5qy5rw201ss5tw201ws}cn{4qs5ku17sw5ou5qy5rw201ss5tw201ws}co{4qs5ku17sw5ou5qy5rw201ss5tw201ws}cp{4qs5ku17sw5ou5qy5rw201ss5tw201ws}6l{17su5tu5os5qw5rs}17s{2ktclvcmvcnvcovcpv4lv4wuckv}5o{ckwclwcmwcnwcowcpw4lw4wu}5q{ckyclycmycnycoycpy4ly4wu5ms}5r{cktcltcmtcntcotcpt4lt4ws}5t{2ktclvcmvcnvcovcpv4lv4wuckv}7q{cksclscmscnscoscps4ls}6p{17su5tu5qw5rs}ek{5qs5rs}el{17su5tu5os5qw5rs}em{17su5tu5os5qs5rs}en{17su5qs5rs}eo{5qs5rs}ep{17su5tu5os5qw5rs}es{5qs}et{17su5tu5qw5rs}eu{17su5tu5qs5rs}ev{5qs}6z{17sv5tv5os5qx5rs}fm{5os5qt5rs}fn{17sv5tv5os5qx5rs}fo{17sv5tv5os5qx5rs}fp{5os5qt5rs}fq{5os5qt5rs}7r{ckuclucmucnucoucpu4lu5os}fs{17sv5tv5os5qx5rs}ft{17ss5ts5qs}fu{17sw5tw5qs}fv{17sw5tw5qs}fw{17ss5ts5qs}fz{ckuclucmucnucoucpu4lu5os5rs}}}")
5436	, 'Helvetica-Oblique': uncompress("{'widths'{k3p2q4mcx1w201n3r201o6o201s1q201t1q201u1q201w2l201x2l201y2l2k1w2l1w202m2n2n3r2o3r2p5t202q6o2r1n2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v1w3w3u3x3u3y3u3z3r4k6p4l4m4m4m4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3m4v4m4w3r4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v1w5w1w5x1w5y2z5z3r6k2l6l3r6m3r6n3m6o3r6p3r6q1w6r3r6s3r6t1q6u1q6v3m6w1q6x5n6y3r6z3r7k3r7l3r7m2l7n3m7o1w7p3r7q3m7r4s7s3m7t3m7u3m7v2l7w1u7x2l7y3u202l3rcl4mal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3rbr1wbs2lbu2obv3rbz3xck4m202k3rcm4mcn4mco4mcp4mcq6ocr4scs4mct4mcu4mcv4mcw1w2m2ncy1wcz1wdl4sdm4y
5436dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3mes3ret3reu3rev3rew1wex1wey1wez1wfl3rfm3rfn3rfo3rfp3rfq3rfr3ufs3xft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3r3u1w17s4m19m3r}'kerning'{5q{4wv}cl{4qs5kw5ow5qs17sv5tv}201t{2wu4w1k2yu}201x{2wu4wy2yu}17s{2ktclucmucnu4otcpu4lu4wycoucku}2w{7qs4qz5k1m17sy5ow5qx5rsfsu5ty7tufzu}2x{17sy5ty5oy5qs}2y{7qs4qz5k1m17sy5ow5qx5rsfsu5ty7tufzu}'fof'-6o7p{17sv5tv5ow}ck{4qs5kw5ow5qs17sv5tv}4l{4qs5kw5ow5qs17sv5tv}cm{4qs5kw5ow5qs17sv5tv}cn{4qs5kw5ow5qs17sv5tv}co{4qs5kw5ow5qs17sv5tv}cp{4qs5kw5ow5qs17sv5tv}6l{17sy5ty5ow}do{17st5tt}4z{17st5tt}7s{fst}dm{17st5tt}dn{17st5tt}5o{ckwclwcmwcnwcowcpw4lw4wv}dp{17st5tt}dq{17st5tt}7t{5ow}ds{17st5tt}5t{2ktclucmucnu4otcpu4lu4wycoucku}fu{17sv5tv5ow}6p{17sy5ty5ow5qs}ek{17sy5ty5ow}el{17sy5ty5ow}em{17sy5ty5ow}en{5ty}eo{17sy5ty5ow}ep{17sy5ty5ow}es{17sy5ty5qs}et{17sy5ty5ow5qs}eu{17sy5ty5ow5qs}ev{17sy5ty5ow5qs}6z{17sy5ty5ow5qs}fm{17sy5ty5ow5qs}fn{17sy5ty5ow5qs}fo{17sy5ty5ow5qs}fp{17sy5ty5qs}fq{17sy5ty5ow5qs}7r{5ow}fs{17sy5ty5ow5qs}ft{17sv5tv5ow}7m{5ow}fv{17sv5tv5ow}fw{17sv5tv5ow}}}")
5437}};
5438
5439/*
5440This event handler is fired when a new jsPDF object is initialized
5441This event handler appends metrics data to standard fonts within
5442that jsPDF instance. The metrics are mapped over Unicode character
5443codes, NOT CIDs or other codes matching the StandardEncoding table of the
5444standard PDF fonts.
5445Future:
5446Also included is the encoding maping table, converting Unicode (UCS-2, UTF-16)
5447char codes to StandardEncoding character codes. The encoding table is to be used
5448somewhere around "pdfEscape" call.
5449*/
5450
5451API.events.push([ 
5452	'addFonts'
5453	,function(fontManagementObjects) {
5454		// fontManagementObjects is {
5455		//	'fonts':font_ID-keyed hash of font objects
5456		//	, 'dictionary': lookup object, linking ["FontFamily"]['Style'] to font ID
5457		//}
5458		var font
5459		, fontID
5460		, metrics
5461		, unicode_section
5462		, encoding = 'Unicode'
5463		, encodingBlock
5464
5465		for (fontID in fontManagementObjects.fonts){
5466			if (fontManagementObjects.fonts.hasOwnProperty(fontID)) {
5467				font = fontManagementObjects.fonts[fontID]
5468
5469				// // we only ship 'Unicode' mappings and metrics. No need for loop.
5470				// // still, leaving this for the future.
5471
5472				// for (encoding in fontMetrics){
5473				// 	if (fontMetrics.hasOwnProperty(encoding)) {
5474
5475						metrics = fontMetrics[encoding][font.PostScriptName]
5476						if (metrics) {
5477							if (font.metadata[encoding]) {
5478								unicode_section = font.metadata[encoding]
5479							} else {
5480								unicode_section = font.metadata[encoding] = {}
5481							}
5482
5483							unicode_section.widths = metrics.widths
5484							unicode_section.kerning = metrics.kerning
5485						}
5486				// 	}
5487				// }
5488				// for (encoding in encodings){
5489				// 	if (encodings.hasOwnProperty(encoding)) {
5490						encodingBlock = encodings[encoding][font.PostScriptName]
5491						if (encodingBlock) {
5492							if (font.metadata[encoding]) {
5493								unicode_section = font.metadata[encoding]
5494							} else {
5495								unicode_section = font.metadata[encoding] = {}
5496							}
5497
5498							unicode_section.encoding = encodingBlock
5499							if (encodingBlock.codePages && encodingBlock.codePages.length) {
5500								font.encoding = encodingBlock.codePages[0]
5501							}
5502						}
5503				// 	}
5504				// }
5505			}
5506		}
5507	}
5508]) // end of adding event handler
5509
5510})(jsPDF.API);
5511/** ==================================================================== 
5512 * jsPDF total_pages plugin
5513 * Copyright (c) 2013 Eduardo Menezes de Morais, [email protected]
5514 * 
5515 * Permission is hereby granted, free of charge, to any person obtaining
5516 * a copy of this software and associated documentation files (the
5517 * "Software"), to deal in the Software without restriction, including
5518 * without limitation the rights to use, copy, modify, merge, publish,
5519 * distribute, sublicense, and/or sell copies of the Software, and to
5520 * permit persons to whom the Software is furnished to do so, subject to
5521 * the following conditions:
5522 * 
5523 * The above copyright notice and this permission notice shall be
5524 * included in all copies or substantial portions of the Software.
5525 * 
5526 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
5527 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
5528 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
5529 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
5530 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
5531 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
5532 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5533 * ====================================================================
5534 */
5535
5536(function(jsPDFAPI) {
5537'use strict';
5538
5539jsPDFAPI.putTotalPages = function(pageExpression) {
5540	'use strict';
5541        var replaceExpression = new RegExp(pageExpression, 'g');
5542        for (var n = 1; n <= this.internal.getNumberOfPages(); n++) {
5543            for (var i = 0; i < this.internal.pages[n].length; i++)
5544               this.internal.pages[n][i] = this.internal.pages[n][i].replace(replaceExpression, this.internal.getNumberOfPages());
5545        }
5546	return this;
5547};
5548
5549})(jsPDF.API);
5550/* Blob.js
5551 * A Blob implementation.
5552 * 2014-07-24
5553 *
5554 * By Eli Grey, http://eligrey.com
5555 * By Devin Samarin, https://github.com/dsamarin
5556 * License: X11/MIT
5557 *   See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
5558 */
5559
5560/*global self, unescape */
5561/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
5562  plusplus: true */
5563
5564/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
5565
5566(function (view) {
5567	"use strict";
5568
5569	view.URL = view.URL || view.webkitURL;
5570
5571	if (view.Blob && view.URL) {
5572		try {
5573			new Blob;
5574			return;
5575		} catch (e) {}
5576	}
5577
5578	// Internally we use a BlobBuilder implementation to base Blob off of
vendor: 5,204 bytes, lines 5579-5751
5579	// in order to support older browsers that only have BlobBuilder
5580	var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
5581		var
5582			  get_class = function(object) {
5583				return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
5584			}
5585			, FakeBlobBuilder = function BlobBuilder() {
5586				this.data = [];
5587			}
5588			, FakeBlob = function Blob(data, type, encoding) {
5589				this.data = data;
5590				this.size = data.length;
5591				this.type = type;
5592				this.encoding = encoding;
5593			}
5594			, FBB_proto = FakeBlobBuilder.prototype
5595			, FB_proto = FakeBlob.prototype
5596			, FileReaderSync = view.FileReaderSync
5597			, FileException = function(type) {
5598				this.code = this[this.name = type];
5599			}
5600			, file_ex_codes = (
5601				  "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
5602				+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
5603			).split(" ")
5604			, file_ex_code = file_ex_codes.length
5605			, real_URL = view.URL || view.webkitURL || view
5606			, real_create_object_URL = real_URL.createObjectURL
5607			, real_revoke_object_URL = real_URL.revokeObjectURL
5608			, URL = real_URL
5609			, btoa = view.btoa
5610			, atob = view.atob
5611
5612			, ArrayBuffer = view.ArrayBuffer
5613			, Uint8Array = view.Uint8Array
5614
5615			, origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/
5616		;
5617		FakeBlob.fake = FB_proto.fake = true;
5618		while (file_ex_code--) {
5619			FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
5620		}
5621		// Polyfill URL
5622		if (!real_URL.createObjectURL) {
5623			URL = view.URL = function(uri) {
5624				var
5625					  uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
5626					, uri_origin
5627				;
5628				uri_info.href = uri;
5629				if (!("origin" in uri_info)) {
5630					if (uri_info.protocol.toLowerCase() === "data:") {
5631						uri_info.origin = null;
5632					} else {
5633						uri_origin = uri.match(origin);
5634						uri_info.origin = uri_origin && uri_origin[1];
5635					}
5636				}
5637				return uri_info;
5638			};
5639		}
5640		URL.createObjectURL = function(blob) {
5641			var
5642				  type = blob.type
5643				, data_URI_header
5644			;
5645			if (type === null) {
5646				type = "application/octet-stream";
5647			}
5648			if (blob instanceof FakeBlob) {
5649				data_URI_header = "data:" + type;
5650				if (blob.encoding === "base64") {
5651					return data_URI_header + ";base64," + blob.data;
5652				} else if (blob.encoding === "URI") {
5653					return data_URI_header + "," + decodeURIComponent(blob.data);
5654				} if (btoa) {
5655					return data_URI_header + ";base64," + btoa(blob.data);
5656				} else {
5657					return data_URI_header + "," + encodeURIComponent(blob.data);
5658				}
5659			} else if (real_create_object_URL) {
5660				return real_create_object_URL.call(real_URL, blob);
5661			}
5662		};
5663		URL.revokeObjectURL = function(object_URL) {
5664			if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
5665				real_revoke_object_URL.call(real_URL, object_URL);
5666			}
5667		};
5668		FBB_proto.append = function(data/*, endings*/) {
5669			var bb = this.data;
5670			// decode data to a binary string
5671			if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
5672				var
5673					  str = ""
5674					, buf = new Uint8Array(data)
5675					, i = 0
5676					, buf_len = buf.length
5677				;
5678				for (; i < buf_len; i++) {
5679					str += String.fromCharCode(buf[i]);
5680				}
5681				bb.push(str);
5682			} else if (get_class(data) === "Blob" || get_class(data) === "File") {
5683				if (FileReaderSync) {
5684					var fr = new FileReaderSync;
5685					bb.push(fr.readAsBinaryString(data));
5686				} else {
5687					// async FileReader won't work as BlobBuilder is sync
5688					throw new FileException("NOT_READABLE_ERR");
5689				}
5690			} else if (data instanceof FakeBlob) {
5691				if (data.encoding === "base64" && atob) {
5692					bb.push(atob(data.data));
5693				} else if (data.encoding === "URI") {
5694					bb.push(decodeURIComponent(data.data));
5695				} else if (data.encoding === "raw") {
5696					bb.push(data.data);
5697				}
5698			} else {
5699				if (typeof data !== "string") {
5700					data += ""; // convert unsupported types to strings
5701				}
5702				// decode UTF-16 to binary string
5703				bb.push(unescape(encodeURIComponent(data)));
5704			}
5705		};
5706		FBB_proto.getBlob = function(type) {
5707			if (!arguments.length) {
5708				type = null;
5709			}
5710			return new FakeBlob(this.data.join(""), type, "raw");
5711		};
5712		FBB_proto.toString = function() {
5713			return "[object BlobBuilder]";
5714		};
5715		FB_proto.slice = function(start, end, type) {
5716			var args = arguments.length;
5717			if (args < 3) {
5718				type = null;
5719			}
5720			return new FakeBlob(
5721				  this.data.slice(start, args > 1 ? end : this.data.length)
5722				, type
5723				, this.encoding
5724			);
5725		};
5726		FB_proto.toString = function() {
5727			return "[object Blob]";
5728		};
5729		FB_proto.close = function() {
5730			this.size = 0;
5731			delete this.data;
5732		};
5733		return FakeBlobBuilder;
5734	}(view));
5735
5736	view.Blob = function(blobParts, options) {
5737		var type = options ? (options.type || "") : "";
5738		var builder = new BlobBuilder();
5739		if (blobParts) {
5740			for (var i = 0, len = blobParts.length; i < len; i++) {
5741				builder.append(blobParts[i]);
5742			}
5743		}
5744		return builder.getBlob(type);
5745	};
5746}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));
5747/* FileSaver.js
5748 * A saveAs() FileSaver implementation.
5749 * 2014-08-29
5750 *
5751 * By Eli Grey, http://eligrey.com
5752 * License: X11/MIT
5753 *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
5754 */
5755
5756/*global self */
5757/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
5758
5759/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
5760
5761var saveAs = saveAs
5762  // IE 10+ (native saveAs)
5763  || (typeof navigator !== "undefined" &&
5764      navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
5765  // Everyone else
5766  || (function(view) {
5767	"use strict";
5768	// IE <10 is explicitly unsupported
5769	if (typeof navigator !== "undefined" &&
5770	    /MSIE [1-9]\./.test(navigator.userAgent)) {
5771		return;
5772	}
5773	var
5774		  doc = view.document
5775		  // only get URL when necessary in case Blob.js hasn't overridden it yet
5776		, get_URL = function() {
5777			return view.URL || view.webkitURL || view;
5778		}
5779		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
5780		, can_use_save_link = "download" in save_link
5781		, click = function(node) {
5782			var event = doc.createEvent("MouseEvents");
5783			event.initMouseEvent(
5784				"click", true, false, view, 0, 0, 0, 0, 0
5785				, false, false, false, false, 0, null
5786			);
5787			node.dispatchEvent(event);
5788		}
5789		, webkit_req_fs = view.webkitRequestFileSystem
5790		, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
5791		, throw_outside = function(ex) {
5792			(view.setImmediate || view.setTimeout)(function() {
5793				throw ex;
5794			}, 0);
5795		}
5796		, force_saveable_type = "application/octet-stream"
5797		, fs_min_size = 0
5798		// See https://code.google.com/p/chromium/issues/detail?id=375297#c7 for
5799		// the reasoning behind the timeout and revocation flow
5800		, arbitrary_revoke_timeout = 10
5801		, revoke = function(file) {
5802			var revoker = function() {
5803				if (typeof file === "string") { // file is an object URL
5804					get_URL().revokeObjectURL(file);
5805				} else { // file is a File
5806					file.remove();
5807				}
5808			};
5809			if (view.chrome) {
5810				revoker();
5811			} else {
5812				setTimeout(revoker, arbitrary_revoke_timeout);
5813			}
5814		}
5815		, dispatch = function(filesaver, event_types, event) {
5816			event_types = [].concat(event_types);
5817			var i = event_types.length;
5818			while (i--) {
5819				var listener = filesaver["on" + event_types[i]];
5820				if (typeof listener === "function") {
5821					try {
5822						listener.call(filesaver, event || filesaver);
5823					} catch (ex) {
5824						throw_outside(ex);
5825					}
5826				}
5827			}
5828		}
5829		, FileSaver = function(blob, name) {
5830			// First try a.download, then web filesystem, then object URLs
5831			var
5832				  filesaver = this
5833				, type = blob.type
5834				, blob_changed = false
5835				, object_url
5836				, target_view
5837				, dispatch_all = function() {
5838					dispatch(filesaver, "writestart progress write writeend".split(" "));
5839				}
5840				// on any filesys errors revert to saving with object URLs
5841				, fs_error = function() {
5842					// don't create more object URLs than needed
5843					if (blob_changed || !object_url) {
5844						object_url = get_URL().createObjectURL(blob);
5845					}
5846					if (target_view) {
5847						target_view.location.href = object_url;
5848					} else {
5849						var new_tab = view.open(object_url, "_blank");
5850						if (new_tab == undefined && typeof safari !== "undefined") {
5851							//Apple do not allow window.open, see http://bit.ly/1kZffRI
5852							view.location.href = object_url
5853						}
5854					}
5855					filesaver.readyState = filesaver.DONE;
5856					dispatch_all();
5857					revoke(object_url);
5858				}
5859				, abortable = function(func) {
5860					return function() {
5861						if (filesaver.readyState !== filesaver.DONE) {
5862							return func.apply(this, arguments);
5863						}
5864					};
5865				}
5866				, create_if_not_found = {create: true, exclusive: false}
5867				, slice
5868			;
5869			filesaver.readyState = filesaver.INIT;
5870			if (!name) {
5871				name = "download";
5872			}
5873			if (can_use_save_link) {
5874				object_url = get_URL().createObjectURL(blob);
5875				save_link.href = object_url;
5876				save_link.download = name;
5877				click(save_link);
5878				filesaver.readyState = filesaver.DONE;
5879				dispatch_all();
5880				revoke(object_url);
5881				return;
5882			}
5883			// Object and web filesystem URLs have a problem saving in Google Chrome when
5884			// viewed in a tab, so I force save with application/octet-stream
5885			// http://code.google.com/p/chromium/issues/detail?id=91158
5886			// Update: Google errantly closed 91158, I submitted it again:
5887			// https://code.google.com/p/chromium/issues/detail?id=389642
5888			if (view.chrome && type && type !== force_saveable_type) {
5889				slice = blob.slice || blob.webkitSlice;
5890				blob = slice.call(blob, 0, blob.size, force_saveable_type);
5891				blob_changed = true;
5892			}
5893			// Since I can't be sure that the guessed media type will trigger a download
5894			// in WebKit, I append .download to the filename.
5895			// https://bugs.webkit.org/show_bug.cgi?id=65440
5896			if (webkit_req_fs && name !== "download") {
5897				name += ".download";
5898			}
5899			if (type === force_saveable_type || webkit_req_fs) {
5900				target_view = view;
5901			}
5902			if (!req_fs) {
5903				fs_error();
5904				return;
5905			}
5906			fs_min_size += blob.size;
5907			req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
5908				fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
5909					var save = function() {
5910						dir.getFile(name, create_if_not_found, abortable(function(file) {
5911							file.createWriter(abortable(function(writer) {
5912								writer.onwriteend = function(event) {
5913									target_view.location.href = file.toURL();
5914									filesaver.readyState = filesaver.DONE;
5915									dispatch(filesaver, "writeend", event);
5916									revoke(file);
5917								};
5918								writer.onerror = function() {
5919									var error = writer.error;
5920									if (error.code !== error.ABORT_ERR) {
5921										fs_error();
5922									}
5923								};
5924								"writestart progress write abort".split(" ").forEach(function(event) {
5925									writer["on" + event] = filesaver["on" + event];
5926								});
5927								writer.write(blob);
5928								filesaver.abort = function() {
5929									writer.abort();
5930									filesaver.readyState = filesaver.DONE;
5931								};
5932								filesaver.readyState = filesaver.WRITING;
5933							}), fs_error);
5934						}), fs_error);
5935					};
5936					dir.getFile(name, {create: false}, abortable(function(file) {
5937						// delete file if it already exists
5938						file.remove();
5939						save();
5940					}), abortable(function(ex) {
5941						if (ex.code === ex.NOT_FOUND_ERR) {
5942							save();
5943						} else {
5944							fs_error();
5945						}
5946					}));
5947				}), fs_error);
5948			}), fs_error);
5949		}
5950		, FS_proto = FileSaver.prototype
5951		, saveAs = function(blob, name) {
5952			return new FileSaver(blob, name);
5953		}
5954	;
5955	FS_proto.abort = function() {
5956		var filesaver = this;
5957		filesaver.readyState = filesaver.DONE;
5958		dispatch(filesaver, "abort");
5959	};
5960	FS_proto.readyState = FS_proto.INIT = 0;
5961	FS_proto.WRITING = 1;
5962	FS_proto.DONE = 2;
5963
5964	FS_proto.error =
5965	FS_proto.onwritestart =
5966	FS_proto.onprogress =
5967	FS_proto.onwrite =
5968	FS_proto.onabort =
5969	FS_proto.onerror =
5970	FS_proto.onwriteend =
5971		null;
5972
5973	return saveAs;
5974}(
5975	   typeof self !== "undefined" && self
5976	|| typeof window !== "undefined" && window
5977	|| this.content
5978));
5979// `self` is undefined in Firefox for Android content script context
5980// while `this` is nsIContentFrameMessageManager
5981// with an attribute `content` that corresponds to the window
5982
5983if (typeof module !== "undefined" && module !== null) {
5984  module.exports = saveAs;
5985} else if ((typeof define !== "undefined" && 0)) {
5986  define([], function() {
5987    return saveAs;
5988  });
5989}
5990/*
5991 * Copyright (c) 2012 chick307 <[email protected]>
5992 *
5993 * Licensed under the MIT License.
5994 * http://opensource.org/licenses/mit-license
5995 */
5996
5997void function(global, callback) {
5998	if (typeof module === 'object') {
5999		module.exports = callback();
6000	} else if (0 === 'function') {
6001		define(callback);
6002	} else {
6003		global.adler32cs = callback();
6004	}
6005}(jsPDF, function() {
6006	var _hasArrayBuffer = typeof ArrayBuffer === 'function' &&
6007		typeof Uint8Array === 'function';
6008
6009	var _Buffer = null, _isBuffer = (function() {
6010		if (!_hasArrayBuffer)
6011			return function _isBuffer() { return false };
6012
6013		try {
6014			var buffer = require('buffer');
6015			if (typeof buffer.Buffer === 'function')
6016				_Buffer = buffer.Buffer;
6017		} catch (error) {}
6018
6019		return function _isBuffer(value) {
6020			return value instanceof ArrayBuffer ||
6021				_Buffer !== null && value instanceof _Buffer;
6022		};
6023	}());
6024
6025	var _utf8ToBinary = (function() {
6026		if (_Buffer !== null) {
6027			return function _utf8ToBinary(utf8String) {
6028				return new _Buffer(utf8String, 'utf8').toString('binary');
6029			};
6030		} else {
6031			return function _utf8ToBinary(utf8String) {
6032				return unescape(encodeURIComponent(utf8String));
6033			};
6034		}
6035	}());
6036
6037	var MOD = 65521;
6038
6039	var _update = function _update(checksum, binaryString) {
6040		var a = checksum & 0xFFFF, b = checksum >>> 16;
6041		for (var i = 0, length = binaryString.length; i < length; i++) {
6042			a = (a + (binaryString.charCodeAt(i) & 0xFF)) % MOD;
6043			b = (b + a) % MOD;
6044		}
6045		return (b << 16 | a) >>> 0;
6046	};
6047
6048	var _updateUint8Array = function _updateUint8Array(checksum, uint8Array) {
6049		var a = checksum & 0xFFFF, b = checksum >>> 16;
6050		for (var i = 0, length = uint8Array.length, x; i < length; i++) {
6051			a = (a + uint8Array[i]) % MOD;
6052			b = (b + a) % MOD;
6053		}
6054		return (b << 16 | a) >>> 0
6055	};
6056
6057	var exports = {};
6058
6059	var Adler32 = exports.Adler32 = (function() {
6060		var ctor = function Adler32(checksum) {
6061			if (!(this instanceof ctor)) {
6062				throw new TypeError(
6063					'Constructor cannot called be as a function.');
6064			}
6065			if (!isFinite(checksum = checksum == null ? 1 : +checksum)) {
6066				throw new Error(
6067					'First arguments needs to be a finite number.');
6068			}
6069			this.checksum = checksum >>> 0;
6070		};
6071
6072		var proto = ctor.prototype = {};
6073		proto.constructor = ctor;
6074
6075		ctor.from = function(from) {
6076			from.prototype = proto;
6077			return from;
6078		}(function from(binaryString) {
6079			if (!(this instanceof ctor)) {
6080				throw new TypeError(
6081					'Constructor cannot called be as a function.');
6082			}
6083			if (binaryString == null)
6084				throw new Error('First argument needs to be a string.');
6085			this.checksum = _update(1, binaryString.toString());
6086		});
6087
6088		ctor.fromUtf8 = function(fromUtf8) {
6089			fromUtf8.prototype = proto;
6090			return fromUtf8;
6091		}(function fromUtf8(utf8String) {
6092			if (!(this instanceof ctor)) {
6093				throw new TypeError(
6094					'Constructor cannot called be as a function.');
6095			}
6096			if (utf8String == null)
6097				throw new Error('First argument needs to be a string.');
6098			var binaryString = _utf8ToBinary(utf8String.toString());
6099			this.checksum = _update(1, binaryString);
6100		});
6101
6102		if (_hasArrayBuffer) {
6103			ctor.fromBuffer = function(fromBuffer) {
6104				fromBuffer.prototype = proto;
6105				return fromBuffer;
6106			}(function fromBuffer(buffer) {
6107				if (!(this instanceof ctor)) {
6108					throw new TypeError(
6109						'Constructor cannot called be as a function.');
6110				}
6111				if (!_isBuffer(buffer))
6112					throw new Error('First argument needs to be ArrayBuffer.');
6113				var array = new Uint8Array(buffer);
6114				return this.checksum = _updateUint8Array(1, array);
6115			});
6116		}
6117
6118		proto.update = function update(binaryString) {
6119			if (binaryString == null)
6120				throw new Error('First argument needs to be a string.');
6121			binaryString = binaryString.toString();
6122			return this.checksum = _update(this.checksum, binaryString);
6123		};
6124
6125		proto.updateUtf8 = function updateUtf8(utf8String) {
6126			if (utf8String == null)
6127				throw new Error('First argument needs to be a string.');
6128			var binaryString = _utf8ToBinary(utf8String.toString());
6129			return this.checksum = _update(this.checksum, binaryString);
6130		};
6131
6132		if (_hasArrayBuffer) {
6133			proto.updateBuffer = function updateBuffer(buffer) {
6134				if (!_isBuffer(buffer))
6135					throw new Error('First argument needs to be ArrayBuffer.');
6136				var array = new Uint8Array(buffer);
6137				return this.checksum = _updateUint8Array(this.checksum, array);
6138			};
6139		}
6140
6141		proto.clone = function clone() {
6142			return new Adler32(this.checksum);
6143		};
6144
6145		return ctor;
6146	}());
6147
6148	exports.from = function from(binaryString) {
6149		if (binaryString == null)
6150			throw new Error('First argument needs to be a string.');
6151		return _update(1, binaryString.toString());
6152	};
6153
6154	exports.fromUtf8 = function fromUtf8(utf8String) {
6155		if (utf8String == null)
6156			throw new Error('First argument needs to be a string.');
6157		var binaryString = _utf8ToBinary(utf8String.toString());
6158		return _update(1, binaryString);
6159	};
6160
6161	if (_hasArrayBuffer) {
6162		exports.fromBuffer = function fromBuffer(buffer) {
6163			if (!_isBuffer(buffer))
6164				throw new Error('First argument need to be ArrayBuffer.');
6165			var array = new Uint8Array(buffer);
6166			return _updateUint8Array(1, array);
6167		};
6168	}
6169
6170	return exports;
6171});
6172/*
6173 Deflate.js - https://github.com/gildas-lormeau/zip.js
6174 Copyright (c) 2013 Gildas Lormeau. All rights reserved.
6175
6176 Redistribution and use in source and binary forms, with or without
6177 modification, are permitted provided that the following conditions are met:
6178
6179 1. Redistributions of source code must retain the above copyright notice,
6180 this list of conditions and the following disclaimer.
6181
6182 2. Redistributions in binary form must reproduce the above copyright 
6183 notice, this list of conditions and the following disclaimer in 
6184 the documentation and/or other materials provided with the distribution.
6185
6186 3. The names of the authors may not be used to endorse or promote products
6187 derived from this software without specific prior written permission.
6188
6189 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
6190 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
6191 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
6192 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
6193 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6194 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
6195 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
6196 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
6197 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
6198 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6199 */
6200
6201/*
6202 * This program is based on JZlib 1.0.2 ymnk, JCraft,Inc.
6203 * JZlib is based on zlib-1.1.3, so all credit should go authors
6204 * Jean-loup Gailly([email protected]) and Mark Adler([email protected])
6205 * and contributors of zlib.
6206 */
6207
6208var Deflater = (function(obj) {
6209
6210	// Global
6211
6212	var MAX_BITS = 15;
6213	var D_CODES = 30;
6214	var BL_CODES = 19;
6215
6216	var LENGTH_CODES = 29;
6217	var LITERALS = 256;
6218	var L_CODES = (LITERALS + 1 + LENGTH_CODES);
6219	var HEAP_SIZE = (2 * L_CODES + 1);
6220
6221	var END_BLOCK = 256;
6222
6223	// Bit length codes must not exceed MAX_BL_BITS bits
6224	var MAX_BL_BITS = 7;
6225
6226	// repeat previous bit length 3-6 times (2 bits of repeat count)
6227	var REP_3_6 = 16;
6228
6229	// repeat a zero length 3-10 times (3 bits of repeat count)
6230	var REPZ_3_10 = 17;
6231
6232	// repeat a zero length 11-138 times (7 bits of repeat count)
6233	var REPZ_11_138 = 18;
6234
6235	// The lengths of the bit length codes are sent in order of decreasing
6236	// probability, to avoid transmitting the lengths for unused bit
6237	// length codes.
6238
6239	var Buf_size = 8 * 2;
6240
6241	// JZlib version : "1.0.2"
6242	var Z_DEFAULT_COMPRESSION = -1;
6243
6244	// compression strategy
6245	var Z_FILTERED = 1;
6246	var Z_HUFFMAN_ONLY = 2;
6247	var Z_DEFAULT_STRATEGY = 0;
6248
6249	var Z_NO_FLUSH = 0;
6250	var Z_PARTIAL_FLUSH = 1;
6251	var Z_FULL_FLUSH = 3;
6252	var Z_FINISH = 4;
6253
6254	var Z_OK = 0;
6255	var Z_STREAM_END = 1;
6256	var Z_NEED_DICT = 2;
6257	var Z_STREAM_ERROR = -2;
6258	var Z_DATA_ERROR = -3;
6259	var Z_BUF_ERROR = -5;
6260
6261	// Tree
6262
6263	// see definition of array dist_code below
6264	var _dist_code = [ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6265			10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
6266			12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
6267			13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
6268			14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
6269			14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
6270			15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19,
6271			20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
6272			24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
6273			26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
6274			27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
6275			28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29,
6276			29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
6277			29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 ];
6278
6279	function Tree() {
6280		var that = this;
6281
6282		// dyn_tree; // the dynamic tree
6283		// max_code; // largest code with non zero frequency
6284		// stat_desc; // the corresponding static tree
6285
6286		// Compute the optimal bit lengths for a tree and update the total bit
6287		// length
6288		// for the current block.
6289		// IN assertion: the fields freq and dad are set, heap[heap_max] and
6290		// above are the tree nodes sorted by increasing frequency.
6291		// OUT assertions: the field len is set to the optimal bit length, the
6292		// array bl_count contains the frequencies for each bit length.
6293		// The length opt_len is updated; static_len is also updated if stree is
6294		// not null.
6295		function gen_bitlen(s) {
6296			var tree = that.dyn_tree;
6297			var stree = that.stat_desc.static_tree;
6298			var extra = that.stat_desc.extra_bits;
6299			var base = that.stat_desc.extra_base;
6300			var max_length = that.stat_desc.max_length;
6301			var h; // heap index
6302			var n, m; // iterate over the tree elements
6303			var bits; // bit length
6304			var xbits; // extra bits
6305			var f; // frequency
6306			var overflow = 0; // number of elements with bit length too large
6307
6308			for (bits = 0; bits <= MAX_BITS; bits++)
6309				s.bl_count[bits] = 0;
6310
6311			// In a first pass, compute the optimal bit lengths (which may
6312			// overflow in the case of the bit length tree).
6313			tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
6314
6315			for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
6316				n = s.heap[h];
6317				bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
6318				if (bits > max_length) {
6319					bits = max_length;
6320					overflow++;
6321				}
6322				tree[n * 2 + 1] = bits;
6323				// We overwrite tree[n*2+1] which is no longer needed
6324
6325				if (n > that.max_code)
6326					continue; // not a leaf node
6327
6328				s.bl_count[bits]++;
6329				xbits = 0;
6330				if (n >= base)
6331					xbits = extra[n - base];
6332				f = tree[n * 2];
6333				s.opt_len += f * (bits + xbits);
6334				if (stree)
6335					s.static_len += f * (stree[n * 2 + 1] + xbits);
6336			}
6337			if (overflow === 0)
6338				return;
6339
6340			// This happens for example on obj2 and pic of the Calgary corpus
6341			// Find the first bit length which could increase:
6342			do {
6343				bits = max_length - 1;
6344				while (s.bl_count[bits] === 0)
6345					bits--;
6346				s.bl_count[bits]--; // move one leaf down the tree
6347				s.bl_count[bits + 1] += 2; // move one overflow item as its brother
6348				s.bl_count[max_length]--;
6349				// The brother of the overflow item also moves one step up,
6350				// but this does not affect bl_count[max_length]
6351				overflow -= 2;
6352			} while (overflow > 0);
6353
6354			for (bits = max_length; bits !== 0; bits--) {
6355				n = s.bl_count[bits];
6356				while (n !== 0) {
6357					m = s.heap[--h];
6358					if (m > that.max_code)
6359						continue;
6360					if (tree[m * 2 + 1] != bits) {
6361						s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2];
6362						tree[m * 2 + 1] = bits;
6363					}
6364					n--;
6365				}
6366			}
6367		}
6368
6369		// Reverse the first len bits of a code, using straightforward code (a
6370		// faster
6371		// method would use a table)
6372		// IN assertion: 1 <= len <= 15
6373		function bi_reverse(code, // the value to invert
6374		len // its bit length
6375		) {
6376			var res = 0;
6377			do {
6378				res |= code & 1;
6379				code >>>= 1;
6380				res <<= 1;
6381			} while (--len > 0);
6382			return res >>> 1;
6383		}
6384
6385		// Generate the codes for a given tree and bit counts (which need not be
6386		// optimal).
6387		// IN assertion: the array bl_count contains the bit length statistics for
6388		// the given tree and the field len is set for all tree elements.
6389		// OUT assertion: the field code is set for all tree elements of non
6390		// zero code length.
6391		function gen_codes(tree, // the tree to decorate
6392		max_code, // largest code with non zero frequency
6393		bl_count // number of codes at each bit length
6394		) {
6395			var next_code = []; // next code value for each
6396			// bit length
6397			var code = 0; // running code value
6398			var bits; // bit index
6399			var n; // code index
6400			var len;
6401
6402			// The distribution counts are first used to generate the code values
6403			// without bit reversal.
6404			for (bits = 1; bits <= MAX_BITS; bits++) {
6405				next_code[bits] = code = ((code + bl_count[bits - 1]) << 1);
6406			}
6407
6408			// Check that the bit counts in bl_count are consistent. The last code
6409			// must be all ones.
6410			// Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
6411			// "inconsistent bit counts");
6412			// Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
6413
6414			for (n = 0; n <= max_code; n++) {
6415				len = tree[n * 2 + 1];
6416				if (len === 0)
6417					continue;
6418				// Now reverse the bits
6419				tree[n * 2] = bi_reverse(next_code[len]++, len);
6420			}
6421		}
6422
6423		// Construct one Huffman tree and assigns the code bit strings and lengths.
6424		// Update the total bit length for the current block.
6425		// IN assertion: the field freq is set for all tree elements.
6426		// OUT assertions: the fields len and code are set to the optimal bit length
6427		// and corresponding code. The length opt_len is updated; static_len is
6428		// also updated if stree is not null. The field max_code is set.
6429		that.build_tree = function(s) {
6430			var tree = that.dyn_tree;
6431			var stree = that.stat_desc.static_tree;
6432			var elems = that.stat_desc.elems;
6433			var n, m; // iterate over heap elements
6434			var max_code = -1; // largest code with non zero frequency
6435			var node; // new node being created
6436
6437			// Construct the initial heap, with least frequent element in
6438			// heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
6439			// heap[0] is not used.
6440			s.heap_len = 0;
6441			s.heap_max = HEAP_SIZE;
6442
6443			for (n = 0; n < elems; n++) {
6444				if (tree[n * 2] !== 0) {
6445					s.heap[++s.heap_len] = max_code = n;
6446					s.depth[n] = 0;
6447				} else {
6448					tree[n * 2 + 1] = 0;
6449				}
6450			}
6451
6452			// The pkzip format requires that at least one distance code exists,
6453			// and that at least one bit should be sent even if there is only one
6454			// possible code. So to avoid special checks later on we force at least
6455			// two codes of non zero frequency.
6456			while (s.heap_len < 2) {
6457				node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0;
6458				tree[node * 2] = 1;
6459				s.depth[node] = 0;
6460				s.opt_len--;
6461				if (stree)
6462					s.static_len -= stree[node * 2 + 1];
6463				// node is 0 or 1 so it does not have extra bits
6464			}
6465			that.max_code = max_code;
6466
6467			// The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
6468			// establish sub-heaps of increasing lengths:
6469
6470			for (n = Math.floor(s.heap_len / 2); n >= 1; n--)
6471				s.pqdownheap(tree, n);
6472
6473			// Construct the Huffman tree by repeatedly combining the least two
6474			// frequent nodes.
6475
6476			node = elems; // next internal node of the tree
6477			do {
6478				// n = node of least frequency
6479				n = s.heap[1];
6480				s.heap[1] = s.heap[s.heap_len--];
6481				s.pqdownheap(tree, 1);
6482				m = s.heap[1]; // m = node of next least frequency
6483
6484				s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
6485				s.heap[--s.heap_max] = m;
6486
6487				// Create a new node father of n and m
6488				tree[node * 2] = (tree[n * 2] + tree[m * 2]);
6489				s.depth[node] = Math.max(s.depth[n], s.depth[m]) + 1;
6490				tree[n * 2 + 1] = tree[m * 2 + 1] = node;
6491
6492				// and insert the new node in the heap
6493				s.heap[1] = node++;
6494				s.pqdownheap(tree, 1);
6495			} while (s.heap_len >= 2);
6496
6497			s.heap[--s.heap_max] = s.heap[1];
6498
6499			// At this point, the fields freq and dad are set. We can now
6500			// generate the bit lengths.
6501
6502			gen_bitlen(s);
6503
6504			// The field len is now set, we can generate the bit codes
6505			gen_codes(tree, that.max_code, s.bl_count);
6506		};
6507
6508	}
6509
6510	Tree._length_code = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16,
6511			16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20,
6512			20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
6513			22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
6514			24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
6515			25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
6516			26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 ];
6517
6518	Tree.base_length = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 ];
6519
6520	Tree.base_dist = [ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384,
6521			24576 ];
6522
6523	// Mapping from a distance to a distance code. dist is the distance - 1 and
6524	// must not have side effects. _dist_code[256] and _dist_code[257] are never
6525	// used.
6526	Tree.d_code = function(dist) {
6527		return ((dist) < 256 ? _dist_code[dist] : _dist_code[256 + ((dist) >>> 7)]);
6528	};
6529
6530	// extra bits for each length code
6531	Tree.extra_lbits = [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 ];
6532
6533	// extra bits for each distance code
6534	Tree.extra_dbits = [ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 ];
6535
6536	// extra bits for each bit length code
6537	Tree.extra_blbits = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 ];
6538
6539	Tree.bl_order = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
6540
6541	// StaticTree
6542
6543	function StaticTree(static_tree, extra_bits, extra_base, elems, max_length) {
6544		var that = this;
6545		that.static_tree = static_tree;
6546		that.extra_bits = extra_bits;
6547		that.extra_base = extra_base;
6548		that.elems = elems;
6549		that.max_length = max_length;
6550	}
6551
6552	StaticTree.static_ltree = [ 12, 8, 140, 8, 76, 8, 204, 8, 44, 8, 172, 8, 108, 8, 236, 8, 28, 8, 156, 8, 92, 8, 220, 8, 60, 8, 188, 8, 124, 8, 252, 8, 2, 8,
6553			130, 8, 66, 8, 194, 8, 34, 8, 162, 8, 98, 8, 226, 8, 18, 8, 146, 8, 82, 8, 210, 8, 50, 8, 178, 8, 114, 8, 242, 8, 10, 8, 138, 8, 74, 8, 202, 8, 42,
6554			8, 170, 8, 106, 8, 234, 8, 26, 8, 154, 8, 90, 8, 218, 8, 58, 8, 186, 8, 122, 8, 250, 8, 6, 8, 134, 8, 70, 8, 198, 8, 38, 8, 166, 8, 102, 8, 230, 8,
6555			22, 8, 150, 8, 86, 8, 214, 8, 54, 8, 182, 8, 118, 8, 246, 8, 14, 8, 142, 8, 78, 8, 206, 8, 46, 8, 174, 8, 110, 8, 238, 8, 30, 8, 158, 8, 94, 8,
6556			222, 8, 62, 8, 190, 8, 126, 8, 254, 8, 1, 8, 129, 8, 65, 8, 193, 8, 33, 8, 161, 8, 97, 8, 225, 8, 17, 8, 145, 8, 81, 8, 209, 8, 49, 8, 177, 8, 113,
6557			8, 241, 8, 9, 8, 137, 8, 73, 8, 201, 8, 41, 8, 169, 8, 105, 8, 233, 8, 25, 8, 153, 8, 89, 8, 217, 8, 57, 8, 185, 8, 121, 8, 249, 8, 5, 8, 133, 8,
6558			69, 8, 197, 8, 37, 8, 165, 8, 101, 8, 229, 8, 21, 8, 149, 8, 85, 8, 213, 8, 53, 8, 181, 8, 117, 8, 245, 8, 13, 8, 141, 8, 77, 8, 205, 8, 45, 8,
6559			173, 8, 109, 8, 237, 8, 29, 8, 157, 8, 93, 8, 221, 8, 61, 8, 189, 8, 125, 8, 253, 8, 19, 9, 27
65595, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9,
6560			51, 9, 307, 9, 179, 9, 435, 9, 115, 9, 371, 9, 243, 9, 499, 9, 11, 9, 267, 9, 139, 9, 395, 9, 75, 9, 331, 9, 203, 9, 459, 9, 43, 9, 299, 9, 171, 9,
6561			427, 9, 107, 9, 363, 9, 235, 9, 491, 9, 27, 9, 283, 9, 155, 9, 411, 9, 91, 9, 347, 9, 219, 9, 475, 9, 59, 9, 315, 9, 187, 9, 443, 9, 123, 9, 379,
6562			9, 251, 9, 507, 9, 7, 9, 263, 9, 135, 9, 391, 9, 71, 9, 327, 9, 199, 9, 455, 9, 39, 9, 295, 9, 167, 9, 423, 9, 103, 9, 359, 9, 231, 9, 487, 9, 23,
6563			9, 279, 9, 151, 9, 407, 9, 87, 9, 343, 9, 215, 9, 471, 9, 55, 9, 311, 9, 183, 9, 439, 9, 119, 9, 375, 9, 247, 9, 503, 9, 15, 9, 271, 9, 143, 9,
6564			399, 9, 79, 9, 335, 9, 207, 9, 463, 9, 47, 9, 303, 9, 175, 9, 431, 9, 111, 9, 367, 9, 239, 9, 495, 9, 31, 9, 287, 9, 159, 9, 415, 9, 95, 9, 351, 9,
6565			223, 9, 479, 9, 63, 9, 319, 9, 191, 9, 447, 9, 127, 9, 383, 9, 255, 9, 511, 9, 0, 7, 64, 7, 32, 7, 96, 7, 16, 7, 80, 7, 48, 7, 112, 7, 8, 7, 72, 7,
6566			40, 7, 104, 7, 24, 7, 88, 7, 56, 7, 120, 7, 4, 7, 68, 7, 36, 7, 100, 7, 20, 7, 84, 7, 52, 7, 116, 7, 3, 8, 131, 8, 67, 8, 195, 8, 35, 8, 163, 8,
6567			99, 8, 227, 8 ];
6568
6569	StaticTree.static_dtree = [ 0, 5, 16, 5, 8, 5, 24, 5, 4, 5, 20, 5, 12, 5, 28, 5, 2, 5, 18, 5, 10, 5, 26, 5, 6, 5, 22, 5, 14, 5, 30, 5, 1, 5, 17, 5, 9, 5,
6570			25, 5, 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 ];
6571
6572	StaticTree.static_l_desc = new StaticTree(StaticTree.static_ltree, Tree.extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
6573
6574	StaticTree.static_d_desc = new StaticTree(StaticTree.static_dtree, Tree.extra_dbits, 0, D_CODES, MAX_BITS);
6575
6576	StaticTree.static_bl_desc = new StaticTree(null, Tree.extra_blbits, 0, BL_CODES, MAX_BL_BITS);
6577
6578	// Deflate
6579
6580	var MAX_MEM_LEVEL = 9;
6581	var DEF_MEM_LEVEL = 8;
6582
6583	function Config(good_length, max_lazy, nice_length, max_chain, func) {
6584		var that = this;
6585		that.good_length = good_length;
6586		that.max_lazy = max_lazy;
6587		that.nice_length = nice_length;
6588		that.max_chain = max_chain;
6589		that.func = func;
6590	}
6591
6592	var STORED = 0;
6593	var FAST = 1;
6594	var SLOW = 2;
6595	var config_table = [ new Config(0, 0, 0, 0, STORED), new Config(4, 4, 8, 4, FAST), new Config(4, 5, 16, 8, FAST), new Config(4, 6, 32, 32, FAST),
6596			new Config(4, 4, 16, 16, SLOW), new Config(8, 16, 32, 32, SLOW), new Config(8, 16, 128, 128, SLOW), new Config(8, 32, 128, 256, SLOW),
6597			new Config(32, 128, 258, 1024, SLOW), new Config(32, 258, 258, 4096, SLOW) ];
6598
6599	var z_errmsg = [ "need dictionary", // Z_NEED_DICT
6600	// 2
6601	"stream end", // Z_STREAM_END 1
6602	"", // Z_OK 0
6603	"", // Z_ERRNO (-1)
6604	"stream error", // Z_STREAM_ERROR (-2)
6605	"data error", // Z_DATA_ERROR (-3)
6606	"", // Z_MEM_ERROR (-4)
6607	"buffer error", // Z_BUF_ERROR (-5)
6608	"",// Z_VERSION_ERROR (-6)
6609	"" ];
6610
6611	// block not completed, need more input or more output
6612	var NeedMore = 0;
6613
6614	// block flush performed
6615	var BlockDone = 1;
6616
6617	// finish started, need only more output at next deflate
6618	var FinishStarted = 2;
6619
6620	// finish done, accept no more input or output
6621	var FinishDone = 3;
6622
6623	// preset dictionary flag in zlib header
6624	var PRESET_DICT = 0x20;
6625
6626	var INIT_STATE = 42;
6627	var BUSY_STATE = 113;
6628	var FINISH_STATE = 666;
6629
6630	// The deflate compression method
6631	var Z_DEFLATED = 8;
6632
6633	var STORED_BLOCK = 0;
6634	var STATIC_TREES = 1;
6635	var DYN_TREES = 2;
6636
6637	var MIN_MATCH = 3;
6638	var MAX_MATCH = 258;
6639	var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
6640
6641	function smaller(tree, n, m, depth) {
6642		var tn2 = tree[n * 2];
6643		var tm2 = tree[m * 2];
6644		return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m]));
6645	}
6646
6647	function Deflate() {
6648
6649		var that = this;
6650		var strm; // pointer back to this zlib stream
6651		var status; // as the name implies
6652		// pending_buf; // output still pending
6653		var pending_buf_size; // size of pending_buf
6654		// pending_out; // next pending byte to output to the stream
6655		// pending; // nb of bytes in the pending buffer
6656		var method; // STORED (for zip only) or DEFLATED
6657		var last_flush; // value of flush param for previous deflate call
6658
6659		var w_size; // LZ77 window size (32K by default)
6660		var w_bits; // log2(w_size) (8..16)
6661		var w_mask; // w_size - 1
6662
6663		var window;
6664		// Sliding window. Input bytes are read into the second half of the window,
6665		// and move to the first half later to keep a dictionary of at least wSize
6666		// bytes. With this organization, matches are limited to a distance of
6667		// wSize-MAX_MATCH bytes, but this ensures that IO is always
6668		// performed with a length multiple of the block size. Also, it limits
6669		// the window size to 64K, which is quite useful on MSDOS.
6670		// To do: use the user input buffer as sliding window.
6671
6672		var window_size;
6673		// Actual size of window: 2*wSize, except when the user input buffer
6674		// is directly used as sliding window.
6675
6676		var prev;
6677		// Link to older string with same hash index. To limit the size of this
6678		// array to 64K, this link is maintained only for the last 32K strings.
6679		// An index in this array is thus a window index modulo 32K.
6680
6681		var head; // Heads of the hash chains or NIL.
6682
6683		var ins_h;
6683 // hash index of string to be inserted
6684		var hash_size; // number of elements in hash table
6685		var hash_bits; // log2(hash_size)
6686		var hash_mask; // hash_size-1
6687
6688		// Number of bits by which ins_h must be shifted at each input
6689		// step. It must be such that after MIN_MATCH steps, the oldest
6690		// byte no longer takes part in the hash key, that is:
6691		// hash_shift * MIN_MATCH >= hash_bits
6692		var hash_shift;
6693
6694		// Window position at the beginning of the current output block. Gets
6695		// negative when the window is moved backwards.
6696
6697		var block_start;
6698
6699		var match_length; // length of best match
6700		var prev_match; // previous match
6701		var match_available; // set if previous match exists
6702		var strstart; // start of string to insert
6703		var match_start; // start of matching string
6704		var lookahead; // number of valid bytes ahead in window
6705
6706		// Length of the best match at previous step. Matches not greater than this
6707		// are discarded. This is used in the lazy match evaluation.
6708		var prev_length;
6709
6710		// To speed up deflation, hash chains are never searched beyond this
6711		// length. A higher limit improves compression ratio but degrades the speed.
6712		var max_chain_length;
6713
6714		// Attempt to find a better match only when the current match is strictly
6715		// smaller than this value. This mechanism is used only for compression
6716		// levels >= 4.
6717		var max_lazy_match;
6718
6719		// Insert new strings in the hash table only if the match length is not
6720		// greater than this length. This saves time but degrades compression.
6721		// max_insert_length is used only for compression levels <= 3.
6722
6723		var level; // compression level (1..9)
6724		var strategy; // favor or force Huffman coding
6725
6726		// Use a faster search when the previous match is longer than this
6727		var good_match;
6728
6729		// Stop searching when current match exceeds this
6730		var nice_match;
6731
6732		var dyn_ltree; // literal and length tree
6733		var dyn_dtree; // distance tree
6734		var bl_tree; // Huffman tree for bit lengths
6735
6736		var l_desc = new Tree(); // desc for literal tree
6737		var d_desc = new Tree(); // desc for distance tree
6738		var bl_desc = new Tree(); // desc for bit length tree
6739
6740		// that.heap_len; // number of elements in the heap
6741		// that.heap_max; // element of largest frequency
6742		// The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
6743		// The same heap array is used to build all trees.
6744
6745		// Depth of each subtree used as tie breaker for trees of equal frequency
6746		that.depth = [];
6747
6748		var l_buf; // index for literals or lengths */
6749
6750		// Size of match buffer for literals/lengths. There are 4 reasons for
6751		// limiting lit_bufsize to 64K:
6752		// - frequencies can be kept in 16 bit counters
6753		// - if compression is not successful for the first block, all input
6754		// data is still in the window so we can still emit a stored block even
6755		// when input comes from standard input. (This can also be done for
6756		// all blocks if lit_bufsize is not greater than 32K.)
6757		// - if compression is not successful for a file smaller than 64K, we can
6758		// even emit a stored file instead of a stored block (saving 5 bytes).
6759		// This is applicable only for zip (not gzip or zlib).
6760		// - creating new Huffman trees less frequently may not provide fast
6761		// adaptation to changes in the input data statistics. (Take for
6762		// example a binary file with poorly compressible code followed by
6763		// a highly compressible string table.) Smaller buffer sizes give
6764		// fast adaptation but have of course the overhead of transmitting
6765		// trees more frequently.
6766		// - I can't count above 4
6767		var lit_bufsize;
6768
6769		var last_lit; // running index in l_buf
6770
6771		// Buffer for distances. To simplify the code, d_buf and l_buf have
6772		// the same number of elements. To use different lengths, an extra flag
6773		// array would be necessary.
6774
6775		var d_buf; // index of pendig_buf
6776
6777		// that.opt_len; // bit length of current block with optimal trees
6778		// that.static_len; // bit length of current block with static trees
6779		var matches; // number of string matches in current block
6780		var last_eob_len; // bit length of EOB code for last block
6781
6782		// Output buffer. bits are inserted starting at the bottom (least
6783		// significant bits).
6784		var bi_buf;
6785
6786		// Number of valid bits in bi_buf. All bits above the last valid bit
6787		// are always zero.
6788		var bi_valid;
6789
6790		// number of codes at each bit length for an optimal tree
6791		that.bl_count = [];
6792
6793		// heap used to build the Huffman trees
6794		that.heap = [];
6795
6796		dyn_ltree = [];
6797		dyn_dtree = [];
6798		bl_tree = [];
6799
6800		function lm_init() {
6801			var i;
6802			window_size = 2 * w_size;
6803
6804			head[hash_size - 1] = 0;
6805			for (i = 0; i < hash_size - 1; i++) {
6806				head[i] = 0;
6807			}
6808
6809			// Set the default configuration parameters:
6810			max_lazy_match = config_table[level].max_lazy;
6811			good_match = config_table[level].good_length;
6812			nice_match = config_table[level].nice_length;
6813			max_chain_length = config_table[level].max_chain;
6814
6815			strstart = 0;
6816			block_start = 0;
6817			lookahead = 0;
6818			match_length = prev_length = MIN_MATCH - 1;
6819			match_available = 0;
6820			ins_h = 0;
6821		}
6822
6823		function init_block() {
6824			var i;
6825			// Initialize the trees.
6826			for (i = 0; i < L_CODES; i++)
6827				dyn_ltree[i * 2] = 0;
6828			for (i = 0; i < D_CODES; i++)
6829				dyn_dtree[i * 2] = 0;
6830			for (i = 0; i < BL_CODES; i++)
6831				bl_tree[i * 2] = 0;
6832
6833			dyn_ltree[END_BLOCK * 2] = 1;
6834			that.opt_len = that.static_len = 0;
6835			last_lit = matches = 0;
6836		}
6837
6838		// Initialize the tree data structures for a new zlib stream.
6839		function tr_init() {
6840
6841			l_desc.dyn_tree = dyn_ltree;
6842			l_desc.stat_desc = StaticTree.static_l_desc;
6843
6844			d_desc.dyn_tree = dyn_dtree;
6845			d_desc.stat_desc = StaticTree.static_d_desc;
6846
6847			bl_desc.dyn_tree = bl_tree;
6848			bl_desc.stat_desc = StaticTree.static_bl_desc;
6849
6850			bi_buf = 0;
6851			bi_valid = 0;
6852			last_eob_len = 8; // enough lookahead for inflate
6853
6854			// Initialize the first block of the first file:
6855			init_block();
6856		}
6857
6858		// Restore the heap property by moving down the tree starting at node k,
6859		// exchanging a node with the smallest of its two sons if necessary,
6860		// stopping
6861		// when the heap property is re-established (each father smaller than its
6862		// two sons).
6863		that.pqdownheap = function(tree, // the tree to restore
6864		k // node to move down
6865		) {
6866			var heap = that.heap;
6867			var v = heap[k];
6868			var j = k << 1; // left son of k
6869			while (j <= that.heap_len) {
6870				// Set j to the smallest of the two sons:
6871				if (j < that.heap_len && smaller(tree, heap[j + 1], heap[j], that.depth)) {
6872					j++;
6873				}
6874				// Exit if v is smaller than both sons
6875				if (smaller(tree, v, heap[j], that.depth))
6876					break;
6877
6878				// Exchange v with the smallest son
6879				heap[k] = heap[j];
6880				k = j;
6881				// And continue down the tree, setting j to the left son of k
6882				j <<= 1;
6883			}
6884			heap[k] = v;
6885		};
6886
6887		// Scan a literal or distance tree to determine the frequencies of the codes
6888		// in the bit length tree.
6889		function scan_tree(tree,// the tree to be scanned
6890		max_code // and its largest code of non zero frequency
6891		) {
6892			var n; // iterates over all tree elements
6893			var prevlen = -1; // last emitted length
6894			var curlen; // length of current code
6895			var nextlen = tree[0 * 2 + 1]; // length of next code
6896			var count = 0; // repeat count of the current code
6897			var max_count = 7; // max repeat count
6898			var min_count = 4; // min repeat count
6899
6900			if (nextlen === 0) {
6901				max_count = 138;
6902				min_count = 3;
6903			}
6904			tree[(max_code + 1) * 2 + 1] = 0xffff; // guard
6905
6906			for (n = 0; n <= max_code; n++) {
6907				curlen = nextlen;
6908				nextlen = tree[(n + 1) * 2 + 1];
6909				if (++count < max_count && curlen == nextlen) {
6910					continue;
6911				} else if (count < min_count) {
6912					bl_tree[curlen * 2] += count;
6913				} else if (curlen !== 0) {
6914					if (curlen != prevlen)
6915						bl_tree[curlen * 2]++;
6916					bl_tree[REP_3_6 * 2]++;
6917				} else if (count <= 10) {
6918					bl_tree[REPZ_3_10 * 2]++;
6919				} else {
6920					bl_tree[REPZ_11_138 * 2]++;
6921				}
6922				count = 0;
6923				prevlen = curlen;
6924				if (nextlen === 0) {
6925					max_count = 138;
6926					min_count = 3;
6927				} else if (curlen == nextlen) {
6928					max_count = 6;
6929					min_count = 3;
6930				} else {
6931					max_count = 7;
6932					min_count = 4;
6933				}
6934			}
6935		}
6936
6937		// Construct the Huffman tree for the bit lengths and return the index in
6938		// bl_order of the last bit length code to send.
6939		function build_bl_tree() {
6940			var max_blindex; // index of last bit length code of non zero freq
6941
6942			// Determine the bit length frequencies for literal and distance trees
6943			scan_tree(dyn_ltree, l_desc.max_code);
6944			scan_tree(dyn_dtree, d_desc.max_code);
6945
6946			// Build the bit length tree:
6947			bl_desc.build_tree(that);
6948			// opt_len now includes the length of the tree representations, except
6949			// the lengths of the bit lengths codes and the 5+5+4 bits for the
6950			// counts.
6951
6952			// Determine the number of bit length codes to send. The pkzip format
6953			// requires that at least 4 bit length codes be sent. (appnote.txt says
6954			// 3 but the actual value used is 4.)
6955			for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
6956				if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] !== 0)
6957					break;
6958			}
6959			// Update opt_len to include the bit length tree and counts
6960			that.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
6961
6962			return max_blindex;
6963		}
6964
6965		// Output a byte on the stream.
6966		// IN assertion: there is enough room in pending_buf.
6967		function put_byte(p) {
6968			that.pending_buf[that.pending++] = p;
6969		}
6970
6971		function put_short(w) {
6972			put_byte(w & 0xff);
6973			put_byte((w >>> 8) & 0xff);
6974		}
6975
6976		function putShortMSB(b) {
6977			put_byte((b >> 8) & 0xff);
6978			put_byte((b & 0xff) & 0xff);
6979		}
6980
6981		function send_bits(value, length) {
6982			var val, len = length;
6983			if (bi_valid > Buf_size - len) {
6984				val = value;
6985				// bi_buf |= (val << bi_valid);
6986				bi_buf |= ((val << bi_valid) & 0xffff);
6987				put_short(bi_buf);
6988				bi_buf = val >>> (Buf_size - bi_valid);
6989				bi_valid += len - Buf_size;
6990			} else {
6991				// bi_buf |= (value) << bi_valid;
6992				bi_buf |= (((value) << bi_valid) & 0xffff);
6993				bi_valid += len;
6994			}
6995		}
6996
6997		function send_code(c, tree) {
6998			var c2 = c * 2;
6999			send_bits(tree[c2] & 0xffff, tree[c2 + 1] & 0xffff);
7000		}
7001
7002		// Send a literal or distance tree in compressed form, using the codes in
7003		// bl_tree.
7004		function send_tree(tree,// the tree to be sent
7005		max_code // and its largest code of non zero frequency
7006		) {
7007			var n; // iterates over all tree elements
7008			var prevlen = -1; // last emitted length
7009			var curlen; // length of current code
7010			var nextlen = tree[0 * 2 + 1]; // length of next code
7011			var count = 0; // repeat count of the current code
7012			var max_count = 7; // max repeat count
7013			var min_count = 4; // min repeat count
7014
7015			if (nextlen === 0) {
7016				max_count = 138;
7017				min_count = 3;
7018			}
7019
7020			for (n = 0; n <= max_code; n++) {
7021				curlen = nextlen;
7022				nextlen = tree[(n + 1) * 2 + 1];
7023				if (++count < max_count && curlen == nextlen) {
7024					continue;
7025				} else if (count < min_count) {
7026					do {
7027						send_code(curlen, bl_tree);
7028					} while (--count !== 0);
7029				} else if (curlen !== 0) {
7030					if (curlen != prevlen) {
7031						send_code(curlen, bl_tree);
7032						count--;
7033					}
7034					send_code(REP_3_6, bl_tree);
7035					send_bits(count - 3, 2);
7036				} else if (count <= 10) {
7037					send_code(REPZ_3_10, bl_tree);
7038					send_bits(count - 3, 3);
7039				} else {
7040					send_code(REPZ_11_138, bl_tree);
7041					send_bits(count - 11, 7);
7042				}
7043				count = 0;
7044				prevlen = curlen;
7045				if (nextlen === 0) {
7046					max_count = 138;
7047					min_count = 3;
7048				} else if (curlen == nextlen) {
7049					max_count = 6;
7050					min_count = 3;
7051				} else {
7052					max_count = 7;
7053					min_count = 4;
7054				}
7055			}
7056		}
7057
7058		// Send the header for a block using dynamic Huffman trees: the counts, the
7059		// lengths of the bit length codes, the literal tree and the distance tree.
7060		// IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
7061		function send_all_trees(lcodes, dcodes, blcodes) {
7062			var rank; // index in bl_order
7063
7064			send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt
7065			send_bits(dcodes - 1, 5);
7066			send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt
7067			for (rank = 0; rank < blcodes; rank++) {
7068				send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3);
7069			}
7070			send_tree(dyn_ltree, lcodes - 1); // literal tree
7071			send_tree(dyn_dtree, dcodes - 1); // distance tree
7072		}
7073
7074		// Flush the bit buffer, keeping at most 7 bits in it.
7075		function bi_flush() {
7076			if (bi_valid == 16) {
7077				put_short(bi_buf);
7078				bi_buf = 0;
7079				bi_valid = 0;
7080			} else if (bi_valid >= 8) {
7081				put_byte(bi_buf & 0xff);
7082				bi_buf >>>= 8;
7083				bi_valid -= 8;
7084			}
7085		}
7086
7087		// Send one empty static block to give enough lookahead for inflate.
7088		// This takes 10 bits, of which 7 may remain in the bit buffer.
7089		// The current inflate code requires 9 bits of lookahead. If the
7090		// last two codes for the previous block (real code plus EOB) were coded
7091		// on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
7092		// the last real code. In this case we send two empty static blocks instead
7093		// of one. (There are no problems if the previous block is stored or fixed.)
7094		// To simplify the code, we assume the worst case of last real code encoded
7095		// on one bit only.
7096		function _tr_align() {
7097			send_bits(STATIC_TREES << 1, 3);
7098			send_code(END_BLOCK, StaticTree.static_ltree);
7099
7100			bi_flush();
7101
7102			// Of the 10 bits for the empty block, we have already sent
7103			// (10 - bi_valid) bits. The lookahead for the last real code (before
7104			// the EOB of the previous block) was thus at least one plus the length
7105			// of the EOB plus what we have just sent of the empty static block.
7106			if (1 + last_eob_len + 10 - bi_valid < 9) {
7107				send_bits(STATIC_TREES << 1, 3);
7108				send_code(END_BLOCK, StaticTree.static_ltree);
7109				bi_flush();
7110			}
7111			last_eob_len = 7;
7112		}
7113
7114		// Save the match info and tally the frequency counts. Return true if
7115		// the current block must be flushed.
7116		function _tr_tally(dist, // distance of matched string
7117		lc // match length-MIN_MATCH or unmatched char (if dist==0)
7118		) {
7119			var out_length, in_length, dcode;
7120			that.pending_buf[d_buf + last_lit * 2] = (dist >>> 8) & 0xff;
7121			that.pending_buf[d_buf + last_lit * 2 + 1] = dist & 0xff;
7122
7123			that.pending_buf[l_buf + last_lit] = lc & 0xff;
7124			last_lit++;
7125
7126			if (dist === 0) {
7127				// lc is the unmatched char
7128				dyn_ltree[lc * 2]++;
7129			} else {
7130				matches++;
7131				// Here, lc is the match length - MIN_MATCH
7132				dist--; // dist = match distance - 1
7133				dyn_ltree[(Tree._length_code[lc] + LITERALS + 1) * 2]++;
7134				dyn_dtree[Tree.d_code(dist) * 2]++;
7135			}
7136
7137			if ((last_lit & 0x1fff) === 0 && level > 2) {
7138				// Compute an upper bound for the compressed length
7139				out_length = last_lit * 8;
7140				in_length = strstart - block_start;
7141				for (dcode = 0; dcode < D_CODES; dcode++) {
7142					out_length += dyn_dtree[dcode * 2] * (5 + Tree.extra_dbits[dcode]);
7143				}
7144				out_length >>>= 3;
7145				if ((matches < Math.floor(last_lit / 2)) && out_length < Math.floor(in_length / 2))
7146					return true;
7147			}
7148
7149			return (last_lit == lit_bufsize - 1);
7150			// We avoid equality with lit_bufsize because of wraparound at 64K
7151			// on 16 bit machines and because stored blocks are restricted to
7152			// 64K-1 bytes.
7153		}
7154
7155		// Send the block data compressed using the given Huffman trees
7156		function compress_block(ltree, dtree) {
7157			var dist; // distance of matched string
7158			var lc; // match length or unmatched char (if dist === 0)
7159			var lx = 0; // running index in l_buf
7160			var code; // the code to send
7161			var extra; // number of extra bits to send
7162
7163			if (last_lit !== 0) {
7164				do {
7165					dist = ((that.pending_buf[d_buf + lx * 2] << 8) & 0xff00) | (that.pending_buf[d_buf + lx * 2 + 1] & 0xff);
7166					lc = (that.pending_buf[l_buf + lx]) & 0xff;
7167					lx++;
7168
7169					if (dist === 0) {
7170						send_code(lc, ltree); // send a literal byte
7171					} else {
7172						// Here, lc is the match length - MIN_MATCH
7173						code = Tree._length_code[lc];
7174
7175						send_code(code + LITERALS + 1, ltree); // send the length
7176						// code
7177						extra = Tree.extra_lbits[code];
7178						if (extra !== 0) {
7179							lc -= Tree.base_length[code];
7180							send_bits(lc, extra); // send the extra length bits
7181						}
7182						dist--; // dist is now the match distance - 1
7183						code = Tree.d_code(dist);
7184
7185						send_code(code, dtree); // send the distance code
7186						extra = Tree.extra_dbits[code];
7187						if (extra !== 0) {
7188							dist -= Tree.base_dist[code];
7189							send_bits(dist, extra); // send the extra distance bits
7190						}
7191					} // literal or match pair ?
7192
7193					// Check that the overlay between pending_buf and d_buf+l_buf is
7194					// ok:
7195				} while (lx < last_lit);
7196			}
7197
7198			send_code(END_BLOCK, ltree);
7199			last_eob_len = ltree[END_BLOCK * 2 + 1];
7200		}
7201
7202		// Flush the bit buffer and align the output on a byte boundary
7203		function bi_windup() {
7204			if (bi_valid > 8) {
7205				put_short(bi_buf);
7206			} else if (bi_valid > 0) {
7207				put_byte(bi_buf & 0xff);
7208			}
7209			bi_buf = 0;
7210			bi_valid = 0;
7211		}
7212
7213		// Copy a stored block, storing first the length and its
7214		// one's complement if requested.
7215		function copy_block(buf, // the input data
7216		len, // its length
7217		header // true if block header must be written
7218		) {
7219			bi_windup(); // align on byte boundary
7220			last_eob_len = 8; // enough lookahead for inflate
7221
7222			if (header) {
7223				put_short(len);
7224				put_short(~len);
7225			}
7226
7227			that.pending_buf.set(window.subarray(buf, buf + len), that.pending);
7228			that.pending += len;
7229		}
7230
7231		// Send a stored block
7232		function _tr_stored_block(buf, // input block
7233		stored_len, // length of input block
7234		eof // true if this is the last block for a file
7235		) {
7236			send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type
7237			copy_block(buf, stored_len, true); // with header
7238		}
7239
7240		// Determine the best encoding for the current block: dynamic trees, static
7241		// trees or store, and output the encoded block to the zip file.
7242		function _tr_flush_block(buf, // input block, or NULL if too old
7243		stored_len, // length of input block
7244		eof // true if this is the last block for a file
7245		) {
7246			var opt_lenb, static_lenb;// opt_len and static_len in bytes
7247			var max_blindex = 0; // index of last bit length code of non zero freq
7248
7249			// Build the Huffman trees unless a stored block is forced
7250			if (level > 0) {
7251				// Construct the literal and distance trees
7252				l_desc.build_tree(that);
7253
7254				d_desc.build_tree(that);
7255
7256				// At this point, opt_len and static_len are the total bit lengths
7257				// of
7258				// the compressed block data, excluding the tree representations.
7259
7260				// Build the bit length tree for the above two trees, and get the
7261				// index
7262				// in bl_order of the last bit length code to send.
7263				max_blindex = build_bl_tree();
7264
7265				// Determine the best encoding. Compute first the block length in
7266				// bytes
7267				opt_lenb = (that.opt_len + 3 + 7) >>> 3;
7268				static_lenb = (that.static_len + 3 + 7) >>> 3;
7269
7270				if (static_lenb <= opt_lenb)
7271					opt_lenb = static_lenb;
7272			} else {
7273				opt_lenb = static_lenb = stored_len + 5; // force a stored block
7274			}
7275
7276			if ((stored_len + 4 <= opt_lenb) && buf != -1) {
7277				// 4: two words for the lengths
7278				// The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
7279				// Otherwise we can't have processed more than WSIZE input bytes
7280				// since
7281				// the last block flush, because compression would have been
7282				// successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
7283				// transform a block into a stored block.
7284				_tr_stored_block(buf, stored_len, eof);
7285			} else if (static_lenb == opt_lenb) {
7286				send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3);
7287				compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
7288			} else {
7289				send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3);
7290				send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1);
7291				compress_block(dyn_ltree, dyn_dtree);
7292			}
7293
7294			// The above check is made mod 2^32, for files larger than 512 MB
7295			// and uLong implemented on 32 bits.
7296
7297			init_block();
7298
7299			if (eof) {
7300				bi_windup();
7301			}
7302		}
7303
7304		function flush_block_only(eof) {
7305			_tr_flush_block(block_start >= 0 ? block_start : -1, strstart - block_start, eof);
7306			block_start = strstart;
7307			strm.flush_pending();
7308		}
7309
7310		// Fill the window when the lookahead becomes insufficient.
7311		// Updates strstart and lookahead.
7312		//
7313		// IN assertion: lookahead < MIN_LOOKAHEAD
7314		// OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
7315		// At least one byte has been read, or avail_in === 0; reads are
7316		// performed for at least two bytes (required for the zip translate_eol
7317		// option -- not supported here).
7318		function fill_window() {
7319			var n, m;
7320			var p;
7321			var more; // Amount of free space at the end of the window.
7322
7323			do {
7324				more = (window_size - lookahead - strstart);
7325
7326				// Deal with !@#$% 64K limit:
7327				if (more === 0 && strstart === 0 && lookahead === 0) {
7328					more = w_size;
7329				} else if (more == -1) {
7330					// Very unlikely, but possible on 16 bit machine if strstart ==
7331					// 0
7332					// and lookahead == 1 (input done one byte at time)
7333					more--;
7334
7335					// If the window is almost full and there is insufficient
7336					// lookahead,
7337					// move the upper half to the lower one to make room in the
7338					// upper half.
7339				} else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) {
7340					window.set(window.subarray(w_size, w_size + w_size), 0);
7341
7342					match_start -= w_size;
7343					strstart -= w_size; // we now have strstart >= MAX_DIST
7344					block_start -= w_size;
7345
7346					// Slide the hash table (could be avoided with 32 bit values
7347					// at the expense of memory usage). We slide even when level ==
7348					// 0
7349					// to keep the hash table consistent if we switch back to level
7350					// > 0
7351					// later. (Using level 0 permanently is not an optimal usage of
7352					// zlib, so we don't care about this pathological case.)
7353
7354					n = hash_size;
7355					p = n;
7356					do {
7357						m = (head[--p] & 0xffff);
7358						head[p] = (m >= w_size ? m - w_size : 0);
7359					} while (--n !== 0);
7360
7361					n = w_size;
7362					p = n;
7363					do {
7364						m = (prev[--p] & 0xffff);
7365						prev[p] = (m >= w_size ? m - w_size : 0);
7366						// If n is not on any hash chain, prev[n] is garbage but
7367						// its value will never be used.
7368					} while (--n !== 0);
7369					more += w_size;
7370				}
7371
7372				if (strm.avail_in === 0)
7373					return;
7374
7375				// If there was no sliding:
7376				// strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
7377				// more == window_size - lookahead - strstart
7378				// => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
7379				// => more >= window_size - 2*WSIZE + 2
7380				// In the BIG_MEM or MMAP case (not yet supported),
7381				// window_size == input_size + MIN_LOOKAHEAD &&
7382				// strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
7383				// Otherwise, window_size == 2*WSIZE so more >= 2.
7384				// If there was sliding, more >= WSIZE. So in all cases, more >= 2.
7385
7386				n = strm.read_buf(window, strstart + lookahead, more);
7387				lookahead += n;
7388
7389				// Initialize the hash value now that we have some input:
7390				if (lookahead >= MIN_MATCH) {
7391					ins_h = window[strstart] & 0xff;
7392					ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
7393				}
7394				// If the whole input has less than MIN_MATCH bytes, ins_h is
7395				// garbage,
7396				// but this is not important since only literal bytes will be
7397				// emitted.
7398			} while (lookahead < MIN_LOOKAHEAD && strm.avail_in !== 0);
7399		}
7400
7401		// Copy without compression as much as possible from the input stream,
7402		// return
7403		// the current block state.
7404		// This function does not insert new strings in the dictionary since
7405		// uncompressible data is probably not useful. This function is used
7406		// only for the level=0 compression option.
7407		// NOTE: this function should be optimized to avoid extra copying from
7408		// window to pending_buf.
7409		function deflate_stored(flush) {
7410			// Stored blocks are limited to 0xffff bytes, pending_buf is limited
7411			// to pending_buf_size, and each stored block has a 5 byte header:
7412
7413			var max_block_size = 0xffff;
7414			var max_start;
7415
7416			if (max_block_size > pending_buf_size - 5) {
7417				max_block_size = pending_buf_size - 5;
7418			}
7419
7420			// Copy as much as possible from input to output:
7421			while (true) {
7422				// Fill the window as much as possible:
7423				if (lookahead <= 1) {
7424					fill_window();
7425					if (lookahead === 0 && flush == Z_NO_FLUSH)
7426						return NeedMore;
7427					if (lookahead === 0)
7428						break; // flush the current block
7429				}
7430
7431				strstart += lookahead;
7432				lookahead = 0;
7433
7434				// Emit a stored block if pending_buf will be full:
7435				max_start = block_start + max_block_size;
7436				if (strstart === 0 || strstart >= max_start) {
7437					// strstart === 0 is possible when wraparound on 16-bit machine
7438					lookahead = (strstart - max_start);
7439					strstart = max_start;
7440
7441					flush_block_only(false);
7442					if (strm.avail_out === 0)
7443						return NeedMore;
7444
7445				}
7446
7447				// Flush if we may have to slide, otherwise block_start may become
7448				// negative and the data will be gone:
7449				if (strstart - block_start >= w_size - MIN_LOOKAHEAD) {
7450					flush_block_only(false);
7451					if (strm.avail_out === 0)
7452						return NeedMore;
7453				}
7454			}
7455
7456			flush_block_only(flush == Z_FINISH);
7457			if (strm.avail_out === 0)
7458				return (flush == Z_FINISH) ? FinishStarted : NeedMore;
7459
7460			return flush == Z_FINISH ? FinishDone : BlockDone;
7461		}
7462
7463		function longest_match(cur_match) {
7464			var chain_length = max_chain_length; // max hash chain length
7465			var scan = strstart; // current string
7466			var match; // matched string
7467			var len; // length of current match
7468			var best_len = prev_length; // best match length so far
7469			var limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0;
7470			var _nice_match = nice_match;
7471
7472			// Stop when cur_match becomes <= limit. To simplify the code,
7473			// we prevent matches with the string of window index 0.
7474
7475			var wmask = w_mask;
7476
7477			var strend = strstart + MAX_MATCH;
7478			var scan_end1 = window[scan + best_len - 1];
7479			var scan_end = window[scan + best_len];
7480
7481			// The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of
7482			// 16.
7483			// It is easy to get rid of this optimization if necessary.
7484
7485			// Do not waste too much time if we already have a good match:
7486			if (prev_length >= good_match) {
7487				chain_length >>= 2;
7488			}
7489
7490			// Do not look for matches beyond the end of the input. This is
7491			// necessary
7492			// to make deflate deterministic.
7493			if (_nice_match > lookahead)
7494				_nice_match = lookahead;
7495
7496			do {
7497				match = cur_match;
7498
7499				// Skip to next match if the match length cannot increase
7500				// or if the match length is less than 2:
7501				if (window[match + best_len] != scan_end || window[match + best_len - 1] != scan_end1 || window[match] != window[scan]
7502						|| window[++match] != window[scan + 1])
7503					continue;
7504
7505				// The check at best_len-1 can be removed because it will be made
7506				// again later. (This heuristic is not always a win.)
7507				// It is not necessary to compare scan[2] and match[2] since they
7508				// are always equal when the other bytes match, given that
7509				// the hash keys are equal and that HASH_BITS >= 8.
7510				scan += 2;
7511				match++;
7512
7513				// We check for insufficient lookahead only every 8th comparison;
7514				// the 256th check will be made at strstart+258.
7515				do {
7516				} while (window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match]
7517						&& window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match]
7518						&& window[++scan] == window[++match] && window[++scan] == window[++match] && scan < strend);
7519
7520				len = MAX_MATCH - (strend - scan);
7521				scan = strend - MAX_MATCH;
7522
7523				if (len > best_len) {
7524					match_start = cur_match;
7525					best_len = len;
7526					if (len >= _nice_match)
7527						break;
7528					scan_end1 = window[scan + best_len - 1];
7529					scan_end = window[scan + best_len];
7530				}
7531
7532			} while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length !== 0);
7533
7534			if (best_len <= lookahead)
7535				return best_len;
7536			return lookahead;
7537		}
7538
7539		// Compress as much as possible from the input stream, return the current
7540		// block state.
7541		// This function does not perform lazy evaluation of matches and inserts
7542		// new strings in the dictionary only for unmatched strings or for short
7543		// matches. It is used only for the fast compression options.
7544		function deflate_fast(flush) {
7545			// short hash_head = 0; // head of the hash chain
7546			var hash_head = 0; // head of the hash chain
7547			var bflush; // set if current block must be flushed
7548
7549			while (true) {
7550				// Make sure that we always have enough lookahead, except
7551				// at the end of the input file. We need MAX_MATCH bytes
7552				// for the next match, plus MIN_MATCH bytes to insert the
7553				// string following the next match.
7554				if (lookahead < MIN_LOOKAHEAD) {
7555					fill_window();
7556					if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
7557						return NeedMore;
7558					}
7559					if (lookahead === 0)
7560						break; // flush the current block
7561				}
7562
7563				// Insert the string window[strstart .. strstart+2] in the
7564				// dictionary, and set hash_head to the head of the hash chain:
7565				if (lookahead >= MIN_MATCH) {
7566					ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
7567
7568					// prev[strstart&w_mask]=hash_head=head[ins_h];
7569					hash_head = (head[ins_h] & 0xffff);
7570					prev[strstart & w_mask] = head[ins_h];
7571					head[ins_h] = strstart;
7572				}
7573
7574				// Find the longest match, discarding those <= prev_length.
7575				// At this point we have always match_length < MIN_MATCH
7576
7577				if (hash_head !== 0 && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
7578					// To simplify the code, we prevent matches with the string
7579					// of window index 0 (in particular we have to avoid a match
7580					// of the string with itself at the start of the input file).
7581					if (strategy != Z_HUFFMAN_ONLY) {
7582						match_length = longest_match(hash_head);
7583					}
7584					// longest_match() sets match_start
7585				}
7586				if (match_length >= MIN_MATCH) {
7587					// check_match(strstart, match_start, match_length);
7588
7589					bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH);
7590
7591					lookahead -= match_length;
7592
7593					// Insert new strings in the hash table only if the match length
7594					// is not too large. This saves time but degrades compression.
7595					if (match_length <= max_lazy_match && lookahead >= MIN_MATCH) {
7596						match_length--; // string at strstart already in hash table
7597						do {
7598							strstart++;
7599
7600							ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
7601							// prev[strstart&w_mask]=hash_head=head[ins_h];
7602							hash_head = (head[ins_h] & 0xffff);
7603							prev[strstart & w_mask] = head[ins_h];
7604							head[ins_h] = strstart;
7605
7606							// strstart never exceeds WSIZE-MAX_MATCH, so there are
7607							// always MIN_MATCH bytes ahead.
7608						} while (--match_length !== 0);
7609						strstart++;
7610					} else {
7611						strstart += match_length;
7612						match_length = 0;
7613						ins_h = window[strstart] & 0xff;
7614
7615						ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
7616						// If lookahead < MIN_MATCH, ins_h is garbage, but it does
7617						// not
7618						// matter since it will be recomputed at next deflate call.
7619					}
7620				} else {
7621					// No match, output a literal byte
7622
7623					bflush = _tr_tally(0, window[strstart] & 0xff);
7624					lookahead--;
7625					strstart++;
7626				}
7627				if (bflush) {
7628
7629					flush_block_only(false);
7630					if (strm.avail_out === 0)
7631						return NeedMore;
7632				}
7633			}
7634
7635			flush_block_only(flush == Z_FINISH);
7636			if (strm.avail_out === 0) {
7637				if (flush == Z_FINISH)
7638					return FinishStarted;
7639				else
7640					return NeedMore;
7641			}
7642			return flush == Z_FINISH ? FinishDone : BlockDone;
7643		}
7644
7645		// Same as above, but achieves better compression. We use a lazy
7646		// evaluation for matches: a match is finally adopted only if there is
7647		// no better match at the next window position.
7648		function deflate_slow(flush) {
7649			// short hash_head = 0; // head of hash chain
7650			var hash_head = 0; // head of hash chain
7651			var bflush; // set if current block must be flushed
7652			var max_insert;
7653
7654			// Process the input block.
7655			while (true) {
7656				// Make sure that we always have enough lookahead, except
7657				// at the end of the input file. We need MAX_MATCH bytes
7658				// for the next match, plus MIN_MATCH bytes to insert the
7659				// string following the next match.
7660
7661				if (lookahead < MIN_LOOKAHEAD) {
7662					fill_window();
7663					if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
7664						return NeedMore;
7665					}
7666					if (lookahead === 0)
7667						break; // flush the current block
7668				}
7669
7670				// Insert the string window[strstart .. strstart+2] in the
7671				// dictionary, and set hash_head to the head of the hash chain:
7672
7673				if (lookahead >= MIN_MATCH) {
7674					ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
7675					// prev[strstart&w_mask]=hash_head=head[ins_h];
7676					hash_head = (head[ins_h] & 0xffff);
7677					prev[strstart & w_mask] = head[ins_h];
7678					head[ins_h] = strstart;
7679				}
7680
7681				// Find the longest match, discarding those <= prev_length.
7682				prev_length = match_length;
7683				prev_match = match_start;
7684				match_length = MIN_MATCH - 1;
7685
7686				if (hash_head !== 0 && prev_length < max_lazy_match && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
7687					// To simplify the code, we prevent matches with the string
7688					// of window index 0 (in particular we have to avoid a match
7689					// of the string with itself at the start of the input file).
7690
7691					if (strategy != Z_HUFFMAN_ONLY) {
7692						match_length = longest_match(hash_head);
7693					}
7694					// longest_match() sets match_start
7695
7696					if (match_length <= 5 && (strategy == Z_FILTERED || (match_length == MIN_MATCH && strstart - match_start > 4096))) {
7697
7698						// If prev_match is also MIN_MATCH, match_start is garbage
7699						// but we will ignore the current match anyway.
7700						match_length = MIN_MATCH - 1;
7701					}
7702				}
7703
7704				// If there was a match at the previous step and the current
7705				// match is not better, output the previous match:
7706				if (prev_length >= MIN_MATCH && match_length <= prev_length) {
7707					max_insert = strstart + lookahead - MIN_MATCH;
7708					// Do not insert strings in hash table beyond this.
7709
7710					// check_match(strstart-1, prev_match, prev_length);
7711
7712					bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH);
7713
7714					// Insert in hash table all strings up to the end of the match.
7715					// strstart-1 and strstart are already inserted. If there is not
7716					// enough lookahead, the last two strings are not inserted in
7717					// the hash table.
7718					lookahead -= prev_length - 1;
7719					prev_length -= 2;
7720					do {
7721						if (++strstart <= max_insert) {
7722							ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
7723							// prev[strstart&w_mask]=hash_head=head[ins_h];
7724							hash_head = (head[ins_h] & 0xffff);
7725							prev[strstart & w_mask] = head[ins_h];
7726							head[ins_h] = strstart;
7727						}
7728					} while (--prev_length !== 0);
7729					match_available = 0;
7730					match_length = MIN_MATCH - 1;
7731					strstart++;
7732
7733					if (bflush) {
7734						flush_block_only(false);
7735						if (strm.avail_out === 0)
7736							return NeedMore;
7737					}
7738				} else if (match_available !== 0) {
7739
7740					// If there was no match at the previous position, output a
7741					// single literal. If there was a match but the current match
7742					// is longer, truncate the previous match to a single literal.
7743
7744					bflush = _tr_tally(0, window[strstart - 1] & 0xff);
7745
7746					if (bflush) {
7747						flush_block_only(false);
7748					}
7749					strstart++;
7750					lookahead--;
7751					if (strm.avail_out === 0)
7752						return NeedMore;
7753				} else {
7754					// There is no previous match to compare with, wait for
7755					// the next step to decide.
7756
7757					match_available = 1;
7758					strstart++;
7759					lookahead--;
7760				}
7761			}
7762
7763			if (match_available !== 0) {
7764				bflush = _tr_tally(0, window[strstart - 1] & 0xff);
7765				match_available = 0;
7766			}
7767			flush_block_only(flush == Z_FINISH);
7768
7769			if (strm.avail_out === 0) {
7770				if (flush == Z_FINISH)
7771					return FinishStarted;
7772				else
7773					return NeedMore;
7774			}
7775
7776			return flush == Z_FINISH ? FinishDone : BlockDone;
7777		}
7778
7779		function deflateReset(strm) {
7780			strm.total_in = strm.total_out = 0;
7781			strm.msg = null; //
7782			
7783			that.pending = 0;
7784			that.pending_out = 0;
7785
7786			status = BUSY_STATE;
7787
7788			last_flush = Z_NO_FLUSH;
7789
7790			tr_init();
7791			lm_init();
7792			return Z_OK;
7793		}
7794
7795		that.deflateInit = function(strm, _level, bits, _method, memLevel, _strategy) {
7796			if (!_method)
7797				_method = Z_DEFLATED;
7798			if (!memLevel)
7799				memLevel = DEF_MEM_LEVEL;
7800			if (!_strategy)
7801				_strategy = Z_DEFAULT_STRATEGY;
7802
7803			// byte[] my_version=ZLIB_VERSION;
7804
7805			//
7806			// if (!version || version[0] != my_version[0]
7807			// || stream_size != sizeof(z_stream)) {
7808			// return Z_VERSION_ERROR;
7809			// }
7810
7811			strm.msg = null;
7812
7813			if (_level == Z_DEFAULT_COMPRESSION)
7814				_level = 6;
7815
7816			if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || _method != Z_DEFLATED || bits < 9 || bits > 15 || _level < 0 || _level > 9 || _strategy < 0
7817					|| _strategy > Z_HUFFMAN_ONLY) {
7818				return Z_STREAM_ERROR;
7819			}
7820
7821			strm.dstate = that;
7822
7823			w_bits = bits;
7824			w_size = 1 << w_bits;
7825			w_mask = w_size - 1;
7826
7827			hash_bits = memLevel + 7;
7828			hash_size = 1 << hash_bits;
7829			hash_mask = hash_size - 1;
7830			hash_shift = Math.floor((hash_bits + MIN_MATCH - 1) / MIN_MATCH);
7831
7832			window = new Uint8Array(w_size * 2);
7833			prev = [];
7834			head = [];
7835
7836			lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
7837
7838			// We overlay pending_buf and d_buf+l_buf. This works since the average
7839			// output size for (length,distance) codes is <= 24 bits.
7840			that.pending_buf = new Uint8Array(lit_bufsize * 4);
7841			pending_buf_size = lit_bufsize * 4;
7842
7843			d_buf = Math.floor(lit_bufsize / 2);
7844			l_buf = (1 + 2) * lit_bufsize;
7845
7846			level = _level;
7847
7848			strategy = _strategy;
7849			method = _method & 0xff;
7850
7851			return deflateReset(strm);
7852		};
7853
7854		that.deflateEnd = function() {
7855			if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) {
7856				return Z_STREAM_ERROR;
7857			}
7858			// Deallocate in reverse order of allocations:
7859			that.pending_buf = null;
7860			head = null;
7861			prev = null;
7862			window = null;
7863			// free
7864			that.dstate = null;
7865			return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
7866		};
7867
7868		that.deflateParams = function(strm, _level, _strategy) {
7869			var err = Z_OK;
7870
7871			if (_level == Z_DEFAULT_COMPRESSION) {
7872				_level = 6;
7873			}
7874			if (_level < 0 || _level > 9 || _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
7875				return Z_STREAM_ERROR;
7876			}
7877
7878			if (config_table[level].func != config_table[_level].func && strm.total_in !== 0) {
7879				// Flush the last buffer:
7880				err = strm.deflate(Z_PARTIAL_FLUSH);
7881			}
7882
7883			if (level != _level) {
7884				level = _level;
7885				max_lazy_match = config_table[level].max_lazy;
7886				good_match = config_table[level].good_length;
7887				nice_match = config_table[level].nice_length;
7888				max_chain_length = config_table[level].max_chain;
7889			}
7890			strategy = _strategy;
7891			return err;
7892		};
7893
7894		that.deflateSetDictionary = function(strm, dictionary, dictLength) {
7895			var length = dictLength;
7896			var n, index = 0;
7897
7898			if (!dictionary || status != INIT_STATE)
7899				return Z_STREAM_ERROR;
7900
7901			if (length < MIN_MATCH)
7902				return Z_OK;
7903			if (length > w_size - MIN_LOOKAHEAD) {
7904				length = w_size - MIN_LOOKAHEAD;
7905				index = dictLength - length; // use the tail of the dictionary
7906			}
7907			window.set(dictionary.subarray(index, index + length), 0);
7908
7909			strstart = length;
7910			block_start = length;
7911
7912			// Insert all strings in the hash table (except for the last two bytes).
7913			// s->lookahead stays null, so s->ins_h will be recomputed at the next
7914			// call of fill_window.
7915
7916			ins_h = window[0] & 0xff;
7917			ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask;
7918
7919			for (n = 0; n <= length - MIN_MATCH; n++) {
7920				ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
7921				prev[n & w_mask] = head[ins_h];
7922				head[ins_h] = n;
7923			}
7924			return Z_OK;
7925		};
7926
7927		that.deflate = function(_strm, flush) {
7928			var i, header, level_flags, old_flush, bstate;
7929
7930			if (flush > Z_FINISH || flush < 0) {
7931				return Z_STREAM_ERROR;
7932			}
7933
7934			if (!_strm.next_out || (!_strm.next_in && _strm.avail_in !== 0) || (status == FINISH_STATE && flush != Z_FINISH)) {
7935				_strm.msg = z_errmsg[Z_NEED_DICT - (Z_STREAM_ERROR)];
7936				return Z_STREAM_ERROR;
7937			}
7938			if (_strm.avail_out === 0) {
7939				_strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
7940				return Z_BUF_ERROR;
7941			}
7942
7943			strm = _strm; // just in case
7944			old_flush = last_flush;
7945			last_flush = flush;
7946
7947			// Write the zlib header
7948			if (status == INIT_STATE) {
7949				header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8;
7950				level_flags = ((level - 1) & 0xff) >> 1;
7951
7952				if (level_flags > 3)
7953					level_flags = 3;
7954				header |= (level_flags << 6);
7955				if (strstart !== 0)
7956					header |= PRESET_DICT;
7957				header += 31 - (header % 31);
7958
7959				status = BUSY_STATE;
7960				putShortMSB(header);
7961			}
7962
7963			// Flush as much pending output as possible
7964			if (that.pending !== 0) {
7965				strm.flush_pending();
7966				if (strm.avail_out === 0) {
7967					// console.log(" avail_out==0");
7968					// Since avail_out is 0, deflate will be called again with
7969					// more output space, but possibly with both pending and
7970					// avail_in equal to zero. There won't be anything to do,
7971					// but this is not an error situation so make sure we
7972					// return OK instead of BUF_ERROR at next call of deflate:
7973					last_flush = -1;
7974					return Z_OK;
7975				}
7976
7977				// Make sure there is something to do and avoid duplicate
7978				// consecutive
7979				// flushes. For repeated and useless calls with Z_FINISH, we keep
7980				// returning Z_STREAM_END instead of Z_BUFF_ERROR.
7981			} else if (strm.avail_in === 0 && flush <= old_flush && flush != Z_FINISH) {
7982				strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
7983				return Z_BUF_ERROR;
7984			}
7985
7986			// User must not provide more input after the first FINISH:
7987			if (status == FINISH_STATE && strm.avail_in !== 0) {
7988				_strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
7989				return Z_BUF_ERROR;
7990			}
7991
7992			// Start a new block or continue the current one.
7993			if (strm.avail_in !== 0 || lookahead !== 0 || (flush != Z_NO_FLUSH && status != FINISH_STATE)) {
7994				bstate = -1;
7995				switch (config_table[level].func) {
7996				case STORED:
7997					bstate = deflate_stored(flush);
7998					break;
7999				case FAST:
8000					bstate = deflate_fast(flush);
8001					break;
8002				case SLOW:
8003					bstate = deflate_slow(flush);
8004					break;
8005				default:
8006				}
8007
8008				if (bstate == FinishStarted || bstate == FinishDone) {
8009					status = FINISH_STATE;
8010				}
8011				if (bstate == NeedMore || bstate == FinishStarted) {
8012					if (strm.avail_out === 0) {
8013						last_flush = -1; // avoid BUF_ERROR next call, see above
8014					}
8015					return Z_OK;
8016					// If flush != Z_NO_FLUSH && avail_out === 0, the next call
8017					// of deflate should use the same flush parameter to make sure
8018					// that the flush is complete. So we don't have to output an
8019					// empty block here, this will be done at next call. This also
8020					// ensures that for a very small output buffer, we emit at most
8021					// one empty block.
8022				}
8023
8024				if (bstate == BlockDone) {
8025					if (flush == Z_PARTIAL_FLUSH) {
8026						_tr_align();
8027					} else { // FULL_FLUSH or SYNC_FLUSH
8028						_tr_stored_block(0, 0, false);
8029						// For a full flush, this empty block will be recognized
8030						// as a special marker by inflate_sync().
8031						if (flush == Z_FULL_FLUSH) {
8032							// state.head[s.hash_size-1]=0;
8033							for (i = 0; i < hash_size/*-1*/; i++)
8034								// forget history
8035								head[i] = 0;
8036						}
8037					}
8038					strm.flush_pending();
8039					if (strm.avail_out === 0) {
8040						last_flush = -1; // avoid BUF_ERROR at next call, see above
8041						return Z_OK;
8042					}
8043				}
8044			}
8045
8046			if (flush != Z_FINISH)
8047				return Z_OK;
8048			return Z_STREAM_END;
8049		};
8050	}
8051
8052	// ZStream
8053
8054	function ZStream() {
8055		var that = this;
8056		that.next_in_index = 0;
8057		that.next_out_index = 0;
8058		// that.next_in; // next input byte
8059		that.avail_in = 0; // number of bytes available at next_in
8060		that.total_in = 0; // total nb of input bytes read so far
8061		// that.next_out; // next output byte should be put there
8062		that.avail_out = 0; // remaining free space at next_out
8063		that.total_out = 0; // total nb of bytes output so far
8064		// that.msg;
8065		// that.dstate;
8066	}
8067
8068	ZStream.prototype = {
8069		deflateInit : function(level, bits) {
8070			var that = this;
8071			that.dstate = new Deflate();
8072			if (!bits)
8073				bits = MAX_BITS;
8074			return that.dstate.deflateInit(that, level, bits);
8075		},
8076
8077		deflate : function(flush) {
8078			var that = this;
8079			if (!that.dstate) {
8080				return Z_STREAM_ERROR;
8081			}
8082			return that.dstate.deflate(that, flush);
8083		},
8084
8085		deflateEnd : function() {
8086			var that = this;
8087			if (!that.dstate)
8088				return Z_STREAM_ERROR;
8089			var ret = that.dstate.deflateEnd();
8090			that.dstate = null;
8091			return ret;
8092		},
8093
8094		deflateParams : function(level, strategy) {
8095			var that = this;
8096			if (!that.dstate)
8097				return Z_STREAM_ERROR;
8098			return that.dstate.deflateParams(that, level, strategy);
8099		},
8100
8101		deflateSetDictionary : function(dictionary, dictLength) {
8102			var that = this;
8103			if (!that.dstate)
8104				return Z_STREAM_ERROR;
8105			return that.dstate.deflateSetDictionary(that, dictionary, dictLength);
8106		},
8107
8108		// Read a new buffer from the current input stream, update the
8109		// total number of bytes read. All deflate() input goes through
8110		// this function so some applications may wish to modify it to avoid
8111		// allocating a large strm->next_in buffer and copying from it.
8112		// (See also flush_pending()).
8113		read_buf : function(buf, start, size) {
8114			var that = this;
8115			var len = that.avail_in;
8116			if (len > size)
8117				len = size;
8118			if (len === 0)
8119				return 0;
8120			that.avail_in -= len;
8121			buf.set(that.next_in.subarray(that.next_in_index, that.next_in_index + len), start);
8122			that.next_in_index += len;
8123			that.total_in += len;
8124			return len;
8125		},
8126
8127		// Flush as much pending output as possible. All deflate() output goes
8128		// through this function so some applications may wish to modify it
8129		// to avoid allocating a large strm->next_out buffer and copying into it.
8130		// (See also read_buf()).
8131		flush_pending : function() {
8132			var that = this;
8133			var len = that.dstate.pending;
8134
8135			if (len > that.avail_out)
8136				len = that.avail_out;
8137			if (len === 0)
8138				return;
8139
8140			// if (that.dstate.pending_buf.length <= that.dstate.pending_out || that.next_out.length <= that.next_out_index
8141			// || that.dstate.pending_buf.length < (that.dstate.pending_out + len) || that.next_out.length < (that.next_out_index +
8142			// len)) {
8143			// console.log(that.dstate.pending_buf.length + ", " + that.dstate.pending_out + ", " + that.next_out.length + ", " +
8144			// that.next_out_index + ", " + len);
8145			// console.log("avail_out=" + that.avail_out);
8146			// }
8147
8148			that.next_out.set(that.dstate.pending_buf.subarray(that.dstate.pending_out, that.dstate.pending_out + len), that.next_out_index);
8149
8150			that.next_out_index += len;
8151			that.dstate.pending_out += len;
8152			that.total_out += len;
8153			that.avail_out -= len;
8154			that.dstate.pending -= len;
8155			if (that.dstate.pending === 0) {
8156				that.dstate.pending_out = 0;
8157			}
8158		}
8159	};
8160
8161	// Deflater
8162
8163	return function Deflater(level) {
8164		var that = this;
8165		var z = new ZStream();
8166		var bufsize = 512;
8167		var flush = Z_NO_FLUSH;
8168		var buf = new Uint8Array(bufsize);
8169
8170		if (typeof level == "undefined")
8171			level = Z_DEFAULT_COMPRESSION;
8172		z.deflateInit(level);
8173		z.next_out = buf;
8174
8175		that.append = function(data, onprogress) {
8176			var err, buffers = [], lastIndex = 0, bufferIndex = 0, bufferSize = 0, array;
8177			if (!data.length)
8178				return;
8179			z.next_in_index = 0;
8180			z.next_in = data;
8181			z.avail_in = data.length;
8182			do {
8183				z.next_out_index = 0;
8184				z.avail_out = bufsize;
8185				err = z.deflate(flush);
8186				if (err != Z_OK)
8187					throw "deflating: " + z.msg;
8188				if (z.next_out_index)
8189					if (z.next_out_index == bufsize)
8190						buffers.push(new Uint8Array(buf));
8191					else
8192						buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
8193				bufferSize += z.next_out_index;
8194				if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) {
8195					onprogress(z.next_in_index);
8196					lastIndex = z.next_in_index;
8197				}
8198			} while (z.avail_in > 0 || z.avail_out === 0);
8199			array = new Uint8Array(bufferSize);
8200			buffers.forEach(function(chunk) {
8201				array.set(chunk, bufferIndex);
8202				bufferIndex += chunk.length;
8203			});
8204			return array;
8205		};
8206		that.flush = function() {
8207			var err, buffers = [], bufferIndex = 0, bufferSize = 0, array;
8208			do {
8209				z.next_out_index = 0;
8210				z.avail_out = bufsize;
8211				err = z.deflate(Z_FINISH);
8212				if (err != Z_STREAM_END && err != Z_OK)
8213					throw "deflating: " + z.msg;
8214				if (bufsize - z.avail_out > 0)
8215					buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
8216				bufferSize += z.next_out_index;
8217			} while (z.avail_in > 0 || z.avail_out === 0);
8218			z.deflateEnd();
8219			array = new Uint8Array(bufferSize);
8220			buffers.forEach(function(chunk) {
8221				array.set(chunk, bufferIndex);
8222				bufferIndex += chunk.length;
8223			});
8224			return array;
8225		};
8226	};
8227})(this);
8228// Generated by CoffeeScript 1.4.0
8229
8230/*
8231# PNG.js
8232# Copyright (c) 2011 Devon Govett
8233# MIT LICENSE
8234# 
8235# Permission is hereby granted, free of charge, to any person obtaining a copy of this 
8236# software and associated documentation files (the "Software"), to deal in the Software 
8237# without restriction, including without limitation the rights to use, copy, modify, merge, 
8238# publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 
8239# to whom the Software is furnished to do so, subject to the following conditions:
8240# 
8241# The above copyright notice and this permission notice shall be included in all copies or 
8242# substantial portions of the Software.
8243# 
8244# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
8245# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
8246# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
8247# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
8248# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8249*/
8250
8251
8252(function(global) {
8253  var PNG;
8254
8255  PNG = (function() {
8256    var APNG_BLEND_OP_OVER, APNG_BLEND_OP_SOURCE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_NONE, APNG_DISPOSE_OP_PREVIOUS, makeImage, scratchCanvas, scratchCtx;
8257
8258    PNG.load = function(url, canvas, callback) {
8259      var xhr,
8260        _this = this;
8261      if (typeof canvas === 'function') {
8262        callback = canvas;
8263      }
8264      xhr = new XMLHttpRequest;
8265      xhr.open("GET", url, true);
8266      xhr.responseType = "arraybuffer";
8267      xhr.onload = function() {
8268        var data, png;
8269        data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
8270        png = new PNG(data);
8271        if (typeof (canvas != null ? canvas.getContext : void 0) === 'function') {
8272          png.render(canvas);
8273        }
8274        return typeof callback === "function" ? callback(png) : void 0;
8275      };
8276      return xhr.send(null);
8277    };
8278
8279    APNG_DISPOSE_OP_NONE = 0;
8280
8281    APNG_DISPOSE_OP_BACKGROUND = 1;
8282
8283    APNG_DISPOSE_OP_PREVIOUS = 2;
8284
8285    APNG_BLEND_OP_SOURCE = 0;
8286
8287    APNG_BLEND_OP_OVER = 1;
8288
8289    function PNG(data) {
8290      var chunkSize, colors, palLen, delayDen, delayNum, frame, i, index, key, section, palShort, text, _i, _j, _ref;
8291      this.data = data;
8292      this.pos = 8;
8293      this.palette = [];
8294      this.imgData = [];
8295      this.transparency = {};
8296      this.animation = null;
8297      this.text = {};
8298      frame = null;
8299      while (true) {
8300        chunkSize = this.readUInt32();
8301        section = ((function() {
8302          var _i, _results;
8303          _results = [];
8304          for (i = _i = 0; _i < 4; i = ++_i) {
8305            _results.push(String.fromCharCode(this.data[this.pos++]));
8306          }
8307          return _results;
8308        }).call(this)).join('');
8309        switch (section) {
8310          case 'IHDR':
8311            this.width = this.readUInt32();
8312            this.height = this.readUInt32();
8313            this.bits = this.data[this.pos++];
8314            this.colorType = this.data[this.pos++];
8315            this.compressionMethod = this.data[this.pos++];
8316            this.filterMethod = this.data[this.pos++];
8317            this.interlaceMethod = this.data[this.pos++];
8318            break;
8319          case 'acTL':
8320            this.animation = {
8321              numFrames: this.readUInt32(),
8322              numPlays: this.readUInt32() || Infinity,
8323              frames: []
8324            };
8325            break;
8326          case 'PLTE':
8327            this.palette = this.read(chunkSize);
8328            break;
8329          case 'fcTL':
8330            if (frame) {
8331              this.animation.frames.push(frame);
8332            }
8333            this.pos += 4;
8334            frame = {
8335              width: this.readUInt32(),
8336              height: this.readUInt32(),
8337              xOffset: this.readUInt32(),
8338              yOffset: this.readUInt32()
8339            };
8340            delayNum = this.readUInt16();
8341            delayDen = this.readUInt16() || 100;
8342            frame.delay = 1000 * delayNum / delayDen;
8343            frame.disposeOp = this.data[this.pos++];
8344            frame.blendOp = this.data[this.pos++];
8345            frame.data = [];
8346            break;
8347          case 'IDAT':
8348          case 'fdAT':
8349            if (section === 'fdAT') {
8350              this.pos += 4;
8351              chunkSize -= 4;
8352            }
8353            data = (frame != null ? frame.data : void 0) || this.imgData;
8354            for (i = _i = 0; 0 <= chunkSize ? _i < chunkSize : _i > chunkSize; i = 0 <= chunkSize ? ++_i : --_i) {
8355              data.push(this.data[this.pos++]);
8356            }
8357            break;
8358          case 'tRNS':
8359            this.transparency = {};
8360            switch (this.colorType) {
8361              case 3:
8362            	palLen = this.palette.length/3;
8363                this.transparency.indexed = this.read(chunkSize);
8364                if(this.transparency.indexed.length > palLen)
8365                	throw new Error('More transparent colors than palette size');
8366                /*
8367                 * According to the PNG spec trns should be increased to the same size as palette if shorter
8368                 */
8369                //palShort = 255 - this.transparency.indexed.length;
8370                palShort = palLen - this.transparency.indexed.length;
8371                if (palShort > 0) {
8372                  for (i = _j = 0; 0 <= palShort ? _j < palShort : _j > palShort; i = 0 <= palShort ? ++_j : --_j) {
8373                    this.transparency.indexed.push(255);
8374                  }
8375                }
8376                break;
8377              case 0:
8378                this.transparency.grayscale = this.read(chunkSize)[0];
8379                break;
8380              case 2:
8381                this.transparency.rgb = this.read(chunkSize);
8382            }
8383            break;
8384          case 'tEXt':
8385            text = this.read(chunkSize);
8386            index = text.indexOf(0);
8387            key = String.fromCharCode.apply(String, text.slice(0, index));
8388            this.text[key] = String.fromCharCode.apply(String, text.slice(index + 1));
8389            break;
8390          case 'IEND':
8391            if (frame) {
8392              this.animation.frames.push(frame);
8393            }
8394            this.colors = (function() {
8395              switch (this.colorType) {
8396                case 0:
8397                case 3:
8398                case 4:
8399                  return 1;
8400                case 2:
8401                case 6:
8402                  return 3;
8403              }
8404            }).call(this);
8405            this.hasAlphaChannel = (_ref = this.colorType) === 4 || _ref === 6;
8406            colors = this.colors + (this.hasAlphaChannel ? 1 : 0);
8407            this.pixelBitlength = this.bits * colors;
8408            this.colorSpace = (function() {
8409              switch (this.colors) {
8410                case 1:
8411                  return 'DeviceGray';
8412                case 3:
8413                  return 'DeviceRGB';
8414              }
8415            }).call(this);
8416            this.imgData = new Uint8Array(this.imgData);
8417            return;
8418          default:
8419            this.pos += chunkSize;
8420        }
8421        this.pos += 4;
8422        if (this.pos > this.data.length) {
8423          throw new Error("Incomplete or corrupt PNG file");
8424        }
8425      }
8426      return;
8427    }
8428
8429    PNG.prototype.read = function(bytes) {
8430      var i, _i, _results;
8431      _results = [];
8432      for (i = _i = 0; 0 <= bytes ? _i < bytes : _i > bytes; i = 0 <= bytes ? ++_i : --_i) {
8433        _results.push(this.data[this.pos++]);
8434      }
8435      return _results;
8436    };
8437
8438    PNG.prototype.readUInt32 = function() {
8439      var b1, b2, b3, b4;
8440      b1 = this.data[this.pos++] << 24;
8441      b2 = this.data[this.pos++] << 16;
8442      b3 = this.data[this.pos++] << 8;
8443      b4 = this.data[this.pos++];
8444      return b1 | b2 | b3 | b4;
8445    };
8446
8447    PNG.prototype.readUInt16 = function() {
8448      var b1, b2;
8449      b1 = this.data[this.pos++] << 8;
8450      b2 = this.data[this.pos++];
8451      return b1 | b2;
8452    };
8453
8454    PNG.prototype.decodePixels = function(data) {
8455      var abyte, c, col, i, left, length, p, pa, paeth, pb, pc, pixelBytes, pixels, pos, row, scanlineLength, upper, upperLeft, _i, _j, _k, _l, _m;
8456      if (data == null) {
8457        data = this.imgData;
8458      }
8459      if (data.length === 0) {
8460        return new Uint8Array(0);
8461      }
8462      data = new FlateStream(data);
8463      data = data.getBytes();
8464      pixelBytes = this.pixelBitlength / 8;
8465      scanlineLength = pixelBytes * this.width;
8466      pixels = new Uint8Array(scanlineLength * this.height);
8467      length = data.length;
8468      row = 0;
8469      pos = 0;
8470      c = 0;
8471      while (pos < length) {
8472        switch (data[pos++]) {
8473          case 0:
8474            for (i = _i = 0; _i < scanlineLength; i = _i += 1) {
8475              pixels[c++] = data[pos++];
8476            }
8477            break;
8478          case 1:
8479            for (i = _j = 0; _j < scanlineLength; i = _j += 1) {
8480              abyte = data[pos++];
8481              left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
8482              pixels[c++] = (abyte + left) % 256;
8483            }
8484            break;
8485          case 2:
8486            for (i = _k = 0; _k < scanlineLength; i = _k += 1) {
8487              abyte = data[pos++];
8488              col = (i - (i % pixelBytes)) / pixelBytes;
8489              upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
8490              pixels[c++] = (upper + abyte) % 256;
8491            }
8492            break;
8493          case 3:
8494            for (i = _l = 0; _l < scanlineLength; i = _l += 1) {
8495              abyte = data[pos++];
8496              col = (i - (i % pixelBytes)) / pixelBytes;
8497              left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
8498              upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
8499              pixels[c++] = (abyte + Math.floor((left + upper) / 2)) % 256;
8500            }
8501            break;
8502          case 4:
8503            for (i = _m = 0; _m < scanlineLength; i = _m += 1) {
8504              abyte = data[pos++];
8505              col = (i - (i % pixelBytes)) / pixelBytes;
8506              left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
8507              if (row === 0) {
8508                upper = upperLeft = 0;
8509              } else {
8510                upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
8511                upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)];
8512              }
8513              p = left + upper - upperLeft;
8514              pa = Math.abs(p - left);
8515              pb = Math.abs(p - upper);
8516              pc = Math.abs(p - upperLeft);
8517              if (pa <= pb && pa <= pc) {
8518                paeth = left;
8519              } else if (pb <= pc) {
8520                paeth = upper;
8521              } else {
8522                paeth = upperLeft;
8523              }
8524              pixels[c++] = (abyte + paeth) % 256;
8525            }
8526            break;
8527          default:
8528            throw new Error("Invalid filter algorithm: " + data[pos - 1]);
8529        }
8530        row++;
8531      }
8532      return pixels;
8533    };
8534
8535    PNG.prototype.decodePalette = function() {
8536      var c, i, length, palette, pos, ret, transparency, _i, _ref, _ref1;
8537      palette = this.palette;
8538      transparency = this.transparency.indexed || [];
8539      ret = new Uint8Array((transparency.length || 0) + palette.length);
8540      pos = 0;
8541      length = palette.length;
8542      c = 0;
8543      for (i = _i = 0, _ref = palette.length; _i < _ref; i = _i += 3) {
8544        ret[pos++] = palette[i];
8545        ret[pos++] = palette[i + 1];
8546        ret[pos++] = palette[i + 2];
8547        ret[pos++] = (_ref1 = transparency[c++]) != null ? _ref1 : 255;
8548      }
8549      return ret;
8550    };
8551
8552    PNG.prototype.copyToImageData = function(imageData, pixels) {
8553      var alpha, colors, data, i, input, j, k, length, palette, v, _ref;
8554      colors = this.colors;
8555      palette = null;
8556      alpha = this.hasAlphaChannel;
8557      if (this.palette.length) {
8558        palette = (_ref = this._decodedPalette) != null ? _ref : this._decodedPalette = this.decodePalette();
8559        colors = 4;
8560        alpha = true;
8561      }
8562      data = imageData.data || imageData;
8563      length = data.length;
8564      input = palette || pixels;
8565      i = j = 0;
8566      if (colors === 1) {
8567        while (i < length) {
8568          k = palette ? pixels[i / 4] * 4 : j;
8569          v = input[k++];
8570          data[i++] = v;
8571          data[i++] = v;
8572          data[i++] = v;
8573          data[i++] = alpha ? input[k++] : 255;
8574          j = k;
8575        }
8576      } else {
8577        while (i < length) {
8578          k = palette ? pixels[i / 4] * 4 : j;
8579          data[i++] = input[k++];
8580          data[i++] = input[k++];
8581          data[i++] = input[k++];
8582          data[i++] = alpha ? input[k++] : 255;
8583          j = k;
8584        }
8585      }
8586    };
8587
8588    PNG.prototype.decode = function() {
8589      var ret;
8590      ret = new Uint8Array(this.width * this.height * 4);
8591      this.copyToImageData(ret, this.decodePixels());
8592      return ret;
8593    };
8594
8595    try {
8596        scratchCanvas = global.document.createElement('canvas');
8597        scratchCtx = scratchCanvas.getContext('2d');
8598    } catch(e) {
8599        return -1;
8600    }
8601
8602    makeImage = function(imageData) {
8603      var img;
8604      scratchCtx.width = imageData.width;
8605      scratchCtx.height = imageData.height;
8606      scratchCtx.clearRect(0, 0, imageData.width, imageData.height);
8607      scratchCtx.putImageData(imageData, 0, 0);
8608      img = new Image;
8609      img.src = scratchCanvas.toDataURL();
8610      return img;
8611    };
8612
8613    PNG.prototype.decodeFrames = function(ctx) {
8614      var frame, i, imageData, pixels, _i, _len, _ref, _results;
8615      if (!this.animation) {
8616        return;
8617      }
8618      _ref = this.animation.frames;
8619      _results = [];
8620      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
8621        frame = _ref[i];
8622        imageData = ctx.createImageData(frame.width, frame.height);
8623        pixels = this.decodePixels(new Uint8Array(frame.data));
8624        this.copyToImageData(imageData, pixels);
8625        frame.imageData = imageData;
8626        _results.push(frame.image = makeImage(imageData));
8627      }
8628      return _results;
8629    };
8630
8631    PNG.prototype.renderFrame = function(ctx, number) {
8632      var frame, frames, prev;
8633      frames = this.animation.frames;
8634      frame = frames[number];
8635      prev = frames[number - 1];
8636      if (number === 0) {
8637        ctx.clearRect(0, 0, this.width, this.height);
8638      }
8639      if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_BACKGROUND) {
8640        ctx.clearRect(prev.xOffset, prev.yOffset, prev.width, prev.height);
8641      } else if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_PREVIOUS) {
8642        ctx.putImageData(prev.imageData, prev.xOffset, prev.yOffset);
8643      }
8644      if (frame.blendOp === APNG_BLEND_OP_SOURCE) {
8645        ctx.clearRect(frame.xOffset, frame.yOffset, frame.width, frame.height);
8646      }
8647      return ctx.drawImage(frame.image, frame.xOffset, frame.yOffset);
8648    };
8649
8650    PNG.prototype.animate = function(ctx) {
8651      var doFrame, frameNumber, frames, numFrames, numPlays, _ref,
8652        _this = this;
8653      frameNumber = 0;
8654      _ref = this.animation, numFrames = _ref.numFrames, frames = _ref.frames, numPlays = _ref.numPlays;
8655      return (doFrame = function() {
8656        var f, frame;
8657        f = frameNumber++ % numFrames;
8658        frame = frames[f];
8659        _this.renderFrame(ctx, f);
8660        if (numFrames > 1 && frameNumber / numFrames < numPlays) {
8661          return _this.animation._timeout = setTimeout(doFrame, frame.delay);
8662        }
8663      })();
8664    };
8665
8666    PNG.prototype.stopAnimation = function() {
8667      var _ref;
8668      return clearTimeout((_ref = this.animation) != null ? _ref._timeout : void 0);
8669    };
8670
8671    PNG.prototype.render = function(canvas) {
8672      var ctx, data;
8673      if (canvas._png) {
8674        canvas._png.stopAnimation();
8675      }
8676      canvas._png = this;
8677      canvas.width = this.width;
8678      canvas.height = this.height;
8679      ctx = canvas.getContext("2d");
8680      if (this.animation) {
8681        this.decodeFrames(ctx);
8682        return this.animate(ctx);
8683      } else {
8684        data = ctx.createImageData(this.width, this.height);
8685        this.copyToImageData(data, this.decodePixels());
8686        return ctx.putImageData(data, 0, 0);
8687      }
8688    };
8689
8690    return PNG;
8691
8692  })();
8693
8694  global.PNG = PNG;
8695
8696})(typeof window !== "undefined" && window || this);
8697/*
8698 * Extracted from pdf.js
8699 * https://github.com/andreasgal/pdf.js
8700 *
8701 * Copyright (c) 2011 Mozilla Foundation
8702 *
8703 * Contributors: Andreas Gal <[email protected]>
8704 *               Chris G Jones <[email protected]>
8705 *               Shaon Barman <[email protected]>
8706 *               Vivien Nicolas <[email protected]>
8707 *               Justin D'Arcangelo <[email protected]>
8708 *               Yury Delendik
8709 *
8710 * Permission is hereby granted, free of charge, to any person obtaining a
8711 * copy of this software and associated documentation files (the "Software"),
8712 * to deal in the Software without restriction, including without limitation
8713 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8714 * and/or sell copies of the Software, and to permit persons to whom the
8715 * Software is furnished to do so, subject to the following conditions:
8716 *
8717 * The above copyright notice and this permission notice shall be included in
8718 * all copies or substantial portions of the Software.
8719 *
8720 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8721 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
8722 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
8723 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
8724 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
8725 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
8726 * DEALINGS IN THE SOFTWARE.
8727 */
8728
8729var DecodeStream = (function() {
8730  function constructor() {
8731    this.pos = 0;
8732    this.bufferLength = 0;
8733    this.eof = false;
8734    this.buffer = null;
8735  }
8736
8737  constructor.prototype = {
8738    ensureBuffer: function decodestream_ensureBuffer(requested) {
8739      var buffer = this.buffer;
8740      var current = buffer ? buffer.byteLength : 0;
8741      if (requested < current)
8742        return buffer;
8743      var size = 512;
8744      while (size < requested)
8745        size <<= 1;
8746      var buffer2 = new Uint8Array(size);
8747      for (var i = 0; i < current; ++i)
8748        buffer2[i] = buffer[i];
8749      return this.buffer = buffer2;
8750    },
8751    getByte: function decodestream_getByte() {
8752      var pos = this.pos;
8753      while (this.bufferLength <= pos) {
8754        if (this.eof)
8755          return null;
8756        this.readBlock();
8757      }
8758      return this.buffer[this.pos++];
8759    },
8760    getBytes: function decodestream_getBytes(length) {
8761      var pos = this.pos;
8762
8763      if (length) {
8764        this.ensureBuffer(pos + length);
8765        var end = pos + length;
8766
8767        while (!this.eof && this.bufferLength < end)
8768          this.readBlock();
8769
8770        var bufEnd = this.bufferLength;
8771        if (end > bufEnd)
8772          end = bufEnd;
8773      } else {
8774        while (!this.eof)
8775          this.readBlock();
8776
8777        var end = this.bufferLength;
8778      }
8779
8780      this.pos = end;
8781      return this.buffer.subarray(pos, end);
8782    },
8783    lookChar: function decodestream_lookChar() {
8784      var pos = this.pos;
8785      while (this.bufferLength <= pos) {
8786        if (this.eof)
8787          return null;
8788        this.readBlock();
8789      }
8790      return String.fromCharCode(this.buffer[this.pos]);
8791    },
8792    getChar: function decodestream_getChar() {
8793      var pos = this.pos;
8794      while (this.bufferLength <= pos) {
8795        if (this.eof)
8796          return null;
8797        this.readBlock();
8798      }
8799      return String.fromCharCode(this.buffer[this.pos++]);
8800    },
8801    makeSubStream: function decodestream_makeSubstream(start, length, dict) {
8802      var end = start + length;
8803      while (this.bufferLength <= end && !this.eof)
8804        this.readBlock();
8805      return new Stream(this.buffer, start, length, dict);
8806    },
8807    skip: function decodestream_skip(n) {
8808      if (!n)
8809        n = 1;
8810      this.pos += n;
8811    },
8812    reset: function decodestream_reset() {
8813      this.pos = 0;
8814    }
8815  };
8816
8817  return constructor;
8818})();
8819
8820var FlateStream = (function() {
8821  if (typeof Uint32Array === 'undefined') {
8822    return undefined;
8823  }
8824  var codeLenCodeMap = new Uint32Array([
8825    16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
8826  ]);
8827
8828  var lengthDecode = new Uint32Array([
8829    0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,
8830    0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,
8831    0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073,
8832    0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102
8833  ]);
8834
8835  var distDecode = new Uint32Array([
8836    0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,
8837    0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,
8838    0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01,
8839    0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001
8840  ]);
8841
8842  var fixedLitCodeTab = [new Uint32Array([
8843    0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,
8844    0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,
8845    0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0,
8846    0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0,
8847    0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8,
8848    0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8,
8849    0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8,
8850    0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8,
8851    0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4,
8852    0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4,
8853    0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4,
8854    0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4,
8855    0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc,
8856    0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec,
8857    0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc,
8858    0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc,
8859    0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2,
8860    0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2,
8861    0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2,
8862    0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2,
8863    0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca,
8864    0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea,
8865    0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da,
8866    0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa,
8867    0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6,
8868    0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6,
8869    0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6,
8870    0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6,
8871    0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce,
8872    0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee,
8873    0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de,
8874    0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe,
8875    0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1,
8876    0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1,
8877    0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1,
8878    0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1,
8879    0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9,
8880    0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9,
8881    0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9,
8882    0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9,
8883    0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5,
8884    0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5,
8885    0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5,
8886    0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5,
8887    0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd,
8888    0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed,
8889    0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd,
8890    0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd,
8891    0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3,
8892    0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3,
8893    0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3,
8894    0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3,
8895    0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb,
8896    0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb,
8897    0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db,
8898    0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb,
8899    0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7,
8900    0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7,
8901    0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7,
8902    0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 
89020x900f7,
8903    0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf,
8904    0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef,
8905    0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df,
8906    0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff
8907  ]), 9];
8908
8909  var fixedDistCodeTab = [new Uint32Array([
8910    0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,
8911    0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,
8912    0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d,
8913    0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
8914  ]), 5];
8915  
8916  function error(e) {
8917      throw new Error(e)
8918  }
8919
8920  function constructor(bytes) {
8921    //var bytes = stream.getBytes();
8922    var bytesPos = 0;
8923
8924    var cmf = bytes[bytesPos++];
8925    var flg = bytes[bytesPos++];
8926    if (cmf == -1 || flg == -1)
8927      error('Invalid header in flate stream');
8928    if ((cmf & 0x0f) != 0x08)
8929      error('Unknown compression method in flate stream');
8930    if ((((cmf << 8) + flg) % 31) != 0)
8931      error('Bad FCHECK in flate stream');
8932    if (flg & 0x20)
8933      error('FDICT bit set in flate stream');
8934
8935    this.bytes = bytes;
8936    this.bytesPos = bytesPos;
8937
8938    this.codeSize = 0;
8939    this.codeBuf = 0;
8940
8941    DecodeStream.call(this);
8942  }
8943
8944  constructor.prototype = Object.create(DecodeStream.prototype);
8945
8946  constructor.prototype.getBits = function(bits) {
8947    var codeSize = this.codeSize;
8948    var codeBuf = this.codeBuf;
8949    var bytes = this.bytes;
8950    var bytesPos = this.bytesPos;
8951
8952    var b;
8953    while (codeSize < bits) {
8954      if (typeof (b = bytes[bytesPos++]) == 'undefined')
8955        error('Bad encoding in flate stream');
8956      codeBuf |= b << codeSize;
8957      codeSize += 8;
8958    }
8959    b = codeBuf & ((1 << bits) - 1);
8960    this.codeBuf = codeBuf >> bits;
8961    this.codeSize = codeSize -= bits;
8962    this.bytesPos = bytesPos;
8963    return b;
8964  };
8965
8966  constructor.prototype.getCode = function(table) {
8967    var codes = table[0];
8968    var maxLen = table[1];
8969    var codeSize = this.codeSize;
8970    var codeBuf = this.codeBuf;
8971    var bytes = this.bytes;
8972    var bytesPos = this.bytesPos;
8973
8974    while (codeSize < maxLen) {
8975      var b;
8976      if (typeof (b = bytes[bytesPos++]) == 'undefined')
8977        error('Bad encoding in flate stream');
8978      codeBuf |= (b << codeSize);
8979      codeSize += 8;
8980    }
8981    var code = codes[codeBuf & ((1 << maxLen) - 1)];
8982    var codeLen = code >> 16;
8983    var codeVal = code & 0xffff;
8984    if (codeSize == 0 || codeSize < codeLen || codeLen == 0)
8985      error('Bad encoding in flate stream');
8986    this.codeBuf = (codeBuf >> codeLen);
8987    this.codeSize = (codeSize - codeLen);
8988    this.bytesPos = bytesPos;
8989    return codeVal;
8990  };
8991
8992  constructor.prototype.generateHuffmanTable = function(lengths) {
8993    var n = lengths.length;
8994
8995    // find max code length
8996    var maxLen = 0;
8997    for (var i = 0; i < n; ++i) {
8998      if (lengths[i] > maxLen)
8999        maxLen = lengths[i];
9000    }
9001
9002    // build the table
9003    var size = 1 << maxLen;
9004    var codes = new Uint32Array(size);
9005    for (var len = 1, code = 0, skip = 2;
9006         len <= maxLen;
9007         ++len, code <<= 1, skip <<= 1) {
9008      for (var val = 0; val < n; ++val) {
9009        if (lengths[val] == len) {
9010          // bit-reverse the code
9011          var code2 = 0;
9012          var t = code;
9013          for (var i = 0; i < len; ++i) {
9014            code2 = (code2 << 1) | (t & 1);
9015            t >>= 1;
9016          }
9017
9018          // fill the table entries
9019          for (var i = code2; i < size; i += skip)
9020            codes[i] = (len << 16) | val;
9021
9022          ++code;
9023        }
9024      }
9025    }
9026
9027    return [codes, maxLen];
9028  };
9029
9030  constructor.prototype.readBlock = function() {
9031    function repeat(stream, array, len, offset, what) {
9032      var repeat = stream.getBits(len) + offset;
9033      while (repeat-- > 0)
9034        array[i++] = what;
9035    }
9036
9037    // read block header
9038    var hdr = this.getBits(3);
9039    if (hdr & 1)
9040      this.eof = true;
9041    hdr >>= 1;
9042
9043    if (hdr == 0) { // uncompressed block
9044      var bytes = this.bytes;
9045      var bytesPos = this.bytesPos;
9046      var b;
9047
9048      if (typeof (b = bytes[bytesPos++]) == 'undefined')
9049        error('Bad block header in flate stream');
9050      var blockLen = b;
9051      if (typeof (b = bytes[bytesPos++]) == 'undefined')
9052        error('Bad block header in flate stream');
9053      blockLen |= (b << 8);
9054      if (typeof (b = bytes[bytesPos++]) == 'undefined')
9055        error('Bad block header in flate stream');
9056      var check = b;
9057      if (typeof (b = bytes[bytesPos++]) == 'undefined')
9058        error('Bad block header in flate stream');
9059      check |= (b << 8);
9060      if (check != (~blockLen & 0xffff))
9061        error('Bad uncompressed block length in flate stream');
9062
9063      this.codeBuf = 0;
9064      this.codeSize = 0;
9065
9066      var bufferLength = this.bufferLength;
9067      var buffer = this.ensureBuffer(bufferLength + blockLen);
9068      var end = bufferLength + blockLen;
9069      this.bufferLength = end;
9070      for (var n = bufferLength; n < end; ++n) {
9071        if (typeof (b = bytes[bytesPos++]) == 'undefined') {
9072          this.eof = true;
9073          break;
9074        }
9075        buffer[n] = b;
9076      }
9077      this.bytesPos = bytesPos;
9078      return;
9079    }
9080
9081    var litCodeTable;
9082    var distCodeTable;
9083    if (hdr == 1) { // compressed block, fixed codes
9084      litCodeTable = fixedLitCodeTab;
9085      distCodeTable = fixedDistCodeTab;
9086    } else if (hdr == 2) { // compressed block, dynamic codes
9087      var numLitCodes = this.getBits(5) + 257;
9088      var numDistCodes = this.getBits(5) + 1;
9089      var numCodeLenCodes = this.getBits(4) + 4;
9090
9091      // build the code lengths code table
9092      var codeLenCodeLengths = Array(codeLenCodeMap.length);
9093      var i = 0;
9094      while (i < numCodeLenCodes)
9095        codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3);
9096      var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
9097
9098      // build the literal and distance code tables
9099      var len = 0;
9100      var i = 0;
9101      var codes = numLitCodes + numDistCodes;
9102      var codeLengths = new Array(codes);
9103      while (i < codes) {
9104        var code = this.getCode(codeLenCodeTab);
9105        if (code == 16) {
9106          repeat(this, codeLengths, 2, 3, len);
9107        } else if (code == 17) {
9108          repeat(this, codeLengths, 3, 3, len = 0);
9109        } else if (code == 18) {
9110          repeat(this, codeLengths, 7, 11, len = 0);
9111        } else {
9112          codeLengths[i++] = len = code;
9113        }
9114      }
9115
9116      litCodeTable =
9117        this.generateHuffmanTable(codeLengths.slice(0, numLitCodes));
9118      distCodeTable =
9119        this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes));
9120    } else {
9121      error('Unknown block type in flate stream');
9122    }
9123
9124    var buffer = this.buffer;
9125    var limit = buffer ? buffer.length : 0;
9126    var pos = this.bufferLength;
9127    while (true) {
9128      var code1 = this.getCode(litCodeTable);
9129      if (code1 < 256) {
9130        if (pos + 1 >= limit) {
9131          buffer = this.ensureBuffer(pos + 1);
9132          limit = buffer.length;
9133        }
9134        buffer[pos++] = code1;
9135        continue;
9136      }
9137      if (code1 == 256) {
9138        this.bufferLength = pos;
9139        return;
9140      }
9141      code1 -= 257;
9142      code1 = lengthDecode[code1];
9143      var code2 = code1 >> 16;
9144      if (code2 > 0)
9145        code2 = this.getBits(code2);
9146      var len = (code1 & 0xffff) + code2;
9147      code1 = this.getCode(distCodeTable);
9148      code1 = distDecode[code1];
9149      code2 = code1 >> 16;
9150      if (code2 > 0)
9151        code2 = this.getBits(code2);
9152      var dist = (code1 & 0xffff) + code2;
9153      if (pos + len >= limit) {
9154        buffer = this.ensureBuffer(pos + len);
9155        limit = buffer.length;
9156      }
9157      for (var k = 0; k < len; ++k, ++pos)
9158        buffer[pos] = buffer[pos - dist];
9159    }
9160  };
9161
9162  return constructor;
9163})();/**
9164 * JavaScript Polyfill functions for jsPDF
9165 * Collected from public resources by
9166 * https://github.com/diegocr
9167 */
9168
9169(function (global) {
9170	var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
9171
9172	if (typeof global.btoa === 'undefined') {
9173		global.btoa = function(data) {
9174			//  discuss at: http://phpjs.org/functions/base64_encode/
9175			// original by: Tyler Akins (http://rumkin.com)
9176			// improved by: Bayron Guevara
9177			// improved by: Thunder.m
9178			// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
9179			// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
9180			// improved by: Rafal Kukawski (http://kukawski.pl)
9181			// bugfixed by: Pellentesque Malesuada
9182			//   example 1: base64_encode('Kevin van Zonneveld');
9183			//   returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
9184
9185			var o1,o2,o3,h1,h2,h3,h4,bits,i = 0,ac = 0,enc = '',tmp_arr = [];
9186
9187			if (!data) {
9188				return data;
9189			}
9190
9191			do { // pack three octets into four hexets
9192				o1 = data.charCodeAt(i++);
9193				o2 = data.charCodeAt(i++);
9194				o3 = data.charCodeAt(i++);
9195
9196				bits = o1 << 16 | o2 << 8 | o3;
9197
9198				h1 = bits >> 18 & 0x3f;
9199				h2 = bits >> 12 & 0x3f;
9200				h3 = bits >> 6 & 0x3f;
9201				h4 = bits & 0x3f;
9202
9203				// use hexets to index into b64, and append result to encoded string
9204				tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
9205			} while (i < data.length);
9206
9207			enc = tmp_arr.join('');
9208
9209			var r = data.length % 3;
9210
9211			return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
9212		};
9213	}
9214
9215	if (typeof global.atob === 'undefined') {
9216		global.atob = function(data) {
9217			//  discuss at: http://phpjs.org/functions/base64_decode/
9218			// original by: Tyler Akins (http://rumkin.com)
9219			// improved by: Thunder.m
9220			// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
9221			// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
9222			//    input by: Aman Gupta
9223			//    input by: Brett Zamir (http://brett-zamir.me)
9224			// bugfixed by: Onno Marsman
9225			// bugfixed by: Pellentesque Malesuada
9226			// bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
9227			//   example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
9228			//   returns 1: 'Kevin van Zonneveld'
9229
9230			var o1,o2,o3,h1,h2,h3,h4,bits,i = 0,ac = 0,dec = '',tmp_arr = [];
9231
9232			if (!data) {
9233				return data;
9234			}
9235
9236			data += '';
9237
9238			do { // unpack four hexets into three octets using index points in b64
9239				h1 = b64.indexOf(data.charAt(i++));
9240				h2 = b64.indexOf(data.charAt(i++));
9241				h3 = b64.indexOf(data.charAt(i++));
9242				h4 = b64.indexOf(data.charAt(i++));
9243
9244				bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
9245
9246				o1 = bits >> 16 & 0xff;
9247				o2 = bits >> 8 & 0xff;
9248				o3 = bits & 0xff;
9249
9250				if (h3 == 64) {
9251					tmp_arr[ac++] = String.fromCharCode(o1);
9252				} else if (h4 == 64) {
9253					tmp_arr[ac++] = String.fromCharCode(o1, o2);
9254				} else {
9255					tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
9256				}
9257			} while (i < data.length);
9258
9259			dec = tmp_arr.join('');
9260
9261			return dec;
9262		};
9263	}
9264
9265	if (!Array.prototype.map) {
9266		Array.prototype.map = function(fun /*, thisArg */) {
9267			if (this === void 0 || this === null || typeof fun !== "function")
9268				throw new TypeError();
9269
9270			var t = Object(this), len = t.length >>> 0, res = new Array(len);
9271			var thisArg = arguments.length > 1 ? arguments[1] : void 0;
9272			for (var i = 0; i < len; i++) {
9273				// NOTE: Absolute correctness would demand Object.defineProperty
9274				//       be used.  But this method is fairly new, and failure is
9275				//       possible only if Object.prototype or Array.prototype
9276				//       has a property |i| (very unlikely), so use a less-correct
9277				//       but more portable alternative.
9278				if (i in t)
9279					res[i] = fun.call(thisArg, t[i], i, t);
9280			}
9281
9282			return res;
9283		};
9284	}
9285
9286
9287	if(!Array.isArray) {
9288		Array.isArray = function(arg) {
9289			return Object.prototype.toString.call(arg) === '[object Array]';
9290		};
9291	}
9292
9293	if (!Array.prototype.forEach) {
9294		Array.prototype.forEach = function(fun, thisArg) {
9295			"use strict";
9296
9297			if (this === void 0 || this === null || typeof fun !== "function")
9298				throw new TypeError();
9299
9300			var t = Object(this), len = t.length >>> 0;
9301			for (var i = 0; i < len; i++) {
9302				if (i in t)
9303					fun.call(thisArg, t[i], i, t);
9304			}
9305		};
9306	}
9307
9308	if (!Object.keys) {
9309		Object.keys = (function () {
9310			'use strict';
9311
9312			var hasOwnProperty = Object.prototype.hasOwnProperty,
9313				hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
9314				dontEnums = ['toString','toLocaleString','valueOf','hasOwnProperty',
9315					'isPrototypeOf','propertyIsEnumerable','constructor'],
9316				dontEnumsLength = dontEnums.length;
9317
9318			return function (obj) {
9319				if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
9320					throw new TypeError();
9321				}
9322				var result = [], prop, i;
9323
9324				for (prop in obj) {
9325					if (hasOwnProperty.call(obj, prop)) {
9326						result.push(prop);
9327					}
9328				}
9329
9330				if (hasDontEnumBug) {
9331					for (i = 0; i < dontEnumsLength; i++) {
9332						if (hasOwnProperty.call(obj, dontEnums[i])) {
9333							result.push(dontEnums[i]);
9334						}
9335					}
9336				}
9337				return result;
9338			};
9339		}());
9340	}
9341
9342	if (!String.prototype.trim) {
9343		String.prototype.trim = function () {
9344			return this.replace(/^\s+|\s+$/g, '');
9345		};
9346	}
9347	if (!String.prototype.trimLeft) {
9348		String.prototype.trimLeft = function() {
9349			return this.replace(/^\s+/g, "");
9350		};
9351	}
9352	if (!String.prototype.trimRight) {
9353		String.prototype.trimRight = function() {
9354			return this.replace(/\s+$/g, "");
9355		};
9356	}
9357
9358})(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this);

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.