PageSourceSearch

https://omnisecure.berlin/wp-content/themes/tkt/js/jspdf.js?ver=6.8.10

js omnisecure.berlin collected 2026-10-02 06:02:44 UTC 756,180 bytes, 17,003 lines download raw bytes

1(function (global, factory) {
2    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3        typeof define === 'function' && define.amd ? define(factory) :
4            (global.jspdf = factory());
5}(this, function () { 'use strict';
6
7    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
8        return typeof obj;
9    } : function (obj) {
10        return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj;
11    };
12
13    /** @preserve
14     * jsPDF - PDF Document creation from JavaScript
15     * Version 1.3.2 Built on 2016-09-30T20:33:17.116Z
16     *                           CommitID 7d854cc77d
17     *
18     * Copyright (c) 2010-2014 James Hall <[email protected]>, https://github.com/MrRio/jsPDF
19     *               2010 Aaron Spike, https://github.com/acspike
20     *               2012 Willow Systems Corporation, willow-systems.com
21     *               2012 Pablo Hess, https://github.com/pablohess
22     *               2012 Florian Jenett, https://github.com/fjenett
23     *               2013 Warren Weckesser, https://github.com/warrenweckesser
24     *               2013 Youssef Beddad, https://github.com/lifof
25     *               2013 Lee Driscoll, https://github.com/lsdriscoll
26     *               2013 Stefan Slonevskiy, https://github.com/stefslon
27     *               2013 Jeremy Morel, https://github.com/jmorel
28     *               2013 Christoph Hartmann, https://github.com/chris-rock
29     *               2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
30     *               2014 James Makes, https://github.com/dollaruw
31     *               2014 Diego Casorran, https://github.com/diegocr
32     *               2014 Steven Spungin, https://github.com/Flamenco
33     *               2014 Kenneth Glassey, https://github.com/Gavvers
34     *
35     * Licensed under the MIT License
36     *
37     * Contributor(s):
38     *    siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,
39     *    kim3er, mfo, alnorth, Flamenco
40     */
41
42    /**
43     * Creates new jsPDF document object instance.
44     *
45     * @class
46     * @param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l")
47     * @param unit        Measurement unit to be used when coordinates are specified.
48     *                    One of "pt" (points), "mm" (Default), "cm", "in"
49     * @param format      One of 'pageFormats' as shown below, default: a4
50     * @returns {jsPDF}
51     * @name jsPDF
52     */
53    var jsPDF = function (global) {
54        'use strict';
55
56        var pdfVersion = '1.3',
57            pageFormats = { // Size in pt of various paper formats
58                'a0': [2383.94, 3370.39], 'a1': [1683.78, 2383.94],
59                'a2': [1190.55, 1683.78], 'a3': [841.89, 1190.55],
60                'a4': [595.28, 841.89], 'a5': [419.53, 595.28],
61                'a6': [297.64, 419.53], 'a7': [209.76, 297.64],
62                'a8': [147.40, 209.76], 'a9': [104.88, 147.40],
63                'a10': [73.70, 104.88], 'b0': [2834.65, 4008.19],
64                'b1': [2004.09, 2834.65], 'b2': [1417.32, 2004.09],
65                'b3': [1000.63, 1417.32], 'b4': [708.66, 1000.63],
66                'b5': [498.90, 708.66], 'b6': [354.33, 498.90],
67                'b7': [249.45, 354.33], 'b8': [175.75, 249.45],
68                'b9': [124.72, 175.75], 'b10': [87.87, 124.72],
69                'c0': [2599.37, 3676.54], 'c1': [1836.85, 2599.37],
70                'c2': [1298.27, 1836.85], 'c3': [918.43, 1298.27],
71                'c4': [649.13, 918.43], 'c5': [459.21, 649.13],
72                'c6': [323.15, 459.21], 'c7': [229.61, 323.15],
73                'c8': [161.57, 229.61], 'c9': [113.39, 161.57],
74                'c10': [79.37, 113.39], 'dl': [311.81, 623.62],
75                'letter': [612, 792],
76                'government-letter': [576, 756],
77                'legal': [612, 1008],
78                'junior-legal': [576, 360],
79                'ledger': [1224, 792],
80                'tabloid': [792, 1224],
81                'credit-card': [153, 243]
82            };
83
84        /**
85         * jsPDF's Internal PubSub Implementation.
86         * See mrrio.github.io/jsPDF/doc/symbols/PubSub.html
87         * Backward compatible rewritten on 2014 by
88         * Diego Casorran, https://github.com/diegocr
89         *
90         * @class
91         * @name PubSub
92         */
93        function PubSub(context) {
94            var topics = {};
95
96            this.subscribe = function (topic, callback, once) {
97                if (typeof callback !== 'function') {
98                    return false;
99                }
100
101                if (!topics.hasOwnProperty(topic)) {
102                    topics[topic] = {};
103                }
104
105                var id = Math.random().toString(35);
106                topics[topic][id] = [callback, !!once];
107
108                return id;
109            };
110
111            this.unsubscribe = function (token) {
112                for (var topic in topics) {
113                    if (topics[topic][token]) {
114                        delete topics[topic][token];
115                        return true;
116                    }
117                }
118                return false;
119            };
120
121            this.publish = function (topic) {
122                if (topics.hasOwnProperty(topic)) {
123                    var args = Array.prototype.slice.call(arguments, 1),
124                        idr = [];
125
126                    for (var id in topics[topic]) {
127                        var sub = topics[topic][id];
128                        try {
129                            sub[0].apply(context, args);
130                        } catch (ex) {
131                            if (global.console) {
132                                console.error('jsPDF PubSub Error', ex.message, ex);
133                            }
134                        }
135                        if (sub[1]) idr.push(id);
136                    }
137                    if (idr.length) idr.forEach(this.unsubscribe);
138                }
139            };
140        }
141
142        /**
143         * @constructor
144         * @private
145         */
146        function jsPDF(orientation, unit, format, compressPdf) {
147            var options = {};
148
149            if ((typeof orientation === 'undefined' ? 'undefined' : _typeof(orientation)) === 'object') {
150                options = orientation;
151
152                orientation = options.orientation;
153                unit = options.unit || unit;
154                format = options.format || format;
155                compressPdf = options.compress || options.compressPdf || compressPdf;
156            }
157
158            // Default options
159            unit = unit || 'mm';
160            format = format || 'a4';
161            orientation = ('' + (orientation || 'P')).toLowerCase();
162
163            var format_as_string = ('' + format).toLowerCase(),
164                compress = !!compressPdf && typeof Uint8Array === 'function',
165                textColor = options.textColor || '0 g',
166                drawColor = options.drawColor || '0 G',
167                activeFontSize = options.fontSize || 16,
168                lineHeightProportion = options.lineHeight || 1.15,
169                lineWidth = options.lineWidth || 0.200025,
170                // 2mm
171                objectNumber = 2,
172                // 'n' Current object number
173                outToPages = !1,
174                // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content
175                offsets = [],
176                // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes.
177                fonts = {},
178                // collection of font objects, where key is fontKey - a dynamically created label for a given font.
179                fontmap = {},
180                // mapping structure fontName > fontStyle > font key - performance layer. See addFont()
181                activeFontKey,
182                // will be string representing the KEY of the font as combination of fontName + fontStyle
183                k,
184                // Scale factor
185                tmp,
186                page = 0,
187                currentPage,
188                pages = [],
189                pagesContext = [],
190                // same index as pages and pagedim
191                pagedim = [],
192                content = [],
193                additionalObjects = [],
194                lineCapID = 0,
195                lineJoinID = 0,
196                content_length = 0,
197                pageWidth,
198                pageHeight,
199                pageMode,
200                zoomMode,
201                layoutMode,
202                documentProperties = {
203                    'title': '',
204                    'subject': '',
205                    'author': '',
206                    'keywords': '',
207                    'creator': ''
208                },
209                API = {},
210                events = new PubSub(API),
211
212
213                /////////////////////
214                // Private functions
215                /////////////////////
216                f2 = function f2(number) {
217                    return number.toFixed(2); // Ie, %.2f
218                },
219                f3 = function f3(number) {
220                    return number.toFixed(3); // Ie, %.3f
221                },
222                padd2 = function padd2(number) {
223                    return ('0' + parseInt(number)).slice(-2);
224                },
225                out = function out(string) {
226                    if (outToPages) {
227                        /* set by beginPage */
228                        pages[currentPage].push(string);
229                    } else {
230                        // +1 for '\n' that will be used to join 'content'
231                        content_length += string.length + 1;
232                        content.push(string);
233                    }
234                },
235                newObject = function newObject() {
236                    // Begin a new object
237                    objectNumber++;
238                    offsets[objectNumber] = content_length;
239                    out(objectNumber + ' 0 obj');
240                    return objectNumber;
241                },
242
243                // Does not output the object until after the pages have been output.
244                // Returns an object containing the objectId and content.
245                // All pages have been added so the object ID can be estimated to start right after.
246                // This does not modify the current objectNumber;  It must be updated after the newObjects are output.
247                newAdditionalObject = function newAdditionalObject() {
248                    var objId = pages.length * 2 + 1;
249                    objId += additionalObjects.length;
250                    var obj = { objId: objId, content: '' };
251                    additionalObjects.push(obj);
252                    return obj;
253                },
254
255                // Does not output the object.  The caller must call newObjectDeferredBegin(oid) before outputing any data
256                newObjectDeferred = function newObjectDeferred() {
257                    objectNumber++;
258                    offsets[objectNumber] = function () {
259                        return content_length;
260                    };
261                    return objectNumber;
262                },
263                newObjectDeferredBegin = function newObjectDeferredBegin(oid) {
264                    offsets[oid] = content_length;
265                },
266                putStream = function putStream(str) {
267                    out('stream');
268                    out(str);
269                    out('endstream');
270                },
271                putPages = function putPages() {
272                    var n,
273                        p,
274                        arr,
275                        i,
276                        deflater,
277                        adler32,
278                        adler32cs,
279                        wPt,
280                        hPt,
281                        pageObjectNumbers = [];
282
283                    adler32cs = global.adler32cs || jsPDF.adler32cs;
284                    if (compress && typeof adler32cs === 'undefined') {
285                        compress = false;
286                    }
287
288                    // outToPages = false as set in endDocument(). out() writes to content.
289
290                    for (n = 1; n <= page; n++) {
291                        pageObjectNumbers.push(newObject());
292                        wPt = (pageWidth = pagedim[n].width) * k;
293                        hPt = (pageHeight = pagedim[n].height) * k;
294                        out('<</Type /Page');
295                        out('/Parent 1 0 R');
296                        out('/Resources 2 0 R');
297                        out('/MediaBox [0 0 ' + f2(wPt) + ' ' + f2(hPt) + ']');
298                        // Added for annotation plugin
299                        events.publish('putPage', { pageNumber: n, page: pages[n] });
300                        out('/Contents ' + (objectNumber + 1) + ' 0 R');
301                        out('>>');
302                        out('endobj');
303
304                        // Page content
305                        p = pages[n].join('\n');
306                        newObject();
307                        if (compress) {
308                            arr = [];
309                            i = p.length;
310                            while (i--) {
311                                arr[i] = p.charCodeAt(i);
312                            }
313                            adler32 = adler32cs.from(p);
314                            deflater = new Deflater(6);
315                            deflater.append(new Uint8Array(arr));
316                            p = deflater.flush();
317                            arr = new Uint8Array(p.length + 6);
318                            arr.set(new Uint8Array([120, 156])), arr.set(p, 2);
319                            arr.set(new Uint8Array([adler32 & 0xFF, adler32 >> 8 & 0xFF, adler32 >> 16 & 0xFF, adler32 >> 24 & 0xFF]), p.length + 2);
320                            p = String.fromCharCode.apply(null, arr);
321                            out('<</Length ' + p.length + ' /Filter [/FlateDecode]>>');
322                        } else {
323                            out('<</Length ' + p.length + '>>');
324                        }
325                        putStream(p);
326                        out('endobj');
327                    }
328                    offsets[1] = content_length;
329                    out('1 0 obj');
330                    out('<</Type /Pages');
331                    var kids = '/Kids [';
332                    for (i = 0; i < page; i++) {
333                        kids += pageObjectNumbers[i] + ' 0 R ';
334                    }
335                    out(kids + ']');
336                    out('/Count ' + page);
337                    out('>>');
338                    out('endobj');
339                    events.publish('postPutPages');
340                },
341                putFont = function putFont(font) {
342                    font.objectNumber = newObject();
343                    out('<</BaseFont/' + font.PostScriptName + '/Type/Font');
344                    if (typeof font.encoding === 'string') {
345                        out('/Encoding/' + font.encoding);
346                    }
347                    out('/Subtype/Type1>>');
348                    out('endobj');
349                },
350                putFonts = function putFonts() {
351                    for (var fontKey in fonts) {
352                        if (fonts.hasOwnProperty(fontKey)) {
353                            putFont(fonts[fontKey]);
354                        }
355                    }
356                },
357                putXobjectDict = function putXobjectDict() {
358                    // Loop through images, or other data objects
359                    events.publish('putXobjectDict');
360                },
361                putResourceDictionary = function putResourceDictionary() {
362                    out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
363                    out('/Font <<');
364
365                    // Do this for each font, the '1' bit is the index of the font
366                    for (var fontKey in fonts) {
367                        if (fonts.hasOwnProperty(fontKey)) {
368                            out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R');
369                        }
370                    }
371                    out('>>');
372                    out('/XObject <<');
373                    putXobjectDict();
374                    out('>>');
375                },
376                putResources = function putResources() {
377                    putFonts();
378                    events.publish('putResources');
379                    // Resource dictionary
380                    offsets[2] = content_length;
381                    out('2 0 obj');
382                    out('<<');
383                    putResourceDictionary();
384                    out('>>');
385                    out('endobj');
386                    events.publish('postPutResources');
387                },
388                putAdditionalObjects = function putAdditionalObjects() {
389                    events.publish('putAdditionalObjects');
390                    for (var i = 0; i < additionalObjects.length; i++) {
391                        var obj = additionalObjects[i];
392                        offsets[obj.objId] = content_length;
393                        out(obj.objId + ' 0 obj');
394                        out(obj.content);
395                        ;
396                        out('endobj');
397                    }
398                    objectNumber += additionalObjects.length;
399                    events.publish('postPutAdditionalObjects');
400                },
401                addToFontDictionary = function addToFontDictionary(fontKey, fontName, fontStyle) {
402                    // this is mapping structure for quick font key lookup.
403                    // returns the KEY of the font (ex: "F1") for a given
404                    // pair of font name and type (ex: "Arial". "Italic")
405                    if (!fontmap.hasOwnProperty(fontName)) {
406                        fontmap[fontName] = {};
407                    }
408                    fontmap[fontName][fontStyle] = fontKey;
409                },
410
411                /**
412                 * FontObject describes a particular font as member of an instnace of jsPDF
413                 *
414                 * It's a collection of properties like 'id' (to be used in PDF stream),
415                 * 'fontName' (font's family name), 'fontStyle' (font's style variant label)
416                 *
417                 * @class
418                 * @public
419                 * @property id {String} PDF-document-instance-specific label assinged to the font.
420                 * @property PostScriptName {String} PDF specification full name for the font
421                 * @property encoding {Object} Encoding_name-to-Font_metrics_object mapping.
422                 * @name FontObject
423                 */
424                addFont = function addFont(PostScriptName, fontName, fontStyle, encoding) {
425                    var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10),
426
427                        // This is FontObject
428                        font = fonts[fontKey] = {
429                            'id': fontKey,
430                            'PostScriptName': PostScriptName,
431                            'fontName': fontName,
432                            'fontStyle': fontStyle,
433                            'encoding': encoding,
434                            'metadata': {}
435                        };
436                    addToFontDictionary(fontKey, fontName, fontStyle);
437                    events.publish('addFont', font);
438
439                    return fontKey;
440                },
441                addFonts = function addFonts() {
442
443                    var HELVETICA = "helvetica",
444                        TIMES = "times",
445                        COURIER = "courier",
446                        NORMAL = "normal",
447                        BOLD = "bold",
448                        ITALIC = "italic",
449                        BOLD_ITALIC = "bolditalic",
450                        encoding = 'StandardEncoding',
451                        ZAPF = "zapfdingbats",
452                        standardFonts = [['Helvetica', HELVETICA, NORMAL], ['Helvetica-Bold', HELVETICA, BOLD], ['Helvetica-Oblique', HELVETICA, ITALIC], ['Helvetica-BoldOblique', HELVETICA, BOLD_ITALIC], ['Courier', COURIER, NORMAL], ['Courier-Bold', COURIER, BOLD], ['Courier-Oblique', COURIER, ITALIC], ['Courier-BoldOblique', COURIER, BOLD_ITALIC], ['Times-Roman', TIMES, NORMAL], ['Times-Bold', TIMES, BOLD], ['Times-Italic', TIMES, ITALIC], ['Times-BoldItalic', TIMES, BOLD_ITALIC], ['ZapfDingbats', ZAPF]];
453
454                    for (var i = 0, l = standardFonts.length; i < l; i++) {
455                        var fontKey = addFont(standardFonts[i][0], standardFonts[i][1], standardFonts[i][2], encoding);
456
457                        // adding aliases for standard fonts, this time matching the capitalization
458                        var parts = standardFonts[i][0].split('-');
459                        addToFontDictionary(fontKey, parts[0], parts[1] || '');
460                    }
461                    events.publish('addFonts', { fonts: fonts, dictionary: fontmap });
462                },
463                SAFE = function __safeCall(fn) {
464                    fn.foo = function __safeCallWrapper() {
465                        try {
466                            return fn.apply(this, arguments);
467                        } catch (e) {
468                            var stack = e.stack || '';
469                            if (~stack.indexOf(' at ')) stack = stack.split(" at ")[1];
470                            var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message;
471                            if (global.console) {
472                                global.console.error(m, e);
473                                if (global.alert) alert(m);
474                            } else {
475                                throw new Error(m);
476                            }
477                        }
478                    };
479                    fn.foo.bar = fn;
480                    return fn.foo;
481                },
482                to8bitStream = function to8bitStream(text, flags) {
483                    /**
484                     * PDF 1.3 spec:
485                     * "For text strings encoded in Unicode, the first two bytes must be 254 followed by
486                     * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts
487                     * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely
488                     * to be a meaningful beginning of a word or phrase.) The remainder of the
489                     * string consists of Unicode character codes, according to the UTF-16 encoding
490                     * specified in the Unicode standard, version 2.0. Commonly used Unicode values
491                     * are represented as 2 bytes per character, with the high-order byte appearing first
492                     * in the string."
493                     *
494                     * In other words, if there are chars in a string with char code above 255, we
495                     * recode the string to UCS2 BE - string doubles in length and BOM is prepended.
496                     *
497                     * HOWEVER!
498                     * Actual *content* (body) text (as opposed to strings used in document properties etc)
499                     * does NOT expect BOM. There, it is treated as a literal GID (Glyph ID)
500                     *
501                     * Because of Adobe's focus on "you subset your fonts!" you are not supposed to have
502                     * a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could
503                     * fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode
504                     * code page. There, however, all characters in the stream are treated as GIDs,
505                     * including BOM, which is the reason we need to skip BOM in content text (i.e. that
506                     * that is tied to a font).
507                     *
508                     * To signal this "special" PDFEscape / to8bitStream handling mode,
509                     * API.text() function sets (unless you overwrite it with manual values
510                     * given to API.text(.., flags) )
511                     * flags.autoencode = true
512                     * flags.noBOM = true
513                     *
514                     * ===================================================================================
515                     * `flags` properties relied upon:
516                     *   .sourceEncoding = string with encoding label.
517                     *                     "Unicode" by default. = encoding of the incoming text.
518                     *                     pass some non-existing encoding name
519                     *                     (ex: 'Do not touch my strings! I know what I am doing.')
520                     *                     to make encoding code skip the encoding step.
521                     *   .outputEncoding = Either valid PDF encoding name
522                     *                     (must be supported by jsPDF font metrics, otherwise no encoding)
523                     *                     or a JS object, where key = sourceCharCode, value = outputCharCode
524                     *                     missing keys will be treated as: sourceCharCode === outputCharCode
525                     *   .noBOM
526                     *       See comment higher above for explanation for why this is important
527                     *   .autoencode
528                     *       See comment higher above for explanation for why this is important
529                     */
530
531                    var i, l, sourceEncoding, encodingBlock, outputEncoding, newtext, isUnicode, ch, bch;
532
533                    flags = flags || {};
534                    sourceEncoding = flags.sourceEncoding || 'Unicode';
535                    outputEncoding = flags.outputEncoding;
536
537                    // This 'encoding' section relies on font metrics format
538                    // attached to font objects by, among others,
539                    // "Willow Systems' standard_font_metrics plugin"
540                    // see jspdf.plugin.standard_font_metrics.js for format
541                    // of the font.metadata.encoding Object.
542                    // It should be something like
543                    //   .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}}
544                    //   .widths = {0:width, code:width, ..., 'fof':divisor}
545                    //   .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...}
546                    if ((flags.autoencode || outputEncoding) && fonts[activeFontKey].metadata && fonts[activeFontKey].metadata[sourceEncoding] && fonts[activeFontKey].metadata[sourceEncoding].encoding) {
547                        encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding;
548
549                        // each font has default encoding. Some have it clearly defined.
550                        if (!outputEncoding && fonts[activeFontKey].encoding) {
551                            outputEncoding = fonts[activeFontKey].encoding;
552                        }
553
554                        // Hmmm, the above did not work? Let's try again, in different place.
555                        if (!outputEncoding && encodingBlock.codePages) {
556                            outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default
557                        }
558
559                        if (typeof outputEncoding === 'string') {
560                            outputEncoding = encodingBlock[outputEncoding];
561                        }
562                        // we want output encoding to be a JS Object, where
563                        // key = sourceEncoding's character code and
564                        // value = outputEncoding's character code.
565                        if (outputEncoding) {
566                            isUnicode = false;
567                            newtext = [];
568                            for (i = 0, l = text.length; i < l; i++) {
569                                ch = outputEncoding[text.charCodeAt(i)];
570                                if (ch) {
571                                    newtext.push(String.fromCharCode(ch));
572                                } else {
573                                    newtext.push(text[i]);
574                                }
575
576                                // since we are looping over chars anyway, might as well
577                                // check for residual unicodeness
578                                if (newtext[i].charCodeAt(0) >> 8) {
579                                    /* more than 255 */
580                                    isUnicode = true;
581                                }
582                            }
583                            text = newtext.join('');
584                        }
585                    }
586
587                    i = text.length;
588                    // isUnicode may be set to false above. Hence the triple-equal to undefined
589                    while (isUnicode === undefined && i !== 0) {
590                        if (text.charCodeAt(i - 1) >> 8) {
591                            /* more than 255 */
592                            isUnicode = true;
593                        }
594                        i--;
595                    }
596                    if (!isUnicode) {
597                        return text;
598                    }
599
600                    newtext = flags.noBOM ? [] : [254, 255];
601                    for (i = 0, l = text.length; i < l; i++) {
602                        ch = text.charCodeAt(i);
603                        bch = ch >> 8; // divide by 256
604                        if (bch >> 8) {
605                            /* something left after dividing by 256 second time */
606                            throw new Error("Character at position " + i + " of string '" + text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE");
607                        }
608                        newtext.push(bch);
609                        newtext.push(ch - (bch << 8));
610                    }
611                    return String.fromCharCode.apply(undefined, newtext);
612                },
613                pdfEscape = function pdfEscape(text, flags) {
614                    /**
615                     * Replace '/', '(', and ')' with pdf-safe versions
616                     *
617                     * Doing to8bitStream does NOT make this PDF display unicode text. For that
618                     * we also need to reference a unicode font and embed it - royal pain in the rear.
619                     *
620                     * There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars,
621                     * which JavaScript Strings are happy to provide. So, while we still cannot display
622                     * 2-byte characters property, at least CONDITIONALLY converting (entire string containing)
623                     * 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF
624                     * is still parseable.
625                     * This will allow immediate support for unicode in document properties strings.
626                     */
627                    return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
628                },
629                putInfo = function putInfo() {
630                    out('/Producer (jsPDF ' + jsPDF.version + ')');
631                    for (var key in documentProperties) {
632                        if (documentProperties.hasOwnProperty(key) && documentProperties[key]) {
633                            out('/' + key.substr(0, 1).toUpperCase() + key.substr(1) + ' (' + pdfEscape(documentProperties[key]) + ')');
634                        }
635                    }
636                    var created = new Date(),
637                        tzoffset = created.getTimezoneOffset(),
638                        tzsign = tzoffset < 0 ? '+' : '-',
639                        tzhour = Math.floor(Math.abs(tzoffset / 60)),
640                        tzmin = Math.abs(tzoffset % 60),
641                        tzstr = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join('');
642                    out(['/CreationDate (D:', created.getFullYear(), padd2(created.getMonth() + 1), padd2(created.getDate()), padd2(created.getHours()), padd2(created.getMinutes()), padd2(created.getSeconds()), tzstr, ')'].join(''));
643                },
644                putCatalog = function putCatalog() {
645                    out('/Type /Catalog');
646                    out('/Pages 1 0 R');
647                    // PDF13ref Section 7.2.1
648                    if (!zoomMode) zoomMode = 'fullwidth';
649                    switch (zoomMode) {
650                        case 'fullwidth':
651                            out('/OpenAction [3 0 R /FitH null]');
652                            break;
653                        case 'fullheight':
654                            out('/OpenAction [3 0 R /FitV null]');
655                            break;
656                        case 'fullpage':
657                            out('/OpenAction [3 0 R /Fit]');
658                            break;
659                        case 'original':
660                            out('/OpenAction [3 0 R /XYZ null null 1]');
661                            break;
662                        default:
663                            var pcn = '' + zoomMode;
664                            if (pcn.substr(pcn.length - 1) === '%') zoomMode = parseInt(zoomMode) / 100;
665                            if (typeof zoomMode === 'number') {
666                                out('/OpenAction [3 0 R /XYZ null null ' + f2(zoomMode) + ']');
667                            }
668                    }
669                    if (!layoutMode) layoutMode = 'continuous';
670                    switch (layoutMode) {
671                        case 'continuous':
672                            out('/PageLayout /OneColumn');
673                            break;
674                        case 'single':
675                            out('/PageLayout /SinglePage');
676                            break;
677                        case 'two':
678                        case 'twoleft':
679                            out('/PageLayout /TwoColumnLeft');
680                            break;
681                        case 'tworight':
682                            out('/PageLayout /TwoColumnRight');
683                            break;
684                    }
685                    if (pageMode) {
686                        /**
687                         * A name object specifying how the document should be displayed when opened:
688                         * UseNone      : Neither document outline nor thumbnail images visible -- DEFAULT
689                         * UseOutlines  : Document outline visible
690                         * UseThumbs    : Thumbnail images visible
691                         * FullScreen   : Full-screen mode, with no menu bar, window controls, or any other window visible
692                         */
693                        out('/PageMode /' + pageMode);
694                    }
695                    events.publish('putCatalog');
696                },
697                putTrailer = function putTrailer() {
698                    out('/Size ' + (objectNumber + 1));
699                    out('/Root ' + objectNumber + ' 0 R');
700                    out('/Info ' + (objectNumber - 1) + ' 0 R');
701                },
702                beginPage = function beginPage(width, height) {
703                    // Dimensions are stored as user units and converted to points on output
704                    var orientation = typeof height === 'string' && height.toLowerCase();
705                    if (typeof width === 'string') {
706                        var format = width.toLowerCase();
707                        if (pageFormats.hasOwnProperty(format)) {
708                            width = pageFormats[format][0] / k;
709                            height = pageFormats[format][1] / k;
710                        }
711                    }
712                    if (Array.isArray(width)) {
713                        height = width[1];
714                        width = width[0];
715                    }
716                    if (orientation) {
717                        switch (orientation.substr(0, 1)) {
718                            case 'l':
719                                if (height > width) orientation = 's';
720                                break;
721                            case 'p':
722                                if (width > height) orientation = 's';
723                                break;
724                        }
725                        if (orientation === 's') {
726                            tmp = width;
727                            width = height;
728                            height = tmp;
729                        }
730                    }
731                    outToPages = true;
732                    pages[++page] = [];
733                    pagedim[page] = {
734                        width: Number(width) || pageWidth,
735                        height: Number(height) || pageHeight
736                    };
737                    pagesContext[page] = {};
738                    _setPage(page);
739                },
740                _addPage = function _addPage() {
741                    beginPage.apply(this, arguments);
742                    // Set line width
743                    out(f2(lineWidth * k) + ' w');
744                    // Set draw color
745                    out(drawColor);
746                    // resurrecting non-default line caps, joins
747                    if (lineCapID !== 0) {
748                        out(lineCapID + ' J');
749                    }
750                    if (lineJoinID !== 0) {
751                        out(lineJoinID + ' j');
752                    }
753                    events.publish('addPage', { pageNumber: page });
754                },
755                _deletePage = function _deletePage(n) {
756                    if (n > 0 && n <= page) {
757                        pages.splice(n, 1);
758                        pagedim.splice(n, 1);
759                        page--;
760                        if (currentPage > page) {
761                            currentPage = page;
762                        }
763                        this.setPage(currentPage);
764                    }
765                },
766                _setPage = function _setPage(n) {
767                    if (n > 0 && n <= page) {
768                        currentPage = n;
769                        pageWidth = pagedim[n].width;
770                        pageHeight = pagedim[n].height;
771                    }
772                },
773
774                /**
775                 * Returns a document-specific font key - a label assigned to a
776                 * font name + font type combination at the time the font was added
777                 * to the font inventory.
778                 *
779                 * Font key is used as label for the desired font for a block of text
780                 * to be added to the PDF document stream.
781                 * @private
782                 * @function
783                 * @param fontName {String} can be undefined on "falthy" to indicate "use current"
784                 * @param fontStyle {String} can be undefined on "falthy" to indicate "use current"
785                 * @returns {String} Font key.
786                 */
787                _getFont = function _getFont(fontName, fontStyle) {
788                    var key;
789
790                    fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName;
791                    fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle;
792
793                    if (fontName !== undefined) {
794                        fontName = fontName.toLowerCase();
795                    }
796                    switch (fontName) {
797                        case 'sans-serif':
798                        case 'verdana':
799                        case 'arial':
800                        case 'helvetica':
801                            fontName = 'helvetica';
802                            break;
803                        case 'fixed':
804                        case 'monospace':
805                        case 'terminal':
806                        case 'courier':
807                            fontName = 'courier';
808                            break;
809                        case 'serif':
810                        case 'cursive':
811                        case 'fantasy':
812                        default:
813                            fontName = 'times';
814                            break;
815                    }
816
817                    try {
818                        // get a string like 'F3' - the KEY corresponding tot he font + type combination.
819                        key = fontmap[fontName][fontStyle];
820                    } catch (e) {}
821
822                    if (!key) {
823                        //throw new Error("Unable to look up font label for font '" + fontName + "', '"
824                        //+ fontStyle + "'. Refer to getFontList(
824) for available fonts.");
825                        key = fontmap['times'][fontStyle];
826                        if (key == null) {
827                            key = fontmap['times']['normal'];
828                        }
829                    }
830                    return key;
831                },
832                buildDocument = function buildDocument() {
833                    outToPages = false; // switches out() to content
834
835                    objectNumber = 2;
836                    content_length = 0;
837                    content = [];
838                    offsets = [];
839                    additionalObjects = [];
840                    // Added for AcroForm
841                    events.publish('buildDocument');
842
843                    // putHeader()
844                    out('%PDF-' + pdfVersion);
845
846                    putPages();
847
848                    // Must happen after putPages
849                    // Modifies current object Id
850                    putAdditionalObjects();
851
852                    putResources();
853
854                    // Info
855                    newObject();
856                    out('<<');
857                    putInfo();
858                    out('>>');
859                    out('endobj');
860
861                    // Catalog
862                    newObject();
863                    out('<<');
864                    putCatalog();
865                    out('>>');
866                    out('endobj');
867
868                    // Cross-ref
869                    var o = content_length,
870                        i,
871                        p = "0000000000";
872                    out('xref');
873                    out('0 ' + (objectNumber + 1));
874                    out(p + ' 65535 f ');
875                    for (i = 1; i <= objectNumber; i++) {
876                        var offset = offsets[i];
877                        if (typeof offset === 'function') {
878                            out((p + offsets[i]()).slice(-10) + ' 00000 n ');
879                        } else {
880                            out((p + offsets[i]).slice(-10) + ' 00000 n ');
881                        }
882                    }
883                    // Trailer
884                    out('trailer');
885                    out('<<');
886                    putTrailer();
887                    out('>>');
888                    out('startxref');
889                    out('' + o);
890                    out('%%EOF');
891
892                    outToPages = true;
893
894                    return content.join('\n');
895                },
896                getStyle = function getStyle(style) {
897                    // see path-painting operators in PDF spec
898                    var op = 'S'; // stroke
899                    if (style === 'F') {
900                        op = 'f'; // fill
901                    } else if (style === 'FD' || style === 'DF') {
902                        op = 'B'; // both
903                    } else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') {
904                        /*
905                   Allow direct use of these PDF path-painting operators:
906                   - f	fill using nonzero winding number rule
907                   - f*	fill using even-odd rule
908                   - B	fill then stroke with fill using non-zero winding number rule
909                   - B*	fill then stroke with fill using even-odd rule
910                   */
911                        op = style;
912                    }
913                    return op;
914                },
915                getArrayBuffer = function getArrayBuffer() {
916                    var data = buildDocument(),
917                        len = data.length,
918                        ab = new ArrayBuffer(len),
919                        u8 = new Uint8Array(ab);
920
921                    while (len--) {
922                        u8[len] = data.charCodeAt(len);
923                    }return ab;
924                },
925                getBlob = function getBlob() {
926                    return new Blob([getArrayBuffer()], { type: "application/pdf" });
927                },
928
929                /**
930                 * Generates the PDF document.
931                 *
932                 * If `type` argument is undefined, output is raw body of resulting PDF returned as a string.
933                 *
934                 * @param {String}
934 type A string identifying one of the possible output types.
935                 * @param {Object} options An object providing some additional signalling to PDF generator.
936                 * @function
937                 * @returns {jsPDF}
938                 * @methodOf jsPDF#
939                 * @name output
940                 */
941                _output = SAFE(function (type, options) {
942                    var datauri = ('' + type).substr(0, 6) === 'dataur' ? 'data:application/pdf;base64,' + btoa(buildDocument()) : 0;
943
944                    switch (type) {
945                        case undefined:
946                            return buildDocument();
947                        case 'save':
948                            if (navigator.getUserMedia) {
949                                if (global.URL === undefined || global.URL.createObjectURL === undefined) {
950                                    return API.output('dataurlnewwindow');
951                                }
952                            }
953                            saveAs(getBlob(), options);
954                            if (typeof saveAs.unload === 'function') {
955                                if (global.setTimeout) {
956                                    setTimeout(saveAs.unload, 911);
957                                }
958                            }
959                            break;
960                        case 'arraybuffer':
961                            return getArrayBuffer();
962                        case 'blob':
963                            return getBlob();
964                        case 'bloburi':
965                        case 'bloburl':
966                            // User is responsible of calling revokeObjectURL
967                            return global.URL && global.URL.createObjectURL(getBlob()) || void 0;
968                        case 'datauristring':
969                        case 'dataurlstring':
970                            return datauri;
971                        case 'dataurlnewwindow':
972                            var nW = global.open(datauri);
973                            if (nW || typeof safari === "undefined") return nW;
974                        /* pass through */
975                        case 'datauri':
976                        case 'dataurl':
977                            return global.document.location.href = datauri;
978                        default:
979                            throw new Error('Output type "' + type + '" is not supported.');
980                    }
981                    // @TODO: Add different output options
982                });
983
984            switch (unit) {
985                case 'pt':
986                    k = 1;
987                    break;
988                case 'mm':
989                    k = 72 / 25.4000508;
990                    break;
991                case 'cm':
992                    k = 72 / 2.54000508;
993                    break;
994                case 'in':
995                    k = 72;
996                    break;
997                case 'px':
998                    k = 96 / 72;
999                    break;
1000                case 'pc':
1001                    k = 12;
1002                    break;
1003                case 'em':
1004                    k = 12;
1005                    break;
1006                case 'ex':
1007                    k = 6;
1008                    break;
1009                default:
1010                    throw 'Invalid unit: ' + unit;
1011            }
1012
1013            //---------------------------------------
1014            // Public API
1015
1016            /**
1017             * Object exposing internal API to plugins
1018             * @public
1019             */
1020            API.internal = {
1021                'pdfEscape': pdfEscape,
1022                'getStyle': getStyle,
1023                /**
1024                 * Returns {FontObject} describing a particular font.
1025                 * @public
1026                 * @function
1027                 * @param fontName {String} (Optional) Font's family name
1028                 * @param fontStyle {String} (Optional) Font's style variation name (Example:"Italic")
1029                 * @returns {FontObject}
1030                 */
1031                'getFont': function getFont() {
1032                    return fonts[_getFont.apply(API, arguments)];
1033                },
1034                'getFontSize': function getFontSize() {
1035                    return activeFontSize;
1036                },
1037                'getLineHeight': function getLineHeight() {
1038                    return activeFontSize * lineHeightProportion;
1039                },
1040                'write': function write(string1 /*, string2, string3, etc */) {
1041                    out(arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' '));
1042                },
1043                'getCoordinateString': function getCoordinateString(value) {
1044                    return f2(value * k);
1045                },
1046                'getVerticalCoordinateString': function getVerticalCoordinateString(value) {
1047                    return f2((pageHeight - value) * k);
1048                },
1049                'collections': {},
1050                'newObject': newObject,
1051                'newAdditionalObject': newAdditionalObject,
1052                'newObjectDeferred': newObjectDeferred,
1053                'newObjectDeferredBegin': newObjectDeferredBegin,
1054                'putStream': putStream,
1055                'events': events,
1056                // ratio that you use in multiplication of a given "size" number to arrive to 'point'
1057                // units of measurement.
1058                // scaleFactor is set at initialization of the document and calculated against the stated
1059                // default measurement units for the document.
1060                // If default is "mm", k is the number that will turn number in 'mm' into 'points' number.
1061                // through multiplication.
1062                'scaleFactor': k,
1063                'pageSize': {
1064                    get width() {
1065                        return pageWidth;
1066                    },
1067                    get height() {
1068                        return pageHeight;
1069                    }
1070                },
1071                'output': function output(type, options) {
1072                    return _output(type, options);
1073                },
1074                'getNumberOfPages': function getNumberOfPages() {
1075                    return pages.length - 1;
1076                },
1077                'pages': pages,
1078                'out': out,
1079                'f2': f2,
1080                'getPageInfo': function getPageInfo(pageNumberOneBased) {
1081                    var objId = (pageNumberOneBased - 1) * 2 + 3;
1082                    return { objId: objId, pageNumber: pageNumberOneBased, pageContext: pagesContext[pageNumberOneBased] };
1083                },
1084                'getCurrentPageInfo': function getCurrentPageInfo() {
1085                    var objId = (currentPage - 1) * 2 + 3;
1086                    return { objId: objId, pageNumber: currentPage, pageContext: pagesContext[currentPage] };
1087                },
1088                'getPDFVersion': function getPDFVersion() {
1089                    return pdfVersion;
1090                }
1091            };
1092
1093            /**
1094             * Adds (and transfers the focus to) new page to the PDF document.
1095             * @function
1096             * @returns {jsPDF}
1097             *
1098             * @methodOf jsPDF#
1099             * @name addPage
1100             */
1101            API.addPage = function () {
1102                _addPage.apply(this, arguments);
1103                return this;
1104            };
1105            API.setPage = function () {
1106                _setPage.apply(this, arguments);
1107                return this;
1108            };
1109            API.insertPage = function (beforePage) {
1110                this.addPage();
1111                this.movePage(currentPage, beforePage);
1112                return this;
1113            };
1114            API.movePage = function (targetPage, beforePage) {
1115                if (targetPage > beforePage) {
1116                    var tmpPages = pages[targetPage];
1117                    var tmpPagedim = pagedim[targetPage];
1118                    var tmpPagesContext = pagesContext[targetPage];
1119                    for (var i = targetPage; i > beforePage; i--) {
1120                        pages[i] = pages[i - 1];
1121                        pagedim[i] = pagedim[i - 1];
1122                        pagesContext[i] = pagesContext[i - 1];
1123                    }
1124                    pages[beforePage] = tmpPages;
1125                    pagedim[beforePage] = tmpPagedim;
1126                    pagesContext[beforePage] = tmpPagesContext;
1127                    this.setPage(beforePage);
1128                } else if (targetPage < beforePage) {
1129                    var tmpPages = pages[targetPage];
1130                    var tmpPagedim = pagedim[targetPage];
1131                    var tmpPagesContext = pagesContext[targetPage];
1132                    for (var i = targetPage; i < beforePage; i++) {
1133                        pages[i] = pages[i + 1];
1134                        pagedim[i] = pagedim[i + 1];
1135                        pagesContext[i] = pagesContext[i + 1];
1136                    }
1137                    pages[beforePage] = tmpPages;
1138                    pagedim[beforePage] = tmpPagedim;
1139                    pagesContext[beforePage] = tmpPagesContext;
1140                    this.setPage(beforePage);
1141                }
1142                return this;
1143            };
1144
1145            API.deletePage = function () {
1146                _deletePage.apply(this, arguments);
1147                return this;
1148            };
1149            API.setDisplayMode = function (zoom, layout, pmode) {
1150                zoomMode = zoom;
1151                layoutMode = layout;
1152                pageMode = pmode;
1153                return this;
1154            },
1155
1156                /**
1157                 * Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings.
1158                 *
1159                 * @function
1160                 * @param {String|Array}
1160 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.
1161                 * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1162                 * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1163                 * @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.
1164                 * @returns {jsPDF}
1165                 * @methodOf jsPDF#
1166                 * @name text
1167                 */
1168                API.text = function (text, x, y, flags, angle, align) {
1169                    /**
1170                     * Inserts something like this into PDF
1171                     *   BT
1172                     *    /F1 16 Tf  % Font name + size
1173                     *    16 TL % How many units down for next line in multiline text
1174                     *    0 g % color
1175                     *    28.35 813.54 Td % position
1176                     *    (line one) Tj
1177                     *    T* (line two) Tj
1178                     *    T* (line three) Tj
1179                     *   ET
1180                     */
1181                    function ESC(s) {
1182                        s = s.split("\t").join(Array(options.TabLen || 9).join(" "));
1183                        return pdfEscape(s, flags);
1184                    }
1185
1186                    // Pre-August-2012 the order of arguments was function(x, y, text, flags)
1187                    // in effort to make all calls have similar signature like
1188                    //   function(data, coordinates... , miscellaneous)
1189                    // this method had its args flipped.
1190                    // code below allows backward compatibility with old arg order.
1191                    if (typeof text === 'number') {
1192                        tmp = y;
1193                        y = x;
1194                        x = text;
1195                        text = tmp;
1196                    }
1197
1198                    // If there are any newlines in text, we assume
1199                    // the user wanted to print multiple lines, so break the
1200                    // text up into an array.  If the text is already an array,
1201                    // we assume the user knows what they are doing.
1202                    // Convert text into an array anyway to simplify
1203                    // later code.
1204                    if (typeof text === 'string') {
1205                        if (text.match(/[\n\r]/)) {
1206                            text = text.split(/\r\n|\r|\n/g);
1207                        } else {
1208                            text = [text];
1209                        }
1210                    }
1211                    if (typeof angle === 'string') {
1212                        align = angle;
1213                        angle = null;
1214                    }
1215                    if (typeof flags === 'string') {
1216                        align = flags;
1217                        flags = null;
1218                    }
1219                    if (typeof flags === 'number') {
1220                        angle = flags;
1221                        flags = null;
1222                    }
1223                    var xtra = '',
1224                        mode = 'Td',
1225                        todo;
1226                    if (angle) {
1227                        angle *= Math.PI / 180;
1228                        var c = Math.cos(angle),
1229                            s = Math.sin(angle);
1230                        xtra = [f2(c), f2(s), f2(s * -1), f2(c), ''].join(" ");
1231                        mode = 'Tm';
1232                    }
1233                    flags = flags || {};
1234                    if (!('noBOM' in flags)) flags.noBOM = true;
1235                    if (!('autoencode' in flags)) flags.autoencode = true;
1236
1237                    var strokeOption = '';
1238                    var pageContext = this.internal.getCurrentPageInfo().pageContext;
1239                    if (true === flags.stroke) {
1240                        if (pageContext.lastTextWasStroke !== true) {
1241                            strokeOption = '1 Tr\n';
1242                            pageContext.lastTextWasStroke = true;
1243                        }
1244                    } else {
1245                        if (pageContext.lastTextWasStroke) {
1246                            strokeOption = '0 Tr\n';
1247                        }
1248                        pageContext.lastTextWasStroke = false;
1249                    }
1250
1251                    if (typeof this._runningPageHeight === 'undefined') {
1252                        this._runningPageHeight = 0;
1253                    }
1254
1255                    if (typeof text === 'string') {
1256                        text = ESC(text);
1257                    } else if (Object.prototype.toString.call(text) === '[object Array]') {
1258                        // we don't want to destroy  original text array, so cloning it
1259                        var sa = text.concat(),
1260                            da = [],
1261                            len = sa.length;
1262                        // we do array.join('text that must not be PDFescaped")
1263                        // thus, pdfEscape each component separately
1264                        while (len--) {
1265                            da.push(ESC(sa.shift()));
1266                        }
1267                        var linesLeft = Math.ceil((pageHeight - y - this._runningPageHeight) * k / (activeFontSize * lineHeightProportion));
1268                        if (0 <= linesLeft && linesLeft < da.length + 1) {
1269                            //todo = da.splice(linesLeft-1);
1270                        }
1271
1272                        if (align) {
1273                            var left,
1274                                prevX,
1275                                maxLineLength,
1276                                leading = activeFontSize * lineHeightProportion,
1277                                lineWidths = text.map(function (v) {
1278                                    return this.getStringUnitWidth(v) * activeFontSize / k;
1279                                }, this);
1280                            maxLineLength = Math.max.apply(Math, lineWidths);
1281                            // The first line uses the "main" Td setting,
1282                            // and the subsequent lines are offset by the
1283                            // previous line's x coordinate.
1284                            if (align === "center") {
1285                                // The passed in x coordinate defines
1286                                // the center point.
1287                                left = x - maxLineLength / 2;
1288                                x -= lineWidths[0] / 2;
1289                            } else if (align === "right") {
1290                                // The passed in x coordinate defines the
1291                                // rightmost point of the text.
1292                                left = x - maxLineLength;
1293                                x -= lineWidths[0];
1294                            } else {
1295                                throw new Error('Unrecognized alignment option, use "center" or "right".');
1296                            }
1297                            prevX = x;
1298                            text = da[0];
1299                            for (var i = 1, len = da.length; i < len; i++) {
1300                                var delta = maxLineLength - lineWidths[i];
1301                                if (align === "center") delta /= 2;
1302                                // T* = x-offset leading Td ( text )
1303                                text += ") Tj\n" + (left - prevX + delta) + " -" + leading + " Td (" + da[i];
1304                                prevX = left + delta;
1305                            }
1306                        } else {
1307                            text = da.join(") Tj\nT* (");
1308                        }
1309                    } else {
1310                        throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.');
1311                    }
1312                    // Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates
1313
1314                    // BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET
1315                    // if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations)
1316                    // Thus, there is NO useful, *reliable* concept of "default" font for a page.
1317                    // The fact that "default" (reuse font used before) font worked before in basic cases is an accident
1318                    // - readers dealing smartly with brokenness of jsPDF's markup.
1319
1320                    var curY;
1321
1322                    if (todo) {
1323                        //this.addPage();
1324                        //this._runningPageHeight += y -  (activeFontSize * 1.7 / k);
1325                        //curY = f2(pageHeight - activeFontSize * 1.7 /k);
1326                    } else {
1327                        curY = f2((pageHeight - y) * k);
1328                    }
1329                    //curY = f2((pageHeight - (y - this._runningPageHeight)) * k);
1330
1331                    //			if (curY < 0){
1332                    //				console.log('auto page break');
1333                    //				this.addPage();
1334                    //				this._runningPageHeight = y -  (activeFontSize * 1.7 / k);
1335                    //				curY = f2(pageHeight - activeFontSize * 1.7 /k);
1336                    //			}
1337
1338                    out('BT\n/' + activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size
1339                        activeFontSize * lineHeightProportion + ' TL\n' + // line spacing
1340                        strokeOption + // stroke option
1341                        textColor + '\n' + xtra + f2(x * k) + ' ' + curY + ' ' + mode + '\n(' + text 
1341+ ') Tj\nET');
1342
1343                    if (todo) {
1344                        //this.text( todo, x, activeFontSize * 1.7 / k);
1345                        //this.text( todo, x, this._runningPageHeight + (activeFontSize * 1.7 / k));
1346                        this.text(todo, x, y); // + (activeFontSize * 1.7 / k));
1347                    }
1348
1349                    return this;
1350                };
1351
1352            API.lstext = function (text, x, y, spacing) {
1353                for (var i = 0, len = text.length; i < len; i++, x += spacing) {
1354                    this.text(text[i], x, y);
1355                }
1356            };
1357
1358            API.line = function (x1, y1, x2, y2) {
1359                return this.lines([[x2 - x1, y2 - y1]], x1, y1);
1360            };
1361
1362            API.clip = function () {
1363                // By patrick-roberts, github.com/MrRio/jsPDF/issues/328
1364                // Call .clip() after calling .rect() with a style argument of null
1365                out('W'); // clip
1366                out('S'); // stroke path; necessary for clip to work
1367            };
1368
1369            /**
1370             * This fixes the previous function clip(). Perhaps the 'stroke path' hack was due to the missing 'n' instruction?
1371             * We introduce the fixed version so as to not break API.
1372             * @param fillRule
1373             */
1374            API.clip_fixed = function (fillRule) {
1375                // Call .clip() after calling drawing ops with a style argument of null
1376                // W is the PDF clipping op
1377                if ('evenodd' === fillRule) {
1378                    out('W*');
1379                } else {
1380                    out('W');
1381                }
1382                // End the path object without filling or stroking it.
1383                // This operator is a path-painting no-op, used primarily for the side effect of changing the current clipping path
1384                // (see Section 4.4.3, “Clipping Path Operators”)
1385                out('n');
1386            };
1387
1388            /**
1389             * Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates.
1390             * All data points in `lines` are relative to last line origin.
1391             * `x`, `y` become x1,y1 for first line / curve in the set.
1392             * For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point.
1393             * 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.
1394             *
1395             * @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line
1396             * @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves).
1397             * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1398             * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1399             * @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.
1400             * @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.
1401             * @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point.
1402             * @function
1403             * @returns {jsPDF}
1404             * @methodOf jsPDF#
1405             * @name lines
1406             */
1407            API.lines = function (lines, x, y, scale, style, closed) {
1408                var scalex, scaley, i, l, leg, x2, y2, x3, y3, x4, y4;
1409
1410                // Pre-August-2012 the order of arguments was function(x, y, lines, scale, style)
1411                // in effort to make all calls have similar signature like
1412                //   function(content, coordinateX, coordinateY , miscellaneous)
1413                // this method had its args flipped.
1414                // code below allows backward compatibility with old arg order.
1415                if (typeof lines === 'number') {
1416                    tmp = y;
1417                    y = x;
1418                    x = lines;
1419                    lines = tmp;
1420                }
1421
1422                scale = scale || [1, 1];
1423
1424                // starting point
1425                out(f3(x * k) + ' ' + f3((pageHeight - y) * k) + ' m ');
1426
1427                scalex = scale[0];
1428                scaley = scale[1];
1429                l = lines.length;
1430                //, x2, y2 // bezier only. In page default measurement "units", *after* scaling
1431                //, x3, y3 // bezier only. In page default measurement "units", *after* scaling
1432                // ending point for all, lines and bezier. . In page default measurement "units", *after* scaling
1433                x4 = x; // last / ending point = starting point for first item.
1434                y4 = y; // last / ending point = starting point for first item.
1435
1436                for (i = 0; i < l; i++) {
1437                    leg = lines[i];
1438                    if (leg.length === 2) {
1439                        // simple line
1440                        x4 = leg[0] * scalex + x4; // here last x4 was prior ending point
1441                        y4 = leg[1] * scaley + y4; // here last y4 was prior ending point
1442                        out(f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' l');
1443                    } else {
1444                        // bezier curve
1445                        x2 = leg[0] * scalex + x4; // here last x4 is prior ending point
1446                        y2 = leg[1] * scaley + y4; // here last y4 is prior ending point
1447                        x3 = leg[2] * scalex + x4; // here last x4 is prior ending point
1448                        y3 = leg[3] * scaley + y4; // here last y4 is prior ending point
1449                        x4 = leg[4] * scalex + x4; // here last x4 was prior ending point
1450                        y4 = leg[5] * scaley + y4; // here last y4 was prior ending point
1451                        out(f3(x2 * k) + ' ' + f3((pageHeight - y2) * k) + ' ' + f3(x3 * k) + ' ' + f3((pageHeight - y3) * k) + ' ' + f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' c');
1452                    }
1453                }
1454
1455                if (closed) {
1456                    out(' h');
1457                }
1458
1459                // stroking / filling / both the path
1460                if (style !== null) {
1461                    out(getStyle(style));
1462                }
1463                return this;
1464            };
1465
1466            /**
1467             * Adds a rectangle to PDF
1468             *
1469             * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1470             * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1471             * @param {Number} w Width (in units declared at inception of PDF document)
1472             * @param {Number} h Height (in units declared at inception of PDF document)
1473             * @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.
1474             * @function
1475             * @returns {jsPDF}
1476             * @methodOf jsPDF#
1477             * @name rect
1478             */
1479            API.rect = function (x, y, w, h, style) {
1480                var op = getStyle(style);
1481                out([f2(x * k), f2((pageHeight - y) * k), f2(w * k), f2(-h * k), 're'].join(' '));
1482
1483                if (style !== null) {
1484                    out(getStyle(style));
1485                }
1486
1487                return this;
1488            };
1489
1490            /**
1491             * Adds a triangle to PDF
1492             *
1493             * @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page
1494             * @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1495             * @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page
1496             * @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1497             * @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page
1498             * @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1499             * @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.
1500             * @function
1501             * @returns {jsPDF}
1502             * @methodOf jsPDF#
1503             * @name triangle
1504             */
1505            API.triangle = function (x1, y1, x2, y2, x3, y3, style) {
1506                this.lines([[x2 - x1, y2 - y1], // vector to point 2
1507                        [x3 - x2, y3 - y2], // vector to point 3
1508                        [x1 - x3, y1 - y3] // closing vector back to point 1
1509                    ], x1, y1, // start of path
1510                    [1, 1], style, true);
1511                return this;
1512            };
1513
1514            /**
1515             * Adds a rectangle with rounded corners to PDF
1516             *
1517             * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1518             * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1519             * @param {Number} w Width (in units declared at inception of PDF document)
1520             * @param {Number} h Height (in units declared at inception of PDF document)
1521             * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
1522             * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
1523             * @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.
1524             * @function
1525             * @returns {jsPDF}
1526             * @methodOf jsPDF#
1527             * @name roundedRect
1528             */
1529            API.roundedRect = function (x, y, w, h, rx, ry, style) {
1530                var MyArc = 4 / 3 * (Math.SQRT2 - 1);
1531                this.lines([[w - 2 * rx, 0], [rx * MyArc, 0, rx, ry - ry * MyArc, rx, ry], [0, h - 2 * ry], [0, ry * MyArc, -(rx * MyArc), ry, -rx, ry], [-w + 2 * rx, 0], [-(rx * MyArc), 0, -rx, -(ry * MyArc), -rx, -ry], [0, -h + 2 * ry], [0, -(ry * MyArc), rx * MyArc, -ry, rx, -ry]], x + rx, y, // start of path
1532                    [1, 1], style);
1533                return this;
1534            };
1535
1536            /**
1537             * Adds an ellipse to PDF
1538             *
1539             * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1540             * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1541             * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
1542             * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
1543             * @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.
1544             * @function
1545             * @returns {jsPDF}
1546             * @methodOf jsPDF#
1547             * @name ellipse
1548             */
1549            API.ellipse = function (x, y, rx, ry, style) {
1550                var lx = 4 / 3 * (Math.SQRT2 - 1) * rx,
1551                    ly = 4 / 3 * (Math.SQRT2 - 1) * ry;
1552
1553                out([f2((x + rx) * k), f2((pageHeight - y) * k), 'm', f2((x + rx) * k), f2((pageHeight - (y - ly)) * k), f2((x + lx) * k), f2((pageHeight - (y - ry)) * k), f2(x * k), f2((pageHeight - (y - ry)) * k), 'c'].join(' '));
1554                out([f2((x - lx) * k), f2((pageHeight - (y - ry)) * k), f2((x - rx) * k), f2((pageHeight - (y - ly)) * k), f2((x - rx) * k), f2((pageHeight - y) * k), 'c'].join(' '));
1555                out([f2((x - rx) * k), f2((pageHeight - (y + ly)) * k), f2((x - lx) * k), f2((pageHeight - (y + ry)) * k), f2(x * k), f2((pageHeight - (y + ry)) * k), 'c'].join(' '));
1556                out([f2((x + lx) * k), f2((pageHeight - (y + ry)) * k), f2((x + rx) * k), f2((pageHeight - (y + ly)) * k), f2((x + rx) * k), f2((pageHeight - y) * k), 'c'].join(' '));
1557
1558                if (style !== null) {
1559                    out(getStyle(style));
1560                }
1561
1562                return this;
1563            };
1564
1565            /**
1566             * Adds an circle to PDF
1567             *
1568             * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1569             * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1570             * @param {Number} r Radius (in units declared at inception of PDF document)
1571             * @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.
1572             * @function
1573             * @returns {jsPDF}
1574             * @methodOf jsPDF#
1575             * @name circle
1576             */
1577            API.circle = function (x, y, r, style) {
1578                return this.ellipse(x, y, r, r, style);
1579            };
1580
1581            /**
1582             * Adds a properties to the PDF document
1583             *
1584             * @param {Object} A property_name-to-property_value object structure.
1585             * @function
1586             * @returns {jsPDF}
1587             * @methodOf jsPDF#
1588             * @name setProperties
1589             */
1590            API.setProperties = function (properties) {
1591                // copying only those properties we can render.
1592                for (var property in documentProperties) {
1593                    if (documentProperties.hasOwnProperty(property) && properties[property]) {
1594                        documentProperties[property] = properties[property];
1595                    }
1596                }
1597                return this;
1598            };
1599
1600            /**
1601             * Sets font size for upcoming text elements.
1602             *
1603             * @param {Number} size Font size in points.
1604             * @function
1605             * @returns {jsPDF}
1606             * @methodOf jsPDF#
1607             * @name setFontSize
1608             */
1609            API.setFontSize = function (size) {
1610                activeFontSize = size;
1611                return this;
1612            };
1613
1614            /**
1615             * Sets text font face, variant for upcoming text elements.
1616             * See output of jsPDF.getFontList() for possible font names, styles.
1617             *
1618             * @param {String} fontName Font name or family. Example: "times"
1619             * @param {String} fontStyle Font style or variant. Example: "italic"
1620             * @function
1621             * @returns {jsPDF}
1622             * @methodOf jsPDF#
1623             * @name setFont
1624             */
1625            API.setFont = function (fontName, fontStyle) {
1626                activeFontKey = _getFont(fontName, fontStyle);
1627                // if font is not found, the above line blows up and we never go further
1628                return this;
1629            };
1630
1631            /**
1632             * Switches font style or variant for upcoming text elements,
1633             * while keeping the font face or family same.
1634             * See output of jsPDF.getFontList() for possible font names, styles.
1635             *
1636             * @param {String} style Font style or variant. Example: "italic"
1637             * @function
1638             * @returns {jsPDF}
1639             * @methodOf jsPDF#
1640             * @name setFontStyle
1641             */
1642            API.setFontStyle = API.setFontType = function (style) {
1643                activeFontKey = _getFont(undefined, style);
1644                // if font is not found, the above line blows up and we never go further
1645                return this;
1646            };
1647
1648            /**
1649             * Returns an object - a tree of fontName to fontStyle relationships available to
1650             * active PDF document.
1651             *
1652             * @public
1653             * @function
1654             * @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... }
1655             * @methodOf jsPDF#
1656             * @name getFontList
1657             */
1658            API.getFontList = function () {
1659                // TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added.
1660                var list = {},
1661                    fontName,
1662                    fontStyle,
1663                    tmp;
1664
1665                for (fontName in fontmap) {
1666                    if (fontmap.hasOwnProperty(fontName)) {
1667                        list[fontName] = tmp = [];
1668                        for (fontStyle in fontmap[fontName]) {
1669                            if (fontmap[fontName].hasOwnProperty(fontStyle)) {
1670                                tmp.push(fontStyle);
1671                            }
1672                        }
1673                    }
1674                }
1675
1676                return list;
1677            };
1678
1679            /**
1680             * Add a custom font.
1681             *
1682             * @param {String} Postscript name of the Font.  Example: "Menlo-Regular"
1683             * @param {String} Name of font-family from @font-face definition.  Example: "Menlo Regular"
1684             * @param {String} Font style.  Example: "normal"
1685             * @function
1686             * @returns the {fontKey} (same as the internal method)
1687             * @methodOf jsPDF#
1688             * @name addFont
1689             */
1690            API.addFont = function (postScriptName, fontName, fontStyle) {
1691                addFont(postScriptName, fontName, fontStyle, 'StandardEncoding');
1692            };
1693
1694            /**
1695             * Sets line width for upcoming lines.
1696             *
1697             * @param {Number} width Line width (in units declared at inception of PDF document)
1698             * @function
1699             * @returns {jsPDF}
1700             * @methodOf jsPDF#
1701             * @name setLineWidth
1702             */
1703            API.setLineWidth = function (width) {
1704                out((width * k).toFixed(2) + ' w');
1705                return this;
1706            };
1707
1708            /**
1709             * Sets the stroke color for upcoming elements.
1710             *
1711             * Depending on the number of arguments given, Gray, RGB, or CMYK
1712             * color space is implied.
1713             *
1714             * When only ch1 is given, "Gray" color space is implied and it
1715             * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
1716             * if values are communicated as String types, or in range from 0 (black)
1717             * to 255 (white) if communicated as Number type.
1718             * The RGB-like 0-255 range is provided for backward compatibility.
1719             *
1720             * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
1721             * value must be in the range from 0.00 (minimum intensity) to to 1.00
1722             * (max intensity) if values are communicated as String types, or
1723             * from 0 (min intensity) to to 255 (max intensity) if values are communicated
1724             * as Number types.
1725             * The RGB-like 0-255 range is provided for backward compatibility.
1726             *
1727             * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
1728             * value must be a in the range from 0.00 (0% concentration) to to
1729             * 1.00 (100% concentration)
1730             *
1731             * Because JavaScript treats fixed point numbers badly (rounds to
1732             * floating point nearest to binary representation) it is highly advised to
1733             * communicate the fractional numbers as String types, not JavaScript Number type.
1734             *
1735             * @param {Number|String} ch1 Color channel value
1736             * @param {Number|String} ch2 Color channel value
1737             * @param {Number|String} ch3 Color channel value
1738             * @param {Number|String} ch4 Color channel value
1739             *
1740             * @function
1741             * @returns {jsPDF}
1742             * @methodOf jsPDF#
1743             * @name setDrawColor
1744             */
1745            API.setDrawColor = function (ch1, ch2, ch3, ch4) {
1746                var color;
1747                if (ch2 === undefined || ch4 === undefined && ch1 === ch2 === ch3) {
1748                    // Gray color space.
1749                    if (typeof ch1 === 'string') {
1750                        color = ch1 + ' G';
1751                    } else {
1752                        color = f2(ch1 / 255) + ' G';
1753                    }
1754                } else if (ch4 === undefined) {
1755                    // RGB
1756                    if (typeof ch1 === 'string') {
1757                        color = [ch1, ch2, ch3, 'RG'].join(' ');
1758                    } else {
1759                        color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' ');
1760                    }
1761                } else {
1762                    // CMYK
1763                    if (typeof ch1 === 'string') {
1764                        color = [ch1, ch2, ch3, ch4, 'K'].join(' ');
1765                    } else {
1766                        color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' ');
1767                    }
1768                }
1769
1770                out(color);
1771                return this;
1772            };
1773
1774            /**
1775             * Sets the fill color for upcoming elements.
1776             *
1777             * Depending on the number of arguments given, Gray, RGB, or CMYK
1778             * color space is implied.
1779             *
1780             * When only ch1 is given, "Gray" color space is implied and it
1781             * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
1782             * if values are communicated as String types, or in range from 0 (black)
1783             * to 255 (white) if communicated as Number type.
1784             * The RGB-like 0-255 range is provided for backward compatibility.
1785             *
1786             * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
1787             * value must be in the range from 0.00 (minimum intensity) to to 1.00
1788             * (max intensity) if values are communicated as String types, or
1789             * from 0 (min intensity) to to 255 (max intensity) if values are communicated
1790             * as Number types.
1791             * The RGB-like 0-255 range is provided for backward compatibility.
1792             *
1793             * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
1794             * value must be a in the range from 0.00 (0% concentration) to to
1795             * 1.00 (100% concentration)
1796             *
1797             * Because JavaScript treats fixed point numbers badly (rounds to
1798             * floating point nearest to binary representation) it is highly advised to
1799             * communicate the fractional numbers as String types, not JavaScript Number type.
1800             *
1801             * @param {Number|String} ch1 Color channel value
1802             * @param {Number|String} ch2 Color channel value
1803             * @param {Number|String} ch3 Color channel value
1804             * @param {Number|String} ch4 Color channel value
1805             *
1806             * @function
1807             * @returns {jsPDF}
1808             * @methodOf jsPDF#
1809             * @name setFillColor
1810             */
1811            API.setFillColor = function (ch1, ch2, ch3, ch4) {
1812                var color;
1813
1814                if (ch2 === undefined || ch4 === undefined && ch1 === ch2 === ch3) {
1815                    // Gray color space.
1816                    if (typeof ch1 === 'string') {
1817                        color = ch1 + ' g';
1818                    } else {
1819                        color = f2(ch1 / 255) + ' g';
1820                    }
1821                } else if (ch4 === undefined || (typeof ch4 === 'undefined' ? 'undefined' : _typeof(ch4)) === 'object') {
1822                    // RGB
1823                    if (typeof ch1 === 'string') {
1824                        color = [ch1, ch2, ch3, 'rg'].join(' ');
1825                    } else {
1826                        color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' ');
1827                    }
1828                    if (ch4 && ch4.a === 0) {
1829                        //TODO Implement transparency.
1830                        //WORKAROUND use white for now
1831                        color = ['255', '255', '255', 'rg'].join(' ');
1832                    }
1833                } else {
1834                    // CMYK
1835                    if (typeof ch1 === 'string') {
1836                        color = [ch1, ch2, ch3, ch4, 'k'].join(' ');
1837                    } else {
1838                        color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' ');
1839                    }
1840                }
1841
1842                out(color);
1843                return this;
1844            };
1845
1846            /**
1847             * Sets the text color for upcoming elements.
1848             * If only one, first argument is given,
1849             * treats the value as gray-scale color value.
1850             *
1851             * @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF'
1852             * @param {Number} g Green channel color value in range 0-255
1853             * @param {Number} b Blue channel color value in range 0-255
1854             * @function
1855             * @returns {jsPDF}
1856             * @methodOf jsPDF#
1857             * @name setTextColor
1858             */
1859            API.setTextColor = function (r, g, b) {
1860                if (typeof r === 'string' && /^#[0-9A-Fa-f]{6}$/.test(r)) {
1861                    var hex = parseInt(r.substr(1), 16);
1862                    r = hex >> 16 & 255;
1863                    g = hex >> 8 & 255;
1864                    b = hex & 255;
1865                }
1866
1867                if (r === 0 && g === 0 && b === 0 || typeof g === 'undefined') {
1868                    textColor = f3(r / 255) + ' g';
1869                } else {
1870                    textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' ');
1871                }
1872                return this;
1873            };
1874
1875            /**
1876             * Is an Object providing a mapping from human-readable to
1877             * integer flag values designating the varieties of line cap
1878             * and join styles.
1879             *
1880             * @returns {Object}
1881             * @fieldOf jsPDF#
1882             * @name CapJoinStyles
1883             */
1884            API.CapJoinStyles = {
1885                0: 0,
1886                'butt': 0,
1887                'but': 0,
1888                'miter': 0,
1889                1: 1,
1890                'round': 1,
1891                'rounded': 1,
1892                'circle': 1,
1893                2: 2,
1894                'projecting': 2,
1895                'project': 2,
1896                'square': 2,
1897                'bevel': 2
1898            };
1899
1900            /**
1901             * Sets the line cap styles
1902             * See {jsPDF.CapJoinStyles} for variants
1903             *
1904             * @param {String|Number} style A string or number identifying the type of line cap
1905             * @function
1906             * @returns {jsPDF}
1907             * @methodOf jsPDF#
1908             * @name setLineCap
1909             */
1910            API.setLineCap = function (style) {
1911                var id = this.CapJoinStyles[style];
1912                if (id === undefined) {
1913                    throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
1914                }
1915                lineCapID = id;
1916                out(id + ' J');
1917
1918                return this;
1919            };
1920
1921            /**
1922             * Sets the line join styles
1923             * See {jsPDF.CapJoinStyles} for variants
1924             *
1925             * @param {String|Number} style A string or number identifying the type of line join
1926             * @function
1927             * @returns {jsPDF}
1928             * @methodOf jsPDF#
1929             * @name setLineJoin
1930             */
1931            API.setLineJoin = function (style) {
1932                var id = this.CapJoinStyles[style];
1933                if (id === undefined) {
1934                    throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
1935                }
1936                lineJoinID = id;
1937                out(id + ' j');
1938
1939                return this;
1940            };
1941
1942            // Output is both an internal (for plugins) and external function
1943            API.output = _output;
1944
1945            /**
1946             * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf')
1947             * @param  {String} filename The filename including extension.
1948             *
1949             * @function
1950             * @returns {jsPDF}
1951             * @methodOf jsPDF#
1952             * @name save
1953             */
1954            API.save = function (filename) {
1955                API.output('save', filename);
1956            };
1957
1958            // applying plugins (more methods) ON TOP of built-in API.
1959            // this is intentional as we allow plugins to override
1960            // built-ins
1961            for (var plugin in jsPDF.API) {
1962                if (jsPDF.API.hasOwnProperty(plugin)) {
1963                    if (plugin === 'events' && jsPDF.API.events.length) {
1964                        (function (events, newEvents) {
1965
1966                            // jsPDF.API.events is a JS Array of Arrays
1967                            // where each Array is a pair of event name, handler
1968                            // Events were added by plugins to the jsPDF instantiator.
1969                            // These are always added to the new instance and some ran
1970                            // during instantiation.
1971                            var eventname, handler_and_args, i;
1972
1973                            for (i = newEvents.length - 1; i !== -1; i--) {
1974                                // subscribe takes 3 args: 'topic', function, runonce_flag
1975                                // if undefined, runonce is false.
1976                                // users can attach callback directly,
1977                                // or they can attach an array with [callback, runonce_flag]
1978                                // that's what the "apply" magic is for below.
1979                                eventname = newEvents[i][0];
1980                                handler_and_args = newEvents[i][1];
1981                                events.subscribe.apply(events, [eventname].concat(typeof handler_and_args === 'function' ? [handler_and_args] : handler_and_args));
1982                            }
1983                        })(events, jsPDF.API.events);
1984                    } else {
1985                        API[plugin] = jsPDF.API[plugin];
1986                    }
1987                }
1988            }
1989
1990            //////////////////////////////////////////////////////
1991            // continuing initialization of jsPDF Document object
1992            //////////////////////////////////////////////////////
1993            // Add the first page automatically
1994            addFonts();
1995            activeFontKey = 'F1';
1996            _addPage(format, orientation);
1997
1998            events.publish('initialized');
1999            return API;
2000        }
2001
2002        /**
2003         * jsPDF.API is a STATIC property of jsPDF class.
2004         * jsPDF.API is an object you can add methods and properties to.
2005         * The methods / properties you add will show up in new jsPDF objects.
2006         *
2007         * One property is prepopulated. It is the 'events' Object. Plugin authors can add topics,
2008         * callbacks to this object. These will be reassigned to all new instances of jsPDF.
2009         * Examples:
2010         * jsPDF.API.events['initialized'] = function(){ 'this' is API object }
2011         * jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object }
2012         *
2013         * @static
2014         * @public
2015         * @memberOf jsPDF
2016         * @name API
2017         *
2018         * @example
2019         * jsPDF.API.mymethod = function(){
2020         *   // 'this' will be ref to internal API object. see jsPDF source
2021         *   // , so you can refer to built-in methods like so:
2022         *   //     this.line(....)
2023         *   //     this.text(....)
2024         * }
2025         * var pdfdoc = new jsPDF()
2026         * pdfdoc.mymethod() // <- !!!!!!
2027         */
2028        jsPDF.API = { events: [] };
2029        jsPDF.version = "1.3.2 2016-09-30T20:33:17.116Z:jameshall";
2030
2031        if (typeof define === 'function' && define.amd) {
2032            define('jsPDF', function () {
2033                return jsPDF;
2034            });
2035        } else if (typeof module !== 'undefined' && module.exports) {
2036            module.exports = jsPDF;
2037        } else {
2038            global.jsPDF = jsPDF;
2039        }
2040        return jsPDF;
2041    }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined);
2042    /*rollup-keeper-start*/window.tmp = jsPDF;
2043
2044    /**
2045     * jsPDF AcroForm Plugin
2046     * Copyright (c) 2016 Alexander Weidt, https://github.com/BiggA94
2047     *
2048     * Licensed under the MIT License.
2049     * http://opensource.org/licenses/mit-license
2050     */
2051
2052    (window.AcroForm = function (jsPDFAPI) {
2053        'use strict';
2054
2055        var AcroForm = window.AcroForm;
2056
2057        AcroForm.scale = function (x) {
2058            return x * (acroformPlugin.internal.scaleFactor / 1); // 1 = (96 / 72)
2059        };
2060        AcroForm.antiScale = function (x) {
2061            return 1 / acroformPlugin.internal.scaleFactor * x;
2062        };
2063
2064        var acroformPlugin = {
2065            fields: [],
2066            xForms: [],
2067            /**
2068             * acroFormDictionaryRoot contains information about the AcroForm Dictionary
2069             * 0: The Event-Token, the AcroFormDictionaryCallback has
2070             * 1: The Object ID of the Root
2071             */
2072            acroFormDictionaryRoot: null,
2073            /**
2074             * After the PDF gets evaluated, the reference to the root has to be reset,
2075             * this indicates, whether the root has already been printed out
2076             */
2077            printedOut: false,
2078            internal: null
2079        };
2080
2081        jsPDF.API.acroformPlugin = acroformPlugin;
2082
2083        var annotReferenceCallback = function annotReferenceCallback() {
2084            for (var i in this.acroformPlugin.acroFormDictionaryRoot.Fields) {
2085                var formObject = this.acroformPlugin.acroFormDictionaryRoot.Fields[i];
2086                // add Annot Reference!
2087                if (formObject.hasAnnotation) {
2088                    // If theres an Annotation Widget in the Form Object, put the Reference in the /Annot array
2089                    createAnnotationReference.call(this, formObject);
2090                }
2091            }
2092        };
2093
2094        var createAcroForm = function createAcroForm() {
2095            if (this.acroformPlugin.acroFormDictionaryRoot) {
2096                //return;
2097                throw new Error("Exception while creating AcroformDictionary");
2098            }
2099
2100            // The Object Number of the AcroForm Dictionary
2101            this.acroformPlugin.acroFormDictionaryRoot = new AcroForm.AcroFormDictionary();
2102
2103            this.acroformPlugin.internal = this.internal;
2104
2105            // add Callback for creating the AcroForm Dictionary
2106            this.acroformPlugin.acroFormDictionaryRoot._eventID = this.internal.events.subscribe('postPutResources', AcroFormDictionaryCallback);
2107
2108            this.internal.events.subscribe('buildDocument', annotReferenceCallback); //buildDocument
2109
2110            // Register event, that is triggered when the DocumentCatalog is written, in order to add /AcroForm
2111            this.internal.events.subscribe('putCatalog', putCatalogCallback);
2112
2113            // Register event, that creates all Fields
2114            this.internal.events.subscribe('postPutPages', createFieldCallback);
2115        };
2116
2117        /**
2118         * Create the Reference to the widgetAnnotation, so that it gets referenced in the Annot[] int the+
2119         * (Requires the Annotation Plugin)
2120         */
2121        var createAnnotationReference = function createAnnotationReference(object) {
2122            var options = {
2123                type: 'reference',
2124                object: object
2125            };
2126            jsPDF.API.annotationPlugin.annotations[this.internal.getPageInfo(object.page).pageNumber].push(options);
2127        };
2128
2129        var putForm = function putForm(formObject) {
2130            if (this.acroformPlugin.printedOut) {
2131                this.acroformPlugin.printedOut = false;
2132                this.acroformPlugin.acroFormDictionaryRoot = null;
2133            }
2134            if (!this.acroformPlugin.acroFormDictionaryRoot) {
2135                createAcroForm.call(this);
2136            }
2137            this.acroformPlugin.acroFormDictionaryRoot.Fields.push(formObject);
2138        };
2139
2140        // Callbacks
2141
2142        var putCatalogCallback = function putCatalogCallback() {
2143            //Put reference to AcroForm to DocumentCatalog
2144            if (typeof this.acroformPlugin.acroFormDictionaryRoot != 'undefined') {
2145                // for safety, shouldn't normally be the case
2146                this.internal.write('/AcroForm ' + this.acroformPlugin.acroFormDictionaryRoot.objId + ' ' + 0 + ' R');
2147            } else {
2148                console.log('Root missing...');
2149            }
2150        };
2151
2152        /**
2153         * Adds /Acroform X 0 R to Document Catalog,
2154         * and creates the AcroForm Dictionary
2155         */
2156        var AcroFormDictionaryCallback = function AcroFormDictionaryCallback() {
2157            // Remove event
2158            this.internal.events.unsubscribe(this.acroformPlugin.acroFormDictionaryRoot._eventID);
2159
2160            delete this.acroformPlugin.acroFormDictionaryRoot._eventID;
2161
2162            this.acroformPlugin.printedOut = true;
2163        };
2164
2165        /**
2166         * Creates the single Fields and writes them into the Document
2167         *
2168         * If fieldArray is set, use the fields that are inside it instead of the fields from the AcroRoot
2169         * (for the FormXObjects...)
2170         */
2171        var createFieldCallback = function createFieldCallback(fieldArray) {
2172            var standardFields = !fieldArray;
2173
2174            if (!fieldArray) {
2175                // in case there is no fieldArray specified, we want to print out the Fields of the AcroForm
2176                // Print out Root
2177                this.internal.newObjectDeferredBegin(this.acroformPlugin.acroFormDictionaryRoot.objId);
2178                this.internal.out(this.acroformPlugin.acroFormDictionaryRoot.getString());
2179            }
2180
2181            var fieldArray = fieldArray || this.acroformPlugin.acroFormDictionaryRoot.Kids;
2182
2183            for (var i in fieldArray) {
2184                var key = i;
2185                var form = fieldArray[i];
2186
2187                var oldRect = form.Rect;
2188
2189                if (form.Rect) {
2190                    form.Rect = AcroForm.internal.calculateCoordinates.call(this, form.Rect);
2191                }
2192
2193                // Start Writing the Object
2194                this.internal.newObjectDeferredBegin(form.objId);
2195
2196                var content = "";
2197                content += form.objId + " 0 obj\n";
2198
2199                content += "<<\n" + form.getContent();
2200
2201                form.Rect = oldRect;
2202
2203                if (form.hasAppearanceStream && !form.appearanceStreamContent) {
2204                    // Calculate Appearance
2205                    var appearance = AcroForm.internal.calculateAppearanceStream.call(this, form);
2206                    content += "/AP << /N " + appearance + " >>\n";
2207
2208                    this.acroformPlugin.xForms.push(appearance);
2209                }
2210
2211                // Assume AppearanceStreamContent is a Array with N,R,D (at least one of them!)
2212                if (form.appearanceStreamContent) {
2213                    content += "/AP << ";
2214                    // Iterate over N,R and D
2215                    for (var k in form.appearanceStreamContent) {
2216                        var value = form.appearanceStreamContent[k];
2217                        content += "/" + k + " ";
2218                        content += "<< ";
2219                        if (Object.keys(value).length >= 1 || Array.isArray(value)) {
2220                            // appearanceStream is an Array or Object!
2221                            for (var i in value) {
2222                                var obj = value[i];
2223                                if (typeof obj === 'function') {
2224                                    // if Function is referenced, call it in order to get the FormXObject
2225                                    obj = obj.call(this, form);
2226                                }
2227                                content += "/" + i + " " + obj + " ";
2228
2229                                // In case the XForm is already used, e.g. OffState of CheckBoxes, don't add it
2230                                if (!(this.acroformPlugin.xForms.indexOf(obj) >= 0)) this.acroformPlugin.xForms.push(obj);
2231                            }
2232                        } else {
2233                            var obj = value;
2234                            if (typeof obj === 'function') {
2235                                // if Function is referenced, call it in order to get the FormXObject
2236                                obj = obj.call(this, form);
2237                            }
2238                            content += "/" + i + " " + obj + " \n";
2239                            if (!(this.acroformPlugin.xForms.indexOf(obj) >= 0)) this.acroformPlugin.xForms.push(obj);
2240                        }
2241                        content += " >>\n";
2242                    }
2243
2244                    // appearance stream is a normal Object..
2245                    content += ">>\n";
2246                }
2247
2248                content += ">>\nendobj\n";
2249
2250                this.internal.out(content);
2251            }
2252            if (standardFields) {
2253                createXFormObjectCallback.call(this, this.acroformPlugin.xForms);
2254            }
2255        };
2256
2257        var createXFormObjectCallback = function createXFormObjectCallback(fieldArray) {
2258            for (var i in fieldArray) {
2259                var key = i;
2260                var form = fieldArray[i];
2261                // Start Writing the Object
2262                this.internal.newObjectDeferredBegin(form && form.objId);
2263
2264                var content = "";
2265                content += form ? form.getString() : '';
2266                this.internal.out(content);
2267
2268                delete fieldArray[key];
2269            }
2270        };
2271
2272        // Public:
2273
2274        jsPDFAPI.addField = function (fieldObject) {
2275            //var opt = parseOptions(fieldObject);
2276            if (fieldObject instanceof AcroForm.TextField) {
2277                addTextField.call(this, fieldObject);
2278            } else if (fieldObject instanceof AcroForm.ChoiceField) {
2279                addChoiceField.call(this, fieldObject);
2280            } else if (fieldObject instanceof AcroForm.Button) {
2281                addButton.call(this, fieldObject);
2282            } else if (fieldObject instanceof AcroForm.ChildClass) {
2283                putForm.call(this, fieldObject);
2284            } else if (fieldObject) {
2285                // try to put..
2286                putForm.call(this, fieldObject);
2287            }
2288            fieldObject.page = this.acroformPlugin.internal.getCurrentPageInfo().pageNumber;
2289            return this;
2290        };
2291
2292        // ############### sort in:
2293
2294        /**
2295         * Button
2296         * FT = Btn
2297         */
2298        var addButton = function addButton(options) {
2299            var options = options || new AcroForm.Field();
2300
2301            options.FT = '/Btn';
2302
2303            /**
2304             * Calculating the Ff entry:
2305             *
2306             * The Ff entry contains flags, that have to be set bitwise
2307             * In the Following the number in the Comment is the BitPosition
2308             */
2309            var flags = options.Ff || 0;
2310
2311            // 17, Pushbutton
2312            if (options.pushbutton) {
2313                // Options.pushbutton should be 1 or 0
2314                flags = AcroForm.internal.setBitPosition(flags, 17);
2315                delete options.pushbutton;
2316            }
2317
2318            //16, Radio
2319            if (options.radio) {
2320                //flags = options.Ff | options.radio << 15;
2321                flags = AcroForm.internal.setBitPosition(flags, 16);
2322                delete options.radio;
2323            }
2324
2325            // 15, NoToggleToOff (Radio buttons only
2326            if (options.noToggleToOff) {
2327                //flags = options.Ff | options.noToggleToOff << 14;
2328                flags = AcroForm.internal.setBitPosition(flags, 15);
2329                //delete options.noToggleToOff;
2330            }
2331
2332            // In case, there is no Flag set, it is a check-box
2333            options.Ff = flags;
2334
2335            putForm.call(this, options);
2336        };
2337
2338        var addTextField = function addTextField(options) {
2339            var options = options || new AcroForm.Field();
2340
2341            options.FT = '/Tx';
2342
2343            /**
2344             * Calculating the Ff entry:
2345             *
2346             * The Ff entry contains flags, that have to be set bitwise
2347             * In the Following the number in the Comment is the BitPosition
2348             */
2349
2350            var flags = options.Ff || 0;
2351
2352            // 13, multiline
2353            if (options.multiline) {
2354                // Set Flag
2355                flags = flags | 1 << 12;
2356                // Remove multiline from FieldObject
2357                //delete options.multiline;
2358            }
2359
2360            // 14, Password
2361            if (options.password) {
2362                flags = flags | 1 << 13;
2363                //delete options.password;
2364            }
2365
2366            // 21, FileSelect, PDF 1.4...
2367            if (options.fileSelect) {
2368                flags = flags | 1 << 20;
2369                //delete options.fileSelect;
2370            }
2371
2372            // 23, DoNotSpellCheck, PDF 1.4...
2373            if (options.doNotSpellCheck) {
2374                flags = flags | 1 << 22;
2375                //delete options.doNotSpellCheck;
2376            }
2377
2378            // 24, DoNotScroll, PDF 1.4...
2379            if (options.doNotScroll) {
2380                flags = flags | 1 << 23;
2381                //delete options.doNotScroll;
2382            }
2383
2384            options.Ff = options.Ff || flags;
2385
2386            // Add field
2387            putForm.call(this, options);
2388        };
2389
2390        var addChoiceField = function addChoiceField(opt) {
2391            var options = opt || new AcroForm.Field();
2392
2393            options.FT = '/Ch';
2394
2395            /**
2396             * Calculating the Ff entry:
2397             *
2398             * The Ff entry contains flags, that have to be set bitwise
2399             * In the Following the number in the Comment is the BitPosition
2400             */
2401
2402            var flags = options.Ff || 0;
2403
2404            // 18, Combo (If not set, the choiceField is a listBox!!)
2405            if (options.combo) {
2406                // Set Flag
2407                flags = AcroForm.internal.setBitPosition(flags, 18);
2408                // Remove combo from FieldObject
2409                delete options.combo;
2410            }
2411
2412            // 19, Edit
2413            if (options.edit) {
2414                flags = AcroForm.internal.setBitPosition(flags, 19);
2415                delete options.edit;
2416            }
2417
2418            // 20, Sort
2419            if (options.sort) {
2420                flags = AcroForm.internal.setBitPosition(flags, 20);
2421                delete options.sort;
2422            }
2423
2424            // 22, MultiSelect (PDF 1.4)
2425            if (options.multiSelect && this.internal.getPDFVersion() >= 1.4) {
2426                flags = AcroForm.internal.setBitPosition(flags, 22);
2427                delete options.multiSelect;
2428            }
2429
2430            // 23, DoNotSpellCheck (PDF 1.4)
2431            if (options.doNotSpellCheck && this.internal.getPDFVersion() >= 1.4) {
2432                flags = AcroForm.internal.setBitPosition(flags, 23);
2433                delete options.doNotSpellCheck;
2434            }
2435
2436            options.Ff = flags;
2437
2438            //options.hasAnnotation = true;
2439
2440            // Add field
2441            putForm.call(this, options);
2442        };
2443    })(jsPDF.API);
2444
2445    var AcroForm = window.AcroForm;
2446
2447    AcroForm.internal = {};
2448
2449    AcroForm.createFormXObject = function (formObject) {
2450        var xobj = new AcroForm.FormXObject();
2451        var height = AcroForm.Appearance.internal.getHeight(formObject) || 0;
2452        var width = AcroForm.Appearance.internal.getWidth(formObject) || 0;
2453        xobj.BBox = [0, 0, width, height];
2454        return xobj;
2455    };
2456
2457    // Contains Methods for creating standard appearances
2458    AcroForm.Appearance = {
2459        CheckBox: {
2460            createAppearanceStream: function createAppearanceStream() {
2461                var appearance = {
2462                    N: {
2463                        On: AcroForm.Appearance.CheckBox.YesNormal
2464                    },
2465                    D: {
2466                        On: AcroForm.Appearance.CheckBox.YesPushDown,
2467                        Off: AcroForm.Appearance.CheckBox.OffPushDown
2468                    }
2469                };
2470
2471                return appearance;
2472            },
2473            /**
2474             * If any other icons are needed, the number between the brackets can be changed
2475             * @returns {string}
2476             */
2477            createMK: function createMK() {
2478                // 3-> Hook
2479                return "<< /CA (3)>>";
2480            },
2481            /**
2482             * Returns the standard On Appearance for a CheckBox
2483             * @returns {AcroForm.FormXObject}
2484             */
2485            YesPushDown: function YesPushDown(formObject) {
2486                var xobj = AcroForm.createFormXObject(formObject);
2487                var stream = "";
2488                // F13 is ZapfDingbats (Symbolic)
2489                formObject.Q = 1; // set text-alignment as centered
2490                var calcRes = AcroForm.internal.calculateX(formObject, "3", "ZapfDingbats", 50);
2491                stream += "0.749023 g\n\
2492             0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\
2493             f\n\
2494             BMC\n\
2495             q\n\
2496             0 0 1 rg\n\
2497             /F13 " + calcRes.fontSize + " Tf 0 g\n\
2498             BT\n";
2499                stream += calcRes.text;
2500                stream += "ET\n\
2501             Q\n\
2502             EMC\n";
2503                xobj.stream = stream;
2504                return xobj;
2505            },
2506
2507            YesNormal: function YesNormal(formObject) {
2508                var xobj = AcroForm.createFormXObject(formObject);
2509                var stream = "";
2510                formObject.Q = 1; // set text-alignment as centered
2511                var calcRes = AcroForm.internal.calculateX(formObject, "3", "ZapfDingbats", AcroForm.Appearance.internal.getHeight(formObject) * 0.9);
2512                stream += "1 g\n\
25130 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\
2514f\n\
2515q\n\
25160 0 1 rg\n\
25170 0 " + (AcroForm.Appearance.internal.getWidth(formObject) - 1) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 1) + " re\n\
2518W\n\
2519n\n\
25200 g\n\
2521BT\n\
2522/F13 " + calcRes.fontSize + " Tf 0 g\n";
2523                stream += calcRes.text;
2524                stream += "ET\n\
2525             Q\n";
2526                xobj.stream = stream;
2527                return xobj;
2528            },
2529
2530            /**
2531             * Returns the standard Off Appearance for a CheckBox
2532             * @returns {AcroForm.FormXObject}
2533             */
2534            OffPushDown: function OffPushDown(formObject) {
2535                var xobj = AcroForm.createFormXObject(formObject);
2536                var stream = "";
2537                stream += "0.749023 g\n\
2538            0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\
2539            f\n";
2540                xobj.stream = stream;
2541                return xobj;
2542            }
2543        },
2544
2545        RadioButton: {
2546            Circle: {
2547                createAppearanceStream: function createAppearanceStream(name) {
2548                    var appearanceStreamContent = {
2549                        D: {
2550                            'Off': AcroForm.Appearance.RadioButton.Circle.OffPushDown
2551                        },
2552                        N: {}
2553                    };
2554                    appearanceStreamContent.N[name] = AcroForm.Appearance.RadioButton.Circle.YesNormal;
2555                    appearanceStreamContent.D[name] = AcroForm.Appearance.RadioButton.Circle.YesPushDown;
2556                    return appearanceStreamContent;
2557                },
2558                createMK: function createMK() {
2559                    return "<< /CA (l)>>";
2560                },
2561
2562                YesNormal: function YesNormal(formObject) {
2563                    var xobj = AcroForm.createFormXObject(formObject);
2564                    var stream = "";
2565                    // Make the Radius of the Circle relative to min(height, width) of formObject
2566                    var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formObject) / 4;
2567                    // The Borderpadding...
2568                    DotRadius *= 0.9;
2569                    var c = AcroForm.Appearance.internal.Bezier_C;
2570                    /*
2571                   The Following is a Circle created with Bezier-Curves.
2572                   */
2573                    stream += "q\n\
25741 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2575" + DotRadius + " 0 m\n\
2576" + DotRadius + " " + DotRadius * c + " " + DotRadius * c + " " + DotRadius + " 0 " + DotRadius + " c\n\
2577-" + DotRadius * c + " " + DotRadius + " -" + DotRadius + " " + DotRadius * c + " -" + DotRadius + " 0 c\n\
2578-" + DotRadius + " -" + DotRadius * c + " -" + DotRadius * c + " -" + DotRadius + " 0 -" + DotRadius + " c\n\
2579" + DotRadius * c + " -" + DotRadius + " " + DotRadius + " -" + DotRadius * c + " " + DotRadius + " 0 c\n\
2580f\n\
2581Q\n";
2582                    xobj.stream = stream;
2583                    return xobj;
2584                },
2585                YesPushDown: function YesPushDown(formObject) {
2586                    var xobj = AcroForm.createFormXObject(formObject);
2587                    var stream = "";
2588                    var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formOb
2588ject) / 4;
2589                    // The Borderpadding...
2590                    DotRadius *= 0.9;
2591                    // Save results for later use; no need to waste processor ticks on doing math
2592                    var k = DotRadius * 2;
2593                    // var c = AcroForm.Appearance.internal.Bezier_C;
2594                    var kc = k * AcroForm.Appearance.internal.Bezier_C;
2595                    var dc = DotRadius * AcroForm.Appearance.internal.Bezier_C;
2596                    //                 stream += "0.749023 g\n\
2597                    //             q\n\
2598                    //           1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2599                    // " + DotRadius * 2 + " 0 m\n\
2600                    // " + DotRadius * 2 + " " + DotRadius * 2 * c + " " + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 " + DotRadius * 2 + " c\n\
2601                    // -" + DotRadius * 2 * c + " " + DotRadius * 2 + " -" + DotRadius * 2 + " " + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 c\n\
2602                    // -" + DotRadius * 2 + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 -" + DotRadius * 2 + " c\n\
2603                    // " + DotRadius * 2 * c + " -" + DotRadius * 2 + " " + DotRadius * 2 + " -" + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 c\n\
2604                    //             f\n\
2605                    //             Q\n\
2606                    //             0 g\n\
2607                    //             q\n\
2608                    //             1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2609                    // " + DotRadius + " 0 m\n\
2610                    // " + DotRadius + " " + DotRadius * c + " " + DotRadius * c + " " + DotRadius + " 0 " + DotRadius + " c\n\
2611                    // -" + DotRadius * c + " " + DotRadius + " -" + DotRadius + " " + DotRadius * c + " -" + DotRadius + " 0 c\n\
2612                    // -" + DotRadius + " -" + DotRadius * c + " -" + DotRadius * c + " -" + DotRadius + " 0 -" + DotRadius + " c\n\
2613                    // " + DotRadius * c + " -" + DotRadius + " " + DotRadius + " -" + DotRadius * c + " " + DotRadius + " 0 c\n\
2614                    //             f\n\
2615                    //             Q\n";
2616
2617                    //  FASTER VERSION with less processor ticks spent on math operations
2618                    stream += "0.749023 g\n\
2619            q\n\
2620           1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2621" + k + " 0 m\n\
2622" + k + " " + kc + " " + kc + " " + k + " 0 " + k + " c\n\
2623-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c\n\
2624-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c\n\
2625" + kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c\n\
2626            f\n\
2627            Q\n\
2628            0 g\n\
2629            q\n\
2630            1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2631" + DotRadius + " 0 m\n\
2632" + DotRadius + " " + dc + " " + dc + " " + DotRadius + " 0 " + DotRadius + " c\n\
2633-" + dc + " " + DotRadius + " -" + DotRadius + " " + dc + " -" + DotRadius + " 0 c\n\
2634-" + DotRadius + " -" + dc + " -" + dc + " -" + DotRadius + " 0 -" + DotRadius + " c\n\
2635" + dc + " -" + DotRadius + " " + DotRadius + " -" + dc + " " + DotRadius + " 0 c\n\
2636            f\n\
2637            Q\n";
2638                    xobj.stream = stream;
2639                    return xobj;
2640                },
2641                OffPushDown: function OffPushDown(formObject) {
2642                    var xobj = AcroForm.createFormXObject(formObject);
2643                    var stream = "";
2644                    var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formObject) / 4;
2645                    // The Borderpadding...
2646                    DotRadius *= 0.9;
2647                    // Save results for later use; no need to waste processor ticks on doing math
2648                    var k = DotRadius * 2;
2649                    // var c = AcroForm.Appearance.internal.Bezier_C;
2650                    var kc = k * AcroForm.Appearance.internal.Bezier_C;
2651                    //                 stream += "0.749023 g\n\
2652                    //             q\n\
2653                    //  1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formOb
2653ject) / 2 + " cm\n\
2654                    // " + DotRadius * 2 + " 0 m\n\
2655                    // " + DotRadius * 2 + " " + DotRadius * 2 * c + " " + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 " + DotRadius * 2 + " c\n\
2656                    // -" + DotRadius * 2 * c + " " + DotRadius * 2 + " -" + DotRadius * 2 + " " + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 c\n\
2657                    // -" + DotRadius * 2 + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 -" + DotRadius * 2 + " c\n\
2658                    // " + DotRadius * 2 * c + " -" + DotRadius * 2 + " " + DotRadius * 2 + " -" + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 c\n\
2659                    //             f\n\
2660                    //             Q\n";
2661
2662                    //  FASTER VERSION with less processor ticks spent on math operations
2663                    stream += "0.749023 g\n\
2664            q\n\
2665 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2666" + k + " 0 m\n\
2667" + k + " " + kc + " " + kc + " " + k + " 0 " + k + " c\n\
2668-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c\n\
2669-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c\n\
2670" + kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c\n\
2671            f\n\
2672            Q\n";
2673                    xobj.stream = stream;
2674                    return xobj;
2675                }
2676            },
2677
2678            Cross: {
2679                /**
2680                 * Creates the Actual AppearanceDictionary-References
2681                 * @param name
2682                 * @returns
2683                 */
2684                createAppearanceStream: function createAppearanceStream(name) {
2685                    var appearanceStreamContent = {
2686                        D: {
2687                            'Off': AcroForm.Appearance.RadioButton.Cross.OffPushDown
2688                        },
2689                        N: {}
2690                    };
2691                    appearanceStreamContent.N[name] = AcroForm.Appearance.RadioButton.Cross.YesNormal;
2692                    appearanceStreamContent.D[name] = AcroForm.Appearance.RadioButton.Cross.YesPushDown;
2693                    return appearanceStreamContent;
2694                },
2695                createMK: function createMK() {
2696                    return "<< /CA (8)>>";
2697                },
2698
2699                YesNormal: function YesNormal(formObject) {
2700                    var xobj = AcroForm.createFormXObject(formObject);
2701                    var stream = "";
2702                    var cross = AcroForm.Appearance.internal.calculateCross(formObject);
2703                    stream += "q\n\
2704            1 1 " + (AcroForm.Appearance.internal.getWidth(formObject) - 2) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 2) + " re\n\
2705            W\n\
2706            n\n\
2707            " + cross.x1.x + " " + cross.x1.y + " m\n\
2708            " + cross.x2.x + " " + cross.x2.y + " l\n\
2709            " + cross.x4.x + " " + cross.x4.y + " m\n\
2710            " + cross.x3.x + " " + cross.x3.y + " l\n\
2711            s\n\
2712            Q\n";
2713                    xobj.stream = stream;
2714                    return xobj;
2715                },
2716                YesPushDown: function YesPushDown(formObject) {
2717                    var xobj = AcroForm.createFormXObject(formObject);
2718                    var cross = AcroForm.Appearance.internal.calculateCross(formObject);
2719                    var stream = "";
2720                    stream += "0.749023 g\n\
2721            0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\
2722            f\n\
2723            q\n\
2724            1 1 " + (AcroForm.Appearance.internal.getWidth(formObject) - 2) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 2) + " re\n\
2725            W\n\
2726            n\n\
2727            " + cross.x1.x + " " + cross.x1.y + " m\n\
2728            " + cross.x2.x + " " + cross.x2.y + " l\n\
2729            " + cross.x4.x + " " + cross.x4.y + " m\n\
2730            " + cross.x3.x + " " + cross.x3.y + " l\n\
2731            s\n\
2732            Q\n";
2733                    xobj.stream = stream;
2734                    return xobj;
2735                },
2736                OffPushDown: function OffPushDown(formObject) {
2737                    var xobj = AcroForm.createFormXObject(formOb
2737ject);
2738                    var stream = "";
2739                    stream += "0.749023 g\n\
2740            0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\
2741            f\n";
2742                    xobj.stream = stream;
2743                    return xobj;
2744                }
2745            }
2746        },
2747
2748        /**
2749         * Returns the standard Appearance
2750         * @returns {AcroForm.FormXObject}
2751         */
2752        createDefaultAppearanceStream: function createDefaultAppearanceStream(formObject) {
2753            var stream = "";
2754            // Set Helvetica to Standard Font (size: auto)
2755            // Color: Black
2756            stream += "/Helv 0 Tf 0 g";
2757            return stream;
2758        }
2759    };
2760
2761    AcroForm.Appearance.internal = {
2762        Bezier_C: 0.551915024494,
2763
2764        calculateCross: function calculateCross(formObject) {
2765            var min = function min(x, y) {
2766                return x > y ? y : x;
2767            };
2768
2769            var width = AcroForm.Appearance.internal.getWidth(formObject);
2770            var height = AcroForm.Appearance.internal.getHeight(formObject);
2771            var a = min(width, height);
2772            var crossSize = a;
2773            var borderPadding = 2; // The Padding in px
2774
2775
2776            var cross = {
2777                x1: { // upperLeft
2778                    x: (width - a) / 2,
2779                    y: (height - a) / 2 + a },
2780                x2: { // lowerRight
2781                    x: (width - a) / 2 + a,
2782                    y: (height - a) / 2 //borderPadding
2783                },
2784                x3: { // lowerLeft
2785                    x: (width - a) / 2,
2786                    y: (height - a) / 2 //borderPadding
2787                },
2788                x4: { // upperRight
2789                    x: (width - a) / 2 + a,
2790                    y: (height - a) / 2 + a }
2791            };
2792
2793            return cross;
2794        }
2795    };
2796    AcroForm.Appearance.internal.getWidth = function (formObject) {
2797        return formObject.Rect[2]; //(formObject.Rect[2] - formObject.Rect[0]) || 0;
2798    };
2799    AcroForm.Appearance.internal.getHeight = function (formObject) {
2800        return formObject.Rect[3]; //(formObject.Rect[1] - formObject.Rect[3]) || 0;
2801    };
2802
2803    // ##########################
2804
2805    //### For inheritance:
2806    AcroForm.internal.inherit = function (child, parent) {
2807        var ObjectCreate = Object.create || function (o) {
2808            var F = function F() {};
2809            F.prototype = o;
2810            return new F();
2811        };
2812        child.prototype = Object.create(parent.prototype);
2813        child.prototype.constructor = child;
2814    };
2815
2816    // ### Handy Functions:
2817
2818    AcroForm.internal.arrayToPdfArray = function (array) {
2819        if (Array.isArray(array)) {
2820            var content = ' [';
2821            for (var i in array) {
2822                var element = array[i].toString();
2823                content += element;
2824                content += i < array.length - 1 ? ' ' : '';
2825            }
2826            content += ']';
2827
2828            return content;
2829        }
2830    };
2831
2832    AcroForm.internal.toPdfString = function (string) {
2833        string = string || "";
2834
2835        // put Bracket at the Beginning of the String
2836        if (string.indexOf('(') !== 0) {
2837            string = '(' + string;
2838        }
2839
2840        if (string.substring(string.length - 1) != ')') {
2841            string += '(';
2842        }
2843        return string;
2844    };
2845
2846    // ##########################
2847    //          Classes
2848    // ##########################
2849
2850
2851    AcroForm.PDFObject = function () {
2852        // The Object ID in the PDF Object Model
2853        // todo
2854        var _objId;
2855        Object.defineProperty(this, 'objId', {
2856            get: function get() {
2857                if (!_objId) {
2858                    if (this.internal) {
2859                        _objId = this.internal.newObjectDeferred();
2860                    } else if (jsPDF.API.acroformPlugin.internal) {
2861                        // todo - find better option, that doesn't rely on a Global Static var
2862                        _objId = jsPDF.API.acroformPlugin.internal.newObjectDeferred();
2863                    }
2864                }
2865                if (!_objId) {
2866                    console.log("Couldn't create Object ID");
2867                }
2868                return _objId;
2869            },
2870            configurable: false
2871        });
2872    };
2873
2874    AcroForm.PDFObject.prototype.toString = function () {
2875        return this.objId + " 0 R";
2876    };
2877
2878    AcroForm.PDFObject.prototype.getString = function () {
2879        var res = this.objId + " 0 obj\n<<";
2880        var content = this.getContent();
2881
2882        res += content + ">>\n";
2883        if (this.stream) {
2884            res += "stream\n";
2885            res += this.stream;
2886            res += "endstream\n";
2887        }
2888        res += "endobj\n";
2889        return res;
2890    };
2891
2892    AcroForm.PDFObject.prototype.getContent = function () {
2893        /**
2894         * Prints out all enumerable Variables from the Object
2895         * @param fieldObject
2896         * @returns {string}
2897         */
2898        var createContentFromFieldObject = function createContentFromFieldObject(fieldObject) {
2899            var content = '';
2900
2901            var keys = Object.keys(fieldObject).filter(function (key) {
2902                return key != 'content' && key != 'appearanceStreamContent' && key.substring(0, 1) != "_";
2903            });
2904
2905            for (var i in keys) {
2906                var key = keys[i];
2907                var value = fieldObject[key];
2908
2909                /*if (key == 'Rect' && value) {
2910               value = AcroForm.internal.calculateCoordinates.call(jsPDF.API.acroformPlugin.internal, value);
2911               }*/
2912
2913                if (value) {
2914                    if (Array.isArray(value)) {
2915                        content += '/' + key + ' ' + AcroForm.internal.arrayToPdfArray(value) + "\n";
2916                    } else if (value instanceof AcroForm.PDFObject) {
2917                        // In case it is a reference to another PDFObject, take the referennce number
2918                        content += '/' + key + ' ' + value.objId + " 0 R" + "\n";
2919                    } else {
2920                        content += '/' + key + ' ' + value + '\n';
2921                    }
2922                }
2923            }
2924            return content;
2925        };
2926
2927        var object = "";
2928
2929        object += createContentFromFieldObject(this);
2930        return object;
2931    };
2932
2933    AcroForm.FormXObject = function () {
2934        AcroForm.PDFObject.call(this);
2935        this.Type = "/XObject";
2936        this.Subtype = "/Form";
2937        this.FormType = 1;
2938        this.BBox;
2939        this.Matrix;
2940        this.Resources = "2 0 R";
2941        this.PieceInfo;
2942        var _stream;
2943        Object.defineProperty(this, 'Length', {
2944            enumerable: true,
2945            get: function get() {
2946                return _stream !== undefined ? _stream.length : 0;
2947            }
2948        });
2949        Object.defineProperty(this, 'stream', {
2950            enumerable: false,
2951            set: function set(val) {
2952                _stream = val;
2953            },
2954            get: function get() {
2955                if (_stream) {
2956                    return _stream;
2957                } else {
2958                    return null;
2959                }
2960            }
2961        });
2962    };
2963
2964    AcroForm.internal.inherit(AcroForm.FormXObject, AcroForm.PDFObject);
2965
2966    AcroForm.AcroFormDictionary = function () {
2967        AcroForm.PDFObject.call(this);
2968        var _Kids = [];
2969        Object.defineProperty(this, 'Kids', {
2970            enumerable: false,
2971            configurable: true,
2972            get: function get() {
2973                if (_Kids.length > 0) {
2974                    return _Kids;
2975                } else {
2976                    return;
2977                }
2978            }
2979        });
2980        Object.defineProperty(this, 'Fields', {
2981            enumerable: true,
2982            configurable: true,
2983            get: function get() {
2984                return _Kids;
2985            }
2986        });
2987        // Default Appearance
2988        this.DA;
2989    };
2990
2991    AcroForm.internal.inherit(AcroForm.AcroFormDictionary, AcroForm.PDFObject);
2992
2993    // ##### The Objects, the User can Create:
2994
2995
2996    // The Field Object contains the Variables, that every Field needs
2997    // Rectangle for Appearance: lower_left_X, lower_left_Y, width, height
2998    AcroForm.Field = function () {
2999        'use strict';
3000
3001        AcroForm.PDFObject.call(this);
3002
3003        var _Rect;
3004        Object.defineProperty(this, 'Rect', {
3005            enumerable: true,
3006            configurable: false,
3007            get: function get() {
3008                if (!_Rect) {
3009                    return;
3010                }
3011                var tmp = _Rect;
3012                //var calculatedRes = AcroForm.internal.calculateCoordinates(_Rect); // do later!
3013                return tmp;
3014            },
3015            set: function set(val) {
3016                _Rect = val;
3017            }
3018        });
3019
3020        var _FT = "";
3021        Object.defineProperty(this, 'FT', {
3022            enumerable: true,
3023            set: function set(val) {
3024                _FT = val;
3025            },
3026            get: function get() {
3027                return _FT;
3028            }
3029        });
3030        /**
3031         * The Partial name of the Field Object.
3032         * It has to be unique.
3033         */
3034        var _T;
3035
3036        Object.defineProperty(this, 'T', {
3037            enumerable: true,
3038            configurable: false,
3039            set: function set(val) {
3040                _T = val;
3041            },
3042            get: function get() {
3043                if (!_T || _T.length < 1) {
3044                    if (this instanceof AcroForm.ChildClass) {
3045                        // In case of a Child from a Radio´Group, you don't need a FieldName!!!
3046                        return;
3047                    }
3048                    return "(FieldObject" + AcroForm.Field.FieldNum++ + ")";
3049                }
3050                if (_T.substring(0, 1) == "(" && _T.substring(_T.length - 1)) {
3051                    return _T;
3052                }
3053                return "(" + _T + ")";
3054            }
3055        });
3056
3057        var _DA;
3058        // Defines the default appearance (Needed for variable Text)
3059        Object.defineProperty(this, 'DA', {
3060            enumerable: true,
3061            get: function get() {
3062                if (!_DA) {
3063                    return;
3064                }
3065                return '(' + _DA + ')';
3066            },
3067            set: function set(val) {
3068                _DA = val;
3069            }
3070        });
3071
3072        var _DV;
3073        // Defines the default value
3074        Object.defineProperty(this, 'DV', {
3075            enumerable: true,
3076            configurable: true,
3077            get: function get() {
3078                if (!_DV) {
3079                    return;
3080                }
3081                return _DV;
3082            },
3083            set: function set(val) {
3084                _DV = val;
3085            }
3086        });
3087
3088        //this.Type = "/Annot";
3089        //this.Subtype = "/Widget";
3090        Object.defineProperty(this, 'Type', {
3091            enumerable: true,
3092            get: function get() {
3093                return this.hasAnnotation ? "/Annot" : null;
3094            }
3095        });
3096
3097        Object.defineProperty(this, 'Subtype', {
3098            enumerable: true,
3099            get: function get() {
3100                return this.hasAnnotation ? "/Widget" : null;
3101            }
3102        });
3103
3104        /**
3105         *
3106         * @type {Array}
3107         */
3108        this.BG;
3109
3110        Object.defineProperty(this, 'hasAnnotation', {
3111            enumerable: false,
3112            get: function get() {
3113                if (this.Rect || this.BC || this.BG) {
3114                    return true;
3115                }
3116                return false;
3117            }
3118        });
3119
3120        Object.defineProperty(this, 'hasAppearanceStream', {
3121            enumerable: false,
3122            configurable: true,
3123            writable: true
3124        });
3125
3126        Object.defineProperty(this, 'page', {
3127            enumerable: false,
3128            configurable: true,
3129            writable: true
3130        });
3131    };
3132    AcroForm.Field.FieldNum = 0;
3133
3134    AcroForm.internal.inherit(AcroForm.Field, AcroForm.PDFObject);
3135
3136    AcroForm.ChoiceField = function () {
3137        AcroForm.Field.call(this);
3138        // Field Type = Choice Field
3139        this.FT = "/Ch";
3140        // options
3141        this.Opt = [];
3142        this.V = '()';
3143        // Top Index
3144        this.TI = 0;
3145        /**
3146         * Defines, whether the
3147         * @type {boolean}
3148         */
3149        this.combo = false;
3150        /**
3151         * Defines, whether the Choice Field is an Edit Field.
3152         * An Edit Field is automatically an Combo Field.
3153         */
3154        Object.defineProperty(this, 'edit', {
3155            enumerable: true,
3156            set: function set(val) {
3157                if (val == true) {
3158                    this._edit = true;
3159                    // ComboBox has to be true
3160                    this.combo = true;
3161                } else {
3162                    this._edit = false;
3163                }
3164            },
3165            get: function get() {
3166                if (!this._edit) {
3167                    return false;
3168                }
3169                return this._edit;
3170            },
3171            configurable: false
3172        });
3173        this.hasAppearanceStream = true;
3174        Object.defineProperty(this, 'V', {
3175            get: function get() {
3176                AcroForm.internal.toPdfString();
3177            }
3178        });
3179    };
3180    AcroForm.internal.inherit(AcroForm.ChoiceField, AcroForm.Field);
3181    window["ChoiceField"] = AcroForm.ChoiceField;
3182
3183    AcroForm.ListBox = function () {
3184        AcroForm.ChoiceField.call(this);
3185        //var combo = true;
3186    };
3187    AcroForm.internal.inherit(AcroForm.ListBox, AcroForm.ChoiceField);
3188    window["ListBox"] = AcroForm.ListBox;
3189
3190    AcroForm.ComboBox = function () {
3191        AcroForm.ListBox.call(this);
3192        this.combo = true;
3193    };
3194    AcroForm.internal.inherit(AcroForm.ComboBox, AcroForm.ListBox);
3195    window["ComboBox"] = AcroForm.ComboBox;
3196
3197    AcroForm.EditBox = function () {
3198        AcroForm.ComboBox.call(this);
3199        this.edit = true;
3200    };
3201    AcroForm.internal.inherit(AcroForm.EditBox, AcroForm.ComboBox);
3202    window["EditBox"] = AcroForm.EditBox;
3203
3204    AcroForm.Button = function () {
3205        AcroForm.Field.call(this);
3206        this.FT = "/Btn";
3207        //this.hasAnnotation = true;
3208    };
3209    AcroForm.internal.inherit(AcroForm.Button, AcroForm.Field);
3210    window["Button"] = AcroForm.Button;
3211
3212    AcroForm.PushButton = function () {
3213        AcroForm.Button.call(this);
3214        this.pushbutton = true;
3215    };
3216    AcroForm.internal.inherit(AcroForm.PushButton, AcroForm.Button);
3217    window["PushButton"] = AcroForm.PushButton;
3218
3219    AcroForm.RadioButton = function () {
3220        AcroForm.Button.call(this);
3221        this.radio = true;
3222        var _Kids = [];
3223        Object.defineProperty(this, 'Kids', {
3224            enumerable: true,
3225            get: function get() {
3226                if (_Kids.length > 0) {
3227                    return _Kids;
3228                }
3229            }
3230        });
3231
3232        Object.defineProperty(this, '__Kids', {
3233            get: function get() {
3234                return _Kids;
3235            }
3236        });
3237
3238        var _noToggleToOff;
3239
3240        Object.defineProperty(this, 'noToggleToOff', {
3241            enumerable: false,
3242            get: function get() {
3243                return _noToggleToOff;
3244            },
3245            set: function set(val) {
3246                _noToggleToOff = val;
3247            }
3248        });
3249
3250        //this.hasAnnotation = false;
3251    };
3252    AcroForm.internal.inherit(AcroForm.RadioButton, AcroForm.Button);
3253    window["RadioButton"] = AcroForm.RadioButton;
3254
3255    /*
3256   * The Child classs of a RadioButton (the radioGroup)
3257   * -> The single Buttons
3258   */
3259    AcroForm.ChildClass = function (parent, name) {
3260        AcroForm.Field.call(this);
3261        this.Parent = parent;
3262
3263        // todo: set AppearanceType as variable that can be set from the outside...
3264        this._AppearanceType = AcroForm.Appearance.RadioButton.Circle; // The Default appearanceType is the Circle
3265        this.appearanceStreamContent = this._AppearanceType.createAppearanceStream(name);
3266
3267        // Set Print in the Annot Flag
3268        this.F = AcroForm.internal.setBitPosition(this.F, 3, 1);
3269
3270        // Set AppearanceCharacteristicsDictionary with default appearance if field is not interacting with user
3271        this.MK = this._AppearanceType.createMK(); // (8) -> Cross, (1)-> Circle, ()-> nothing
3272
3273        // Default Appearance is Off
3274        this.AS = "/Off"; // + name;
3275
3276        this._Name = name;
3277    };
3278    AcroForm.internal.inherit(AcroForm.ChildClass, AcroForm.Field);
3279
3280    AcroForm.RadioButton.prototype.setAppearance = function (appearance) {
3281        if (!('createAppearanceStream' in appearance && 'createMK' in appearance)) {
3282            console.log("Couldn't assign Appearance to RadioButton. Appearance was Invalid!");
3283            return;
3284        }
3285        for (var i in this.__Kids) {
3286            var child = this.__Kids[i];
3287
3288            child.appearanceStreamContent = appearance.createAppearanceStream(child._Name);
3289            child.MK = appearance.createMK();
3290        }
3291    };
3292
3293    AcroForm.RadioButton.prototype.createOption = function (name) {
3294        var parent = this;
3295        var kidCount = this.__Kids.length;
3296
3297        // Create new Child for RadioGroup
3298        var child = new AcroForm.ChildClass(parent, name);
3299        // Add to Parent
3300        this.__Kids.push(child);
3301
3302        jsPDF.API.addField(child);
3303
3304        return child;
3305    };
3306
3307    AcroForm.CheckBox = function () {
3308        Button.call(this);
3309        this.appearanceStreamContent = AcroForm.Appearance.CheckBox.createAppearanceStream();
3310        this.MK = AcroForm.Appearance.CheckBox.createMK();
3311        this.AS = "/On";
3312        this.V = "/On";
3313    };
3314    AcroForm.internal.inherit(AcroForm.CheckBox, AcroForm.Button);
3315    window["CheckBox"] = AcroForm.CheckBox;
3316
3317    AcroForm.TextField = function () {
3318        AcroForm.Field.call(this);
3319        this.DA = AcroForm.Appearance.createDefaultAppearanceStream();
3320        this.F = 4;
3321        var _V;
3322        Object.defineProperty(this, 'V', {
3323            get: function get() {
3324                if (_V) {
3325                    return "(" + _V + ")";
3326                } else {
3327                    return _V;
3328                }
3329            },
3330            enumerable: true,
3331            set: function set(val) {
3332                _V = val;
3333            }
3334        });
3335
3336        var _DV;
3337        Object.defineProperty(this, 'DV', {
3338            get: function get() {
3339                if (_DV) {
3340                    return "(" + _DV + ")";
3341                } else {
3342                    return _DV;
3343                }
3344            },
3345            enumerable: true,
3346            set: function set(val) {
3347                _DV = val;
3348            }
3349        });
3350
3351        var _multiline = false;
3352        Object.defineProperty(this, 'multiline', {
3353            enumerable: false,
3354            get: function get() {
3355                return _multiline;
3356            },
3357            set: function set(val) {
3358                _multiline = val;
3359            }
3360        });
3361
3362        //this.multiline = false;
3363        //this.password = false;
3364        /**
3365         * For PDF 1.4
3366         * @type {boolean}
3367         */
3368        //this.fileSelect = false;
3369        /**
3370         * For PDF 1.4
3371         * @type {boolean}
3372         */
3373        //this.doNotSpellCheck = false;
3374        /**
3375         * For PDF 1.4
3376         * @type {boolean}
3377         */
3378            //this.doNotScroll = false;
3379
3380        var _MaxLen = false;
3381        Object.defineProperty(this, 'MaxLen', {
3382            enumerable: true,
3383            get: function get() {
3384                return _MaxLen;
3385            },
3386            set: function set(val) {
3387                _MaxLen = val;
3388            }
3389        });
3390
3391        Object.defineProperty(this, 'hasAppearanceStream', {
3392            enumerable: false,
3393            get: function get() {
3394                return this.V || this.DV;
3395            }
3396        });
3397    };
3398    AcroForm.internal.inherit(AcroForm.TextField, AcroForm.Field);
3399    window["TextField"] = AcroForm.TextField;
3400
3401    AcroForm.PasswordField = function () {
3402        TextField.call(this);
3403        Object.defineProperty(this, 'password', {
3404            value: true,
3405            enumerable: false,
3406            configurable: false,
3407            writable: false
3408        });
3409    };
3410    AcroForm.internal.inherit(AcroForm.PasswordField, AcroForm.TextField);
3411    window["PasswordField"] = AcroForm.PasswordField;
3412
3413    // ############ internal functions
3414
3415    /*
3416   * small workaround for calculating the TextMetric approximately
3417   * @param text
3418   * @param fontsize
3419   * @returns {TextMetrics} (Has Height and Width)
3420   */
3421    AcroForm.internal.calculateFontSpace = function (text, fontsize, fonttype) {
3422        var fonttype = fonttype || "helvetica";
3423        //re-use canvas object for speed improvements
3424        var canvas = AcroForm.internal.calculateFontSpace.canvas || (AcroForm.internal.calculateFontSpace.canvas = document.createElement('canvas'));
3425
3426        var context = canvas.getContext('2d');
3427        context.save();
3428        var newFont = fontsize + " " + fonttype;
3429        context.font = newFont;
3430        var res = context.measureText(text);
3431        context.fontcolor = 'black';
3432        // Calculate height:
3433        var context = canvas.getContext('2d');
3434        res.height = context.measureText("3").width * 1.5; // 3 because in ZapfDingbats its a Hook and a 3 in normal fonts
3435        context.restore();
3436
3437        var width = res.width;
3438
3439        return res;
3440    };
3441
3442    AcroForm.internal.calculateX = function (formObject, text, font, maxFontSize) {
3443        var maxFontSize = maxFontSize || 12;
3444        var font = font || "helvetica";
3445        var returnValue = {
3446            text: "",
3447            fontSize: ""
3448        };
3449        // Remove Brackets
3450        text = text.substr(0, 1) == '(' ? text.substr(1) : text;
3451        text = text.substr(text.length - 1) == ')' ? text.substr(0, text.length - 1) : text;
3452        // split into array of words
3453        var textSplit = text.split(' ');
3454
3455        /**
3456         * the color could be ((alpha)||(r,g,b)||(c,m,y,k))
3457         * @type {string}
3458         */
3459        var color = "0 g\n";
3460        var fontSize = maxFontSize; // The Starting fontSize (The Maximum)
3461        var lineSpacing = 2;
3462        var borderPadding = 2;
3463
3464        var height = AcroForm.Appearance.internal.getHeight(formObject) || 0;
3465        height = height < 0 ? -height : height;
3466        var width = AcroForm.Appearance.internal.getWidth(formObject) || 0;
3467        width = width < 0 ? -width : width;
3468
3469        var isSmallerThanWidth = function isSmallerThanWidth(i, lastLine, fontSize) {
3470            if (i + 1 < textSplit.length) {
3471                var tmp = lastLine + " " + textSplit[i + 1];
3472                var TextWidth = AcroForm.internal.calculateFontSpace(tmp, fontSize + "px", font).width;
3473                var FieldWidth = width - 2 * borderPadding;
3474                return TextWidth <= FieldWidth;
3475            } else {
3476                return false;
3477            }
3478        };
3479
3480        fontSize++;
3481        FontSize: while (true) {
3482            var text = "";
3483            fontSize--;
3484            var textHeight = AcroForm.internal.calculateFontSpace("3", fontSize + "px", font).height;
3485            var startY = formObject.multiline ? height - fontSize : (height - textHeight) / 2;
3486            startY += lineSpacing;
3487            var startX = -borderPadding;
3488
3489            var lastX = startX,
3490                lastY = startY;
3491            var firstWordInLine = 0,
3492                lastWordInLine = 0;
3493            var lastLength = 0;
3494
3495            var y = 0;
3496            if (fontSize == 0) {
3497                // In case, the Text doesn't fit at all
3498                fontSize = 12;
3499                text = "(...) Tj\n";
3500                text += "% Width of Text: " + AcroForm.internal.calculateFontSpace(text, "1px").width + ", FieldWidth:" + width + "\n";
3501                break;
3502            }
3503
3504            lastLength = AcroForm.internal.calculateFontSpace(textSplit[0] + " ", fontSize + "px", font).width;
3505
3506            var lastLine = "";
3507            var lineCount = 0;
3508            Line: for (var i in textSplit) {
3509                lastLine += textSplit[i] + " ";
3510                // Remove last blank
3511                lastLine = lastLine.substr(lastLine.length - 1) == " " ? lastLine.substr(0, lastLine.length - 1) : lastLine;
3512                var key = parseInt(i);
3513                lastLength = AcroForm.internal.calculateFontSpace(lastLine + " ", fontSize + "px", font).width;
3514                var nextLineIsSmaller = isSmallerThanWidth(key, lastLine, fontSize);
3515                var isLastWord = i >= textSplit.length - 1;
3516                if (nextLineIsSmaller && !isLastWord) {
3517                    lastLine += " ";
3518                    continue; // Line
3519                } else if (!nextLineIsSmaller && !isLastWord) {
3520                    if (!formObject.multiline) {
3521                        continue FontSize;
3522                    } else {
3523                        if ((textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) {
3524                            // If the Text is higher than the FieldObject
3525                            continue FontSize;
3526                        }
3527                        lastWordInLine = key;
3528                        // go on
3529                    }
3530                } else if (isLastWord) {
3531                    lastWordInLine = key;
3532                } else {
3533                    if (formObject.multiline && (textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) {
3534                        // If the Text is higher than the FieldObject
3535                        continue FontSize;
3536                    }
3537                }
3538
3539                var line = '';
3540
3541                for (var x = firstWordInLine; x <= lastWordInLine; x++) {
3542                    line += textSplit[x] + ' ';
3543                }
3544
3545                // Remove last blank
3546                line = line.substr(line.length - 1) == " " ? line.substr(0, line.length - 1) : line;
3547                //lastLength -= blankSpace.width;
3548                lastLength = AcroForm.internal.calculateFontSpace(line, fontSize + "px", font).width;
3549
3550                // Calculate startX
3551                switch (formObject.Q) {
3552                    case 2:
3553                        // Right justified
3554                        startX = width - lastLength - borderPadding;
3555                        break;
3556                    case 1:
3557                        // Q = 1 := Text-Alignment: Center
3558                        startX = (width - lastLength) / 2;
3559                        break;
3560                    case 0:
3561                    default:
3562                        startX = borderPadding;
3563                        break;
3564                }
3565                text += startX + ' ' + lastY + ' Td\n';
3566                text += '(' + line + ') Tj\n';
3567                // reset X in PDF
3568                text += -startX + ' 0 Td\n';
3569
3570                // After a Line, adjust y position
3571                lastY = -(fontSize + lineSpacing);
3572                lastX = startX;
3573
3574                // Reset for next iteration step
3575                lastLength = 0;
3576                firstWordInLine = lastWordInLine + 1;
3577                lineCount++;
3578
3579                lastLine = "";
3580                continue Line;
3581            }
3582            break;
3583        }
3584
3585        returnValue.text = text;
3586        returnValue.fontSize = fontSize;
3587
3588        return returnValue;
3589    };
3590
3591    AcroForm.internal.calculateAppearanceStream = function (formObject) {
3592        if (formObject.appearanceStreamContent) {
3593            // If appearanceStream is already set, use it
3594            return formObject.appearanceStreamContent;
3595        }
3596
3597        if (!formObject.V && !formObject.DV) {
3598            return;
3599        }
3600
3601        // else calculate it
3602
3603        var stream = '';
3604
3605        var text = formObject.V || formObject.DV;
3606
3607        var calcRes = AcroForm.internal.calculateX(formObject, text);
3608
3609        stream += '/Tx BMC\n' + 'q\n' +
3610            //color + '\n' +
3611            '/F1 ' + calcRes.fontSize + ' Tf\n' +
3612            // Text Matrix
3613            '1 0 0 1 0 0 Tm\n';
3614        // Begin Text
3615        stream += 'BT\n';
3616        stream += calcRes.text;
3617        // End Text
3618        stream += 'ET\n';
3619        stream += 'Q\n' + 'EMC\n';
3620
3621        var appearanceStreamContent = new AcroForm.createFormXObject(formObject);
3622
3623        appearanceStreamContent.stream = stream;
3624
3625        var appearance = {
3626            N: {
3627                'Normal': appearanceStreamContent
3628            }
3629        };
3630
3631        return appearanceStreamContent;
3632    };
3633
3634    /*
3635   * Converts the Parameters from x,y,w,h to lowerLeftX, lowerLeftY, upperRightX, upperRightY
3636   * @param x
3637   * @param y
3638   * @param w
3639   * @param h
3640   * @returns {*[]}
3641   */
3642    AcroForm.internal.calculateCoordinates = function (x, y, w, h) {
3643        var coordinates = {};
3644
3645        if (this.internal) {
3646            var mmtopx = function mmtopx(x) {
3647                return x * this.internal.scaleFactor;
3648            };
3649
3650            if (Array.isArray(x)) {
3651                x[0] = AcroForm.scale(x[0]);
3652                x[1] = AcroForm.scale(x[1]);
3653                x[2] = AcroForm.scale(x[2]);
3654                x[3] = AcroForm.scale(x[3]);
3655
3656                coordinates.lowerLeft_X = x[0] || 0;
3657                coordinates.lowerLeft_Y = mmtopx.call(this, this.internal.pageSize.height) - x[3] - x[1] || 0;
3658                coordinates.upperRight_X = x[0] + x[2] || 0;
3659                coordinates.upperRight_Y = mmtopx.call(this, this.internal.pageSize.height) - x[1] || 0;
3660            } else {
3661                x = AcroForm.scale(x);
3662                y = AcroForm.scale(y);
3663                w = AcroForm.scale(w);
3664                h = AcroForm.scale(h);
3665                coordinates.lowerLeft_X = x || 0;
3666                coordinates.lowerLeft_Y = this.internal.pageSize.height - y || 0;
3667                coordinates.upperRight_X = x + w || 0;
3668                coordinates.upperRight_Y = this.internal.pageSize.height - y + h || 0;
3669            }
3670        } else {
3671            // old method, that is fallback, if we can't get the pageheight, the coordinate-system starts from lower left
3672            if (Array.isArray(x)) {
3673                coordinates.lowerLeft_X = x[0] || 0;
3674                coordinates.lowerLeft_Y = x[1] || 0;
3675                coordinates.upperRight_X = x[0] + x[2] || 0;
3676                coordinates.upperRight_Y = x[1] + x[3] || 0;
3677            } else {
3678                coordinates.lowerLeft_X = x || 0;
3679                coordinates.lowerLeft_Y = y || 0;
3680                coordinates.upperRight_X = x + w || 0;
3681                coordinates.upperRight_Y = y + h || 0;
3682            }
3683        }
3684
3685        return [coordinates.lowerLeft_X, coordinates.lowerLeft_Y, coordinates.upperRight_X, coordinates.upperRight_Y];
3686    };
3687
3688    AcroForm.internal.calculateColor = function (r, g, b) {
3689        var color = new Array(3);
3690        color.r = r | 0;
3691        color.g = g | 0;
3692        color.b = b | 0;
3693        return color;
3694    };
3695
3696    AcroForm.internal.getBitPosition = function (variable, position) {
3697        variable = variable || 0;
3698        var bitMask = 1;
3699        bitMask = bitMask << position - 1;
3700        return variable | bitMask;
3701    };
3702
3703    AcroForm.internal.setBitPosition = function (variable, position, value) {
3704        variable = variable || 0;
3705        value = value || 1;
3706
3707        var bitMask = 1;
3708        bitMask = bitMask << position - 1;
3709
3710        if (value == 1) {
3711            // Set the Bit to 1
3712            var variable = variable | bitMask;
3713        } else {
3714            // Set the Bit to 0
3715            var variable = variable & ~bitMask;
3716        }
3717
3718        return variable;
3719    };
3720
3721    /**
3722     * jsPDF addHTML PlugIn
3723     * Copyright (c) 2014 Diego Casorran
3724     *
3725     * Licensed under the MIT License.
3726     * http://opensource.org/licenses/mit-license
3727     */
3728
3729    (function (jsPDFAPI) {
3730        'use strict';
3731
3732        /**
3733         * Renders an HTML element to canvas object which added to the PDF
3734         *
3735         * This PlugIn requires html2canvas: https://github.com/niklasvh/html2canvas
3736         *            OR rasterizeHTML: https://github.com/cburgmer/rasterizeHTML.js
3737         *
3738         * @public
3739         * @function
3740         * @param element {Mixed} HTML Element, or anything supported by html2canvas.
3741         * @param x {Number} starting X coordinate in jsPDF instance's declared units.
3742         * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
3743         * @param options {Object} Additional options, check the code below.
3744         * @param callback {Function} to call when the rendering has finished.
3745         *
3746         * NOTE: Every parameter is optional except 'element' and 'callback', in such
3747         *       case the image is positioned at 0x0 covering the whole PDF document
3748         *       size. Ie, to easily take screenshots of webpages saving them to PDF.
3749         */
3750
3751        jsPDFAPI.addHTML = function (element, x, y, options, callback) {
3752            'use strict';
3753
3754            if (typeof html2canvas === 'undefined' && typeof rasterizeHTML === 'undefined') throw new Error('You need either ' + 'https://github.com/niklasvh/html2canvas' + ' or https://github.com/cburgmer/rasterizeHTML.js');
3755
3756            if (typeof x !== 'number') {
3757                options = x;
3758                callback = y;
3759            }
3760
3761            if (typeof options === 'function') {
3762                callback = options;
3763                options = null;
3764            }
3765
3766            var I = this.internal,
3767                K = I.scaleFactor,
3768                W = I.pageSize.width,
3769                H = I.pageSize.height;
3770
3771            options = options || {};
3772            options.onrendered = function (obj) {
3773                x = parseInt(x) || 0;
3774                y = parseInt(y) || 0;
3775                var dim = options.dim || {};
3776                var h = dim.h || 0;
3777                var w = dim.w || Math.min(W, obj.width / K) - x;
3778
3779                var format = 'JPEG';
3780                if (options.format) format = options.format;
3781
3782                if (obj.height > H && options.pagesplit) {
3783                    var crop = function () {
3784                        var cy = 0;
3785                        while (1) {
3786                            var canvas = document.createElement('canvas');
3787                            canvas.width = Math.min(W * K, obj.width);
3788                            canvas.height = Math.min(H * K, obj.height - cy);
3789                            var ctx = canvas.getContext('2d');
3790                            ctx.drawImage(obj, 0, cy, obj.width, canvas.height, 0, 0, canvas.width, canvas.height);
3791                            var args = [canvas, x, cy ? 0 : y, canvas.width / K, canvas.height / K, format, null, 'SLOW'];
3792                            this.addImage.apply(this, args);
3793                            cy += canvas.height;
3794                            if (cy >= obj.height) break;
3795                            this.addPage();
3796                        }
3797                        callback(w, cy, null, args);
3798                    }.bind(this);
3799                    if (obj.nodeName === 'CANVAS') {
3800                        var img = new Image();
3801                        img.onload = crop;
3802                        img.src = obj.toDataURL("image/png");
3803                        obj = img;
3804                    } else {
3805                        crop();
3806                    }
3807                } else {
3808                    var alias = Math.random().toString(35);
3809                    var args = [obj, x, y, w, h, format, alias, 'SLOW'];
3810
3811                    this.addImage.apply(this, args);
3812
3813                    callback(w, h, alias, args);
3814                }
3815            }.bind(this);
3816
3817            if (typeof html2canvas !== 'undefined' && !options.rstz) {
3818                return html2canvas(element, options);
3819            }
3820
3821            if (typeof rasterizeHTML !== 'undefined') {
3822                var meth = 'drawDocument';
3823                if (typeof element === 'string') {
3824                    meth = /^http/.test(element) ? 'drawURL' : 'drawHTML';
3825                }
3826                options.width = options.width || W * K;
3827                return rasterizeHTML[meth](element, void 0, options).then(function (r) {
3828                    options.onrendered(r.image);
3829                }, function (e) {
3830                    callback(null, e);
3831                });
3832            }
3833
3834            return null;
3835        };
3836    })(jsPDF.API);
3837
3838    /** @preserve
3839     * jsPDF addImage plugin
3840     * Copyright (c) 2012 Jason Siefken, https://github.com/siefkenj/
3841     *               2013 Chris Dowling, https://github.com/gingerchris
3842     *               2013 Trinh Ho, https://github.com/ineedfat
3843     *               2013 Edwin Alejandro Perez, https://github.com/eaparango
3844     *               2013 Norah Smith, https://github.com/burnburnrocket
3845     *               2014 Diego Casorran, https://github.com/diegocr
3846     *               2014 James Robb, https://github.com/jamesbrobb
3847     *
3848     *
3849     */
3850
3851    ;(function (jsPDFAPI) {
3852        'use strict';
3853
3854        var namespace = 'addImage_',
3855            supported_image_types = ['jpeg', 'jpg', 'png'];
3856
3857        // Image functionality ported from pdf.js
3858        var putImage = function putImage(img) {
3859
3860                var objectNumber = this.internal.newObject(),
3861                    out = this.internal.write,
3862                    putStream = this.internal.putStream;
3863
3864                img['n'] = objectNumber;
3865
3866                out('<</Type /XObject');
3867                out('/Subtype /Image');
3868                out('/Width ' + img['w']);
3869                out('/Height ' + img['h']);
3870                if (img['cs'] === this.color_spaces.INDEXED) {
3871                    out('/ColorSpace [/Indexed /DeviceRGB '
3872                        // if an indexed png defines more than one colour with transparency, we've created a smask
3873                        + (img['pal'].length / 3 - 1) + ' ' + ('smask' in img ? objectNumber + 2 : objectNumber + 1) + ' 0 R]');
3874                } else {
3875                    out('/ColorSpace /' + img['cs']);
3876                    if (img['cs'] === this.color_spaces.DEVICE_CMYK) {
3877                        out('/Decode [1 0 1 0 1 0 1 0]');
3878                    }
3879                }
3880                out('/BitsPerComponent ' + img['bpc']);
3881                if ('f' in img) {
3882                    out('/Filter /' + img['f']);
3883                }
3884                if ('dp' in img) {
3885                    out('/DecodeParms <<' + img['dp'] + '>>');
3886                }
3887                if ('trns' in img && img['trns'].constructor == Array) {
3888                    var trns = '',
3889                        i = 0,
3890                        len = img['trns'].length;
3891                    for (; i < len; i++) {
3892                        trns += img['trns'][i] + ' ' + img['trns'][i] + ' ';
3893                    }out('/Mask [' + trns + ']');
3894                }
3895                if ('smask' in img) {
3896                    out('/SMask ' + (objectNumber + 1) + ' 0 R');
3897                }
3898                out('/Length ' + img['data'].length + '>>');
3899
3900                putStream(img['data']);
3901
3902                out('endobj');
3903
3904                // Soft mask
3905                if ('smask' in img) {
3906                    var dp = '/Predictor ' + img['p'] + ' /Colors 1 /BitsPerComponent ' + img['bpc'] + ' /Columns ' + img['w'];
3907                    var smask = { 'w': img['w'], 'h': img['h'], 'cs': 'DeviceGray', 'bpc': img['bpc'], 'dp': dp, 'data': img['smask'] };
3908                    if ('f' in img) smask.f = img['f'];
3909                    putImage.call(this, smask);
3910                }
3911
3912                //Palette
3913                if (img['cs'] === this.color_spaces.INDEXED) {
3914
3915                    this.internal.newObject();
3916                    //out('<< /Filter / ' + img['f'] +' /Length ' + img['pal'].length + '>>');
3917                    //putStream(zlib.compress(img['pal']));
3918                    out('<< /Length ' + img['pal'].length + '>>');
3919                    putStream(this.arrayBufferToBinaryString(new Uint8Array(img['pal'])));
3920                    out('endobj');
3921                }
3922            },
3923            putResourcesCallback = function putResourcesCallback() {
3924                var images = this.internal.collections[namespace + 'images'];
3925                for (var i in images) {
3926                    putImage.call(this, images[i]);
3927                }
3928            },
3929            putXObjectsDictCallback = function putXObjectsDictCallback() {
3930                var images = this.internal.collections[namespace + 'images'],
3931                    out = this.internal.write,
3932                    image;
3933                for (var i in images) {
3934                    image = images[i];
3935                    out('/I' + image['i'], image['n'], '0', 'R');
3936                }
3937            },
3938            checkCompressValue = function checkCompressValue(value) {
3939                if (value && typeof value === 'string') value = value.toUpperCase();
3940                return value in jsPDFAPI.image_compression ? value : jsPDFAPI.image_compression.NONE;
3941            },
3942            getImages = function getImages() {
3943                var images = this.internal.collections[namespace + 'images'];
3944                //first run, so initialise stuff
3945                if (!images) {
3946                    this.internal.collections[namespace + 'images'] = images = {};
3947                    this.internal.events.subscribe('putResources', putResourcesCallback);
3948                    this.internal.events.subscribe('putXobjectDict', putXObjectsDictCallback);
3949                }
3950
3951                return images;
3952            },
3953            getImageIndex = function getImageIndex(images) {
3954                var imageIndex = 0;
3955
3956                if (images) {
3957                    // this is NOT the first time this method is ran on this instance of jsPDF object.
3958                    imageIndex = Object.keys ? Object.keys(images).length : function (o) {
3959                        var i = 0;
3960                        for (var e in o) {
3961                            if (o.hasOwnProperty(e)) {
3962                                i++;
3963                            }
3964                        }
3965                        return i;
3966                    }(images);
3967                }
3968
3969                return imageIndex;
3970            },
3971            notDefined = function notDefined(value) {
3972                return typeof value === 'undefined' || value === null;
3973            },
3974            generateAliasFromData = function generateAliasFromData(data) {
3975                return typeof data === 'string' && jsPDFAPI.sHashCode(data);
3976            },
3977            doesNotSupportImageType = function doesNotSupportImageType(type) {
3978                return supported_image_types.indexOf(type) === -1;
3979            },
3980            processMethodNotEnabled = function processMethodNotEnabled(type) {
3981                return typeof jsPDFAPI['process' + type.toUpperCase()] !== 'function';
3982            },
3983            isDOMElement = function isDOMElement(object) {
3984                return (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && object.nodeType === 1;
3985            },
3986            createDataURIFromElement = function createDataURIFromElement(element, format, angle) {
3987
3988                //if element is an image which uses data url definition, just return the dataurl
3989                if (element.nodeName === 'IMG' && element.hasAttribute('src')) {
3990                    var src = '' + element.getAttribute('src');
3991                    if (!angle && src.indexOf('data:image/') === 0) return src;
3992
3993                    // only if the user doesn't care about a format
3994                    if (!format && /\.png(?:[?#].*)?$/i.test(src)) format = 'png';
3995                }
3996
3997                if (element.nodeName === 'CANVAS') {
3998                    var canvas = element;
3999                } else {
4000                    var canvas = document.createElement('canvas');
4001                    canvas.width = element.clientWidth || element.width;
4002                    canvas.height = element.clientHeight || element.height;
4003
4004                    var ctx = canvas.getContext('2d');
4005                    if (!ctx) {
4006                        throw 'addImage requires canvas to be supported by browser.';
4007                    }
4008                    if (angle) {
4009                        var x,
4010                            y,
4011                            b,
4012                            c,
4013                            s,
4014                            w,
4015                            h,
4016                            to_radians = Math.PI / 180,
4017                            angleInRadians;
4018
4019                        if ((typeof angle === 'undefined' ? 'undefined' : _typeof(angle)) === 'object') {
4020                            x = angle.x;
4021                            y = angle.y;
4022                            b = angle.bg;
4023                            angle = angle.angle;
4024                        }
4025                        angleInRadians = angle * to_radians;
4026                        c = Math.abs(Math.cos(angleInRadians));
4027                        s = Math.abs(Math.sin(angleInRadians));
4028                        w = canvas.width;
4029                        h = canvas.height;
4030                        canvas.width = h * s + w * c;
4031                        canvas.height = h * c + w * s;
4032
4033                        if (isNaN(x)) x = canvas.width / 2;
4034                        if (isNaN(y)) y = canvas.height / 2;
4035
4036                        ctx.clearRect(0, 0, canvas.width, canvas.height);
4037                        ctx.fillStyle = b || 'white';
4038                        ctx.fillRect(0, 0, canvas.width, canvas.height);
4039                        ctx.save();
4040                        ctx.translate(x, y);
4041                        ctx.rotate(angleInRadians);
4042                        ctx.drawImage(element, -(w / 2), -(h / 2));
4043                        ctx.rotate(-angleInRadians);
4044                        ctx.translate(-x, -y);
4045                        ctx.restore();
4046                    } else {
4047                        ctx.drawImage(element, 0, 0, canvas.width, canvas.height);
4048                    }
4049                }
4050                return canvas.toDataURL(('' + format).toLowerCase() == 'png' ? 'image/png' : 'image/jpeg');
4051            },
4052            checkImagesForAlias = function checkImagesForAlias(alias, images) {
4053                var cached_info;
4054                if (images) {
4055                    for (var e in images) {
4056                        if (alias === images[e].alias) {
4057                            cached_info = images[e];
4058                            break;
4059                        }
4060                    }
4061                }
4062                return cached_info;
4063            },
4064            determineWidthAndHeight = function determineWidthAndHeight(w, h, info) {
4065                if (!w && !h) {
4066                    w = -96;
4067                    h = -96;
4068                }
4069                if (w < 0) {
4070                    w = -1 * info['w'] * 72 / w / this.internal.scaleFactor;
4071                }
4072                if (h < 0) {
4073                    h = -1 * info['h'] * 72 / h / this.internal.scaleFactor;
4074                }
4075                if (w === 0) {
4076                    w = h * info['w'] / info['h'];
4077                }
4078                if (h === 0) {
4079                    h = w * info['h'] / info['w'];
4080                }
4081
4082                return [w, h];
4083            },
4084            writeImageToPDF = function writeImageToPDF(x, y, w, h, info, index, images) {
4085                var dims = determineWidthAndHeight.call(this, w, h, info),
4086                    coord = this.internal.getCoordinateString,
4087                    vcoord = this.internal.getVerticalCoordinateString;
4088
4089                w = dims[0];
4090                h = dims[1];
4091
4092                images[index] = info;
4093
4094                this.internal.write('q', coord(w), '0 0', coord(h) // TODO: check if this should be shifted by vcoord
4095                    , coord(x), vcoord(y + h), 'cm /I' + info['i'], 'Do Q');
4096            };
4097
4098        /**
4099         * COLOR SPACES
4100         */
4101        jsPDFAPI.color_spaces = {
4102            DEVICE_RGB: 'DeviceRGB',
4103            DEVICE_GRAY: 'DeviceGray',
4104            DEVICE_CMYK: 'DeviceCMYK',
4105            CAL_GREY: 'CalGray',
4106            CAL_RGB: 'CalRGB',
4107            LAB: 'Lab',
4108            ICC_BASED: 'ICCBased',
4109            INDEXED: 'Indexed',
4110            PATTERN: 'Pattern',
4111            SEPARATION: 'Separation',
4112            DEVICE_N: 'DeviceN'
4113        };
4114
4115        /**
4116         * DECODE METHODS
4117         */
4118        jsPDFAPI.decode = {
4119            DCT_DECODE: 'DCTDecode',
4120            FLATE_DECODE: 'FlateDecode',
4121            LZW_DECODE: 'LZWDecode',
4122            JPX_DECODE: 'JPXDecode',
4123            JBIG2_DECODE: 'JBIG2Decode',
4124            ASCII85_DECODE: 'ASCII85Decode',
4125            ASCII_HEX_DECODE: 'ASCIIHexDecode',
4126            RUN_LENGTH_DECODE: 'RunLengthDecode',
4127            CCITT_FAX_DECODE: 'CCITTFaxDecode'
4128        };
4129
4130        /**
4131         * IMAGE COMPRESSION TYPES
4132         */
4133        jsPDFAPI.image_compression = {
4134            NONE: 'NONE',
4135            FAST: 'FAST',
4136            MEDIUM: 'MEDIUM',
4137            SLOW: 'SLOW'
4138        };
4139
4140        jsPDFAPI.sHashCode = function (str) {
4141            return Array.prototype.reduce && str.split("").reduce(function (a, b) {
4142                a = (a << 5) - a + b.charCodeAt(0);return a & a;
4143            }, 0);
4144        };
4145
4146        jsPDFAPI.isString = function (object) {
4147            return typeof object === 'string';
4148        };
4149
4150        /**
4151         * Strips out and returns info from a valid base64 data URI
4152         * @param {String[dataURI]} a valid data URI of format 'data:[<MIME-type>][;base64],<data>'
4153         * @returns an Array containing the following
4154         * [0] the complete data URI
4155         * [1] <MIME-type>
4156         * [2] format - the second part of the mime-type i.e 'png' in 'image/png'
4157         * [4] <data>
4158         */
4159        jsPDFAPI.extractInfoFromBase64DataURI = function (dataURI) {
4160            return (/^data:([\w]+?\/([\w]+?));base64,(.+?)$/g.exec(dataURI)
4161            );
4162        };
4163
4164        /**
4165         * Check to see if ArrayBuffer is supported
4166         */
4167        jsPDFAPI.supportsArrayBuffer = function () {
4168            return typeof ArrayBuffer !== 'undefined' && typeof Uint8Array !== 'undefined';
4169        };
4170
4171        /**
4172         * Tests supplied object to determine if ArrayBuffer
4173         * @param {Object[object]}
4174         */
4175        jsPDFAPI.isArrayBuffer = function (object) {
4176            if (!this.supportsArrayBuffer()) return false;
4177            return object instanceof ArrayBuffer;
4178        };
4179
4180        /**
4181         * Tests supplied object to determine if it implements the ArrayBufferView (TypedArray) interface
4182         * @param {Object[object]}
4183         */
4184        jsPDFAPI.isArrayBufferView = function (object) {
4185            if (!this.supportsArrayBuffer()) return false;
4186            if (typeof Uint32Array === 'undefined') return false;
4187            return object instanceof Int8Array || object instanceof Uint8Array || typeof Uint8ClampedArray !== 'undefined' && object instanceof Uint8ClampedArray || object instanceof Int16Array || object instanceof Uint16Array || object instanceof Int32Array || object instanceof Uint32Array || object instanceof Float32Array || object instanceof Float64Array;
4188        };
4189
4190        /**
4191         * Exactly what it says on the tin
4192         */
4193        jsPDFAPI.binaryStringToUint8Array = function (binary_string) {
4194            /*
4195     * not sure how efficient this will be will bigger files. Is there a native method?
4196     */
4197            var len = binary_string.length;
4198            var bytes = new Uint8Array(len);
4199            for (var i = 0; i < len; i++) {
4200                bytes[i] = binary_string.charCodeAt(i);
4201            }
4202            return bytes;
4203        };
4204
4205        /**
4206         * @see this discussion
4207         * http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers
4208         *
4209         * As stated, i imagine the method below is highly inefficent for large files.
4210         *
4211         * Also of note from Mozilla,
4212         *
4213         * "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)."
4214         *
4215         * https://developer.mozilla.org/en-US/Add-ons/Code_snippets/StringView
4216         *
4217         * Although i'm strugglig to see how StringView solves this issue? Doesn't appear to be a direct method for conversion?
4218         *
4219         * Async method using Blob and FileReader could be best, but i'm not sure how to fit it into the flow?
4220         */
4221        jsPDFAPI.arrayBufferToBinaryString = function (buffer) {
4222            /*if('TextDecoder' in window){
4223    	var decoder = new TextDecoder('ascii');
4224    	return decoder.decode(buffer);
4225    }*/
4226
4227            if (this.isArrayBuffer(buffer)) buffer = new Uint8Array(buffer);
4228
4229            var binary_string = '';
4230            var len = buffer.byteLength;
4231            for (var i = 0; i < len; i++) {
4232                binary_string += String.fromCharCode(buffer[i]);
4233            }
4234            return binary_string;
4235            /*
4236     * Another solution is the method below - convert array buffer straight to base64 and then use atob
4237     */
4238            //return atob(this.arrayBufferToBase64(buffer));
4239        };
4240
4241        /**
4242         * Converts an ArrayBuffer directly to base64
4243         *
4244         * Taken from here
4245         *
4246         * http://jsperf.com/encoding-xhr-image-data/31
4247         *
4248         * Need to test if this is a better solution for larger files
4249         *
4250         */
4251        jsPDFAPI.arrayBufferToBase64 = function (arrayBuffer) {
4252            var base64 = '';
4253            var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
4254
4255            var bytes = new Uint8Array(arrayBuffer);
4256            var byteLength = bytes.byteLength;
4257            var byteRemainder = byteLength % 3;
4258            var mainLength = byteLength - byteRemainder;
4259
4260            var a, b, c, d;
4261            var chunk;
4262
4263            // Main loop deals with bytes in chunks of 3
4264            for (var i = 0; i < mainLength; i = i + 3) {
4265                // Combine the three bytes into a single integer
4266                chunk = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2];
4267
4268                // Use bitmasks to extract 6-bit segments from the triplet
4269                a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
4270                b = (chunk & 258048) >> 12; // 258048   = (2^6 - 1) << 12
4271                c = (chunk & 4032) >> 6; // 4032     = (2^6 - 1) << 6
4272                d = chunk & 63; // 63       = 2^6 - 1
4273
4274                // Convert the raw binary segments to the appropriate ASCII encoding
4275                base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
4276            }
4277
4278            // Deal with the remaining bytes and padding
4279            if (byteRemainder == 1) {
4280                chunk = bytes[mainLength];
4281
4282                a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
4283
4284                // Set the 4 least significant bits to zero
4285                b = (chunk & 3) << 4; // 3   = 2^2 - 1
4286
4287                base64 += encodings[a] + encodings[b] + '==';
4288            } else if (byteRemainder == 2) {
4289                chunk = bytes[mainLength] << 8 | bytes[mainLength + 1];
4290
4291                a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
4292                b = (chunk & 1008) >> 4; // 1008  = (2^6 - 1) << 4
4293
4294                // Set the 2 least significant bits to zero
4295                c = (chunk & 15) << 2; // 15    = 2^4 - 1
4296
4297                base64 += encodings[a] + encodings[b] + encodings[c] + '=';
4298            }
4299
4300            return base64;
4301        };
4302
4303        jsPDFAPI.createImageInfo = function (data, wd, ht, cs, bpc, f, imageIndex, alias, dp, trns, pal, smask, p) {
4304            var info = {
4305                alias: alias,
4306                w: wd,
4307                h: ht,
4308                cs: cs,
4309                bpc: bpc,
4310                i: imageIndex,
4311                data: data
4312                // n: objectNumber will be added by putImage code
4313            };
4314
4315            if (f) info.f = f;
4316            if (dp) info.dp = dp;
4317            if (trns) info.trns = trns;
4318            if (pal) info.pal = pal;
4319            if (smask) info.smask = smask;
4320            if (p) info.p = p; // predictor parameter for PNG compression
4321
4322            return info;
4323        };
4324
4325        jsPDFAPI.addImage = function (imageData, format, x, y, w, h, alias, compression, rotation) {
4326            'use strict';
4327
4328            if (typeof format !== 'string') {
4329                var tmp = h;
4330                h = w;
4331                w = y;
4332                y = x;
4333                x = format;
4334                format = tmp;
4335            }
4336
4337            if ((typeof imageData === 'undefined' ? 'undefined' : _typeof(imageData)) === 'object' && !isDOMElement(imageData) && "imageData" in imageData) {
4338                var options = imageData;
4339
4340                imageData = options.imageData;
4341                format = options.format || format;
4342                x = options.x || x || 0;
4343                y = options.y || y || 0;
4344                w = options.w || w;
4345                h = options.h || h;
4346                alias = options.alias || alias;
4347                compression = options.compression || compression;
4348                rotation = options.rotation || options.angle || rotation;
4349            }
4350
4351            if (isNaN(x) || isNaN(y)) {
4352                console.error('jsPDF.addImage: Invalid coordinates', arguments);
4353                throw new Error('Invalid coordinates passed to jsPDF.addImage');
4354            }
4355
4356            var images = getImages.call(this),
4357                info;
4358
4359            if (!(info = checkImagesForAlias(imageData, images))) {
4360                var dataAsBinaryString;
4361
4362                if (isDOMElement(imageData)) imageData = createDataURIFromElement(imageData, format, rotation);
4363
4364                if (notDefined(alias)) alias = generateAliasFromData(imageData);
4365
4366                if (!(info = checkImagesForAlias(alias, images))) {
4367
4368                    if (this.isString(imageData)) {
4369
4370                        var base64Info = this.extractInfoFromBase64DataURI(imageData);
4371
4372                        if (base64Info) {
4373
4374                            format = base64Info[2];
4375                            imageData = atob(base64Info[3]); //convert to binary string
4376                        } else {
4377
4378                            if (imageData.charCodeAt(0) === 0x89 && imageData.charCodeAt(1) === 0x50 && imageData.charCodeAt(2) === 0x4e && imageData.charCodeAt(3) === 0x47) format = 'png';
4379                        }
4380                    }
4381                    format = (format || 'JPEG').toLowerCase();
4382
4383                    if (doesNotSupportImageType(format)) throw new Error('addImage currently only supports formats ' + supported_image_types + ', not \'' + format + '\'');
4384
4385                    if (processMethodNotEnabled(format)) throw new Error('please ensure that the plugin for \'' + format + '\' support is added');
4386
4387                    /**
4388                     * need to test if it's more efficient to convert all binary strings
4389                     * to TypedArray - or should we just leave and process as string?
4390                     */
4391                    if (this.supportsArrayBuffer()) {
4392                        // no need to convert if imageData is already uint8array
4393                        if (!(imageData instanceof Uint8Array)) {
4394                            dataAsBinaryString = imageData;
4395                            imageData = this.binaryStringToUint8Array(imageData);
4396                        }
4397                    }
4398
4399                    info = this['process' + format.toUpperCase()](imageData, getImageIndex(images), alias, checkCompressValue(compression), dataAsBinaryString);
4400
4401                    if (!info) throw new Error('An unkwown error occurred whilst processing the image');
4402                }
4403            }
4404
4405            writeImageToPDF.call(this, x, y, w, h, info, info.i, images);
4406
4407            return this;
4408        };
4409
4410        /**
4411         * JPEG SUPPORT
4412         **/
4413
4414            //takes a string imgData containing the raw bytes of
4415            //a jpeg image and returns [width, height]
4416            //Algorithm from: http://www.64lines.com/jpeg-width-height
4417        var getJpegSize = function getJpegSize(imgData) {
4418                'use strict';
4419
4420                var width, height, numcomponents;
4421                // Verify we have a valid jpeg header 0xff,0xd8,0xff,0xe0,?,?,'J','F','I','F',0x00
4422                if (!imgData.charCodeAt(0) === 0xff || !imgData.charCodeAt(1) === 0xd8 || !imgData.charCodeAt(2) === 0xff || !imgData.charCodeAt(3) === 0xe0 || !imgData.charCodeAt(6) === 'J'.charCodeAt(0) || !imgData.charCodeAt(7) === 'F'.charCodeAt(0) || !imgData.charCodeAt(8) === 'I'.charCodeAt(0) || !imgData.charCodeAt(9) === 'F'.charCodeAt(0) || !imgData.charCodeAt(10) === 0x00) {
4423                    throw new Error('getJpegSize requires a binary string jpeg file');
4424                }
4425                var blockLength = imgData.charCodeAt(4) * 256 + imgData.charCodeAt(5);
4426                var i = 4,
4427                    len = imgData.length;
4428                while (i < len) {
4429                    i += blockLength;
4430                    if (imgData.charCodeAt(i) !== 0xff) {
4431                        throw new Error('getJpegSize could not find the size of the image');
4432                    }
4433                    if (imgData.charCodeAt(i + 1) === 0xc0 || //(SOF) Huffman  - Baseline DCT
4434                        imgData.charCodeAt(i + 1) === 0xc1 || //(SOF) Huffman  - Extended sequential DCT
4435                        imgData.charCodeAt(i + 1) === 0xc2 || // Progressive DCT (SOF2)
4436                        imgData.charCodeAt(i + 1) === 0xc3 || // Spatial (sequential) lossless (SOF3)
4437                        imgData.charCodeAt(i + 1) === 0xc4 || // Differential sequential DCT (SOF5)
4438                        imgData.charCodeAt(i + 1) === 0xc5 || // Differential progressive DCT (SOF6)
4439                        imgData.charCodeAt(i + 1) === 0xc6 || // Differential spatial (SOF7)
4440                        imgData.charCodeAt(i + 1) === 0xc7) {
4441                        height = imgData.charCodeAt(i + 5) * 256 + imgData.charCodeAt(i + 6);
4442                        width = imgData.charCodeAt(i + 7) * 256 + imgData.charCodeAt(i + 8);
4443                        numcomponents = imgData.charCodeAt(i + 9);
4444                        return [width, height, numcomponents];
4445                    } else {
4446                        i += 2;
4447                        blockLength = imgData.charCodeAt(i) * 256 + imgData.charCodeAt(i + 1);
4448                    }
4449                }
4450            },
4451            getJpegSizeFromBytes = function getJpegSizeFromBytes(data) {
4452
4453                var hdr = data[0] << 8 | data[1];
4454
4455                if (hdr !== 0xFFD8) throw new Error('Supplied data is not a JPEG');
4456
4457                var len = data.length,
4458                    block = (data[4] << 8) + data[5],
4459                    pos = 4,
4460                    bytes,
4461                    width,
4462                    height,
4463                    numcomponents;
4464
4465                while (pos < len) {
4466                    pos += block;
4467                    bytes = readBytes(data, pos);
4468                    block = (bytes[2] << 8) + bytes[3];
4469                    if ((bytes[1] === 0xC0 || bytes[1] === 0xC2) && bytes[0] === 0xFF && block > 7) {
4470                        bytes = readBytes(data, pos + 5);
4471                        width = (bytes[2] << 8) + bytes[3];
4472                        height = (bytes[0] << 8) + bytes[1];
4473                        numcomponents = bytes[4];
4474                        return { width: width, height: height, numcomponents: numcomponents };
4475                    }
4476
4477                    pos += 2;
4478                }
4479
4480                throw new Error('getJpegSizeFromBytes could not find the size of the image');
4481            },
4482            readBytes = function readBytes(data, offset) {
4483                return data.subarray(offset, offset + 5);
4484            };
4485
4486        jsPDFAPI.processJPEG = function (data, index, alias, compression, dataAsBinaryString) {
4487            'use strict';
4488
4489            var colorSpace = this.color_spaces.DEVICE_RGB,
4490                filter = this.decode.DCT_DECODE,
4491                bpc = 8,
4492                dims;
4493
4494            if (this.isString(data)) {
4495                dims = getJpegSize(data);
4496                return this.createImageInfo(data, dims[0], dims[1], dims[3] == 1 ? this.color_spaces.DEVICE_GRAY : colorSpace, bpc, filter, index, alias);
4497            }
4498
4499            if (this.isArrayBuffer(data)) data = new Uint8Array(data);
4500
4501            if (this.isArrayBufferView(data)) {
4502
4503                dims = getJpegSizeFromBytes(data);
4504
4505                // if we already have a stored binary string rep use that
4506                data = dataAsBinaryString || this.arrayBufferToBinaryString(data);
4507
4508                return this.createImageInfo(data, dims.width, dims.height, dims.numcomponents == 1 ? this.color_spaces.DEVICE_GRAY : colorSpace, bpc, filter, index, alias);
4509            }
4510
4511            return null;
4512        };
4513
4514        jsPDFAPI.processJPG = function () /*data, index, alias, compression, dataAsBinaryString*/{
4515            return this.processJPEG.apply(this, arguments);
4516        };
4517    })(jsPDF.API);
4518
4519    /**
4520     * jsPDF Annotations PlugIn
4521     * Copyright (c) 2014 Steven Spungin (TwelveTone LLC)  [email protected]
4522     *
4523     * Licensed under the MIT License.
4524     * http://opensource.org/licenses/mit-license
4525     */
4526
4527    /**
4528     * There are many types of annotations in a PDF document. Annotations are placed
4529     * on a page at a particular location. They are not 'attached' to an object.
4530     * <br />
4531     * This plugin current supports <br />
4532     * <li> Goto Page (set pageNumber and top in options)
4533     * <li> Goto Name (set name and top in options)
4534     * <li> Goto URL (set url in options)
4535     * <p>
4536     * 	The destination magnification factor can also be specified when goto is a page number or a named destination. (see documentation below)
4537     *  (set magFactor in options).  XYZ is the default.
4538     * </p>
4539     * <p>
4540     *  Links, Text, Popup, and FreeText are supported.
4541     * </p>
4542     * <p>
4543     * Options In PDF spec Not Implemented Yet
4544     * <li> link border
4545     * <li> named target
4546     * <li> page coordinates
4547     * <li> destination page scaling and layout
4548     * <li> actions other than URL and GotoPage
4549     * <li> background / hover actions
4550     * </p>
4551     */
4552
4553    /*
4554      Destination Magnification Factors
4555      See PDF 1.3 Page 386 for meanings and options
4556
4557      [supported]
4558  	XYZ (options; left top zoom)
4559  	Fit (no options)
4560  	FitH (options: top)
4561  	FitV (options: left)
4562
4563  	[not supported]
4564  	FitR
4565  	FitB
4566  	FitBH
4567  	FitBV
4568   */
4569
4570    (function (jsPDFAPI) {
4571        'use strict';
4572
4573        var annotationPlugin = {
4574
4575            /**
4576             * An array of arrays, indexed by <em>pageNumber</em>.
4577             */
4578            annotations: [],
4579
4580            f2: function f2(number) {
4581                return number.toFixed(2);
4582            },
4583
4584            notEmpty: function notEmpty(obj) {
4585                if (typeof obj != 'undefined') {
4586                    if (obj != '') {
4587                        return true;
4588                    }
4589                }
4590            }
4591        };
4592
4593        jsPDF.API.annotationPlugin = annotationPlugin;
4594
4595        jsPDF.API.events.push(['addPage', function (info) {
4596            this.annotationPlugin.annotations[info.pageNumber] = [];
4597        }]);
4598
4599        jsPDFAPI.events.push(['putPage', function (info) {
4600            //TODO store annotations in pageContext so reorder/remove will not affect them.
4601            var pageAnnos = this.annotationPlugin.annotations[info.pageNumber];
4602
4603            var found = false;
4604            for (var a = 0; a < pageAnnos.length && !found; a++) {
4605                var anno = pageAnnos[a];
4606                switch (anno.type) {
4607                    case 'link':
4608                        if (annotationPlugin.notEmpty(anno.options.url) || annotationPlugin.notEmpty(anno.options.pageNumber)) {
4609                            found = true;
4610                            break;
4611                        }
4612                    case 'reference':
4613                    case 'text':
4614                    case 'freetext':
4615                        found = true;
4616                        break;
4617                }
4618            }
4619            if (found == false) {
4620                return;
4621            }
4622
4623            this.internal.write("/Annots [");
4624            var f2 = this.annotationPlugin.f2;
4625            var k = this.internal.scaleFactor;
4626            var pageHeight = this.internal.pageSize.height;
4627            var pageInfo = this.internal.getPageInfo(info.pageNumber);
4628            for (var a = 0; a < pageAnnos.length; a++) {
4629                var anno = pageAnnos[a];
4630
4631                switch (anno.type) {
4632                    case 'reference':
4633                        // References to Widget Anotations (for AcroForm Fields)
4634                        this.internal.write(' ' + anno.object.objId + ' 0 R ');
4635                        break;
4636                    case 'text':
4637                        // Create a an object for both the text and the popup
4638                        var objText = this.internal.newAdditionalObject();
4639                        var objPopup = this.internal.newAdditionalObject();
4640
4641                        var title = anno.title || 'Note';
4642                        var rect = "/Rect [" + f2(anno.bounds.x * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + " " + f2((anno.bounds.x + anno.bounds.w) * k) + " " + f2((pageHeight - anno.bounds.y) * k) + "] ";
4643                        line = '<</Type /Annot /Subtype /' + 'Text' + ' ' + rect + '/Contents (' + anno.contents + ')';
4644                        line += ' /Popup ' + objPopup.objId + " 0 R";
4645                        line += ' /P ' + pageInfo.objId + " 0 R";
4646                        line += ' /T (' + title + ') >>';
4647                        objText.content = line;
4648
4649                        var parent = objText.objId + ' 0 R';
4650                        var popoff = 30;
4651                        var rect = "/Rect [" + f2((anno.bounds.x + popoff) * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + " " + f2((anno.bounds.x + anno.bounds.w + popoff) * k) + " " + f2((pageHeight - anno.bounds.y) * k) + "] ";
4652                        //var rect2 = "/Rect [" + f2(anno.bounds.x * k) + " " + f2((pageHeight - anno.bounds.y) * k) + " " + f2(anno.bounds.x + anno.bounds.w * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + "] ";
4653                        line = '<</Type /Annot /Subtype /' + 'Popup' + ' ' + rect + ' /Parent ' + parent;
4654                        if (anno.open) {
4655                            line += ' /Open true';
4656                        }
4657                        line += ' >>';
4658                        objPopup.content = line;
4659
4660                        this.internal.write(objText.objId, '0 R', objPopup.objId, '0 R');
4661
4662                        break;
4663                    case 'freetext':
4664                        var rect = "/Rect [" + f2(anno.bounds.x * k) + " " + f2((pageHeight - anno.bounds.y) * k) + " " + f2(anno.bounds.x + anno.bounds.w * k) + " " + f2(pageHeight - (anno.bounds.y + anno.bounds.h) * k) + "] ";
4665                        var color = anno.color || '#000000';
4666                        line = '<</Type /Annot /Subtype /' + 'FreeText' + ' ' + rect + '/Contents (' + anno.contents + ')';
4667                        line += ' /DS(font: Helvetica,sans-serif 12.0pt; text-align:left; color:#' + color + ')';
4668                        line += ' /Border [0 0 0]';
4669                        line += ' >>';
4670                        this.internal.write(line);
4671                        break;
4672                    case 'link':
4673                        if (anno.options.name) {
4674                            var loc = this.annotations._nameMap[anno.options.name];
4675                            anno.options.pageNumber = loc.page;
4676                            anno.options.top = loc.y;
4677                        } else {
4678                            if (!anno.options.top) {
4679                                anno.options.top = 0;
4680                            }
4681                        }
4682
4683                        //var pageHeight = this.internal.pageSize.height * this.internal.scaleFactor;
4684                        var rect = "/Rect [" + f2(anno.x * k) + " " + f2((pageHeight - anno.y) * k) + " " + f2(anno.x + anno.w * k) + " " + f2(pageHeight - (anno.y + anno.h) * k) + "] ";
4685
4686                        var line = '';
4687                        if (anno.options.url) {
4688                            line = '<</Type /Annot /Subtype /Link ' + rect + '/Border [0 0 0] /A <</S /URI /URI (' + anno.options.url + ') >>';
4689                        } else if (anno.options.pageNumber) {
4690                            // first page is 0
4691                            var info = this.internal.getPageInfo(anno.options.pageNumber);
4692                            line = '<</Type /Annot /Subtype /Link ' + rect + '/Border [0 0 0] /Dest [' + info.objId + " 0 R";
4693                            anno.options.magFactor = anno.options.magFactor || "XYZ";
4694                            switch (anno.options.magFactor) {
4695                                case 'Fit':
4696                                    line += ' /Fit]';
4697                                    break;
4698                                case 'FitH':
4699                                    //anno.options.top = anno.options.top || f2(pageHeight * k);
4700                                    line += ' /FitH ' + anno.options.top + ']';
4701                                    break;
4702                                case 'FitV':
4703                                    anno.options.left = anno.options.left || 0;
4704                                    line += ' /FitV ' + anno.options.left + ']';
4705                                    break;
4706                                case 'XYZ':
4707                                default:
4708                                    var top = f2((pageHeight - anno.options.top) * k); // || f2(pageHeight * k);
4709                                    anno.options.left = anno.options.left || 0;
4710                                    // 0 or null zoom will not change zoom factor
4711                                    if (typeof anno.options.zoom === 'undefined') {
4712                                        anno.options.zoom = 0;
4713                                    }
4714                                    line += ' /XYZ ' + anno.options.left + ' ' + top + ' ' + anno.options.zoom + ']';
4715                                    break;
4716                            }
4717                        } else {
4718                            // TODO error - should not be here
4719                        }
4720                        if (line != '') {
4721                            line += " >>";
4722                            this.internal.write(line);
4723                        }
4724                        break;
4725                }
4726            }
4727            this.internal.write("]");
4728        }]);
4729
4730        jsPDFAPI.createAnnotation = function (options) {
4731            switch (options.type) {
4732                case 'link':
4733                    this.link(options.bounds.x, options.bounds.y, options.bounds.w, options.bounds.h, options);
4734                    break;
4735                case 'text':
4736                case 'freetext':
4737                    this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push(options);
4738                    break;
4739            }
4740        };
4741
4742        /**
4743         * valid options
4744         * <li> pageNumber or url [required]
4745         * <p>If pageNumber is specified, top and zoom may also be specified</p>
4746         */
4747        jsPDFAPI.link = function (x, y, w, h, options) {
4748            'use strict';
4749
4750            this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push({
4751                x: x,
4752                y: y,
4753                w: w,
4754                h: h,
4755                options: options,
4756                type: 'link'
4757            });
4758        };
4759
4760        /**
4761         * valid options
4762         * <li> pageNumber or url [required]
4763         * <p>If pageNumber is specified, top and zoom may also be specified</p>
4764         */
4765        jsPDFAPI.link = function (x, y, w, h, options) {
4766            'use strict';
4767
4768            this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push({
4769                x: x,
4770                y: y,
4771                w: w,
4772                h: h,
4773                options: options,
4774                type: 'link'
4775            });
4776        };
4777
4778        /**
4779         * Currently only supports single line text.
4780         * Returns the width of the text/link
4781         */
4782        jsPDFAPI.textWithLink = function (text, x, y, options) {
4783            'use strict';
4784
4785            var width = this.getTextWidth(text);
4786            var height = this.internal.getLineHeight();
4787            this.text(text, x, y);
4788            //TODO We really need the text baseline height to do this correctly.
4789            // Or ability to draw text on top, bottom, center, or baseline.
4790            y += height * .2;
4791            this.link(x, y - height, width, height, options);
4792            return width;
4793        };
4794
4795        //TODO move into external library
4796        jsPDFAPI.getTextWidth = function (text) {
4797            'use strict';
4798
4799            var fontSize = this.internal.getFontSize();
4800            var txtWidth = this.getStringUnitWidth(text) * fontSize / this.internal.scaleFactor;
4801            return txtWidth;
4802        };
4803
4804        //TODO move into external library
4805        jsPDFAPI.getLineHeight = function () {
4806            return this.internal.getLineHeight();
4807        };
4808
4809        return this;
4810    })(jsPDF.API);
4811
4812    /**
4813     * jsPDF Autoprint Plugin
4814     *
4815     * Licensed under the MIT License.
4816     * http://opensource.org/licenses/mit-license
4817     */
4818
4819    (function (jsPDFAPI) {
4820        'use strict';
4821
4822        jsPDFAPI.autoPrint = function () {
4823            'use strict';
4824
4825            var refAutoPrintTag;
4826
4827            this.internal.events.subscribe('postPutResources', function () {
4828                refAutoPrintTag = this.internal.newObject();
4829                this.internal.write("<< /S/Named /Type/Action /N/Print >>", "endobj");
4830            });
4831
4832            this.internal.events.subscribe("putCatalog", function () {
4833                this.internal.write("/OpenAction " + refAutoPrintTag + " 0" + " R");
4834            });
4835            return this;
4836        };
4837    })(jsPDF.API);
4838
4839    /**
4840     * jsPDF Canvas PlugIn
4841     * Copyright (c) 2014 Steven Spungin (TwelveTone LLC)  [email protected]
4842     *
4843     * Licensed under the MIT License.
4844     * http://opensource.org/licenses/mit-license
4845     */
4846
4847    /**
4848     * This plugin mimics the HTML5 Canvas
4849     *
4850     * The goal is to provide a way for current canvas users to print directly to a PDF.
4851     */
4852
4853    (function (jsPDFAPI) {
4854        'use strict';
4855
4856        jsPDFAPI.events.push(['initialized', function () {
4857            this.canvas.pdf = this;
4858        }]);
4859
4860        jsPDFAPI.canvas = {
4861            getContext: function getContext(name) {
4862                this.pdf.context2d._canvas = this;
4863                return this.pdf.context2d;
4864            },
4865            style: {}
4866        };
4867
4868        Object.defineProperty(jsPDFAPI.canvas, 'width', {
4869            get: function get() {
4870                return this._width;
4871            },
4872            set: function set(value) {
4873                this._width = value;
4874                this.getContext('2d').pageWrapX = value + 1;
4875            }
4876        });
4877
4878        Object.defineProperty(jsPDFAPI.canvas, 'height', {
4879            get: function get() {
4880                return this._height;
4881            },
4882            set: function set(value) {
4883                this._height = value;
4884                this.getContext('2d').pageWrapY = value + 1;
4885            }
4886        });
4887
4888        return this;
4889    })(jsPDF.API);
4890
4891    /** ====================================================================
4892     * jsPDF Cell plugin
4893     * Copyright (c) 2013 Youssef Beddad, [email protected]
4894     *               2013 Eduardo Menezes de Morais, [email protected]
4895     *               2013 Lee Driscoll, https://github.com/lsdriscoll
4896     *               2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
4897     *               2014 James Hall, [email protected]
4898     *               2014 Diego Casorran, https://github.com/diegocr
4899     *
4900     *
4901     * ====================================================================
4902     */
4903
4904    (function (jsPDFAPI) {
4905        'use strict';
4906        /*jslint browser:true */
4907        /*global document: false, jsPDF */
4908
4909        var fontName,
4910            fontSize,
4911            fontStyle,
4912            padding = 3,
4913            margin = 13,
4914            headerFunction,
4915            lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined },
4916            pages = 1,
4917            setLastCellPosition = function setLastCellPosition(x, y, w, h, ln) {
4918                lastCellPos = { 'x': x, 'y': y, 'w': w, 'h': h, 'ln': ln };
4919            },
4920            getLastCellPosition = function getLastCellPosition() {
4921                return lastCellPos;
4922            },
4923            NO_MARGINS = { left: 0, top: 0, bottom: 0 };
4924
4925        jsPDFAPI.setHeaderFunction = function (func) {
4926            headerFunction = func;
4927        };
4928
4929        jsPDFAPI.getTextDimensions = function (txt) {
4930            fontName = this.internal.getFont().fontName;
4931            fontSize = this.table_font_size || this.internal.getFontSize();
4932            fontStyle = this.internal.getFont().fontStyle;
4933            // 1 pixel = 0.264583 mm and 1 mm = 72/25.4 point
4934            var px2pt = 0.264583 * 72 / 25.4,
4935                dimensions,
4936                text;
4937
4938            text = document.createElement('font');
4939            text.id = "jsPDFCell";
4940
4941            try {
4942                text.style.fontStyle = fontStyle;
4943            } catch (e) {
4944                text.style.fontWeight = fontStyle;
4945            }
4946
4947            text.style.fontName = fontName;
4948            text.style.fontSize = fontSize + 'pt';
4949            try {
4950                text.textContent = txt;
4951            } catch (e) {
4952                text.innerText = txt;
4953            }
4954
4955            document.body.appendChild(text);
4956
4957            dimensions = { w: (text.offsetWidth + 1) * px2pt, h: (text.offsetHeight + 1) * px2pt };
4958
4959            document.body.removeChild(text);
4960
4961            return dimensions;
4962        };
4963
4964        jsPDFAPI.cellAddPage = function () {
4965            var margins = this.margins || NO_MARGINS;
4966
4967            this.addPage();
4968
4969            setLastCellPosition(margins.left, margins.top, undefined, undefined);
4970            //setLastCellPosition(undefined, undefined, undefined, undefined, undefined);
4971            pages += 1;
4972        };
4973
4974        jsPDFAPI.cellInitialize = function () {
4975            lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined };
4976            pages = 1;
4977        };
4978
4979        jsPDFAPI.cell = function (x, y, w, h, txt, ln, align) {
4980            var curCell = getLastCellPosition();
4981            var pgAdded = false;
4982
4983            // If this is not the first cell, we must change its position
4984            if (curCell.ln !== undefined) {
4985                if (curCell.ln === ln) {
4986                    //Same line
4987                    x = curCell.x + curCell.w;
4988                    y = curCell.y;
4989                } else {
4990                    //New line
4991                    var margins = this.margins || NO_MARGINS;
4992                    if (curCell.y + curCell.h + h + margin >= this.internal.pageSize.height - margins.bottom) {
4993                        this.cellAddPage();
4994                        pgAdded = true;
4995                        if (this.printHeaders && this.tableHeaderRow) {
4996                            this.printHeaderRow(ln, true);
4997                        }
4998                    }
4999                    //We ignore the passed y: the lines may have different heights
5000                    y = getLastCellPosition().y + getLastCellPosition().h;
5001                    if (pgAdded) y = margin + 10;
5002                }
5003            }
5004
5005            if (txt[0] !== undefined) {
5006                if (this.printingHeaderRow) {
5007                    this.rect(x, y, w, h, 'FD');
5008                } else {
5009                    this.rect(x, y, w, h);
5010                }
5011                if (align === 'right') {
5012                    if (!(txt instanceof Array)) {
5013                        txt = [txt];
5014                    }
5015                    for (var i = 0; i < txt.length; i++) {
5016                        var currentLine = txt[i];
5017                        var textSize = this.getStringUnitWidth(currentLine) * this.internal.getFontSize();
5018                        this.text(currentLine, x + w - textSize - padding, y + this.internal.getLineHeight() * (i + 1));
5019                    }
5020                } else {
5021                    this.text(txt, x + padding, y + this.internal.getLineHeight());
5022                }
5023            }
5024            setLastCellPosition(x, y, w, h, ln);
5025            return this;
5026        };
5027
5028        /**
5029         * Return the maximum value from an array
5030         * @param array
5031         * @param comparisonFn
5032         * @returns {*}
5033         */
5034        jsPDFAPI.arrayMax = function (array, comparisonFn) {
5035            var max = array[0],
5036                i,
5037                ln,
5038                item;
5039
5040            for (i = 0, ln = array.length; i < ln; i += 1) {
5041                item = array[i];
5042
5043                if (comparisonFn) {
5044                    if (comparisonFn(max, item) === -1) {
5045                        max = item;
5046                    }
5047                } else {
5048                    if (item > max) {
5049                        max = item;
5050                    }
5051                }
5052            }
5053
5054            return max;
5055        };
5056
5057        /**
5058         * Create a table from a set of data.
5059         * @param {Integer} [x] : left-position for top-left corner of table
5060         * @param {Integer} [y] top-position for top-left corner of table
5061         * @param {Object[]} [data] As array of objects containing key-value pairs corresponding to a row of data.
5062         * @param {String[]} [headers] Omit or null to auto-generate headers at a performance cost
5063         * @param {Object} [config.printHeaders] True to print column headers at the top of every page
5064         * @param {Object} [config.autoSize] True to dynamically set the column widths to match the widest cell value
5065         * @param {Object} [config.margins] margin values for left, top, bottom, and width
5066         * @param {Object} [config.fontSize] Integer fontSize to use (optional)
5067         */
5068
5069        jsPDFAPI.table = function (x, y, data, headers, config) {
5070            if (!data) {
5071                throw 'No data for PDF table';
5072            }
5073
5074            var headerNames = [],
5075                headerPrompts = [],
5076                header,
5077                i,
5078                ln,
5079                cln,
5080                columnMatrix = {},
5081                columnWidths = {},
5082                columnData,
5083                column,
5084                columnMinWidths = [],
5085                j,
5086                tableHeaderConfigs = [],
5087                model,
5088                jln,
5089                func,
5090
5091
5092                //set up defaults. If a value is provided in config, defaults will be overwritten:
5093                autoSize = false,
5094                printHeaders = true,
5095                fontSize = 12,
5096                margins = NO_MARGINS;
5097
5098            margins.width = this.internal.pageSize.width;
5099
5100            if (config) {
5101                //override config defaults if the user has specified non-default behavior:
5102                if (config.autoSize === true) {
5103                    autoSize = true;
5104                }
5105                if (config.printHeaders === false) {
5106                    printHeaders = false;
5107                }
5108                if (config.fontSize) {
5109                    fontSize = config.fontSize;
5110                }
5111                if (config.css && typeof config.css['font-size'] !== "undefined") {
5112                    fontSize = config.css['font-size'] * 16;
5113                }
5114                if (config.margins) {
5115                    margins = config.margins;
5116                }
5117            }
5118
5119            /**
5120             * @property {Number} lnMod
5121             * Keep track of the current line number modifier used when creating cells
5122             */
5123            this.lnMod = 0;
5124            lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined }, pages = 1;
5125
5126            this.printHeaders = printHeaders;
5127            this.margins = margins;
5128            this.setFontSize(fontSize);
5129            this.table_font_size = fontSize;
5130
5131            // Set header values
5132            if (headers === undefined || headers === null) {
5133                // No headers defined so we derive from data
5134                headerNames = Object.keys(data[0]);
5135            } else if (headers[0] && typeof headers[0] !== 'string') {
5136                var px2pt = 0.264583 * 72 / 25.4;
5137
5138                // Split header configs into names and prompts
5139                for (i = 0, ln = headers.length; i < ln; i += 1) {
5140                    header = headers[i];
5141                    headerNames.push(header.name);
5142                    headerPrompts.push(header.prompt);
5143                    columnWidths[header.name] = header.width * px2pt;
5144                }
5145            } else {
5146                headerNames = headers;
5147            }
5148
5149            if (autoSize) {
5150                // Create a matrix of columns e.g., {column_title: [row1_Record, row2_Record]}
5151                func = function func(rec) {
5152                    return rec[header];
5153                };
5154
5155                for (i = 0, ln = headerNames.length; i < ln; i += 1) {
5156                    header = headerNames[i];
5157
5158                    columnMatrix[header] = data.map(func);
5159
5160                    // get header width
5161                    columnMinWidths.push(this.getTextDimensions(headerPrompts[i] || header).w);
5162                    column = columnMatrix[header];
5163
5164                    // get cell widths
5165                    for (j = 0, cln = column.length; j < cln; j += 1) {
5166                        columnData = column[j];
5167                        columnMinWidths.push(this.getTextDimensions(columnData).w);
5168                    }
5169
5170                    // get final column width
5171                    columnWidths[header] = jsPDFAPI.arrayMax(columnMinWidths);
5172
5173                    //have to reset
5174                    columnMinWidths = [];
5175                }
5176            }
5177
5178            // -- Construct the table
5179
5180            if (printHeaders) {
5181                var lineHeight = this.calculateLineHeight(headerNames, columnWidths, headerPrompts.length ? headerPrompts : headerNames);
5182
5183                // Construct the header row
5184                for (i = 0, ln = headerNames.length; i < ln; i += 1) {
5185                    header = headerNames[i];
5186                    tableHeaderConfigs.push([x, y, columnWidths[header], lineHeight, String(headerPrompts.length ? headerPrompts[i] : header)]);
5187                }
5188
5189                // Store the table header config
5190                this.setTableHeaderRow(tableHeaderConfigs);
5191
5192                // Print the header for the start of the table
5193                this.printHeaderRow(1, false);
5194            }
5195
5196            // Construct the data rows
5197            for (i = 0, ln = data.length; i < ln; i += 1) {
5198                var lineHeight;
5199                model = data[i];
5200                lineHeight = this.calculateLineHeight(headerNames, columnWidths, model);
5201
5202                for (j = 0, jln = headerNames.length; j < jln; j += 1) {
5203                    header = headerNames[j];
5204                    this.cell(x, y, columnWidths[header], lineHeight, model[header], i + 2, header.align);
5205                }
5206            }
5207            this.lastCellPos = lastCellPos;
5208            this.table_x = x;
5209            this.table_y = y;
5210            return this;
5211        };
5212        /**
5213         * Calculate the height for containing the highest column
5214         * @param {String[]} headerNames is the header, used as keys to the data
5215         * @param {Integer[]} columnWidths is size of each column
5216         * @param {Object[]} model is the line of data we want to calculate the height of
5217         */
5218        jsPDFAPI.calculateLineHeight = function (headerNames, columnWidths, model) {
5219            var header,
5220                lineHeight = 0;
5221            for (var j = 0; j < headerNames.length; j++) {
5222                header = headerNames[j];
5223                model[header] = this.splitTextToSize(String(model[header]), columnWidths[header] - padding);
5224                var h = this.internal.getLineHeight() * model[header].length + padding;
5225                if (h > lineHeight) lineHeight = h;
5226            }
5227            return lineHeight;
5228        };
5229
5230        /**
5231         * Store the config for outputting a table header
5232         * @param {Object[]} config
5233         * An array of cell configs that would define a header row: Each config matches the config used by jsPDFAPI.cell
5234         * except the ln parameter is excluded
5235         */
5236        jsPDFAPI.setTableHeaderRow = function (config) {
5237            this.tableHeaderRow = config;
5238        };
5239
5240        /**
5241         * Output the store header row
5242         * @param lineNumber The line number to output the header at
5243         */
5244        jsPDFAPI.printHeaderRow = function (lineNumber, new_page) {
5245            if (!this.tableHeaderRow) {
5246                throw 'Property tableHeaderRow does not exist.';
5247            }
5248
5249            var tableHeaderCell, tmpArray, i, ln;
5250
5251            this.printingHeaderRow = true;
5252            if (headerFunction !== undefined) {
5253                var position = headerFunction(this, pages);
5254                setLastCellPosition(position[0], position[1], position[2], position[3], -1);
5255            }
5256            this.setFontStyle('bold');
5257            var tempHeaderConf = [];
5258            for (i = 0, ln = this.tableHeaderRow.length; i < ln; i += 1) {
5259                this.setFillColor(200, 200, 200);
5260
5261                tableHeaderCell = this.tableHeaderRow[i];
5262                if (new_page) {
5263                    this.margins.top = margin;
5264                    tableHeaderCell[1] = this.margins && this.margins.top || 0;
5265                    tempHeaderConf.push(tableHeaderCell);
5266                }
5267                tmpArray = [].concat(tableHeaderCell);
5268                this.cell.apply(this, tmpArray.concat(lineNumber));
5269            }
5270            if (tempHeaderConf.length > 0) {
5271                this.setTableHeaderRow(tempHeaderConf);
5272            }
5273            this.setFontStyle('normal');
5274            this.printingHeaderRow = false;
5275        };
5276    })(jsPDF.API);
5277
5278    /**
5279     * jsPDF Context2D PlugIn Copyright (c) 2014 Steven Spungin (TwelveTone LLC) [email protected]
5280     *
5281     * Licensed under the MIT License. http://opensource.org/licenses/mit-license
5282     */
5283
5284    /**
5285     * This plugin mimics the HTML5 Canvas's context2d.
5286     *
5287     * The goal is to provide a way for current canvas implementations to print directly to a PDF.
5288     */
5289
5290    /**
5291     * TODO implement stroke opacity (refactor from fill() method )
5292     * TODO transform angle and radii parameters
5293     */
5294
5295    /**
5296     * require('jspdf.js'); require('lib/css_colors.js');
5297     */
5298
5299    (function (jsPDFAPI) {
5300        'use strict';
5301
5302        jsPDFAPI.events.push(['initialized', function () {
5303            this.context2d.pdf = this;
5304            this.context2d.internal.pdf = this;
5305            this.context2d.ctx = new context();
5306            this.context2d.ctxStack = [];
5307            this.context2d.path = [];
5308        }]);
5309
5310        jsPDFAPI.context2d = {
5311            pageWrapXEnabled: false,
5312            pageWrapYEnabled: false,
5313            pageWrapX: 9999999,
5314            pageWrapY: 9999999,
5315            ctx: new context(),
5316            f2: function f2(number) {
5317                return number.toFixed(2);
5318            },
5319
5320            fillRect: function fillRect(x, y, w, h) {
5321                if (this._isFillTransparent()) {
5322                    return;
5323                }
5324                x = this._wrapX(x);
5325                y = this._wrapY(y);
5326
5327                var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h });
5328                this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "f");
5329            },
5330
5331            strokeRect: function strokeRect(x, y, w, h) {
5332                if (this._isStrokeTransparent()) {
5333                    return;
5334                }
5335                x = this._wrapX(x);
5336                y = this._wrapY(y);
5337
5338                var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h });
5339                this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "s");
5340            },
5341
5342            /**
5343             * We cannot clear PDF commands that were already written to PDF, so we use white instead. <br />
5344             * As a special case, read a special flag (ignoreClearRect) and do nothing if it is set.
5345             * This results in all calls to clearRect() to do nothing, and keep the canvas transparent.
5346             * This flag is stored in the save/restore context and is managed the same way as other drawing states.
5347             * @param x
5348             * @param y
5349             * @param w
5350             * @param h
5351             */
5352            clearRect: function clearRect(x, y, w, h) {
5353                if (this.ctx.ignoreClearRect) {
5354                    return;
5355                }
5356
5357                x = this._wrapX(x);
5358                y = this._wrapY(y);
5359
5360                var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h });
5361                this.save();
5362                this.setFillStyle('#ffffff');
5363                //TODO This is hack to fill with white.
5364                this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "f");
5365                this.restore();
5366            },
5367
5368            save: function save() {
5369                this.ctx._fontSize = this.pdf.internal.getFontSize();
5370                var ctx = new context();
5371                ctx.copy(this.ctx);
5372                this.ctxStack.push(this.ctx);
5373                this.ctx = ctx;
5374            },
5375
5376            restore: function restore() {
5377                this.ctx = this.ctxStack.pop();
5378                this.setFillStyle(this.ctx.fillStyle);
5379                this.setStrokeStyle(this.ctx.strokeStyle);
5380                this.setFont(this.ctx.font);
5381                this.pdf.setFontSize(this.ctx._fontSize);
5382                this.setLineCap(this.ctx.lineCap);
5383                this.setLineWidth(this.ctx.lineWidth);
5384                this.setLineJoin(this.ctx.lineJoin);
5385            },
5386
5387            rect: function rect(x, y, w, h) {
5388                this.moveTo(x, y);
5389                this.lineTo(x + w, y);
5390                this.lineTo(x + w, y + h);
5391                this.lineTo(x, y + h);
5392                this.lineTo(x, y); //TODO not needed
5393                this.closePath();
5394            },
5395
5396            beginPath: function beginPath() {
5397                this.path = [];
5398            },
5399
5400            closePath: function closePath() {
5401                this.path.push({
5402                    type: 'close'
5403                });
5404            },
5405
5406            _getRgba: function _getRgba(style) {
5407                // get the decimal values of r, g, and b;
5408                var rgba = {};
5409
5410                if (this.internal.rxTransparent.test(style)) {
5411                    rgba.r = 0;
5412                    rgba.g = 0;
5413                    rgba.b = 0;
5414                    rgba.a = 0;
5415                } else {
5416                    var m = this.internal.rxRgb.exec(style);
5417                    if (m != null) {
5418                        rgba.r = parseInt(m[1]);
5419                        rgba.g = parseInt(m[2]);
5420                        rgba.b = parseInt(m[3]);
5421                        rgba.a = 1;
5422                    } else {
5423                        m = this.internal.rxRgba.exec(style);
5424                        if (m != null) {
5425                            rgba.r = parseInt(m[1]);
5426                            rgba.g = parseInt(m[2]);
5427                            rgba.b = parseInt(m[3]);
5428                            rgba.a = parseFloat(m[4]);
5429                        } else {
5430                            rgba.a = 1;
5431                            if (style.charAt(0) != '#') {
5432                                style = CssColors.colorNameToHex(style);
5433                                if (!style) {
5434                                    style = '#000000';
5435                                }
5436                            } else {}
5437
5438                            if (style.length === 4) {
5439                                rgba.r = style.substring(1, 2);
5440                                rgba.r += r;
5441                                rgba.g = style.substring(2, 3);
5442                                rgba.g += g;
5443                                rgba.b = style.substring(3, 4);
5444                                rgba.b += b;
5445                            } else {
5446                                rgba.r = style.substring(1, 3);
5447                                rgba.g = style.substring(3, 5);
5448                                rgba.b = style.substring(5, 7);
5449                            }
5450                            rgba.r = parseInt(rgba.r, 16);
5451                            rgba.g = parseInt(rgba.g, 16);
5452                            rgba.b = parseInt(rgba.b, 16);
5453                        }
5454                    }
5455                }
5456                rgba.style = style;
5457                return rgba;
5458            },
5459
5460            setFillStyle: function setFillStyle(style) {
5461                // get the decimal values of r, g, and b;
5462                var r, g, b, a;
5463
5464                if (this.internal.rxTransparent.test(style)) {
5465                    r = 0;
5466                    g = 0;
5467                    b = 0;
5468                    a = 0;
5469                } else {
5470                    var m = this.internal.rxRgb.exec(style);
5471                    if (m != null) {
5472                        r = parseInt(m[1]);
5473                        g = parseInt(m[2]);
5474                        b = parseInt(m[3]);
5475                        a = 1;
5476                    } else {
5477                        m = this.internal.rxRgba.exec(style);
5478                        if (m != null) {
5479                            r = parseInt(m[1]);
5480                            g = parseInt(m[2]);
5481                            b = parseInt(m[3]);
5482                            a = parseFloat(m[4]);
5483                        } else {
5484                            a = 1;
5485                            if (style.charAt(0) != '#') {
5486                                style = CssColors.colorNameToHex(style);
5487                                if (!style) {
5488                                    style = '#000000';
5489                                }
5490                            } else {}
5491
5492                            if (style.length === 4) {
5493                                r = style.substring(1, 2);
5494                                r += r;
5495                                g = style.substring(2, 3);
5496                                g += g;
5497                                b = style.substring(3, 4);
5498                                b += b;
5499                            } else {
5500                                r = style.substring(1, 3);
5501                                g = style.substring(3, 5);
5502                                b = style.substring(5, 7);
5503                            }
5504                            r = parseInt(r, 16);
5505                            g = parseInt(g, 16);
5506                            b = parseInt(b, 16);
5507                        }
5508                    }
5509                }
5510
5511                this.ctx.fillStyle = style;
5512                this.ctx._isFillTransparent = a == 0;
5513                this.ctx._fillOpacity = a;
5514
5515                this.pdf.setFillColor(r, g, b, {
5516                    a: a
5517                });
5518                this.pdf.setTextColor(r, g, b, {
5519                    a: a
5520                });
5521            },
5522
5523            setStrokeStyle: function setStrokeStyle(style) {
5524                var rgba = this._getRgba(style);
5525
5526                this.ctx.strokeStyle = rgba.style;
5527                this.ctx._isStrokeTransparent = rgba.a == 0;
5528                this.ctx._strokeOpacity = rgba.a;
5529
5530                //TODO jsPDF to handle rgba
5531                if (rgba.a === 0) {
5532                    this.pdf.setDrawColor(255, 255, 255);
5533                } else if (rgba.a === 1) {
5534                    this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b);
5535                } else {
5536                    //this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b, {a: rgba.a});
5537                    this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b);
5538                }
5539            },
5540
5541            fillText: function fillText(text, x, y, maxWidth) {
5542                if (this._isFillTransparent()) {
5543                    return;
5544                }
5545                x = this._wrapX(x);
5546                y = this._wrapY(y);
5547
5548                var xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
5549                x = xpt[0];
5550                y = xpt[1];
5551                var rads = this._matrix_rotation(this.ctx._transform);
5552                var degs = rads * 57.2958;
5553
5554                //TODO only push the clip if it has not been applied to the current PDF context
5555                if (this.ctx._clip_path.length > 0) {
5556                    var lines;
5557                    if (window.outIntercept) {
5558                        lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept;
5559                    } else {
5560                        lines = this.pdf.internal.pages[1];
5561                    }
5562                    lines.push("q");
5563                    var origPath = this.path;
5564                    this.path = this.ctx._clip_path;
5565                    this.ctx._clip_path = [];
5566                    this._fill(null, true);
5567                    this.ctx._clip_path = this.path;
5568                    this.path = origPath;
5569                }
5570
5571                this.pdf.text(text, x, this._getBaseline(y), null, degs);
5572
5573                if (this.ctx._clip_path.length > 0) {
5574                    lines.push('Q');
5575                }
5576            },
5577
5578            strokeText: function strokeText(text, x, y, maxWidth) {
5579                if (this._isStrokeTransparent()) {
5580                    return;
5581                }
5582                x = this._wrapX(x);
5583                y = this._wrapY(y);
5584
5585                var xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
5586                x = xpt[0];
5587                y = xpt[1];
5588                var rads = this._matrix_rotation(this.ctx._transform);
5589                var degs = rads * 57.2958;
5590
5591                //TODO only push the clip if it has not been applied to the current PDF context
5592                if (this.ctx._clip_path.length > 0) {
5593                    var lines;
5594                    if (window.outIntercept) {
5595                        lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept;
5596                    } else {
5597                        lines = this.pdf.internal.pages[1];
5598                    }
5599                    lines.push("q");
5600                    var origPath = this.path;
5601                    this.path = this.ctx._clip_path;
5602                    this.ctx._clip_path = [];
5603                    this._fill(null, true);
5604                    this.ctx._clip_path = this.path;
5605                    this.path = origPath;
5606                }
5607
5608                this.pdf.text(text, x, this._getBaseline(y), {
5609                    stroke: true
5610                }, degs);
5611
5612                if (this.ctx._clip_path.length > 0) {
5613                    lines.push('Q');
5614                }
5615            },
5616
5617            setFont: function setFont(font) {
5618                this.ctx.font = font;
5619
5620                //var rx = /\s*(\w+)\s+(\w+)\s+(\w+)\s+([\d\.]+)(px|pt|em)\s+["']?(\w+)['"]?/;
5621                var rx = /\s*(\w+)\s+(\w+)\s+(\w+)\s+([\d\.]+)(px|pt|em)\s+(.*)?/;
5622                m = rx.exec(font);
5623                if (m != null) {
5624                    var fontStyle = m[1];
5625                    var fontVariant = m[2];
5626                    var fontWeight = m[3];
5627                    var fontSize = m[4];
5628                    var fontSizeUnit = m[5];
5629                    var fontFamily = m[6];
5630
5631                    if ('px' === fontSizeUnit) {
5632                        fontSize = Math.floor(parseFloat(fontSize));
5633                        // fontSize = fontSize * 1.25;
5634                    } else if ('em' === fontSizeUnit) {
5635                        fontSize = Math.floor(parseFloat(fontSize) * this.pdf.getFontSize());
5636                    } else {
5637                        fontSize = Math.floor(parseFloat(fontSize));
5638                    }
5639
5640                    this.pdf.setFontSize(fontSize);
5641
5642                    if (fontWeight === 'bold' || fontWeight === '700') {
5643                        this.pdf.setFontStyle('bold');
5644                    } else {
5645                        if (fontStyle === 'italic') {
5646                            this.pdf.setFontStyle('italic');
5647                        } else {
5648                            this.pdf.setFontStyle('normal');
5649                        }
5650                    }
5651
5652                    var name = fontFamily;
5653                    var parts = name.toLowerCase().split(/\s*,\s*/);
5654                    var jsPdfFontName;
5655
5656                    if (parts.indexOf('arial') != -1) {
5657                        jsPdfFontName = 'Arial';
5658                    } else if (parts.indexOf('verdana') != -1) {
5659                        jsPdfFontName = 'Verdana';
5660                    } else if (parts.indexOf('helvetica') != -1) {
5661                        jsPdfFontName = 'Helvetica';
5662                    } else if (parts.indexOf('sans-serif') != -1) {
5663                        jsPdfFontName = 'sans-serif';
5664                    } else if (parts.indexOf('fixed') != -1) {
5665                        jsPdfFontName = 'Fixed';
5666                    } else if (parts.indexOf('monospace') != -1) {
5667                        jsPdfFontName = 'Monospace';
5668                    } else if (parts.indexOf('terminal') != -1) {
5669                        jsPdfFontName = 'Terminal';
5670                    } else if (parts.indexOf('courier') != -1) {
5671                        jsPdfFontName = 'Courier';
5672                    } else if (parts.indexOf('times') != -1) {
5673                        jsPdfFontName = 'Times';
5674                    } else if (parts.indexOf('cursive') != -1) {
5675                        jsPdfFontName = 'Cursive';
5676                    } else if (parts.indexOf('fantasy') != -1) {
5677                        jsPdfFontName = 'Fantasy';
5678                    } else if (parts.indexOf('serif') != -1) {
5679                        jsPdfFontName = 'Serif';
5680                    } else {
5681                        jsPdfFontName = 'Serif';
5682                    }
5683
5684                    //TODO check more cases
5685                    var style;
5686                    if ('bold' === fontWeight) {
5687                        style = 'bold';
5688                    } else {
5689                        style = 'normal';
5690                    }
5691
5692                    this.pdf.setFont(jsPdfFontName, style);
5693                } else {
5694                    var rx = /(\d+)(pt|px|em)\s+(\w+)\s*(\w+)?/;
5695                    var m = rx.exec(font);
5696                    if (m != null) {
5697                        var size = m[1];
5698                        var unit = m[2];
5699                        var name = m[3];
5700                        var style = m[4];
5701                        if (!style) {
5702                            style = 'normal';
5703                        }
5704                        if ('em' === fontSizeUnit) {
5705                            size = Math.floor(parseFloat(fontSize) * this.pdf.getFontSize());
5706                        } else {
5707                            size = Math.floor(parseFloat(size));
5708                        }
5709                        this.pdf.setFontSize(size);
5710                        this.pdf.setFont(name, style);
5711                    }
5712                }
5713            },
5714
5715            setTextBaseline: function setTextBaseline(baseline) {
5716                this.ctx.textBaseline = baseline;
5717            },
5718
5719            getTextBaseline: function getTextBaseline() {
5720                return this.ctx.textBaseline;
5721            },
5722
5723            //TODO implement textAlign
5724            setTextAlign: function setTextAlign(align) {
5725                this.ctx.textAlign = align;
5726            },
5727
5728            getTextAlign: function getTextAlign() {
5729                return this.ctx.textAlign;
5730            },
5731
5732            setLineWidth: function setLineWidth(width) {
5733                this.ctx.lineWidth = width;
5734                this.pdf.setLineWidth(width);
5735            },
5736
5737            setLineCap: function setLineCap(style) {
5738                this.ctx.lineCap = style;
5739                this.pdf.setLineCap(style);
5740            },
5741
5742            setLineJoin: function setLineJoin(style) {
5743                this.ctx.lineJoin = style;
5744                this.pdf.setLineJoin(style);
5745            },
5746
5747            moveTo: function moveTo(x, y) {
5748                x = this._wrapX(x);
5749                y = this._wrapY(y);
5750
5751                var xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
5752                x = xpt[0];
5753                y = xpt[1];
5754
5755                var obj = {
5756                    type: 'mt',
5757                    x: x,
5758                    y: y
5759                };
5760                this.path.push(obj);
5761            },
5762
5763            _wrapX: function _wrapX(x) {
5764                if (this.pageWrapXEnabled) {
5765                    return x % this.pageWrapX;
5766                } else {
5767                    return x;
5768                }
5769            },
5770
5771            _wrapY: function _wrapY(y) {
5772                if (this.pageWrapYEnabled) {
5773                    this._gotoPage(this._page(y));
5774                    return (y - this.lastBreak) % this.pageWrapY;
5775                } else {
5776                    return y;
5777                }
5778            },
5779
5780            transform: function transform(a, b, c, d, e, f) {
5781                //TODO apply to current transformation instead of replacing
5782                this.ctx._transform = [a, b, c, d, e, f];
5783            },
5784
5785            setTransform: function setTransform(a, b, c, d, e, f) {
5786                this.ctx._transform = [a, b, c, d, e, f];
5787            },
5788
5789            _getTransform: function _getTransform() {
5790                return this.ctx._transform;
5791            },
5792
5793            lastBreak: 0,
5794            // Y Position of page breaks.
5795            pageBreaks: [],
5796            // returns: One-based Page Number
5797            // Should only be used if pageWrapYEnabled is true
5798            _page: function _page(y) {
5799                if (this.pageWrapYEnabled) {
5800                    this.lastBreak = 0;
5801                    var manualBreaks = 0;
5802                    var autoBreaks = 0;
5803                    for (var i = 0; i < this.pageBreaks.length; i++) {
5804                        if (y >= this.pageBreaks[i]) {
5805                            manualBreaks++;
5806                            if (this.lastBreak === 0) {
5807                                autoBreaks++;
5808                            }
5809                            var spaceBetweenLastBreak = this.pageBreaks[i] - this.lastBreak;
5810                            this.lastBreak = this.pageBreaks[i];
5811                            var pagesSinceLastBreak = Math.floor(spaceBetweenLastBreak / this.pageWrapY);
5812                            autoBreaks += pagesSinceLastBreak;
5813                        }
5814                    }
5815                    if (this.lastBreak === 0) {
5816                        var pagesSinceLastBreak = Math.floor(y / this.pageWrapY) + 1;
5817                        autoBreaks += pagesSinceLastBreak;
5818                    }
5819                    return autoBreaks + manualBreaks;
5820                } else {
5821                    return this.pdf.internal.getCurrentPageInfo().pageNumber;
5822                }
5823            },
5824
5825            _gotoPage: function _gotoPage(pageOneBased) {
5826                // This is a stub to be overriden if needed
5827            },
5828
5829            lineTo: function lineTo(x, y) {
5830                x = this._wrapX(x);
5831                y = this._wrapY(y);
5832
5833                var xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
5834                x = xpt[0];
5835                y = xpt[1];
5836
5837                var obj = {
5838                    type: 'lt',
5839                    x: x,
5840                    y: y
5841                };
5842                this.path.push(obj);
5843            },
5844
5845            bezierCurveTo: function bezierCurveTo(x1, y1, x2, y2, x, y) {
5846                x1 = this._wrapX(x1);
5847                y1 = this._wrapY(y1);
5848                x2 = this._wrapX(x2);
5849                y2 = this._wrapY(y2);
5850                x = this._wrapX(x);
5851                y = this._wrapY(y);
5852
5853                var xpt;
5854                xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
5855                x = xpt[0];
5856                y = xpt[1];
5857                xpt = this._matrix_map_point(this.ctx._transform, [x1, y1]);
5858                x1 = xpt[0];
5859                y1 = xpt[1];
5860                xpt = this._matrix_map_point(this.ctx._transform, [x2, y2]);
5861                x2 = xpt[0];
5862                y2 = xpt[1];
5863
5864                var obj = {
5865                    type: 'bct',
5866                    x1: x1,
5867                    y1: y1,
5868                    x2: x2,
5869                    y2: y2,
5870                    x: x,
5871                    y: y
5872                };
5873                this.path.push(obj);
5874            },
5875
5876            quadraticCurveTo: function quadraticCurveTo(x1, y1, x, y) {
5877                x1 = this._wrapX(x1);
5878                y1 = this._wrapY(y1);
5879                x = this._wrapX(x);
5880                y = this._wrapY(y);
5881
5882                var xpt;
5883                xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
5884                x = xpt[0];
5885                y = xpt[1];
5886                xpt = this._matrix_map_point(this.ctx._transform, [x1, y1]);
5887                x1 = xpt[0];
5888                y1 = xpt[1];
5889
5890                var obj = {
5891                    type: 'qct',
5892                    x1: x1,
5893                    y1: y1,
5894                    x: x,
5895                    y: y
5896                };
5897                this.path.push(obj);
5898            },
5899
5900            arc: function arc(x, y, radius, startAngle, endAngle, anticlockwise) {
5901                x = this._wrapX(x);
5902                y = this._wrapY(y);
5903
5904                var xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
5905                x = xpt[0];
5906                y = xpt[1];
5907
5908                var obj = {
5909                    type: 'arc',
5910                    x: x,
5911                    y: y,
5912                    radius: radius,
5913                    startAngle: startAngle,
5914                    endAngle: endAngle,
5915                    anticlockwise: anticlockwise
5916                };
5917                this.path.push(obj);
5918            },
5919
5920            drawImage: function drawImage(img, x, y, w, h, x2, y2, w2, h2) {
5921                if (x2 !== undefined) {
5922                    x = x2;
5923                    y = y2;
5924                    w = w2;
5925                    h = h2;
5926                }
5927                x = this._wrapX(x);
5928                y = this._wrapY(y);
5929
5930                var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h });
5931                var xRect2 = this._matrix_map_rect(this.ctx._transform, { x: x2, y: y2, w: w2, h: h2 });
5932
5933                // TODO implement source clipping and image scaling
5934                var format;
5935                var rx = /data:image\/(\w+).*/i;
5936                var m = rx.exec(img);
5937                if (m != null) {
5938                    format = m[1];
5939                } else {
5940                    // format = "jpeg";
5941                    format = "png";
5942                }
5943
5944                this.pdf.addImage(img, format, xRect.x, xRect.y, xRect.w, xRect.h);
5945            },
5946
5947            /**
5948             * Multiply the first matrix by the second
5949             * @param m1
5950             * @param m2
5951             * @returns {*[]}
5952             * @private
5953             */
5954            _matrix_multiply: function _matrix_multiply(m2, m1) {
5955                var sx = m1[0];
5956                var shy = m1[1];
5957                var shx = m1[2];
5958                var sy = m1[3];
5959                var tx = m1[4];
5960                var ty = m1[5];
5961
5962                var t0 = sx * m2[0] + shy * m2[2];
5963                var t2 = shx * m2[0] + sy * m2[2];
5964                var t4 = tx * m2[0] + ty * m2[2] + m2[4];
5965                shy = sx * m2[1] + shy * m2[3];
5966                sy = shx * m2[1] + sy * m2[3];
5967                ty = tx * m2[1] + ty * m2[3] + m2[5];
5968                sx = t0;
5969                shx = t2;
5970                tx = t4;
5971
5972                return [sx, shy, shx, sy, tx, ty];
5973            },
5974
5975            _matrix_rotation: function _matrix_rotation(m) {
5976                return Math.atan2(m[2], m[0]);
5977            },
5978
5979            _matrix_decompose: function _matrix_decompose(matrix) {
5980
5981                var a = matrix[0];
5982                var b = matrix[1];
5983                var c = matrix[2];
5984                var d = matrix[3];
5985
5986                var scaleX = Math.sqrt(a * a + b * b);
5987                a /= scaleX;
5988                b /= scaleX;
5989
5990                var shear = a * c + b * d;
5991                c -= a * shear;
5992                d -= b * shear;
5993
5994                var scaleY = Math.sqrt(c * c + d * d);
5995                c /= scaleY;
5996                d /= scaleY;
5997                shear /= scaleY;
5998
5999                if (a * d < b * c) {
6000                    a = -a;
6001                    b = -b;
6002                    shear = -shear;
6003                    scaleX = -scaleX;
6004                }
6005
6006                return {
6007                    scale: [scaleX, 0, 0, scaleY, 0, 0],
6008                    translate: [1, 0, 0, 1, matrix[4], matrix[5]],
6009                    rotate: [a, b, -b, a, 0, 0],
6010                    skew: [1, 0, shear, 1, 0, 0]
6011                };
6012            },
6013
6014            _matrix_map_point: function _matrix_map_point(m1, pt) {
6015                var sx = m1[0];
6016                var shy = m1[1];
6017                var shx = m1[2];
6018                var sy = m1[3];
6019                var tx = m1[4];
6020                var ty = m1[5];
6021
6022                var px = pt[0];
6023                var py = pt[1];
6024
6025                var x = px * sx + py * shx + tx;
6026                var y = px * shy + py * sy + ty;
6027                return [x, y];
6028            },
6029
6030            _matrix_map_point_obj: function _matrix_map_point_obj(m1, pt) {
6031                var xpt = this._matrix_map_point(m1, [pt.x
6031, pt.y]);
6032                return { x: xpt[0], y: xpt[1] };
6033            },
6034
6035            _matrix_map_rect: function _matrix_map_rect(m1, rect) {
6036                var p1 = this._matrix_map_point(m1, [rect.x, rect.y]);
6037                var p2 = this._matrix_map_point(m1, [rect.x + rect.w, rect.y + rect.h]);
6038                return { x: p1[0], y: p1[1], w: p2[0] - p1[0], h: p2[1] - p1[1] };
6039            },
6040
6041            _matrix_is_identity: function _matrix_is_identity(m1) {
6042                if (m1[0] != 1) {
6043                    return false;
6044                }
6045                if (m1[1] != 0) {
6046                    return false;
6047                }
6048                if (m1[2] != 0) {
6049                    return false;
6050                }
6051                if (m1[3] != 1) {
6052                    return false;
6053                }
6054                if (m1[4] != 0) {
6055                    return false;
6056                }
6057                if (m1[5] != 0) {
6058                    return false;
6059                }
6060                return true;
6061            },
6062
6063            rotate: function rotate(angle) {
6064                var matrix = [Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0.0, 0.0];
6065                this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix);
6066            },
6067
6068            scale: function scale(sx, sy) {
6069                var matrix = [sx, 0.0, 0.0, sy, 0.0, 0.0];
6070                this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix);
6071            },
6072
6073            translate: function translate(x, y) {
6074                var matrix = [1.0, 0.0, 0.0, 1.0, x, y];
6075                this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix);
6076            },
6077
6078            stroke: function stroke() {
6079                if (this.ctx._clip_path.length > 0) {
6080
6081                    var lines;
6082                    if (window.outIntercept) {
6083                        lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept;
6084                    } else {
6085                        lines = this.pdf.internal.pages[1];
6086                    }
6087                    lines.push("q");
6088
6089                    var origPath = this.path;
6090                    this.path = this.ctx._clip_path;
6091                    this.ctx._clip_path = [];
6092                    this._stroke(true);
6093
6094                    this.ctx._clip_path = this.path;
6095                    this.path = origPath;
6096                    this._stroke(false);
6097
6098                    lines.push("Q");
6099                } else {
6100                    this._stroke(false);
6101                }
6102            },
6103
6104            _stroke: function _stroke(isClip) {
6105                if (!isClip && this._isStrokeTransparent()) {
6106                    return;
6107                }
6108
6109                //TODO opacity
6110
6111                var moves = [];
6112                var closed = false;
6113
6114                var xPath = this.path;
6115
6116                for (var i = 0; i < xPath.length; i++) {
6117                    var pt = xPath[i];
6118                    switch (pt.type) {
6119                        case 'mt':
6120                            moves.push({ start: pt, deltas: [], abs: [] });
6121                            break;
6122                        case 'lt':
6123                            var delta = [pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y];
6124                            moves[moves.length - 1].deltas.push(delta);
6125                            moves[moves.length - 1].abs.push(pt);
6126                            break;
6127                        case 'bct':
6128                            var delta = [pt.x1 - xPath[i - 1].x, pt.y1 - xPath[i - 1].y, pt.x2 - xPath[i - 1].x, pt.y2 - xPath[i - 1].y, pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y];
6129                            moves[moves.length - 1].deltas.push(delta);
6130                            break;
6131                        case 'qct':
6132                            // convert to bezier
6133                            var x1 = xPath[i - 1].x + 2.0 / 3.0 * (pt.x1 - xPath[i - 1].x);
6134                            var y1 = xPath[i - 1].y + 2.0 / 3.0 * (pt.y1 - xPath[i - 1].y);
6135                            var x2 = pt.x + 2.0 / 3.0 * (pt.x1 - pt.x);
6136                            var y2 = pt.y + 2.0 / 3.0 * (pt.y1 - pt.y);
6137                            var x3 = pt.x;
6138                            var y3 = pt.y;
6139                            var delta = [x1 - xPath[i - 1].x, y1 - xPath[i - 1].y, x2 - xPath[i - 1].x, y2 - xPath[i - 1].y, x3 - xPath[i - 1].x, y3 - xPath[i - 1].y];
6140                            moves[moves.length - 1].deltas.push(delta);
6141                            break;
6142                        case 'arc':
6143                            moves[moves.length - 1].arc = true;
6144                            moves[moves.length - 1].abs.push(pt);
6145                            break;
6146                        case 'close':
6147                            closed = true;
6148                            break;
6149                    }
6150                }
6151
6152                for (var i = 0; i < moves.length; i++) {
6153                    var style;
6154                    if (i == moves.length - 1) {
6155                        style = 's';
6156                    } else {
6157                        style = null;
6158                    }
6159                    if (moves[i].arc) {
6160                        var arcs = moves[i].abs;
6161                        for (var ii = 0; ii < arcs.length; ii++) {
6162                            var arc = arcs[ii];
6163                            var start = arc.startAngle * 360 / (2 * Math.PI);
6164                            var end = arc.endAngle * 360 / (2 * Math.PI);
6165                            var x = arc.x;
6166                            var y = arc.y;
6167                            this.internal.arc2(this, x, y, arc.radius, start, end, arc.anticlockwise, style, isClip);
6168                        }
6169                    } else {
6170                        var x = moves[i].start.x;
6171                        var y = moves[i].start.y;
6172                        if (!isClip) {
6173                            this.pdf.lines(moves[i].deltas, x, y, null, style);
6174                        } else {
6175                            this.pdf.lines(moves[i].deltas, x, y, null, null);
6176                            this.pdf.clip_fixed();
6177                        }
6178                    }
6179                }
6180            },
6181
6182            _isFillTransparent: function _isFillTransparent() {
6183                return this.ctx._isFillTransparent || this.globalAlpha == 0;
6184            },
6185
6186            _isStrokeTransparent: function _isStrokeTransparent() {
6187                return this.ctx._isStrokeTransparent || this.globalAlpha == 0;
6188            },
6189
6190            fill: function fill(fillRule) {
6191                //evenodd or nonzero (default)
6192                if (this.ctx._clip_path.length > 0) {
6193
6194                    var lines;
6195                    if (window.outIntercept) {
6196                        lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept;
6197                    } else {
6198                        lines = this.pdf.internal.pages[1];
6199                    }
6200                    lines.push("q");
6201
6202                    var origPath = this.path;
6203                    this.path = this.ctx._clip_path;
6204                    this.ctx._clip_path = [];
6205                    this._fill(fillRule, true);
6206
6207                    this.ctx._clip_path = this.path;
6208                    this.path = origPath;
6209                    this._fill(fillRule, false);
6210
6211                    lines.push('Q');
6212                } else {
6213                    this._fill(fillRule, false);
6214                }
6215            },
6216
6217            _fill: function _fill(fillRule, isClip) {
6218                if (this._isFillTransparent()) {
6219                    return;
6220                }
6221                var v2Support = typeof this.pdf.internal.newObject2 === 'function';
6222
6223                var lines;
6224                if (window.outIntercept) {
6225                    lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept;
6226                } else {
6227                    lines = this.pdf.internal.pages[1];
6228                }
6229
6230                // if (this.ctx._clip_path.length > 0) {
6231                //     lines.push('q');
6232                //     var oldPath = this.path;
6233                //     this.path = this.ctx._clip_path;
6234                //     this.ctx._clip_path = [];
6235                //     this._fill(fillRule, true);
6236                //     this.ctx._clip_path = this.path;
6237                //     this.path = oldPath;
6238                // }
6239
6240                var moves = [];
6241                var outInterceptOld = window.outIntercept;
6242
6243                if (v2Support) {
6244                    // Blend and Mask
6245                    switch (this.ctx.globalCompositeOperation) {
6246                        case 'normal':
6247                        case 'source-over':
6248                            break;
6249                        case 'destination-in':
6250                        case 'destination-out':
6251                            //TODO this need to be added to the current group or page
6252                            // define a mask stream
6253                            var obj = this.pdf.internal.newStreamObject();
6254
6255                            // define a mask state
6256                            var obj2 = this.pdf.internal.newObject2();
6257                            obj2.push('<</Type /ExtGState');
6258                            obj2.push('/SMask <</S /Alpha /G ' + obj.objId + ' 0 R>>'); // /S /Luminosity will need to define color space
6259                            obj2.push('>>');
6260
6261                            // add mask to page resources
6262                            var gsName = 'MASK' + obj2.objId;
6263                            this.pdf.internal.addGraphicsState(gsName, obj2.objId);
6264
6265                            var instruction = '/' + gsName + ' gs';
6266                            // add mask to page, group, or stream
6267                            lines.splice(0, 0, 'q');
6268                            lines.splice(1, 0, instruction);
6269                            lines.push('Q');
6270
6271                            window.outIntercept = obj;
6272                            break;
6273                        default:
6274                            var dictionaryEntry = '/' + this.pdf.internal.blendModeMap[this.ctx.globalCompositeOperation.toUpperCase()];
6275                            if (dictionaryEntry) {
6276                                this.pdf.internal.out(dictionaryEntry + ' gs');
6277                            }
6278                            break;
6279                    }
6280                }
6281
6282                var alpha = this.ctx.globalAlpha;
6283                if (this.ctx._fillOpacity < 1) {
6284                    // TODO combine this with global opacity
6285                    alpha = this.ctx._fillOpacity;
6286                }
6287
6288                //TODO check for an opacity graphics state that was already created
6289                //TODO do not set opacity if current value is already active
6290                if (v2Support) {
6291                    var objOpac = this.pdf.internal.newObject2();
6292                    objOpac.push('<</Type /ExtGState');
6293                    //objOpac.push(this.ctx.globalAlpha + " CA"); // Stroke
6294                    //objOpac.push(this.ctx.globalAlpha + " ca"); // Not Stroke
6295                    objOpac.push('/CA ' + alpha); // Stroke
6296                    objOpac.push('/ca ' + alpha); // Not Stroke
6297                    objOpac.push('>>');
6298                    var gsName = 'GS_O_' + objOpac.objId;
6299                    this.pdf.internal.addGraphicsState(gsName, objOpac.objId);
6300                    this.pdf.internal.out('/' + gsName + ' gs');
6301                }
6302
6303                var xPath = this.path;
6304
6305                for (var i = 0; i < xPath.length; i++) {
6306                    var pt = xPath[i];
6307                    switch (pt.type) {
6308                        case 'mt':
6309                            moves.push({ start: pt, deltas: [], abs: [] });
6310                            break;
6311                        case 'lt':
6312                            var delta = [pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y];
6313                            moves[moves.length - 1].deltas.push(delta);
6314                            moves[moves.length - 1].abs.push(pt);
6315                            break;
6316                        case 'bct':
6317                            var delta = [pt.x1 - xPath[i - 1].x, pt.y1 - xPath[i - 1].y, pt.x2 - xPath[i - 1].x, pt.y2 - xPath[i - 1].y, pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y];
6318                            moves[moves.length - 1].deltas.push(delta);
6319                            break;
6320                        case 'qct':
6321                            // convert to bezier
6322                            var x1 = xPath[i - 1].x + 2.0 / 3.0 * (pt.x1 - xPath[i - 1].x);
6323                            var y1 = xPath[i - 1].y + 2.0 / 3.0 * (pt.y1 - xPath[i - 1].y);
6324                            var x2 = pt.x + 2.0 / 3.0 * (pt.x1 - pt.x);
6325                            var y2 = pt.y + 2.0 / 3.0 * (pt.y1 - pt.y);
6326                            var x3 = pt.x;
6327                            var y3 = pt.y;
6328                            var delta = [x1 - xPath[i - 1].x, y1 - xPath[i - 1].y, x2 - xPath[i - 1].x, y2 - xPath[i - 1].y, x3 - xPath[i - 1].x, y3 - xPath[i - 1].y];
6329                            moves[moves.length - 1].deltas.push(delta);
6330                            break;
6331                        case 'arc':
6332                            //TODO this was hack to avoid out of bounds issue
6333                            if (moves.length == 0) {
6334                                moves.push({ start: { x: 0, y: 0 }, deltas: [], abs: [] });
6335                            }
6336                            moves[moves.length - 1].arc = true;
6337                            moves[moves.length - 1].abs.push(pt);
6338                            break;
6339                        case 'close':
6340                            //moves[moves.length - 1].deltas.push('close');
6341                            break;
6342                    }
6343                }
6344
6345                for (var i = 0; i < moves.length; i++) {
6346                    var style;
6347                    if (i == moves.length - 1) {
6348                        style = 'f';
6349                        if (fillRule === 'evenodd') {
6350                            style += '*';
6351                        }
6352                    } else {
6353                        style = null;
6354                    }
6355
6356                    if (moves[i].arc) {
6357                        var arcs = moves[i].abs;
6358                        for (var ii = 0; ii < arcs.length; ii++) {
6359                            var arc = arcs[ii];
6360                            //TODO lines deltas were getting in here
6361                            if (typeof arc.startAngle !== 'undefined') {
6362                                var start = arc.startAngle * 360 / (2 * Math.PI);
6363                                var end = arc.endAngle * 360 / (2 * Math.PI);
6364                                // Add the current position (last move to)
6365                                //var x = moves[i].start.x + arc.x;
6366                                //var y = moves[i].start.y + arc.y;
6367                                var x = arc.x;
6368                                var y = arc.y;
6369                                if (ii == 0) {
6370                                    this.internal.move2(this, x, y);
6371                                }
6372                                this.internal.arc2(this, x, y, arc.radius, start, end, arc.anticlockwise, null, isClip);
6373                            } else {
6374                                this.internal.line2(c2d, arc.x, arc.y);
6375                            }
6376                        }
6377
6378                        // extra move bug causing close to resolve to wrong point
6379                        var x = moves[i].start.x;
6380                        var y = moves[i].start.y;
6381                        this.internal.line2(c2d, x, y);
6382
6383                        this.pdf.internal.out('h');
6384                        this.pdf.internal.out('f');
6385                    } else {
6386                        var x = moves[i].start.x;
6387                        var y = moves[i].start.y;
6388                        if (!isClip) {
6389                            this.pdf.lines(moves[i].deltas, x, y, null, style);
6390                        } else {
6391                            this.pdf.lines(moves[i].deltas, x, y, null, null);
6392                            this.pdf.clip_fixed();
6393                        }
6394                    }
6395                }
6396
6397                window.outIntercept = outInterceptOld;
6398
6399                // if (this.ctx._clip_path.length > 0) {
6400                //     lines.push('Q');
6401                // }
6402            },
6403
6404            pushMask: function pushMask() {
6405                var v2Support = typeof this.pdf.internal.newObject2 === 'function';
6406
6407                if (!v2Support) {
6408                    console.log('jsPDF v2 not enabled');
6409                    return;
6410                }
6411
6412                // define a mask stream
6413                var obj = this.pdf.internal.newStreamObject();
6414
6415                // define a mask state
6416                var obj2 = this.pdf.internal.newObject2();
6417                obj2.push('<</Type /ExtGState');
6418                obj2.push('/SMask <</S /Alpha /G ' + obj.objId + ' 0 R>>'); // /S /Luminosity will need to define color space
6419                obj2.push('>>');
6420
6421                // add mask to page resources
6422                var gsName = 'MASK' + obj2.objId;
6423                this.pdf.internal.addGraphicsState(gsName, obj2.objId);
6424
6425                var instruction = '/' + gsName + ' gs';
6426                this.pdf.internal.out(instruction);
6427            },
6428
6429            clip: function clip() {
6430                //TODO do we reset the path, or just copy it?
6431                if (this.ctx._clip_path.length > 0) {
6432                    for (var i = 0; i < this.path.length; i++) {
6433                        this.ctx._clip_path.push(this.path[i]);
6434                    }
6435                } else {
6436                    this.ctx._clip_path = this.path;
6437                }
6438                this.path = [];
6439            },
6440
6441            measureText: function measureText(text) {
6442                var pdf = this.pdf;
6443                return {
6444                    getWidth: function getWidth() {
6445                        var fontSize = pdf.internal.getFontSize();
6446                        var txtWidth = pdf.getStringUnitWidth(text) * fontSize / pdf.internal.scaleFactor;
6447                        return txtWidth;
6448                    },
6449
6450                    get width() {
6451                        return this.getWidth(text);
6452                    }
6453                };
6454            },
6455            _getBaseline: function _getBaseline(y) {
6456                var height = parseInt(this.pdf.internal.getFontSize());
6457                // TODO Get descent from font descriptor
6458                var descent = height * .25;
6459                switch (this.ctx.textBaseline) {
6460                    case 'bottom':
6461                        return y - descent;
6462                    case 'top':
6463                        return y + height;
6464                    case 'hanging':
6465                        return y + height - descent;
6466                    case 'middle':
6467                        return y + height / 2 - descent;
6468                    case 'ideographic':
6469                        // TODO not implemented
6470                        return y;
6471                    case 'alphabetic':
6472                    default:
6473                        return y;
6474                }
6475            }
6476        };
6477
6478        var c2d = jsPDFAPI.context2d;
6479
6480        // accessor methods
6481        Object.defineProperty(c2d, 'fillStyle', {
6482            set: function set(value) {
6483                this.setFillStyle(value);
6484            },
6485            get: function get() {
6486                return this.ctx.fillStyle;
6487            }
6488        });
6489        Object.defineProperty(c2d, 'strokeStyle', {
6490            set: function set(value) {
6491                this.setStrokeStyle(value);
6492            },
6493            get: function get() {
6494                return this.ctx.strokeStyle;
6495            }
6496        });
6497        Object.defineProperty(c2d, 'lineWidth', {
6498            set: function set(value) {
6499                this.setLineWidth(value);
6500            },
6501            get: function get() {
6502                return this.ctx.lineWidth;
6503            }
6504        });
6505        Object.defineProperty(c2d, 'lineCap', {
6506            set: function set(val) {
6507                this.setLineCap(val);
6508            },
6509            get: function get() {
6510                return this.ctx.lineCap;
6511            }
6512        });
6513        Object.defineProperty(c2d, 'lineJoin', {
6514            set: function set(val) {
6515                this.setLineJoin(val);
6516            },
6517            get: function get() {
6518                return this.ctx.lineJoin;
6519            }
6520        });
6521        Object.defineProperty(c2d, 'miterLimit', {
6522            set: function set(val) {
6523                this.ctx.miterLimit = val;
6524            },
6525            get: function get() {
6526                return this.ctx.miterLimit;
6527            }
6528        });
6529        Object.defineProperty(c2d, 'textBaseline', {
6530            set: function set(value) {
6531                this.setTextBaseline(value);
6532            },
6533            get: function get() {
6534                return this.getTextBaseline();
6535            }
6536        });
6537        Object.defineProperty(c2d, 'textAlign', {
6538            set: function set(value) {
6539                this.setTextAlign(value);
6540            },
6541            get: function get() {
6542                return this.getTextAlign();
6543            }
6544        });
6545        Object.defineProperty(c2d, 'font', {
6546            set: function set(value) {
6547                this.setFont(value);
6548            },
6549            get: function get() {
6550                return this.ctx.font;
6551            }
6552        });
6553        Object.defineProperty(c2d, 'globalCompositeOperation', {
6554            set: function set(value) {
6555                this.ctx.globalCompositeOperation = value;
6556            },
6557            get: function get() {
6558                return this.ctx.globalCompositeOperation;
6559            }
6560        });
6561        Object.defineProperty(c2d, 'globalAlpha', {
6562            set: function set(value) {
6563                this.ctx.globalAlpha = value;
6564            },
6565            get: function get() {
6566                return this.ctx.globalAlpha;
6567            }
6568        });
6569        // Not HTML API
6570        Object.defineProperty(c2d, 'ignoreClearRect', {
6571            set: function set(value) {
6572                this.ctx.ignoreClearRect = value;
6573            },
6574            get: function get() {
6575                return this.ctx.ignoreClearRect;
6576            }
6577        });
6578        // End Not HTML API
6579
6580        c2d.internal = {};
6581
6582        c2d.internal.rxRgb = /rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/;
6583        c2d.internal.rxRgba = /rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/;
6584        c2d.internal.rxTransparent = /transparent|rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*0+\s*\)/;
6585
6586        // http://hansmuller-flex.blogspot.com/2011/10/more-about-
6586approximating-circular-arcs.html
6587        c2d.internal.arc = function (c2d, xc, yc, r, a1, a2, anticlockwise, style) {
6588            var includeMove = true;
6589
6590            var k = this.pdf.internal.scaleFactor;
6591            var pageHeight = this.pdf.internal.pageSize.height;
6592            var f2 = this.pdf.internal.f2;
6593
6594            var a1r = a1 * (Math.PI / 180);
6595            var a2r = a2 * (Math.PI / 180);
6596            var curves = this.createArc(r, a1r, a2r, anticlockwise);
6597            var pathData = null;
6598
6599            for (var i = 0; i < curves.length; i++) {
6600                var curve = curves[i];
6601                if (includeMove && i == 0) {
6602                    this.pdf.internal.out([f2((curve.x1 + xc) * k), f2((pageHeight - (curve.y1 + yc)) * k), 'm', f2((curve.x2 + xc) * k), f2((pageHeight - (curve.y2 + yc)) * k), f2((curve.x3 + xc) * k), f2((pageHeight - (curve.y3 + yc)) * k), f2((curve.x4 + xc) * k), f2((pageHeight - (curve.y4 + yc)) * k), 'c'].join(' '));
6603                } else {
6604                    this.pdf.internal.out([f2((curve.x2 + xc) * k), f2((pageHeight - (curve.y2 + yc)) * k), f2((curve.x3 + xc) * k), f2((pageHeight - (curve.y3 + yc)) * k), f2((curve.x4 + xc) * k), f2((pageHeight - (curve.y4 + yc)) * k), 'c'].join(' '));
6605                }
6606
6607                //c2d._lastPoint = {x: curve.x1 + xc, y: curve.y1 + yc};
6608                c2d._lastPoint = { x: xc, y: yc };
6609                // f2((curve.x1 + xc) * k), f2((pageHeight - (curve.y1 + yc)) * k), 'm', f2((curve.x2 + xc) * k), f2((pageHeight - (curve.y2 + yc)) * k), f2((curve.x3 + xc) * k), f2((pageHeight - (curve.y3 + yc)) * k), f2((curve.x4 + xc) * k), f2((pageHeight - (curve.y4 + yc)) * k), 'c'
6610            }
6611
6612            if (style !== null) {
6613                this.pdf.internal.out(this.pdf.internal.getStyle(style));
6614            }
6615        };
6616
6617        /**
6618         *
6619         * @param x Edge point X
6620         * @param y Edge point Y
6621         * @param r Radius
6622         * @param a1 start angle
6623         * @param a2 end angle
6624         * @param anticlockwise
6625         * @param style
6626         * @param isClip
6627         */
6628        c2d.internal.arc2 = function (c2d, x, y, r, a1, a2, anticlockwise, style, isClip) {
6629            // we need to convert from cartesian to polar here methinks.
6630            var centerX = x; // + r;
6631            var centerY = y;
6632
6633            if (false) {}
6634
6635            if (!isClip) {
6636                this.arc(c2d, centerX, centerY, r, a1, a2, anticlockwise, style);
6637            } else {
6638                this.arc(c2d, centerX, centerY, r, a1, a2, anticlockwise, null);
6639                this.pdf.clip_fixed();
6640            }
6641        };
6642
6643        c2d.internal.move2 = function (c2d, x, y) {
6644            var k = this.pdf.internal.scaleFactor;
6645            var pageHeight = this.pdf.internal.pageSize.height;
6646            var f2 = this.pdf.internal.f2;
6647
6648            this.pdf.internal.out([f2(x * k), f2((pageHeight - y) * k), 'm'].join(' '));
6649            c2d._lastPoint = { x: x, y: y };
6650        };
6651
6652        c2d.internal.line2 = function (c2d, dx, dy) {
6653            var k = this.pdf.internal.scaleFactor;
6654            var pageHeight = this.pdf.internal.pageSize.height;
6655            var f2 = this.pdf.internal.f2;
6656
6657            //var pt = {x: c2d._lastPoint.x + dx, y: c2d._lastPoint.y + dy};
6658            var pt = { x: dx, y: dy };
6659
6660            this.pdf.internal.out([f2(pt.x * k), f2((pageHeight - pt.y) * k), 'l'].join(' '));
6661            //this.pdf.internal.out('f');
6662            c2d._lastPoint = pt;
6663        };
6664
6665        /**
6666         * Return a array of objects that represent bezier curves which approximate the circular arc centered at the origin, from startAngle to endAngle (radians) with the specified radius.
6667         *
6668         * Each bezier curve is an object with four points, where x1,y1 and x4,y4 are the arc's end points and x2,y2 and x3,y3 are the cubic bezier's control points.
6669         */
6670
6671        c2d.internal.createArc = function (radius, startAngle, endAngle, anticlockwise) {
6672
6673            var EPSILON = 0.00001; // Roughly 1/1000th of a degree, see below
6674
6675            // normalize startAngle, endAngle to [-2PI, 2PI]
6676            var twoPI = Math.PI * 2;
6677            var startAngleN = startAngle;
6678            if (startAngleN < twoPI || startAngleN > twoPI) {
6679                startAngleN = startAngleN % twoPI;
6680            }
6681            var endAngleN = endAngle;
6682            if (endAngleN < twoPI || endAngleN > twoPI) {
6683                endAngleN = endAngleN % twoPI;
6684            }
6685
6686            // Compute the sequence of arc curves, up to PI/2 at a time.
6687            // Total arc angle is less than 2PI.
6688            var curves = [];
6689            var piOverTwo = Math.PI / 2.0;
6690            // var sgn = (startAngle < endAngle) ? +1 : -1; // clockwise or counterclockwise
6691            var sgn = anticlockwise ? -1 : +1;
6692
6693            var a1 = startAngle;
6694            for (var totalAngle = Math.min(twoPI, Math.abs(endAngleN - startAngleN)); totalAngle > EPSILON;) {
6695                var a2 = a1 + sgn * Math.min(totalAngle, piOverTwo);
6696                curves.push(this.createSmallArc(radius, a1, a2));
6697                totalAngle -= Math.abs(a2 - a1);
6698                a1 = a2;
6699            }
6700
6701            return curves;
6702        };
6703
6704        /**
6705         * Cubic bezier approximation of a circular arc centered at the origin, from (radians) a1 to a2, where a2-a1 < pi/2. The arc's radius is r.
6706         *
6707         * Returns an object with four points, where x1,y1 and x4,y4 are the arc's end points and x2,y2 and x3,y3 are the cub
6707ic bezier's control points.
6708         *
6709         * This algorithm is based on the approach described in: A. Riškus, "Approximation of a Cubic Bezier Curve by Circular Arcs and Vice Versa," Information Technology and Control, 35(4), 2006 pp. 371-378.
6710         */
6711
6712        c2d.internal.createSmallArc = function (r, a1, a2) {
6713            // Compute all four points for an arc that subtends the same total angle
6714            // but is centered on the X-axis
6715
6716            var a = (a2 - a1) / 2.0;
6717
6718            var x4 = r * Math.cos(a);
6719            var y4 = r * Math.sin(a);
6720            var x1 = x4;
6721            var y1 = -y4;
6722
6723            var q1 = x1 * x1 + y1 * y1;
6724            var q2 = q1 + x1 * x4 + y1 * y4;
6725            var k2 = 4 / 3 * (Math.sqrt(2 * q1 * q2) - q2) / (x1 * y4 - y1 * x4);
6726
6727            var x2 = x1 - k2 * y1;
6728            var y2 = y1 + k2 * x1;
6729            var x3 = x2;
6730            var y3 = -y2;
6731
6732            // Find the arc points' actual locations by computing x1,y1 and x4,y4
6733            // and rotating the control points by a + a1
6734
6735            var ar = a + a1;
6736            var cos_ar = Math.cos(ar);
6737            var sin_ar = Math.sin(ar);
6738
6739            return {
6740                x1: r * Math.cos(a1),
6741                y1: r * Math.sin(a1),
6742                x2: x2 * cos_ar - y2 * sin_ar,
6743                y2: x2 * sin_ar + y2 * cos_ar,
6744                x3: x3 * cos_ar - y3 * sin_ar,
6745                y3: x3 * sin_ar + y3 * cos_ar,
6746                x4: r * Math.cos(a2),
6747                y4: r * Math.sin(a2)
6748            };
6749        };
6750
6751        function context() {
6752            this._isStrokeTransparent = false;
6753            this._strokeOpacity = 1;
6754            this.strokeStyle = '#000000';
6755            this.fillStyle = '#000000';
6756            this._isFillTransparent = false;
6757            this._fillOpacity = 1;
6758            this.font = "12pt times";
6759            this.textBaseline = 'alphabetic'; // top,bottom,middle,ideographic,alphabetic,hanging
6760            this.textAlign = 'start';
6761            this.lineWidth = 1;
6762            this.lineJoin = 'miter'; // round, bevel, miter
6763            this.lineCap = 'butt'; // butt, round, square
6764            this._transform = [1, 0, 0, 1, 0, 0]; // sx, shy, shx, sy, tx, ty
6765            this.globalCompositeOperation = 'normal';
6766            this.globalAlpha = 1.0;
6767            this._clip_path = [];
6768            // TODO miter limit //default 10
6769
6770            // Not HTML API
6771            this.ignoreClearRect = false;
6772
6773            this.copy = function (ctx) {
6774                this._isStrokeTransparent = ctx._isStrokeTransparent;
6775                this._strokeOpacity = ctx._strokeOpacity;
6776                this.strokeStyle = ctx.strokeStyle;
6777                this._isFillTransparent = ctx._isFillTransparent;
6778                this._fillOpacity = ctx._fillOpacity;
6779                this.fillStyle = ctx.fillStyle;
6780                this.font = ctx.font;
6781                this.lineWidth = ctx.lineWidth;
6782                this.lineJoin = ctx.lineJoin;
6783                this.lineCap = ctx.lineCap;
6784                this.textBaseline = ctx.textBaseline;
6785                this.textAlign = ctx.textAlign;
6786                this._fontSize = ctx._fontSize;
6787                this._transform = ctx._transform.slice(0);
6788                this.globalCompositeOperation = ctx.globalCompositeOperation;
6789                this.globalAlpha = ctx.globalAlpha;
6790                this._clip_path = ctx._clip_path.slice(0); //TODO deep copy?
6791
6792                // Not HTML API
6793                this.ignoreClearRect = ctx.ignoreClearRect;
6794            };
6795        }
6796
6797        return this;
6798    })(jsPDF.API);
6799
6800    /** @preserve
6801     * jsPDF fromHTML plugin. BETA stage. API subject to change. Needs browser
6802     * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
6803     *               2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
6804     *               2014 Diego Casorran, https://github.com/diegocr
6805     *               2014 Daniel Husar, https://github.com/danielhusar
6806     *               2014 Wolfgang Gassler, https://github.com/woolfg
6807     *               2014 Steven Spungin, https://github.com/flamenco
6808     *
6809     *
6810     * ====================================================================
6811     */
6812
6813    (function (jsPDFAPI) {
6814        var clone, _DrillForContent, FontNameDB, FontStyleMap, TextAlignMap, FontWeightMap, FloatMap, ClearMap, GetCSS, PurgeWhiteSpace, Renderer, ResolveFont, ResolveUnitedNumber, UnitedNumberMap, elementHandledElsewhere, images, loadImgs, checkForFooter, process, tableToJson;
6815        clone = function () {
6816            return function (obj) {
6817                Clone.prototype = obj;
6818                return new Clone();
6819            };
6820            function Clone() {}
6821        }();
6822        PurgeWhiteSpace = function PurgeWhiteSpace(array) {
6823            var fragment, i, l, lTrimmed, r, rTrimmed, trailingSpace;
6824            i = 0;
6825            l = array.length;
6826            fragment = void 0;
6827            lTrimmed = false;
6828            rTrimmed = false;
6829            while (!lTrimmed && i !== l) {
6830                fragment = array[i] = array[i].trimLeft();
6831                if (fragment) {
6832                    lTrimmed = true;
6833                }
6834                i++;
6835            }
6836            i = l - 1;
6837            while (l && !rTrimmed && i !== -1) {
6838                fragment = array[i] = array[i].trimRight();
6839                if (fragment) {
6840                    rTrimmed = true;
6841                }
6842                i--;
6843            }
6844            r = /\s+$/g;
6845            trailingSpace = true;
6846            i = 0;
6847            while (i !== l) {
6848                // Leave the line breaks intact
6849                if (array[i] != "\u2028") {
6850                    fragment = array[i].replace(/\s+/g, " ");
6851                    if (trailingSpace) {
6852                        fragment = fragment.trimLeft();
6853                    }
6854                    if (fragment) {
6855                        trailingSpace = r.test(fragment);
6856                    }
6857                    array[i] = fragment;
6858                }
6859                i++;
6860            }
6861            return array;
6862        };
6863        Renderer = function Renderer(pdf, x, y, settings) {
6864            this.pdf = pdf;
6865            this.x = x;
6866            this.y = y;
6867            this.settings = settings;
6868            //list of functions which are called after each element-rendering process
6869            this.watchFunctions = [];
6870            this.init();
6871            return this;
6872        };
6873        ResolveFont = function ResolveFont(css_font_family_string) {
6874            var name, part, parts;
6875            name = void 0;
6876            parts = css_font_family_string.split(",");
6877            part = parts.shift();
6878            while (!name && part) {
6879                name = FontNameDB[part.trim().toLowerCase()];
6880                part = parts.shift();
6881            }
6882            return name;
6883        };
6884        ResolveUnitedNumber = function ResolveUnitedNumber(css_line_height_string) {
6885
6886            //IE8 issues
6887            css_line_height_string = css_line_height_string === "auto" ? "0px" : css_line_height_string;
6888            if (css_line_height_string.indexOf("em") > -1 && !isNaN(Number(css_line_height_string.replace("em", "")))) {
6889                css_line_height_string = Number(css_line_height_string.replace("em", "")) * 18.719 + "px";
6890            }
6891            if (css_line_height_string.indexOf("pt") > -1 && !isNaN(Number(css_line_height_string.replace("pt", "")))) {
6892                css_line_height_string = Number(css_line_height_string.replace("pt", "")) * 1.333 + "px";
6893            }
6894
6895            var normal, undef, value;
6896            undef = void 0;
6897            normal = 16.00;
6898            value = UnitedNumberMap[css_line_height_string];
6899            if (value) {
6900                return value;
6901            }
6902            value = {
6903                "xx-small": 9,
6904                "x-small": 11,
6905                small: 13,
6906                medium: 16,
6907                large: 19,
6908                "x-large": 23,
6909                "xx-large": 28,
6910                auto: 0
6911            }[{ css_line_height_string: css_line_height_string }];
6912
6913            if (value !== undef) {
6914                return UnitedNumberMap[css_line_height_string] = value / normal;
6915            }
6916            if (value = parseFloat(css_line_height_string)) {
6917                return UnitedNumberMap[css_line_height_string] = value / normal;
6918            }
6919            value = css_line_height_string.match(/([\d\.]+)(px)/);
6920            if (value.length === 3) {
6921                return UnitedNumberMap[css_line_height_string] = parseFloat(value[1]) / normal;
6922            }
6923            return UnitedNumberMap[css_line_height_string] = 1;
6924        };
6925        GetCSS = function GetCSS(element) {
6926            var css, tmp, computedCSSElement;
6927            computedCSSElement = function (el) {
6928                var compCSS;
6929                compCSS = function (el) {
6930                    if (document.defaultView && document.defaultView.getComputedStyle) {
6931                        return document.defaultView.getComputedStyle(el, null);
6932                    } else if (el.currentStyle) {
6933                        return el.currentStyle;
6934                    } else {
6935                        return el.style;
6936                    }
6937                }(el);
6938                return function (prop) {
6939                    prop = prop.replace(/-\D/g, function (match) {
6940                        return match.charAt(1).toUpperCase();
6941                    });
6942                    return compCSS[prop];
6943                };
6944            }(element);
6945            css = {};
6946            tmp = void 0;
6947            css["font-family"] = ResolveFont(computedCSSElement("font-family")) || "times";
6948            css["font-style"] = FontStyleMap[computedCSSElement("font-style")] || "normal";
6949            css["text-align"] = TextAlignMap[computedCSSElement("text-align")] || "left";
6950            tmp = FontWeightMap[computedCSSElement("font-weight")] || "normal";
6951            if (tmp === "bold") {
6952                if (css["font-style"] === "normal") {
6953                    css["font-style"] = tmp;
6954                } else {
6955                    css["font-style"] = tmp + css["font-style"];
6956                }
6957            }
6958            css["font-size"] = ResolveUnitedNumber(computedCSSElement("font-size")) || 1;
6959            css["line-height"] = ResolveUnitedNumber(computedCSSElement("line-height")) || 1;
6960            css["display"] = computedCSSElement("display") === "inline" ? "inline" : "block";
6961
6962            tmp = css["display"] === "block";
6963            css["margin-top"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-top")) || 0;
6964            css["margin-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-bottom")) || 0;
6965            css["padding-top"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-top")) || 0;
6966            css["padding-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-bottom")) || 0;
6967            css["margin-left"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-left")) || 0;
6968            css["margin-right"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-right")) || 0;
6969            css["padding-left"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-left")) || 0;
6970            css["padding-right"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-right")) || 0;
6971
6972            css["page-break-before"] = computedCSSElement("page-break-before") || "auto";
6973
6974            //float and clearing of floats
6975            css["float"] = FloatMap[computedCSSElement("cssFloat")] || "none";
6976            css["clear"] = ClearMap[computedCSSElement("clear")] || "none";
6977
6978            css["color"] = computedCSSElement("color");
6979
6980            return css;
6981        };
6982        elementHandledElsewhere = function elementHandledElsewhere(element, renderer, elementHandlers) {
6983            var handlers, i, isHandledElsewhere, l, t;
6984            isHandledElsewhere = false;
6985            i = void 0;
6986            l = void 0;
6987            t = void 0;
6988            handlers = elementHandlers["#" + element.id];
6989            if (handlers) {
6990                if (typeof handlers === "function") {
6991                    isHandledElsewhere = handlers(element, renderer);
6992                } else {
6993                    i = 0;
6994                    l = handlers.length;
6995                    while (!isHandledElsewhere && i !== l) {
6996                        isHandledElsewhere = handlers[i](element, renderer);
6997                        i++;
6998                    }
6999                }
7000            }
7001            handlers = elementHandlers[element.nodeName];
7002            if (!isHandledElsewhere && handlers) {
7003                if (typeof handlers === "function") {
7004                    isHandledElsewhere = handlers(element, renderer);
7005                } else {
7006                    i = 0;
7007                    l = handlers.length;
7008                    while (!isHandledElsewhere && i !== l) {
7009                        isHandledElsewhere = handlers[i](element, renderer);
7010                        i++;
7011                    }
7012                }
7013            }
7014            return isHandledElsewhere;
7015        };
7016        tableToJson = function tableToJson(table, renderer) {
7017            var data, headers, i, j, rowData, tableRow, table_obj, table_with, cell, l;
7018            data = [];
7019            headers = [];
7020            i = 0;
7021            l = table.rows[0].cells.length;
7022            table_with = table.clientWidth;
7023            while (i < l) {
7024                cell = table.rows[0].cells[i];
7025                headers[i] = {
7026                    name: cell.textContent.toLowerCase().replace(/\s+/g, ''),
7027                    prompt: cell.textContent.replace(/\r?\n/g, ''),
7028                    width: cell.clientWidth / table_with * renderer.pdf.internal.pageSize.width
7029                };
7030                i++;
7031            }
7032            i = 1;
7033            while (i < table.rows.length) {
7034                tableRow = table.rows[i];
7035                rowData = {};
7036                j = 0;
7037                while (j < tableRow.cells.length) {
7038                    rowData[headers[j].name] = tableRow.cells[j].textContent.replace(/\r?\n/g, '');
7039                    j++;
7040                }
7041                data.push(rowData);
7042                i++;
7043            }
7044            return table_obj = {
7045                rows: data,
7046                headers: headers
7047            };
7048        };
7049        var SkipNode = {
7050            SCRIPT: 1,
7051            STYLE: 1,
7052            NOSCRIPT: 1,
7053            OBJECT: 1,
7054            EMBED: 1,
7055            SELECT: 1
7056        };
7057        var listCount = 1;
7058        _DrillForContent = function DrillForContent(element, renderer, elementHandlers) {
7059            var cn, cns, fragmentCSS, i, isBlock, l, px2pt, table2json, cb;
7060            cns = element.childNodes;
7061            cn = void 0;
7062            fragmentCSS = GetCSS(element);
7063            isBlock = fragmentCSS.display === "block";
7064            if (isBlock) {
7065                renderer.setBlockBoundary();
7066                renderer.setBlockStyle(fragmentCSS);
7067            }
7068            px2pt = 0.264583 * 72 / 25.4;
7069            i = 0;
7070            l = cns.length;
7071            while (i < l) {
7072                cn = cns[i];
7073                if ((typeof cn === "undefined" ? "undefined" : _typeof(cn)) === "object") {
7074
7075                    //execute all watcher functions to e.g. reset floating
7076                    renderer.executeWatchFunctions(cn);
7077
7078                    /*** HEADER rendering **/
7079                    if (cn.nodeType === 1 && cn.nodeName === 'HEADER') {
7080                        var header = cn;
7081                        //store old top margin
7082                        var oldMarginTop = renderer.pdf.margins_doc.top;
7083                        //subscribe for new page event and render header first on every page
7084                        renderer.pdf.internal.events.subscribe('addPage', function (pageInfo) {
7085                            //set current y position to old margin
7086                            renderer.y = oldMarginTop;
7087                            //render all child nodes of the header element
7088                            _DrillForContent(header, renderer, elementHandlers);
7089                            //set margin to old margin + rendered header + 10 space to prevent overlapping
7090                            //important for other plugins (e.g. table) to start rendering at correct position after header
7091                            renderer.pdf.margins_doc.top = renderer.y + 10;
7092                            renderer.y += 10;
7093                        }, false);
7094                    }
7095
7096                    if (cn.nodeType === 8 && cn.nodeName === "#comment") {
7097                        if (~cn.textContent.indexOf("ADD_PAGE")) {
7098                            renderer.pdf.addPage();
7099                            renderer.y = renderer.pdf.margins_doc.top;
7100                        }
7101                    } else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) {
7102                        /*** IMAGE RENDERING ***/
7103                        var cached_image;
7104                        if (cn.nodeName === "IMG") {
7105                            var url = cn.getAttribute("src");
7106                            cached_image = images[renderer.pdf.sHashCode(url) || url];
7107                        }
7108                        if (cached_image) {
7109                            if (renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom < renderer.y + cn.height && renderer.y > renderer.pdf.margins_doc.top) {
7110                                renderer.pdf.addPage();
7111                                renderer.y = renderer.pdf.margins_doc.top;
7112                                //check if we have to set back some values due to e.g. header rendering for new page
7113                                renderer.executeWatchFunctions(cn);
7114                            }
7115
7116                            var imagesCSS = GetCSS(cn);
7117                            var imageX = renderer.x;
7118                            var fontToUnitRatio = 12 / renderer.pdf.internal.scaleFactor;
7119
7120                            //define additional paddings, margins which have to be taken into account for margin calculations
7121                            var additionalSpaceLeft = (imagesCSS["margin-left"] + imagesCSS["padding-left"]) * fontToUnitRatio;
7122                            var additionalSpaceRight = (imagesCSS["margin-right"] + imagesCSS["padding-right"]) * fontToUnitRatio;
7123                            var additionalSpaceTop = (imagesCSS["margin-top"] + imagesCSS["padding-top"]) * fontToUnitRatio;
7124                            var additionalSpaceBottom = (imagesCSS["margin-bottom"] + imagesCSS["padding-bottom"]) * fontToUnitRatio;
7125
7126                            //if float is set to right, move the image to the right border
7127                            //add space if margin is set
7128                            if (imagesCSS['float'] !== undefined && imagesCSS['float'] === 'right') {
7129                                imageX += renderer.settings.width - cn.width - additionalSpaceRight;
7130                            } else {
7131                                imageX += additionalSpaceLeft;
7132                            }
7133
7134                            renderer.pdf.addImage(cached_image, imageX, renderer.y + additionalSpaceTop, cn.width, cn.height);
7135                            cached_image = undefined;
7136                            //if the float prop is specified we have to float the text around the image
7137                            if (imagesCSS['float'] === 'right' || imagesCSS['float'] === 'left') {
7138                                //add functiont to set back coordinates after image rendering
7139                                renderer.watchFunctions.push(function (diffX, thresholdY, diffWidth, el) {
7140                                    //undo drawing box adaptions which were set by floating
7141                                    if (renderer.y >= thresholdY) {
7142                                        renderer.x += diffX;
7143                                        renderer.settings.width += diffWidth;
7144                                        return true;
7145                                    } else if (el && el.nodeType === 1 && !SkipNode[el.nodeName] && renderer.x + el.width > renderer.pdf.margins_doc.left + renderer.pdf.margins_doc.width) {
7146                                        renderer.x += diffX;
7147                                        renderer.y = thresholdY;
7148                                        renderer.settings.width += diffWidth;
7149                                        return true;
7150                                    } else {
7151                                        return false;
7152                                    }
7153                                }.bind(this, imagesCSS['float'] === 'left' ? -cn.width - additionalSpaceLeft - additionalSpaceRight : 0, renderer.y + cn.height + additionalSpaceTop + additionalSpaceBottom, cn.width));
7154                                //reset floating by clear:both divs
7155                                //just set cursorY after the floating element
7156                                renderer.watchFunctions.push(function (yPositionAfterFloating, pages, el) {
7157                                    if (renderer.y < yPositionAfterFloating && pages === renderer.pdf.internal.getNumberOfPages()) {
7158                                        if (el.nodeType === 1 && GetCSS(el).clear === 'both') {
7159                                            renderer.y = yPositionAfterFloating;
7160                                            return true;
7161                                        } else {
7162                                            return false;
7163                                        }
7164                                    } else {
7165                                        return true;
7166                                    }
7167                                }.bind(this, renderer.y + cn.height, renderer.pdf.internal.getNumberOfPages()));
7168
7169                                //if floating is set we decrease the available width by the image width
7170                                renderer.settings.width -= cn.width + additionalSpaceLeft + additionalSpaceRight;
7171                                //if left just add the image width to the X coordinate
7172                                if (imagesCSS['float'] === 'left') {
7173                                    renderer.x += cn.width + additionalSpaceLeft + additionalSpaceRight;
7174                                }
7175                            } else {
7176                                //if no floating is set, move the rendering cursor after the image height
7177                                renderer.y += cn.height + additionalSpaceTop + additionalSpaceBottom;
7178                            }
7179
7180                            /*** TABLE RENDERING ***/
7181                        } else if (cn.nodeName === "TABLE") {
7182                            table2json = tableToJson(cn, renderer);
7183                            renderer.y += 10;
7184                            renderer.pdf.table(renderer.x, renderer.y, table2json.rows, table2json.headers, {
7185                                autoSize: false,
7186                                printHeaders: elementHandlers.printHeaders,
7187                                margins: renderer.pdf.margins_doc,
7188                                css: GetCSS(cn)
7189                            });
7190                            renderer.y = renderer.pdf.lastCellPos.y + renderer.pdf.lastCellPos.h + 20;
7191                        } else if (cn.nodeName === "OL" || cn.nodeName === "UL") {
7192                            listCount = 1;
7193                            if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
7194                                _DrillForContent(cn, renderer, elementHandlers);
7195                            }
7196                            renderer.y += 10;
7197                        } else if (cn.nodeName === "LI") {
7198                            var temp = renderer.x;
7199                            renderer.x += 20 / renderer.pdf.internal.scaleFactor;
7200                            renderer.y += 3;
7201                            if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
7202                                _DrillForContent(cn, renderer, elementHandlers);
7203                            }
7204                            renderer.x = temp;
7205                        } else if (cn.nodeName === "BR") {
7206                            renderer.y += fragmentCSS["font-size"] * renderer.pdf.internal.scaleFactor;
7207                            renderer.addText("\u2028", clone(fragmentCSS));
7208                        } else {
7209                            if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
7210                                _DrillForContent(cn, renderer, elementHandlers);
7211                            }
7212                        }
7213                    } else if (cn.nodeType === 3) {
7214                        var value = cn.nodeValue;
7215                        if (cn.nodeValue && cn.parentNode.nodeName === "LI") {
7216                            if (cn.parentNode.parentNode.nodeName === "OL") {
7217                                value = listCount++ + '. ' + value;
7218                            } else {
7219                                var fontSize = fragmentCSS["font-size"];
7220                                var offsetX = (3 - fontSize * 0.75) * renderer.pdf.internal.scaleFactor;
7221                                var offsetY = fontSize * 0.75 * renderer.pdf.internal.scaleFactor;
7222                                var radius = fontSize * 1.74 / renderer.pdf.internal.scaleFactor;
7223                                cb = function cb(x, y) {
7224                                    this.pdf.circle(x + offsetX, y + offsetY, radius, 'FD');
7225                                };
7226                            }
7227                        }
7228                        // Only add the text if the text node is in the body element
7229                        // Add compatibility with IE11
7230                        if (!!(cn.ownerDocument.body.compareDocumentPosition(cn) & 16)) {
7231                            renderer.addText(value, fragmentCSS);
7232                        }
7233                    } else if (typeof cn === "string") {
7234                        renderer.addText(cn, fragmentCSS);
7235                    }
7236                }
7237                i++;
7238            }
7239            elementHandlers.outY = renderer.y;
7240
7241            if (isBlock) {
7242                return renderer.setBlockBoundary(cb);
7243            }
7244        };
7245        images = {};
7246        loadImgs = function loadImgs(element, renderer, elementHandlers, cb) {
7247            var imgs = element.getElementsByTagName('img'),
7248                l = imgs.length,
7249                found_images,
7250                x = 0;
7251            function done() {
7252                renderer.pdf.internal.events.publish('imagesLoaded');
7253                cb(found_images);
7254            }
7255            function loadImage(url, width, height) {
7256                if (!url) return;
7257                var img = new Image();
7258                found_images = ++x;
7259                img.crossOrigin = '';
7260                img.onerror = img.onload = function () {
7261                    if (img.complete) {
7262                        //to support data urls in images, set width and height
7263                        //as those values are not recognized automatically
7264                        if (img.src.indexOf('data:image/') === 0) {
7265                            img.width = width || img.width || 0;
7266                            img.height = height || img.height || 0;
7267                        }
7268                        //if valid image add to known images array
7269                        if (img.width + img.height) {
7270                            var hash = renderer.pdf.sHashCode(url) || url;
7271                            images[hash] = images[hash] || img;
7272                        }
7273                    }
7274                    if (! --x) {
7275                        done();
7276                    }
7277                };
7278                img.src = url;
7279            }
7280            while (l--) {
7281                loadImage(imgs[l].getAttribute("src"), imgs[l].width, imgs[l].height);
7282            }return x || done();
7283        };
7284        checkForFooter = function checkForFooter(elem, renderer, elementHandlers) {
7285            //check if we can found a <footer> element
7286            var footer = elem.getElementsByTagName("footer");
7287            if (footer.length > 0) {
7288
7289                footer = footer[0];
7290
7291                //bad hack to get height of footer
7292                //creat dummy out and check new y after fake rendering
7293                var oldOut = renderer.pdf.internal.write;
7294                var oldY = renderer.y;
7295                renderer.pdf.internal.write = function () {};
7296                _DrillForContent(footer, renderer, elementHandlers);
7297                var footerHeight = Math.ceil(renderer.y - oldY) + 5;
7298                renderer.y = oldY;
7299                renderer.pdf.internal.write = oldOut;
7300
7301                //add 20% to prevent overlapping
7302                renderer.pdf.margins_doc.bottom += footerHeight;
7303
7304                //Create function render header on every page
7305                var renderFooter = function renderFooter(pageInfo) {
7306                    var pageNumber = pageInfo !== undefined ? pageInfo.pageNumber : 1;
7307                    //set current y position to old margin
7308                    var oldPosition = renderer.y;
7309                    //render all child nodes of the header element
7310                    renderer.y = renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom;
7311                    renderer.pdf.margins_doc.bottom -= footerHeight;
7312
7313                    //check if we have to add page numbers
7314                    var spans = footer.getElementsByTagName('span');
7315                    for (var i = 0; i < spans.length; ++i) {
7316                        //if we find some span element with class pageCounter, set the page
7317                        if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" pageCounter ") > -1) {
7318                            spans[i].innerHTML = pageNumber;
7319                        }
7320                        //if we find some span element with class totalPages, set a variable which is replaced after rendering of all pages
7321                        if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) {
7322                            spans[i].innerHTML = '###jsPDFVarTotalPages###';
7323                        }
7324                    }
7325
7326                    //render footer content
7327                    _DrillForContent(footer, renderer, elementHandlers);
7328                    //set bottom margin to previous height including the footer height
7329                    renderer.pdf.margins_doc.bottom += footerHeight;
7330                    //important for other plugins (e.g. table) to start rendering at correct position after header
7331                    renderer.y = oldPosition;
7332                };
7333
7334                //check if footer contains totalPages which should be replace at the disoposal of the document
7335                var spans = footer.getElementsByTagName('span');
7336                for (var i = 0; i < spans.length; ++i) {
7337                    if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) {
7338                        renderer.pdf.internal.events.subscribe('htmlRenderingFinished', renderer.pdf.putTotalPages.bind(renderer.pdf, '###jsPDFVarTotalPages###'), true);
7339                    }
7340                }
7341
7342                //register event to render footer on every new page
7343                renderer.pdf.internal.events.subscribe('addPage', renderFooter, false);
7344                //render footer on first page
7345                renderFooter();
7346
7347                //prevent footer rendering
7348                SkipNode['FOOTER'] = 1;
7349            }
7350        };
7351        process = function process(pdf, element, x, y, settings, c
7351allback) {
7352            if (!element) return false;
7353            if (typeof element !== "string" && !element.parentNode) element = '' + element.innerHTML;
7354            if (typeof element === "string") {
7355                element = function (element) {
7356                    var $frame, $hiddendiv, framename, visuallyhidden;
7357                    framename = "jsPDFhtmlText" + Date.now().toString() + (Math.random() * 1000).toFixed(0);
7358                    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;";
7359                    $hiddendiv = document.createElement('div');
7360                    $hiddendiv.style.cssText = visuallyhidden;
7361                    $hiddendiv.innerHTML = "<iframe style=\"height:1px;width:1px\" name=\"" + framename + "\" />";
7362                    document.body.appendChild($hiddendiv);
7363                    $frame = window.frames[framename];
7364                    $frame.document.open();
7365                    $frame.document.writeln(element);
7366                    $frame.document.close();
7367                    return $frame.document.body;
7368                }(element.replace(/<\/?script[^>]*?>/gi, ''));
7369            }
7370            var r = new Renderer(pdf, x, y, settings),
7371                out;
7372
7373            // 1. load images
7374            // 2. prepare optional footer elements
7375            // 3. render content
7376            loadImgs.call(this, element, r, settings.elementHandlers, function (found_images) {
7377                checkForFooter(element, r, settings.elementHandlers);
7378                _DrillForContent(element, r, settings.elementHandlers);
7379                //send event dispose for final taks (e.g. footer totalpage replacement)
7380                r.pdf.internal.events.publish('htmlRenderingFinished');
7381                out = r.dispose();
7382                if (typeof callback === 'function') callback(out);else if (found_images) console.error('jsPDF Warning: rendering issues? provide a callback to fromHTML!');
7383            });
7384            return out || { x: r.x, y: r.y };
7385        };
7386        Renderer.prototype.init = function () {
7387            this.paragraph = {
7388                text: [],
7389                style: []
7390            };
7391            return this.pdf.internal.write("q");
7392        };
7393        Renderer.prototype.dispose = function () {
7394            this.pdf.internal.write("Q");
7395            return {
7396                x: this.x,
7397                y: this.y,
7398                ready: true
7399            };
7400        };
7401
7402        //Checks if we have to execute some watcher functions
7403        //e.g. to end text floating around an image
7404        Renderer.prototype.executeWatchFunctions = function (el) {
7405            var ret = false;
7406            var narray = [];
7407            if (this.watchFunctions.length > 0) {
7408                for (var i = 0; i < this.watchFunctions.length; ++i) {
7409                    if (this.watchFunctions[i](el) === true) {
7410                        ret = true;
7411                    } else {
7412                        narray.push(this.watchFunctions[i]);
7413                    }
7414                }
7415                this.watchFunctions = narray;
7416            }
7417            return ret;
7418        };
7419
7420        Renderer.prototype.splitFragmentsIntoLines = function (fragments, styles) {
7421            var currentLineLength, defaultFontSize, ff, fontMetrics, fontMetricsCache, fragment, fragmentChopped, fragmentLength, fragmentSpecificMetrics, fs, k, line, lines, maxLineLength, style;
7422            defaultFontSize = 12;
7423            k = this.pdf.internal.scaleFactor;
7424            fontMetricsCache = {};
7425            ff = void 0;
7426            fs = void 0;
7427            fontMetrics = void 0;
7428            fragment = void 0;
7429            style = void 0;
7430            fragmentSpecificMetrics = void 0;
7431            fragmentLength = void 0;
7432            fragmentChopped = void 0;
7433            line = [];
7434            lines = [line];
7435            currentLineLength = 0;
7436            maxLineLength = this.settings.width;
7437            while (fragments.length) {
7438                fragment = fragments.shift();
7439                style = styles.shift();
7440                if (fragment) {
7441                    ff = style["font-family"];
7442                    fs = style["font-style"];
7443                    fontMetrics = fontMetricsCache[ff + fs];
7444                    if (!fontMetrics) {
7445                        fontMetrics = this.pdf.internal.getFont(ff, fs).metadata.Unicode;
7446                        fontMetricsCache[ff + fs] = fontMetrics;
7447                    }
7448                    fragmentSpecificMetrics = {
7449                        widths: fontMetrics.widths,
7450                        kerning: fontMetrics.kerning,
7451                        fontSize: style["font-size"] * defaultFontSize,
7452                        textIndent: currentLineLength
7453                    };
7454                    fragmentLength = this.pdf.getStringUnitWidth(fragment, fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
7455                    if (fragment == "\u2028") {
7456                        line = [];
7457                        lines.push(line);
7458                    } else if (currentLineLength + fragmentLength > maxLineLength) {
7459                        fragmentChopped = this.pdf.splitTextToSize(fragment, maxLineLength, fragmentSpecificMetrics);
7460                        line.push([fragmentChopped.shift(), style]);
7461                        while (fragmentChopped.length) {
7462                            line = [[fragmentChopped.shift(), style]];
7463                            lines.push(line);
7464                        }
7465                        currentLineLength = this.pdf.getStringUnitWidth(line[0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
7466                    } else {
7467                        line.push([fragment, style]);
7468                        currentLineLength += fragmentLength;
7469                    }
7470                }
7471            }
7472
7473            //if text alignment was set, set margin/indent of each line
7474            if (style['text-align'] !== undefined && (style['text-align'] === 'center' || style['text-align'] === 'right' || style['text-align'] === 'justify')) {
7475                for (var i = 0; i < lines.length; ++i) {
7476                    var length = this.pdf.getStringUnitWidth(lines[i][0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
7477                    //if there is more than on line we have to clone the style object as all lines hold a reference on this object
7478                    if (i > 0) {
7479                        lines[i][0][1] = clone(lines[i][0][1]);
7480                    }
7481                    var space = maxLineLength - length;
7482
7483                    if (style['text-align'] === 'right') {
7484                        lines[i][0][1]['margin-left'] = space;
7485                        //if alignment is not right, it has to be center so split the space to the left and the right
7486                    } else if (style['text-align'] === 'center') {
7487                        lines[i][0][1]['margin-left'] = space / 2;
7488                        //if justify was set, calculate the word spacing and define in by using the css property
7489                    } else if (style['text-align'] === 'justify') {
7490                        var countSpaces = lines[i][0][0].split(' ').length - 1;
7491                        lines[i][0][1]['word-spacing'] = space / countSpaces;
7492                        //ignore the last line in justify mode
7493                        if (i === lines.length - 1) {
7494                            lines[i][0][1]['word-spacing'] = 0;
7495                        }
7496                    }
7497                }
7498            }
7499
7500            return lines;
7501        };
7502        Renderer.prototype.RenderTextFragment = function (text, style) {
7503            var defaultFontSize, font, maxLineHeight;
7504
7505            maxLineHeight = 0;
7506            defaultFontSize = 12;
7507
7508            if (this.pdf.internal.pageSize.height - this.pdf.margins_doc.bottom < this.y + this.pdf.internal.getFontSize()) {
7509                this.pdf.internal.write("ET", "Q");
7510                this.pdf.addPage();
7511                this.y = this.pdf.margins_doc.top;
7512                this.pdf.internal.write("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), style.color, "Td");
7513                //move cursor by one line on new page
7514                maxLineHeight = Math.max(maxLineHeight, style["line-height"], style["font-size"]);
7515                this.pdf.internal.write(0, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td");
7516            }
7517
7518            font = this.pdf.internal.getFont(style["font-family"], style["font-style"]);
7519
7520            // text color
7521            var pdfTextColor = this.getPdfColor(style["color"]);
7522            if (pdfTextColor !== this.lastTextColor) {
7523                this.pdf.internal.write(pdfTextColor);
7524                this.lastTextColor = pdfTextColor;
7525            }
7526
7527            //set the word spacing for e.g. justify style
7528            if (style['word-spacing'] !== undefined && style['word-spacing'] > 0) {
7529                this.pdf.internal.write(style['word-spacing'].toFixed(2), "Tw");
7530            }
7531
7532            this.pdf.internal.write("/" + font.id, (defaultFontSize * style["font-size"]).toFixed(2), "Tf", "(" + this.pdf.internal.pdfEscape(text) + ") Tj");
7533
7534            //set the word spacing back to neutral => 0
7535            if (style['word-spacing'] !== undefined) {
7536                this.pdf.internal.write(0, "Tw");
7537            }
7538        };
7539
7540        // Accepts #FFFFFF, rgb(int,int,int), or CSS Color Name
7541        Renderer.prototype.getPdfColor = function (style) {
7542            var textColor;
7543            var r, g, b;
7544
7545            var rx = /rgb\s*\(\s*(\d+),\s*(\d+),\s*(\d+\s*)\)/;
7546            var m = rx.exec(style);
7547            if (m != null) {
7548                r = parseInt(m[1]);
7549                g = parseInt(m[2]);
7550                b = parseInt(m[3]);
7551            } else {
7552                if (style.charAt(0) != '#') {
7553                    style = CssColors.colorNameToHex(style);
7554                    if (!style) {
7555                        style = '#000000';
7556                    }
7557                }
7558                r = style.substring(1, 3);
7559                r = parseInt(r, 16);
7560                g = style.substring(3, 5);
7561                g = parseInt(g, 16);
7562                b = style.substring(5, 7);
7563                b = parseInt(b, 16);
7564            }
7565
7566            if (typeof r === 'string' && /^#[0-9A-Fa-f]{6}$/.test(r)) {
7567                var hex = parseInt(r.substr(1), 16);
7568                r = hex >> 16 & 255;
7569                g = hex >> 8 & 255;
7570                b = hex & 255;
7571            }
7572
7573            var f3 = this.f3;
7574            if (r === 0 && g === 0 && b === 0 || typeof g === 'undefined') {
7575                textColor = f3(r / 255) + ' g';
7576            } else {
7577                textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' ');
7578            }
7579            return textColor;
7580        };
7581
7582        Renderer.prototype.f3 = function (number) {
7583            return number.toFixed(3); // Ie, %.3f
7584        }, Renderer.prototype.renderParagraph = function (cb) {
7585            var blockstyle, defaultFontSize, fontToUnitRatio, fragments, i, l, line, lines, maxLineHeight, out, paragraphspacing_after, paragraphspacing_before, priorblockstyle, styles, fontSize;
7586            fragments = PurgeWhiteSpace(this.paragraph.text);
7587            styles = this.paragraph.style;
7588            blockstyle = this.paragraph.blockstyle;
7589            priorblockstyle = this.paragraph.priorblockstyle || {};
7590            this.paragraph = {
7591                text: [],
7592                style: [],
7593                blockstyle: {},
7594                priorblockstyle: blockstyle
7595            };
7596            if (!fragments.join("").trim()) {
7597                return;
7598            }
7599            lines = this.splitFragmentsIntoLines(fragments, styles);
7600            line = void 0;
7601            maxLineHeight = void 0;
7602            defaultFontSize = 12;
7603            fontToUnitRatio = defaultFontSize / this.pdf.internal.scaleFactor;
7604            this.priorMarginBottom = this.priorMarginBottom || 0;
7605            paragraphspacing_before = (Math.max((blockstyle["margin-top"] || 0) - this.priorMarginBottom, 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio;
7606            paragraphspacing_after = ((blockstyle["margin-bottom"] || 0) + (blockstyle["padding-bottom"] || 0)) * fontToUnitRatio;
7607            this.priorMarginBottom = blockstyle["margin-bottom"] || 0;
7608
7609            if (blockstyle['page-break-before'] === 'always') {
7610                this.pdf.addPage();
7611                this.y = 0;
7612                paragraphspacing_before = ((blockstyle["margin-top"] || 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio;
7613            }
7614
7615            out = this.pdf.internal.write;
7616            i = void 0;
7617            l = void 0;
7618            this.y += paragraphspacing_before;
7619            out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
7620
7621            //stores the current indent of cursor position
7622            var currentIndent = 0;
7623
7624            while (lines.length) {
7625                line = lines.shift();
7626                maxLineHeight = 0;
7627                i = 0;
7628                l = line.length;
7629                while (i !== l) {
7630                    if (line[i][0].trim()) {
7631                        maxLineHeight = Math.max(maxLineHeight, line[i][1]["line-height"], line[i][1]["font-size"]);
7632                        fontSize = line[i][1]["font-size"] * 7;
7633                    }
7634                    i++;
7635                }
7636                //if we have to move the cursor to adapt the indent
7637                var indentMove = 0;
7638                var wantedIndent = 0;
7639                //if a margin was added (by e.g. a text-alignment), move the cursor
7640                if (line[0][1]["margin-left"] !== undefined && line[0][1]["margin-left"] > 0) {
7641                    wantedIndent = this.pdf.internal.getCoordinateString(line[0][1]["margin-left"]);
7642                    indentMove = wantedIndent - currentIndent;
7643                    currentIndent = wantedIndent;
7644                }
7645                var indentMore = Math.max(blockstyle["margin-left"] || 0, 0) * fontToUnitRatio;
7646                //move the cursor
7647                out(indentMove + indentMore, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td");
7648                i = 0;
7649                l = line.length;
7650                while (i !== l) {
7651                    if (line[i][0]) {
7652                        this.RenderTextFragment(line[i][0], line[i][1]);
7653                    }
7654                    i++;
7655                }
7656                this.y += maxLineHeight * fontToUnitRatio;
7657
7658                //if some watcher function was executed successful, so e.g. margin and widths were changed,
7659                //reset line drawing and calculate position and lines again
7660                //e.g. to stop text floating around an image
7661                if (this.executeWatchFunctions(line[0][1]) && lines.length > 0) {
7662                    var localFragments = [];
7663                    var localStyles = [];
7664                    //create fragment array of
7665                    lines.forEach(function (localLine) {
7666                        var i = 0;
7667                        var l = localLine.length;
7668                        while (i !== l) {
7669                            if (localLine[i][0]) {
7670                                localFragments.push(localLine[i][0] + ' ');
7671                                localStyles.push(localLine[i][1]);
7672                            }
7673                            ++i;
7674                        }
7675                    });
7676                    //split lines again due to possible coordinate changes
7677                    lines = this.splitFragmentsIntoLines(PurgeWhiteSpace(localFragments), localStyles);
7678                    //reposition the current cursor
7679                    out("ET", "Q");
7680                    out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
7681                }
7682            }
7683            if (cb && typeof cb === "function") {
7684                cb.call(this, this.x - 9, this.y - fontSize / 2);
7685            }
7686            out("ET", "Q");
7687            return this.y += paragraphspacing_after;
7688        };
7689        Renderer.prototype.setBlockBoundary = function (cb) {
7690            return this.renderParagraph(cb);
7691        };
7692        Renderer.prototype.setBlockStyle = function (css) {
7693            return this.paragraph.blockstyle = css;
7694        };
7695        Renderer.prototype.addText = function (text, css) {
7696            this.paragraph.text.push(text);
7697            return this.paragraph.style.push(css);
7698        };
7699        FontNameDB = {
7700            helvetica: "helvetica",
7701            "sans-serif": "helvetica",
7702            "times new roman": "times",
7703            serif: "times",
7704            times: "times",
7705            monospace: "courier",
7706            courier: "courier"
7707        };
7708        FontWeightMap = {
7709            100: "normal",
7710            200: "normal",
7711            300: "normal",
7712            400: "normal",
7713            500: "bold",
7714            600: "bold",
7715            700: "bold",
7716            800: "bold",
7717            900: "bold",
7718            normal: "normal",
7719            bold: "bold",
7720            bolder: "bold",
7721            lighter: "normal"
7722        };
7723        FontStyleMap = {
7724            normal: "normal",
7725            italic: "italic",
7726            oblique: "italic"
7727        };
7728        TextAlignMap = {
7729            left: "left",
7730            right: "right",
7731            center: "center",
7732            justify: "justify"
7733        };
7734        FloatMap = {
7735            none: 'none',
7736            right: 'right',
7737            left: 'left'
7738        };
7739        ClearMap = {
7740            none: 'none',
7741            both: 'both'
7742        };
7743        UnitedNumberMap = {
7744            normal: 1
7745        };
7746        /**
7747         * Converts HTML-formatted text into formatted PDF text.
7748         *
7749         * Notes:
7750         * 2012-07-18
7751         * Plugin relies on having browser, DOM around. The HTML is pushed into dom and traversed.
7752         * Plugin relies on jQuery for CSS extraction.
7753         * Targeting HTML output from Markdown templating, which is a very simple
7754         * markup - div, span, em, strong, p. No br-based paragraph separation supported explicitly (but still may work.)
7755         * Images, tables are NOT supported.
7756         *
7757         * @public
7758         * @function
7759         * @param HTML {String or DOM Element} HTML-formatted text, or pointer to DOM element that is to be rendered into PDF.
7760         * @param x {Number} starting X coordinate in jsPDF instance's declared units.
7761         * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
7762         * @param settings {Object} Additional / optional variables controlling parsing, rendering.
7763         * @returns {Object} jsPDF instance
7764         */
7765        jsPDFAPI.fromHTML = function (HTML, x, y, settings, callback, margins) {
7766            "use strict";
7767
7768            this.margins_doc = margins || {
7769                top: 0,
7770                bottom: 0
7771            };
7772            if (!settings) settings = {};
7773            if (!settings.elementHandlers) settings.elementHandlers = {};
7774
7775            return process(this, HTML, isNaN(x) ? 4 : x, isNaN(y) ? 4 : y, settings, c
7775allback);
7776        };
7777    })(jsPDF.API);
7778
7779    /** ====================================================================
7780     * jsPDF JavaScript plugin
7781     * Copyright (c) 2013 Youssef Beddad, [email protected]
7782     *
7783     *
7784     * ====================================================================
7785     */
7786
7787    /*global jsPDF */
7788
7789    (function (jsPDFAPI) {
7790        'use strict';
7791
7792        var jsNamesObj, jsJsObj, text;
7793        jsPDFAPI.addJS = function (txt) {
7794            text = txt;
7795            this.internal.events.subscribe('postPutResources', function (txt) {
7796                jsNamesObj = this.internal.newObject();
7797                this.internal.write('<< /Names [(EmbeddedJS) ' + (jsNamesObj + 1) + ' 0 R] >>', 'endobj');
7798                jsJsObj = this.internal.newObject();
7799                this.internal.write('<< /S /JavaScript /JS (', text, ') >>', 'endobj');
7800            });
7801            this.internal.events.subscribe('putCatalog', function () {
7802                if (jsNamesObj !== undefined && jsJsObj !== undefined) {
7803                    this.internal.write('/Names <</JavaScript ' + jsNamesObj + ' 0 R>>');
7804                }
7805            });
7806            return this;
7807        };
7808    })(jsPDF.API);
7809
7810    /**
7811     * jsPDF Outline PlugIn
7812     * Copyright (c) 2014 Steven Spungin (TwelveTone LLC)  [email protected]
7813     *
7814     * Licensed under the MIT License.
7815     * http://opensource.org/licenses/mit-license
7816     */
7817
7818    /**
7819     * Generates a PDF Outline
7820     */
7821    ;
7822    (function (jsPDFAPI) {
7823        'use strict';
7824
7825        jsPDFAPI.events.push(['postPutResources', function () {
7826            var pdf = this;
7827            var rx = /^(\d+) 0 obj$/;
7828
7829            // Write action goto objects for each page
7830            // this.outline.destsGoto = [];
7831            // for (var i = 0; i < totalPages; i++) {
7832            // var id = pdf.internal.newObject();
7833            // this.outline.destsGoto.push(id);
7834            // pdf.internal.write("<</D[" + (i * 2 + 3) + " 0 R /XYZ null
7835            // null null]/S/GoTo>> endobj");
7836            // }
7837            //
7838            // for (var i = 0; i < dests.length; i++) {
7839            // pdf.internal.write("(page_" + (i + 1) + ")" + dests[i] + " 0
7840            // R");
7841            // }
7842            //
7843            if (this.outline.root.children.length > 0) {
7844                var lines = pdf.outline.render().split(/\r\n/);
7845                for (var i = 0; i < lines.length; i++) {
7846                    var line = lines[i];
7847                    var m = rx.exec(line);
7848                    if (m != null) {
7849                        var oid = m[1];
7850                        pdf.internal.newObjectDeferredBegin(oid);
7851                    }
7852                    pdf.internal.write(line);
7853                }
7854            }
7855
7856            // This code will write named destination for each page reference
7857            // (page_1, etc)
7858            if (this.outline.createNamedDestinations) {
7859                var totalPages = this.internal.pages.length;
7860                // WARNING: this assumes jsPDF starts on page 3 and pageIDs
7861                // follow 5, 7, 9, etc
7862                // Write destination objects for each page
7863                var dests = [];
7864                for (var i = 0; i < totalPages; i++) {
7865                    var id = pdf.internal.newObject();
7866                    dests.push(id);
7867                    var info = pdf.internal.getPageInfo(i + 1);
7868                    pdf.internal.write("<< /D[" + info.objId + " 0 R /XYZ null null null]>> endobj");
7869                }
7870
7871                // assign a name for each destination
7872                var names2Oid = pdf.internal.newObject();
7873                pdf.internal.write('<< /Names [ ');
7874                for (var i = 0; i < dests.length; i++) {
7875                    pdf.internal.write("(page_" + (i + 1) + ")" + dests[i] + " 0 R");
7876                }
7877                pdf.internal.write(' ] >>', 'endobj');
7878
7879                // var kids = pdf.internal.newObject();
7880                // pdf.internal.write('<< /Kids [ ' + names2Oid + ' 0 R');
7881                // pdf.internal.write(' ] >>', 'endobj');
7882
7883                var namesOid = pdf.internal.newObject();
vendor: 7,804 bytes, lines 7884-8091
7884                pdf.internal.write('<< /Dests ' + names2Oid + " 0 R");
7885                pdf.internal.write('>>', 'endobj');
7886            }
7887        }]);
7888
7889        jsPDFAPI.events.push(['putCatalog', function () {
7890            var pdf = this;
7891            if (pdf.outline.root.children.length > 0) {
7892                pdf.internal.write("/Outlines", this.outline.makeRef(this.outline.root));
7893                if (this.outline.createNamedDestinations) {
7894                    pdf.internal.write("/Names " + namesOid + " 0 R");
7895                }
7896                // Open with Bookmarks showing
7897                // pdf.internal.write("/PageMode /UseOutlines");
7898            }
7899        }]);
7900
7901        jsPDFAPI.events.push(['initialized', function () {
7902            var pdf = this;
7903
7904            pdf.outline = {
7905                createNamedDestinations: false,
7906                root: {
7907                    children: []
7908                }
7909            };
7910
7911            var namesOid;
7912            var destsGoto = [];
7913
7914            /**
7915             * Options: pageNumber
7916             */
7917            pdf.outline.add = function (parent, title, options) {
7918                var item = {
7919                    title: title,
7920                    options: options,
7921                    children: []
7922                };
7923                if (parent == null) {
7924                    parent = this.root;
7925                }
7926                parent.children.push(item);
7927                return item;
7928            };
7929
7930            pdf.outline.render = function () {
7931                this.ctx = {};
7932                this.ctx.val = '';
7933                this.ctx.pdf = pdf;
7934
7935                this.genIds_r(this.root);
7936                this.renderRoot(this.root);
7937                this.renderItems(this.root);
7938
7939                return this.ctx.val;
7940            };
7941
7942            pdf.outline.genIds_r = function (node) {
7943                node.id = pdf.internal.newObjectDeferred();
7944                for (var i = 0; i < node.children.length; i++) {
7945                    this.genIds_r(node.children[i]);
7946                }
7947            };
7948
7949            pdf.outline.renderRoot = function (node) {
7950                this.objStart(node);
7951                this.line('/Type /Outlines');
7952                if (node.children.length > 0) {
7953                    this.line('/First ' + this.makeRef(node.children[0]));
7954                    this.line('/Last ' + this.makeRef(node.children[node.children.length - 1]));
7955                }
7956                this.line('/Count ' + this.count_r({
7957                    count: 0
7958                }, node));
7959                this.objEnd();
7960            };
7961
7962            pdf.outline.renderItems = function (node) {
7963                for (var i = 0; i < node.children.length; i++) {
7964                    var item = node.children[i];
7965                    this.objStart(item);
7966
7967                    this.line('/Title ' + this.makeString(item.title));
7968
7969                    this.line('/Parent ' + this.makeRef(node));
7970                    if (i > 0) {
7971                        this.line('/Prev ' + this.makeRef(node.children[i - 1]));
7972                    }
7973                    if (i < node.children.length - 1) {
7974                        this.line('/Next ' + this.makeRef(node.children[i + 1]));
7975                    }
7976                    if (item.children.length > 0) {
7977                        this.line('/First ' + this.makeRef(item.children[0]));
7978                        this.line('/Last ' + this.makeRef(item.children[item.children.length - 1]));
7979                    }
7980
7981                    var count = this.count = this.count_r({
7982                        count: 0
7983                    }, item);
7984                    if (count > 0) {
7985                        this.line('/Count ' + count);
7986                    }
7987
7988                    if (item.options) {
7989                        if (item.options.pageNumber) {
7990                            // Explicit Destination
7991                            //WARNING this assumes page ids are 3,5,7, etc.
7992                            var info = pdf.internal.getPageInfo(item.options.pageNumber);
7993                            this.line('/Dest ' + '[' + info.objId + ' 0 R /XYZ 0 ' + this.ctx.pdf.internal.pageSize.height + ' 0]');
7994                            // this line does not work on all clients (pageNumber instead of page ref)
7995                            //this.line('/Dest ' + '[' + (item.options.pageNumber - 1) + ' /XYZ 0 ' + this.ctx.pdf.internal.pageSize.height + ' 0]');
7996
7997                            // Named Destination
7998                            // this.line('/Dest (page_' + (item.options.pageNumber) + ')');
7999
8000                            // Action Destination
8001                            // var id = pdf.internal.newObject();
8002                            // pdf.internal.write('<</D[' + (item.options.pageNumber - 1) + ' /XYZ null null null]/S/GoTo>> endobj');
8003                            // this.line('/A ' + id + ' 0 R' );
8004                        }
8005                    }
8006                    this.objEnd();
8007                }
8008                for (var i = 0; i < node.children.length; i++) {
8009                    var item = node.children[i];
8010                    this.renderItems(item);
8011                }
8012            };
8013
8014            pdf.outline.line = function (text) {
8015                this.ctx.val += text + '\r\n';
8016            };
8017
8018            pdf.outline.makeRef = function (node) {
8019                return node.id + ' 0 R';
8020            };
8021
8022            pdf.outline.makeString = function (val) {
8023                return '(' + pdf.internal.pdfEscape(val) + ')';
8024            };
8025
8026            pdf.outline.objStart = function (node) {
8027                this.ctx.val += '\r\n' + node.id + ' 0 obj' + '\r\n<<\r\n';
8028            };
8029
8030            pdf.outline.objEnd = function (node) {
8031                this.ctx.val += '>> \r\n' + 'endobj' + '\r\n';
8032            };
8033
8034            pdf.outline.count_r = function (ctx, node) {
8035                for (var i = 0; i < node.children.length; i++) {
8036                    ctx.count++;
8037                    this.count_r(ctx, node.children[i]);
8038                }
8039                return ctx.count;
8040            };
8041        }]);
8042
8043        return this;
8044    })(jsPDF.API);
8045
8046    /**@preserve
8047     *  ====================================================================
8048     * jsPDF PNG PlugIn
8049     * Copyright (c) 2014 James Robb, https://github.com/jamesbrobb
8050     *
8051     *
8052     * ====================================================================
8053     */
8054
8055    (function (jsPDFAPI) {
8056        'use strict';
8057
8058        /*
8059    * @see http://www.w3.org/TR/PNG-Chunks.html
8060    *
8061    Color    Allowed      Interpretation
8062    Type     Bit Depths
8063   	   0       1,2,4,8,16  Each pixel is a grayscale sample.
8064   	   2       8,16        Each pixel is an R,G,B triple.
8065   	   3       1,2,4,8     Each pixel is a palette index;
8066                          a PLTE chunk must appear.
8067   	   4       8,16        Each pixel is a grayscale sample,
8068                          followed by an alpha sample.
8069   	   6       8,16        Each pixel is an R,G,B triple,
8070                          followed by an alpha sample.
8071   */
8072
8073        /*
8074    * PNG filter method types
8075    *
8076    * @see http://www.w3.org/TR/PNG-Filters.html
8077    * @see http://www.libpng.org/pub/png/book/chapter09.html
8078    *
8079    * This is what the value 'Predictor' in decode params relates to
8080    *
8081    * 15 is "optimal prediction", which means the prediction algorithm can change from line to line.
8082    * 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.
8083    *
8084      0       None
8085      1       Sub
8086      2       Up
8087      3       Average
8088      4       Paeth
8089    */
8090
8091        var doesNotHavePngJS = function doesNotHavePngJS() {
8092                return typeof PNG !== 'function' || typeof FlateStream !== 'function';
8093            },
8094            canCompress = function canCompress(value) {
8095                return value !== jsPDFAPI.image_compression.NONE && hasCompressionJS();
8096            },
8097            hasCompressionJS = function hasCompressionJS() {
8098                var inst = typeof Deflater === 'function';
8099                if (!inst) throw new Error("requires deflate.js for compression");
8100                return inst;
8101            },
8102            compressBytes = function compressBytes(bytes, lineLength, colorsPerPixel, compression) {
8103
8104                var level = 5,
8105                    filter_method = filterUp;
8106
8107                switch (compression) {
8108
8109                    case jsPDFAPI.image_compression.FAST:
8110
8111                        level = 3;
8112                        filter_method = filterSub;
8113                        break;
8114
8115                    case jsPDFAPI.image_compression.MEDIUM:
8116
8117                        level = 6;
8118                        filter_method = filterAverage;
8119                        break;
8120
8121                    case jsPDFAPI.image_compression.SLOW:
8122
8123                        level = 9;
8124                        filter_method = filterPaeth; //uses to sum to choose best filter for each line
8125                        break;
8126                }
8127
8128                bytes = applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method);
8129
8130                var header = new Uint8Array(createZlibHeader(level));
8131                var checksum = adler32(bytes);
8132
8133                var deflate = new Deflater(level);
8134                var a = deflate.append(bytes);
8135                var cBytes = deflate.flush();
8136
8137                var len = header.length + a.length + cBytes.length;
8138
8139                var cmpd = new Uint8Array(len + 4);
8140                cmpd.set(header);
8141                cmpd.set(a, header.length);
8142                cmpd.set(cBytes, header.length + a.length);
8143
8144                cmpd[len++] = checksum >>> 24 & 0xff;
8145                cmpd[len++] = checksum >>> 16 & 0xff;
8146                cmpd[len++] = checksum >>> 8 & 0xff;
8147                cmpd[len++] = checksum & 0xff;
8148
8149                return jsPDFAPI.arrayBufferToBinaryString(cmpd);
8150            },
8151            createZlibHeader = function createZlibHeader(bytes, level) {
8152                /*
8153     * @see http://www.ietf.org/rfc/rfc1950.txt for zlib header
8154     */
8155                var cm = 8;
8156                var cinfo = Math.LOG2E * Math.log(0x8000) - 8;
8157                var cmf = cinfo << 4 | cm;
8158
8159                var hdr = cmf << 8;
8160                var flevel = Math.min(3, (level - 1 & 0xff) >> 1);
8161
8162                hdr |= flevel << 6;
8163                hdr |= 0; //FDICT
8164                hdr += 31 - hdr % 31;
8165
8166                return [cmf, hdr & 0xff & 0xff];
8167            },
8168            adler32 = function adler32(array, param) {
8169                var adler = 1;
8170                var s1 = adler & 0xffff,
8171                    s2 = adler >>> 16 & 0xffff;
8172                var len = array.length;
8173                var tlen;
8174                var i = 0;
8175
8176                while (len > 0) {
8177                    tlen = len > param ? param : len;
8178                    len -= tlen;
8179                    do {
8180                        s1 += array[i++];
8181                        s2 += s1;
8182                    } while (--tlen);
8183
8184                    s1 %= 65521;
8185                    s2 %= 65521;
8186                }
8187
8188                return (s2 << 16 | s1) >>> 0;
8189            },
8190            applyPngFilterMethod = function applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method) {
8191                var lines = bytes.length / lineLength,
8192                    result = new Uint8Array(bytes.length + lines),
8193                    filter_methods = getFilterMethods(),
8194                    i = 0,
8195                    line,
8196                    prevLine,
8197                    offset;
8198
8199                for (; i < lines; i++) {
8200                    offset = i * lineLength;
8201                    line = bytes.subarray(offset, offset + lineLength);
8202
8203                    if (filter_method) {
8204                        result.set(filter_method(line, colorsPerPixel, prevLine), offset + i);
8205                    } else {
8206
8207                        var j = 0,
8208                            len = filter_methods.length,
8209                            results = [];
8210
8211                        for (; j < len; j++) {
8212                            results[j] = filter_methods[j](line, colorsPerPixel, prevLine);
8213                        }var ind = getIndexOfSmallestSum(results.concat());
8214
8215                        result.set(results[ind], offset + i);
8216                    }
8217
8218                    prevLine = line;
8219                }
8220
8221                return result;
8222            },
8223            filterNone = function filterNone(line, colorsPerPixel, prevLine) {
8224                /*var result = new Uint8Array(line.length + 1);
8225    result[0] = 0;
8226    result.set(line, 1);*/
8227
8228                var result = Array.apply([], line);
8229                result.unshift(0);
8230
8231                return result;
8232            },
8233            filterSub = function filterSub(line, colorsPerPixel, prevLine) {
8234                var result = [],
8235                    i = 0,
8236                    len = line.length,
8237                    left;
8238
8239                result[0] = 1;
8240
8241                for (; i < len; i++) {
8242                    left = line[i - colorsPerPixel] || 0;
8243                    result[i + 1] = line[i] - left + 0x0100 & 0xff;
8244                }
8245
8246                return result;
8247            },
8248            filterUp = function filterUp(line, colorsPerPixel, prevLine) {
8249                var result = [],
8250                    i = 0,
8251                    len = line.length,
8252                    up;
8253
8254                result[0] = 2;
8255
8256                for (; i < len; i++) {
8257                    up = prevLine && prevLine[i] || 0;
8258                    result[i + 1] = line[i] - up + 0x0100 & 0xff;
8259                }
8260
8261                return result;
8262            },
8263            filterAverage = function filterAverage(line, colorsPerPixel, prevLine) {
8264                var result = [],
8265                    i = 0,
8266                    len = line.length,
8267                    left,
8268                    up;
8269
8270                result[0] = 3;
8271
8272                for (; i < len; i++) {
8273                    left = line[i - colorsPerPixel] || 0;
8274                    up = prevLine && prevLine[i] || 0;
8275                    result[i + 1] = line[i] + 0x0100 - (left + up >>> 1) & 0xff;
8276                }
8277
8278                return result;
8279            },
8280            filterPaeth = function filterPaeth(line, colorsPerPixel, prevLine) {
8281                var result = [],
8282                    i = 0,
8283                    len = line.length,
8284                    left,
8285                    up,
8286                    upLeft,
8287                    paeth;
8288
8289                result[0] = 4;
8290
8291                for (; i < len; i++) {
8292                    left = line[i - colorsPerPixel] || 0;
8293                    up = prevLine && prevLine[i] || 0;
8294                    upLeft = prevLine && prevLine[i - colorsPerPixel] || 0;
8295                    paeth = paethPredictor(left, up, upLeft);
8296                    result[i + 1] = line[i] - paeth + 0x0100 & 0xff;
8297                }
8298
8299                return result;
8300            },
8301            paethPredictor = function paethPredictor(left, up, upLeft) {
8302
8303                var p = left + up - upLeft,
8304                    pLeft = Math.abs(p - left),
8305                    pUp = Math.abs(p - up),
8306                    pUpLeft = Math.abs(p - upLeft);
8307
8308                return pLeft <= pUp && pLeft <= pUpLeft ? left : pUp <= pUpLeft ? up : upLeft;
8309            },
8310            getFilterMethods = function getFilterMethods() {
8311                return [filterNone, filterSub, filterUp, filterAverage, filterPaeth];
8312            },
8313            getIndexOfSmallestSum = function getIndexOfSmallestSum(arrays) {
8314                var i = 0,
8315                    len = arrays.length,
8316                    sum,
8317                    min,
8318                    ind;
8319
8320                while (i < len) {
8321                    sum = absSum(arrays[i].slice(1));
8322
8323                    if (sum < min || !min) {
8324                        min = sum;
8325                        ind = i;
8326                    }
8327
8328                    i++;
8329                }
8330
8331                return ind;
8332            },
8333            absSum = function absSum(array) {
8334                var i = 0,
8335                    len = array.length,
8336                    sum = 0;
8337
8338                while (i < len) {
8339                    sum += Math.abs(array[i++]);
8340                }return sum;
8341            },
8342            getPredictorFromCompression = function getPredictorFromCompression(compression) {
8343                var predictor;
8344                switch (compression) {
8345                    case jsPDFAPI.image_compression.FAST:
8346                        predictor = 11;
8347                        break;
8348
8349                    case jsPDFAPI.image_compression.MEDIUM:
8350                        predictor = 13;
8351                        break;
8352
8353                    case jsPDFAPI.image_compression.SLOW:
8354                        predictor = 14;
8355                        break;
8356                }
8357                return predictor;
8358            },
8359            logImg = function logImg(img) {
8360                console.log("width: " + img.width);
8361                console.log("height: " + img.height);
8362                console.log("bits: " + img.bits);
8363                console.log("colorType: " + img.colorType);
8364                console.log("transparency:");
8365                console.log(img.transparency);
8366                console.log("text:");
8367                console.log(img.text);
8368                console.log("compressionMethod: " + img.compressionMethod);
8369                console.log("filterMethod: " + img.filterMethod);
8370                console.log("interlaceMethod: " + img.interlaceMethod);
8371                console.log("imgData:");
8372                console.log(img.imgData);
8373                console.log("palette:");
8374                console.log(img.palette);
8375                console.log("colors: " + img.colors);
8376                console.log("colorSpace: " + img.colorSpace);
8377                console.log("pixelBitlength: " + img.pixelBitlength);
8378                console.log("hasAlphaChannel: " + img.hasAlphaChannel);
8379            };
8380
8381        jsPDFAPI.processPNG = function (imageData, imageIndex, alias, compression, dataAsBinaryString) {
8382            'use strict';
8383
8384            var colorSpace = this.color_spaces.DEVICE_RGB,
8385                decode = this.decode.FLATE_DECODE,
8386                bpc = 8,
8387                img,
8388                dp,
8389                trns,
8390                colors,
8391                pal,
8392                smask;
8393
8394            /*	if(this.isString(imageData)) {
8395    		}*/
8396
8397            if (this.isArrayBuffer(imageData)) imageData = new Uint8Array(imageData);
8398
8399            if (this.isArrayBufferView(imageData)) {
8400
8401                if (doesNotHavePngJS()) throw new Error("PNG support requires png.js and zlib.js");
8402
8403                img = new PNG(imageData);
8404                imageData = img.imgData;
8405                bpc = img.bits;
8406                colorSpace = img.colorSpace;
8407                colors = img.colors;
8408
8409                //logImg(img);
8410
8411                /*
8412      * colorType 6 - Each pixel is an R,G,B triple, followed by an alpha sample.
8413      *
8414      * colorType 4 - Each pixel is a grayscale sample, followed by an alpha sample.
8415      *
8416      * Extract alpha to create two separate images, using the alpha as a sMask
8417      */
8418                if ([4, 6].indexOf(img.colorType) !== -1) {
8419
8420                    /*
8421       * processes 8 bit RGBA and grayscale + alpha images
8422       */
8423                    if (img.bits === 8) {
8424
8425                        var pixels = img.pixelBitlength == 32 ? new Uint32Array(img.decodePixels().buffer) : img.pixelBitlength == 16 ? new Uint16Array(img.decodePixels().buffer) : new Uint8Array(img.decodePixels().buffer),
8426                            len = pixels.length,
8427                            imgData = new Uint8Array(len * img.colors),
8428                            alphaData = new Uint8Array(len),
8429                            pDiff = img.pixelBitlength - img.bits,
8430                            i = 0,
8431                            n = 0,
8432                            pixel,
8433                            pbl;
8434
8435                        for (; i < len; i++) {
8436                            pixel = pixels[i];
8437                            pbl = 0;
8438
8439                            while (pbl < pDiff) {
8440
8441                                imgData[n++] = pixel >>> pbl & 0xff;
8442                                pbl = pbl + img.bits;
8443                            }
8444
8445                            alphaData[i] = pixel >>> pbl & 0xff;
8446                        }
8447                    }
8448
8449                    /*
8450       * processes 16 bit RGBA and grayscale + alpha images
8451       */
8452                    if (img.bits === 16) {
8453
8454                        var pixels = new Uint32Array(img.decodePixels().buffer),
8455                            len = pixels.length,
8456                            imgData = new Uint8Array(len * (32 / img.pixelBitlength) * img.colors),
8457                            alphaData = new Uint8Array(len * (32 / img.pixelBitlength)),
8458                            hasColors = img.colors > 1,
8459                            i = 0,
8460                            n = 0,
8461                            a = 0,
8462                            pixel;
8463
8464                        while (i < len) {
8465                            pixel = pixels[i++];
8466
8467                            imgData[n++] = pixel >>> 0 & 0xFF;
8468
8469                            if (hasColors) {
8470                                imgData[n++] = pixel >>> 16 & 0xFF;
8471
8472                                pixel = pixels[i++];
8473                                imgData[n++] = pixel >>> 0 & 0xFF;
8474                            }
8475
8476                            alphaData[a++] = pixel >>> 16 & 0xFF;
8477                        }
8478
8479                        bpc = 8;
8480                    }
8481
8482                    if (canCompress(compression)) {
8483
8484                        imageData = compressBytes(imgData, img.width * img.colors, img.colors, compression);
8485                        smask = compressBytes(alphaData, img.width, 1, compression);
8486                    } else {
8487
8488                        imageData = imgData;
8489                        smask = alphaData;
8490                        decode = null;
8491                    }
8492                }
8493
8494                /*
8495      * Indexed png. Each pixel is a palette index.
8496      */
8497                if (img.colorType === 3) {
8498
8499                    colorSpace = this.color_spaces.INDEXED;
8500                    pal = img.palette;
8501
8502                    if (img.transparency.indexed) {
8503
8504                        var trans = img.transparency.indexed;
8505
8506                        var total = 0,
8507                            i = 0,
8508                            len = trans.length;
8509
8510                        for (; i < len; ++i) {
8511                            total += trans[i];
8512                        }total = total / 255;
8513
8514                        /*
8515        * a single color is specified as 100% transparent (0),
8516        * so we set trns to use a /Mask with that index
8517        */
8518                        if (total === len - 1 && trans.indexOf(0) !== -1) {
8519                            trns = [trans.indexOf(0)];
8520
8521                            /*
8522         * there's more than one colour within the palette that specifies
8523         * a transparency value less than 255, so we unroll the pixels to create an image sMask
8524         */
8525                        } else if (total !== len) {
8526
8527                            var pixels = img.decodePixels(),
8528                                alphaData = new Uint8Array(pixels.length),
8529                                i = 0,
8530                                len = pixels.length;
8531
8532                            for (; i < len; i++) {
8533                                alphaData[i] = trans[pixels[i]];
8534                            }smask = compressBytes(alphaData, img.width, 1);
8535                        }
8536                    }
8537                }
8538
8539                var predictor = getPredictorFromCompression(compression);
8540
8541                if (decode === this.decode.FLATE_DECODE) dp = '/Predictor ' + predictor + ' /Colors ' + colors + ' /BitsPerComponent ' + bpc + ' /Columns ' + img.width;else
8542                    //remove 'Predictor' as it applies to the type of png filter applied to its IDAT - we only apply with compression
8543                    dp = '/Colors ' + colors + ' /BitsPerComponent ' + bpc + ' /Columns ' + img.width;
8544
8545                if (this.isArrayBuffer(imageData) || this.isArrayBufferView(imageData)) imageData = this.arrayBufferToBinaryString(imageData);
8546
8547                if (smask && this.isArrayBuffer(smask) || this.isArrayBufferView(smask)) smask = this.arrayBufferToBinaryString(smask);
8548
8549                return this.createImageInfo(imageData, img.width, img.height, colorSpace, bpc, decode, imageIndex, alias, dp, trns, pal, smask, predictor);
8550            }
8551
8552            throw new Error("Unsupported PNG image data, try using JPEG instead.");
8553        };
8554    })(jsPDF.API);
8555
8556    /**
8557     * jsPDF Autoprint Plugin
8558     *
8559     * Licensed under the MIT License.
8560     * http://opensource.org/licenses/mit-license
8561     */
8562
8563    (function (jsPDFAPI) {
8564        'use strict';
8565
8566        jsPDFAPI.autoPrint = function () {
8567            'use strict';
8568
8569            var refAutoPrintTag;
8570
8571            this.internal.events.subscribe('postPutResources', function () {
8572                refAutoPrintTag = this.internal.newObject();
8573                this.internal.write("<< /S/Named /Type/Action /N/Print >>", "endobj");
8574            });
8575
8576            this.internal.events.subscribe("putCatalog", function () {
8577                this.internal.write("/OpenAction " + refAutoPrintTag + " 0" + " R");
8578            });
8579            return this;
8580        };
8581    })(jsPDF.API);
8582
8583    /** @preserve
8584     * jsPDF split_text_to_size plugin - MIT license.
8585     * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
8586     *               2014 Diego Casorran, https://github.com/diegocr
8587     */
8588    /**
8589     *
8590     * ====================================================================
8591     */
8592
8593    ;(function (API) {
8594        'use strict';
8595
8596        /**
8597         Returns an array of length matching length of the 'word' string, with each
8598         cell ocupied by the width of the char in that position.
8599
8600         @function
8601         @param word {String}
8602         @param widths {Object}
8603         @param kerning {Object}
8604         @returns {Array}
8605         */
8606
8607        var getCharWidthsArray = API.getCharWidthsArray = function (text, options) {
8608
8609            if (!options) {
8610                options = {};
8611            }
8612
8613            var widths = options.widths ? options.widths : this.internal.getFont().metadata.Unicode.widths,
8614                widthsFractionOf = widths.fof ? widths.fof : 1,
8615                kerning = options.kerning ? options.kerning : this.internal.getFont().metadata.Unicode.kerning,
8616                kerningFractionOf = kerning.fof ? kerning.fof : 1;
8617
8618            // console.log("widths, kergnings", widths, kerning)
8619
8620            var i,
8621                l,
8622                char_code,
8623                prior_char_code = 0 // for kerning
8624                ,
8625                default_char_width = widths[0] || widthsFractionOf,
8626                output = [];
8627
8628            for (i = 0, l = text.length; i < l; i++) {
8629                char_code = text.charCodeAt(i);
8630                output.push((widths[char_code] || default_char_width) / widthsFractionOf + (kerning[char_code] && kerning[char_code][prior_char_code] || 0) / kerningFractionOf);
8631                prior_char_code = char_code;
8632            }
8633
8634            return output;
8635        };
8636        var getArraySum = function getArraySum(array) {
8637            var i = array.length,
8638                output = 0;
8639            while (i) {
8640                ;i--;
8641                output += array[i];
8642            }
8643            return output;
8644        };
8645        /**
8646         Returns a widths of string in a given font, if the font size is set as 1 point.
8647
8648         In other words, this is "proportional" value. For 1 unit of font size, the length
8649         of the string will be that much.
8650
8651         Multiply by font size to get actual width in *points*
8652         Then divide by 72 to get inches or divide by (72/25.6) to get 'mm' etc.
8653
8654         @public
8655         @function
8656         @param
8657         @returns {Type}
8658         */
8659        var getStringUnitWidth = API.getStringUnitWidth = function (text, options) {
8660            return getArraySum(getCharWidthsArray.call(this, text, options));
8661        };
8662
8663        /**
8664         returns array of lines
8665         */
8666        var splitLongWord = function splitLongWord(word, widths_array, firstLineMaxLen, maxLen) {
8667            var answer = [];
8668
8669            // 1st, chop off the piece that can fit on the hanging line.
8670            var i = 0,
8671                l = word.length,
8672                workingLen = 0;
8673            while (i !== l && workingLen + widths_array[i] < firstLineMaxLen) {
8674                workingLen += widths_array[i];i++;
8675            }
8676            // this is first line.
8677            answer.push(word.slice(0, i));
8678
8679            // 2nd. Split the rest into maxLen pieces.
8680            var startOfLine = i;
8681            workingLen = 0;
8682            while (i !== l) {
8683                if (workingLen + widths_array[i] > maxLen) {
8684                    answer.push(word.slice(startOfLine, i));
8685                    workingLen = 0;
8686                    startOfLine = i;
8687                }
8688                workingLen += widths_array[i];i++;
8689            }
8690            if (startOfLine !== i) {
8691                answer.push(word.slice(startOfLine, i));
8692            }
8693
8694            return answer;
8695        };
8696
8697        // Note, all sizing inputs for this function must be in "font measurement units"
8698        // By default, for PDF, it's "point".
8699        var splitParagraphIntoLines = function splitParagraphIntoLines(text, maxlen, options) {
8700            // at this time works only on Western scripts, ones with space char
8701            // separating the words. Feel free to expand.
8702
8703            if (!options) {
8704                options = {};
8705            }
8706
8707            var line = [],
8708                lines = [line],
8709                line_length = options.textIndent || 0,
8710                separator_length = 0,
8711                current_word_length = 0,
8712                word,
8713                widths_array,
8714                words = text.split(' '),
8715                spaceCharWidth = getCharWidthsArray(' ', options)[0],
8716                i,
8717                l,
8718                tmp,
8719                lineIndent;
8720
8721            if (options.lineIndent === -1) {
8722                lineIndent = words[0].length + 2;
8723            } else {
8724                lineIndent = options.lineIndent || 0;
8725            }
8726            if (lineIndent) {
8727                var pad = Array(lineIndent).join(" "),
8728                    wrds = [];
8729                words.map(function (wrd) {
8730                    wrd = wrd.split(/\s*\n/);
8731                    if (wrd.length > 1) {
8732                        wrds = wrds.concat(wrd.map(function (wrd, idx) {
8733                            return (idx && wrd.length ? "\n" : "") + wrd;
8734                        }));
8735                    } else {
8736                        wrds.push(wrd[0]);
8737                    }
8738                });
8739                words = wrds;
8740                lineIndent = getStringUnitWidth(pad, options);
8741            }
8742
8743            for (i = 0, l = words.length; i < l; i++) {
8744                var force = 0;
8745
8746                word = words[i];
8747                if (lineIndent && word[0] == "\n") {
8748                    word = word.substr(1);
8749                    force = 1;
8750                }
8751                widths_array = getCharWidthsArray(word, options);
8752                current_word_length = getArraySum(widths_array);
8753
8754                if (line_length + separator_length + current_word_length > maxlen || force) {
8755                    if (current_word_length > maxlen) {
8756                        // this happens when you have space-less long URLs for example.
8757                        // we just chop these to size. We do NOT insert hiphens
8758                        tmp = splitLongWord(word, widths_array, maxlen - (line_length + separator_length), maxlen);
8759                        // first line we add to existing line object
8760                        line.push(tmp.shift()); // it's ok to have extra space indicator there
8761                        // last line we make into new line object
8762                        line = [tmp.pop()];
8763                        // lines in the middle we apped to lines object as whole lines
8764                        while (tmp.length) {
8765                            lines.push([tmp.shift()]); // single fragment occupies whole line
8766                        }
8767                        current_word_length = getArraySum(widths_array.slice(word.length - line[0].length));
8768                    } else {
8769                        // just put it on a new line
8770                        line = [word];
8771                    }
8772
8773                    // now we attach new line to lines
8774                    lines.push(line);
8775                    line_length = current_word_length + lineIndent;
8776                    separator_length = spaceCharWidth;
8777                } else {
8778                    line.push(word);
8779
8780                    line_length += separator_length + current_word_length;
8781                    separator_length = spaceCharWidth;
8782                }
8783            }
8784
8785            if (lineIndent) {
8786                var postProcess = function postProcess(ln, idx) {
8787                    return (idx ? pad : '') + ln.join(" ");
8788                };
8789            } else {
8790                var postProcess = function postProcess(ln) {
8791                    return ln.join(" ");
8792                };
8793            }
8794
8795            return lines.map(postProcess);
8796        };
8797
8798        /**
8799         Splits a given string into an array of strings. Uses 'size' value
8800         (in measurement units declared as default for the jsPDF instance)
8801         and the font's "widths" and "Kerning" tables, where available, to
8802         determine display length of a given string for a given font.
8803
8804         We use character's 100% of unit size (height) as width when Width
8805         table or other default width is not available.
8806
8807         @public
8808         @function
8809         @param text {String} Unencoded, regular JavaScript (Unicode, UTF-16 / UCS-2) string.
8810         @param size {Number} Nominal number, measured in units default to this instance of jsPDF.
8811         @param options {Object} Optional flags needed for chopper to do the right thing.
8812         @returns {Array} with strings chopped to size.
8813         */
8814        API.splitTextToSize = function (text, maxlen, options) {
8815            'use strict';
8816
8817            if (!options) {
8818                options = {};
8819            }
8820
8821            var fsize = options.fontSize || this.internal.getFontSize(),
8822                newOptions = function (options) {
8823                    var widths = { 0: 1 },
8824                        kerning = {};
8825
8826                    if (!options.widths || !options.kerning) {
8827                        var f = this.internal.getFont(options.fontName, options.fontStyle),
8828                            encoding = 'Unicode';
8829                        // NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE
8830                        // Actual JavaScript-native String's 16bit char codes used.
8831                        // no multi-byte logic here
8832
8833                        if (f.metadata[encoding]) {
8834                            return {
8835                                widths: f.metadata[encoding].widths || widths,
8836                                kerning: f.metadata[encoding].kerning || kerning
8837                            };
8838                        }
8839                    } else {
8840                        return {
8841                            widths: options.widths,
8842                            kerning: options.kerning
8843                        };
8844                    }
8845
8846                    // then use default values
8847                    return {
8848                        widths: widths,
8849                        kerning: kerning
8850                    };
8851                }.call(this, options);
8852
8853            // first we split on end-of-line chars
8854            var paragraphs;
8855            if (Array.isArray(text)) {
8856                paragraphs = text;
8857            } else {
8858                paragraphs = text.split(/\r?\n/);
8859            }
8860
8861            // now we convert size (max length of line) into "font size units"
8862            // at present time, the "font size unit" is always 'point'
8863            // 'proportional' means, "in proportion to font size"
8864            var fontUnit_maxLen = 1.0 * this.internal.scaleFactor * maxlen / fsize;
8865            // at this time, fsize is always in "points" regardless of the default measurement unit of the doc.
8866            // this may change in the future?
8867            // until then, proportional_maxlen is likely to be in 'points'
8868
8869            // If first line is to be indented (shorter or longer) than maxLen
8870            // we indicate that by using CSS-style "text-indent" option.
8871            // here it's in font units too (which is likely 'points')
8872            // it can be negative (which makes the first line longer than maxLen)
8873            newOptions.textIndent = options.textIndent ? options.textIndent * 1.0 * this.internal.scaleFactor / fsize : 0;
8874            newOptions.lineIndent = options.lineIndent;
8875
8876            var i,
8877                l,
8878                output = [];
8879            for (i = 0, l = paragraphs.length; i < l; i++) {
8880                output = output.concat(splitParagraphIntoLines(paragraphs[i], fontUnit_maxLen, newOptions));
8881            }
8882
8883            return output;
8884        };
8885    })(jsPDF.API);
8886
8887    /** @preserve
8888     jsPDF standard_fonts_metrics plugin
8889     Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
8890     MIT license.
8891     */
8892    /**
8893     *
8894     * ====================================================================
8895     */
8896
8897    ;(function (API) {
8898        'use strict';
8899
8900        /*
8901   # reference (Python) versions of 'compress' and 'uncompress'
8902   # only 'uncompress' function is featured lower as JavaScript
8903   # if you want to unit test "roundtrip", just transcribe the reference
8904   # 'compress' function from Python into JavaScript
8905
8906   def compress(data):
8907
8908   	keys =   '0123456789abcdef'
8909   	values = 'klmnopqrstuvwxyz'
8910   	mapping = dict(zip(keys, values))
8911   	vals = []
8912   	for key in data.keys():
8913   		value = data[key]
8914   		try:
8915   			keystring = hex(key)[2:]
8916   			keystring = keystring[:-1] + mapping[keystring[-1:]]
8917   		except:
8918   			keystring = key.join(["'","'"])
8919   			#print('Keystring is %s' % keystring)
8920
8921   		try:
8922   			if value < 0:
8923   				valuestring = hex(value)[3:]
8924   				numberprefix = '-'
8925   			else:
8926   				valuestring = hex(value)[2:]
8927   				numberprefix = ''
8928   			valuestring = numberprefix + valuestring[:-1] + mapping[valuestring[-1:]]
8929   		except:
8930   			if type(value) == dict:
8931   				valuestring = compress(value)
8932   			else:
8933   				raise Exception("Don't know what to do with value type %s" % type(value))
8934
8935   		vals.append(keystring+valuestring)
8936
8937   	return '{' + ''.join(vals) + '}'
8938
8939   def uncompress(data):
8940
8941   	decoded = '0123456789abcdef'
8942   	encoded = 'klmnopqrstuvwxyz'
8943   	mapping = dict(zip(encoded, decoded))
8944
8945   	sign = +1
8946   	stringmode = False
8947   	stringparts = []
8948
8949   	output = {}
8950
8951   	activeobject = output
8952   	parentchain = []
8953
8954   	keyparts = ''
8955   	valueparts = ''
8956
8957   	key = None
8958
8959   	ending = set(encoded)
8960
8961   	i = 1
8962   	l = len(data) - 1 # stripping starting, ending {}
8963   	while i != l: # stripping {}
8964   		# -, {, }, ' are special.
8965
8966   		ch = data[i]
8967   		i += 1
8968
8969   		if ch == "'":
8970   			if stringmode:
8971   				# end of string mode
8972   				stringmode = False
8973   				key = ''.join(stringparts)
8974   			else:
8975   				# start of string mode
8976   				stringmode = True
8977   				stringparts = []
8978   		elif stringmode == True:
8979   			#print("Adding %s to stringpart" % ch)
8980   			stringparts.append(ch)
8981
8982   		elif ch == '{':
8983   			# start of object
8984   			parentchain.append( [activeobject, key] )
8985   			activeobject = {}
8986   			key = None
8987   			#DEBUG = True
8988   		elif ch == '}':
8989   			# end of object
8990   			parent, key = parentchain.pop()
8991   			parent[key] = activeobject
8992   			key = None
8993   			activeobject = parent
8994   			#DEBUG = False
8995
8996   		elif ch == '-':
8997   			sign = -1
8998   		else:
8999   			# must be number
9000   			if key == None:
9001   				#debug("In Key. It is '%s', ch is '%s'" % (keyparts, ch))
9002   				if ch in ending:
9003   					#debug("End of key")
9004   					keyparts += mapping[ch]
9005   					key = int(keyparts, 16) * sign
9006   					sign = +1
9007   					keyparts = ''
9008   				else:
9009   					keyparts += ch
9010   			else:
9011   				#debug("In value. It is '%s', ch is '%s'" % (valueparts, ch))
9012   				if ch in ending:
9013   					#debug("End of value")
9014   					valueparts += mapping[ch]
9015   					activeobject[key] = int(valueparts, 16) * sign
9016   					sign = +1
9017   					key = None
9018   					valueparts = ''
9019   				else:
9020   					valueparts += ch
9021
9022   			#debug(activeobject)
9023
9024   	return output
9025
9026   */
9027
9028        /**
9029         Uncompresses data compressed into custom, base16-like format.
9030         @public
9031         @function
9032         @param
9033         @returns {Type}
9034         */
9035
9036        var uncompress = function uncompress(data) {
9037
9038            var decoded = '0123456789abcdef',
9039                encoded = 'klmnopqrstuvwxyz',
9040                mapping = {};
9041
9042            for (var i = 0; i < encoded.length; i++) {
9043                mapping[encoded[i]] = decoded[i];
9044            }
9045
9046            var undef,
9047                output = {},
9048                sign = 1,
9049                stringparts // undef. will be [] in string mode
9050
9051                ,
9052                activeobject = output,
9053                parentchain = [],
9054                parent_key_pair,
9055                keyparts = '',
9056                valueparts = '',
9057                key // undef. will be Truthy when Key is resolved.
9058                ,
9059                datalen = data.length - 1 // stripping ending }
9060                ,
9061                ch;
9062
9063            i = 1; // stripping starting {
9064
9065            while (i != datalen) {
9066                // - { } ' are special.
9067
9068                ch = data[i];
9069                i += 1;
9070
9071                if (ch == "'") {
9072                    if (stringparts) {
9073                        // end of string mode
9074                        key = stringparts.join('');
9075                        stringparts = undef;
9076                    } else {
9077                        // start of string mode
9078                        stringparts = [];
9079                    }
9080                } else if (stringparts) {
9081                    stringparts.push(ch);
9082                } else if (ch == '{') {
9083                    // start of object
9084                    parentchain.push([activeobject, key]);
9085                    activeobject = {};
9086                    key = undef;
9087                } else if (ch == '}') {
9088                    // end of object
9089                    parent_key_pair = parentchain.pop();
9090                    parent_key_pair[0][parent_key_pair[1]] = activeobject;
9091                    key = undef;
9092                    activeobject = parent_key_pair[0];
9093                } else if (ch == '-') {
9094                    sign = -1;
9095                } else {
9096                    // must be number
9097                    if (key === undef) {
9098                        if (mapping.hasOwnProperty(ch)) {
9099                            keyparts += mapping[ch];
9100                            key = parseInt(keyparts, 16) * sign;
9101                            sign = +1;
9102                            keyparts = '';
9103                        } else {
9104                            keyparts += ch;
9105                        }
9106                    } else {
9107                        if (mapping.hasOwnProperty(ch)) {
9108                            valueparts += mapping[ch];
9109                            activeobject[key] = parseInt(valueparts, 16) * sign;
9110                            sign = +1;
9111                            key = undef;
9112                            valueparts = '';
9113                        } else {
9114                            valueparts += ch;
9115                        }
9116                    }
9117                }
9118            } // end while
9119
9120            return output;
9121        };
9122
9123        // encoding = 'Unicode'
9124        // NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE. NO clever BOM behavior
9125        // Actual 16bit char codes used.
9126        // no multi-byte logic here
9127
9128        // Unicode characters to WinAnsiEncoding:
9129        // {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}
9130        // as you can see, all Unicode chars are outside of 0-255 range. No char code conflicts.
9131        // this means that you can give Win cp1252 encoded strings to jsPDF for rendering directly
9132        // as well as give strings with some (supported by these fonts) Unicode characters and
9133        // these will be mapped to win cp1252
9134        // for example, you can send char code (cp1252) 0x80 or (unicode) 0x20AC, getting "Euro" glyph displayed in both cases.
9135
9136        var encodingBlock = {
9137                'codePages': ['WinAnsiEncoding'],
9138                'WinAnsiEncoding': uncompress("{19m8n201n9q201o9r201s9l201t9m201u8m201w9n201x9o201y8o202k8q202l8r202m9p202q8p20aw8k203k8t203t8v203u9v2cq8s212m9t15m8w15n9w2dw9s16k8u16l9u17s9z17x8y17y9y}")
9139            },
9140            encodings = { 'Unicode': {
9141                    'Courier': encodingBlock,
9142                    'Courier-Bold': encodingBlock,
9143                    'Courier-BoldOblique': encodingBlock,
9144                    'Courier-Oblique': encodingBlock,
9145                    'Helvetica': encodingBlock,
9146                    'Helvetica-Bold': encodingBlock,
9147                    'Helvetica-BoldOblique': encodingBlock,
9148                    'Helvetica-Oblique': encodingBlock,
9149                    'Times-Roman': encodingBlock,
9150                    'Times-Bold': encodingBlock,
9151                    'Times-BoldItalic': encodingBlock,
9152                    'Times-Italic': encodingBlock
9153                    //	, 'Symbol'
9154                    //	, 'ZapfDingbats'
9155                } }
9156            /**
9157             Resources:
9158             Font metrics data is reprocessed derivative of contents of
9159             "Font Metrics for PDF Core 14 Fonts" package, which exhibits the following copyright and license:
9160
9161             Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
9162
9163             This file and the 14 PostScript(R) AFM files it accompanies may be used,
9164             copied, and distributed for any purpose and without charge, with or without
9165             modification, provided that all copyright notices are retained; that the AFM
9166             files are not distributed without this file; that all modifications to this
9167             file or any of the AFM files are prominently noted in the modified file(s);
9168             and that this paragraph is not modified. Adobe Systems has no responsibility
9169             or obligation to support the use of the AFM files.
9170
9171             */
9172            ,
9173            fontMetrics = { 'Unicode': {
9174                    // all sizing numbers are n/fontMetricsFractionOf = one font size unit
9175                    // this means that if fontMetricsFractionOf = 1000, and letter A's width is 476, it's
9176                    // width is 476/1000 or 47.6% of its height (regardless of font size)
9177                    // At this time this value applies to "widths" and "kerning" numbers.
9178
9179                    // char code 0 represents "default" (average) width - use it for chars missing in this table.
9180                    // key 'fof' represents the "fontMetricsFractionOf" value
9181
9182                    'Courier-Oblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
9183                    '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}}}"),
9184                    'Helvetica-Bold': uncompress("{'widths'{k3s2q4scx1w201n3r201o6o201s1w201t1w201u1w201w3m201x3m201y3m2k1w2l2l202m2n2n3r2o3r2p5t202q6o2r1s2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v2l3w3u3x3u3y3u3z3x4k6l4l4s4m4s4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3r4v4s4w3x4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v2l5w1w5x2l5y3u5z3r6k2l6l3r6m3x6n3r6o3x6p3r6q2l6r3x6s3x6t1w6u1w6v3r6w1w6x5t6y3x6z3x7k3x7l3x7m2r7n3r7o2l7p3x7q3r7r4y7s3r7t3r7u3m7v2r7w1w7x2r7y3u202l3rcl4sal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3xbq3rbr1wbs2lbu2obv3rbz3xck4s202k3rcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw1w2m2zcy1wcz1wdl4sdm4y
9184dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3res3ret3reu3rev3rew1wex1wey1wez1wfl3xfm3xfn3xfo3xfp3xfq3xfr3ufs3xft3xfu3xfv3xfw3xfz3r203k6o212m6o2dw2l2cq2l3t3r3u2l17s4m19m3r}'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}}}"),
9185                    'Courier': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
9186                    'Courier-BoldOblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
9187                    '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}}}")
9188                    //, 'Symbol': uncompress("{'widths'{k3uaw4r19m3m2k1t2l2l202m2y2n3m2p5n202q6o3k3m2s2l2t2l2v3r2w1t3m3m2y1t2z1wbk2sbl3r'fof'6o3n3m3o3m3p3m3q3m3r3m3s3m3t3m3u1w3v1w3w3r3x3r3y3r3z2wbp3t3l3m5v2l5x2l5z3m2q4yfr3r7v3k7w1o7x3k}'kerning'{'fof'-6o}}")
9189                    , 'Helvetica': uncompress("{'widths'{k3p2q4mcx1w201n3r201o6o201s1q201t1q201u1q201w2l201x2l201y2l2k1w2l1w202m2n2n3r2o3r2p5t202q6o2r1n2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v1w3w3u3x3u3y3u3z3r4k6p4l4m4m4m4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3m4v4m4w3r4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v1w5w1w5x1w5y2z5z3r6k2l6l3r6m3r6n3m6o3r6p3r6q1w6r3r6s3r6t1q6u1q6v3m6w1q6x5n6y3r6z3r7k3r7l3r7m2l7n3m7o1w7p3r7q3m7r4s7s3m7t3m7u3m7v2l7w1u7x2l7y3u202l3rcl4mal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3rbr1wbs2lbu2obv3rbz3xck4m202k3rcm4mcn4mco4mcp4mcq6ocr4scs4mct4mcu4mcv4mcw1w2m2ncy1wcz1wdl4sdm4y
9189dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3mes3ret3reu3rev3rew1wex1wey1wez1wfl3rfm3rfn3rfo3rfp3rfq3rfr3ufs3xft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3r3u1w17s4m19m3r}'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}}}"),
9190                    'Helvetica-BoldOblique': uncompress("{'widths'{k3s2q4scx1w201n3r201o6o201s1w201t1w201u1w201w3m201x3m201y3m2k1w2l2l202m2n2n3r2o3r2p5t202q6o2r1s2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v2l3w3u3x3u3y3u3z3x4k6l4l4s4m4s4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3r4v4s4w3x4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v2l5w1w5x2l5y3u5z3r6k2l6l3r6m3x6n3r6o3x6p3r6q2l6r3x6s3x6t1w6u1w6v3r6w1w6x5t6y3x6z3x7k3x7l3x7m2r7n3r7o2l7p3x7q3r7r4y7s3r7t3r7u3m7v2r7w1w7x2r7y3u202l3rcl4sal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3xbq3rbr1wbs2lbu2obv3rbz3xck4s202k3rcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw1w2m2zcy1wcz1wdl4sdm4y
9190dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3res3ret3reu3rev3rew1wex1wey1wez1wfl3xfm3xfn3xfo3xfp3xfq3xfr3ufs3xft3xfu3xfv3xfw3xfz3r203k6o212m6o2dw2l2cq2l3t3r3u2l17s4m19m3r}'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}}}")
9191                    //, 'ZapfDingbats': uncompress("{'widths'{k4u2k1w'fof'6o}'kerning'{'fof'-6o}}")
9192                    , 'Courier-Bold': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
9193                    '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}
9193fv{17su5tu5qs}fw{17su5tu5qs}}}"),
9194                    '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}}}"),
9195                    'Helvetica-Oblique': uncompress("{'widths'{k3p2q4mcx1w201n3r201o6o201s1q201t1q201u1q201w2l201x2l201y2l2k1w2l1w202m2n2n3r2o3r2p5t202q6o2r1n2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v1w3w3u3x3u3y3u3z3r4k6p4l4m4m4m4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3m4v4m4w3r4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v1w5w1w5x1w5y2z5z3r6k2l6l3r6m3r6n3m6o3r6p3r6q1w6r3r6s3r6t1q6u1q6v3m6w1q6x5n6y3r6z3r7k3r7l3r7m2l7n3m7o1w7p3r7q3m7r4s7s3m7t3m7u3m7v2l7w1u7x2l7y3u202l3rcl4mal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3rbr1wbs2lbu2obv3rbz3xck4m202k3rcm4mcn4mco4mcp4mcq6ocr4scs4mct4mcu4mcv4mcw1w2m2ncy1wcz1wdl4sdm4y
9195dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3mes3ret3reu3rev3rew1wex1wey1wez1wfl3rfm3rfn3rfo3rfp3rfq3rfr3ufs3xft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3r3u1w17s4m19m3r}'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}}}")
9196                } };
9197
9198        /*
9199   This event handler is fired when a new jsPDF object is initialized
9200   This event handler appends metrics data to standard fonts within
9201   that jsPDF instance. The metrics are mapped over Unicode character
9202   codes, NOT CIDs or other codes matching the StandardEncoding table of the
9203   standard PDF fonts.
9204   Future:
9205   Also included is the encoding maping table, converting Unicode (UCS-2, UTF-16)
9206   char codes to StandardEncoding character codes. The encoding table is to be used
9207   somewhere around "pdfEscape" call.
9208   */
9209
9210        API.events.push(['addFont', function (font) {
9211            var metrics,
9212                unicode_section,
9213                encoding = 'Unicode',
9214                encodingBlock;
9215
9216            metrics = fontMetrics[encoding][font.PostScriptName];
9217            if (metrics) {
9218                if (font.metadata[encoding]) {
9219                    unicode_section = font.metadata[encoding];
9220                } else {
9221                    unicode_section = font.metadata[encoding] = {};
9222                }
9223
9224                unicode_section.widths = metrics.widths;
9225                unicode_section.kerning = metrics.kerning;
9226            }
9227
9228            encodingBlock = encodings[encoding][font.PostScriptName];
9229            if (encodingBlock) {
9230                if (font.metadata[encoding]) {
9231                    unicode_section = font.metadata[encoding];
9232                } else {
9233                    unicode_section = font.metadata[encoding] = {};
9234                }
9235
9236                unicode_section.encoding = encodingBlock;
9237                if (encodingBlock.codePages && encodingBlock.codePages.length) {
9238                    font.encoding = encodingBlock.codePages[0];
9239                }
9240            }
9241        }]); // end of adding event handler
9242    })(jsPDF.API);
9243
9244    /** @preserve
9245     jsPDF SVG plugin
9246     Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
9247     */
9248    /**
9249     *
9250     * ====================================================================
9251     */
9252
9253    ;(function (jsPDFAPI) {
9254        'use strict';
9255
9256        /**
9257         Parses SVG XML and converts only some of the SVG elements into
9258         PDF elements.
9259
9260         Supports:
9261         paths
9262
9263         @public
9264         @function
9265         @param
9266         @returns {Type}
9267         */
9268
9269        jsPDFAPI.addSVG = function (svgtext, x, y, w, h) {
9270            // 'this' is _jsPDF object returned when jsPDF is inited (new jsPDF())
9271
9272            var undef;
9273
9274            if (x === undef || y === undef) {
9275                throw new Error("addSVG needs values for 'x' and 'y'");
9276            }
9277
9278            function InjectCSS(cssbody, document) {
9279                var styletag = document.createElement('style');
9280                styletag.type = 'text/css';
9281                if (styletag.styleSheet) {
9282                    // ie
9283                    styletag.styleSheet.cssText = cssbody;
9284                } else {
9285                    // others
9286                    styletag.appendChild(document.createTextNode(cssbody));
9287                }
9288                document.getElementsByTagName("head")[0].appendChild(styletag);
9289            }
9290
9291            function createWorkerNode(document) {
9292
9293                var frameID = 'childframe' // Date.now().toString() + '_' + (Math.random() * 100).toString()
9294                    ,
9295                    frame = document.createElement('iframe');
9296
9297                InjectCSS('.jsPDF_sillysvg_iframe {display:none;position:absolute;}', document);
9298
9299                frame.name = frameID;
9300                frame.setAttribute("width", 0);
9301                frame.setAttribute("height", 0);
9302                frame.setAttribute("frameborder", "0");
9303                frame.setAttribute("scrolling", "no");
9304                frame.setAttribute("seamless", "seamless");
9305                frame.setAttribute("class", "jsPDF_sillysvg_iframe");
9306
9307                document.body.appendChild(frame);
9308
9309                return frame;
9310            }
9311
9312            function attachSVGToWorkerNode(svgtext, frame) {
9313                var framedoc = (frame.contentWindow || frame.contentDocument).document;
9314                framedoc.write(svgtext);
9315                framedoc.close();
9316                return framedoc.getElementsByTagName('svg')[0];
9317            }
9318
9319            function convertPathToPDFLinesArgs(path) {
9320                'use strict';
9321                // we will use 'lines' method call. it needs:
9322                // - starting coordinate pair
9323                // - array of arrays of vector shifts (2-len for line, 6 len for bezier)
9324                // - scale array [horizontal, vertical] ratios
9325                // - style (stroke, fill, both)
9326
9327                var x = parseFloat(path[1]),
9328                    y = parseFloat(path[2]),
9329                    vectors = [],
9330                    position = 3,
9331                    len = path.length;
9332
9333                while (position < len) {
9334                    if (path[position] === 'c') {
9335                        vectors.push([parseFloat(path[position + 1]), parseFloat(path[position + 2]), parseFloat(path[position + 3]), parseFloat(path[position + 4]), parseFloat(path[position + 5]), parseFloat(path[position + 6])]);
9336                        position += 7;
9337                    } else if (path[position] === 'l') {
9338                        vectors.push([parseFloat(path[position + 1]), parseFloat(path[position + 2])]);
9339                        position += 3;
9340                    } else {
9341                        position += 1;
9342                    }
9343                }
9344                return [x, y, vectors];
9345            }
9346
9347            var workernode = createWorkerNode(document),
9348                svgnode = attachSVGToWorkerNode(svgtext, workernode),
9349                scale = [1, 1],
9350                svgw = parseFloat(svgnode.getAttribute('width')),
9351                svgh = parseFloat(svgnode.getAttribute('height'));
9352
9353            if (svgw && svgh) {
9354                // setting both w and h makes image stretch to size.
9355                // this may distort the image, but fits your demanded size
9356                if (w && h) {
9357                    scale = [w / svgw, h / svgh];
9358                }
9359                    // if only one is set, that value is set as max and SVG
9360                // is scaled proportionately.
9361                else if (w) {
9362                    scale = [w / svgw, w / svgw];
9363                } else if (h) {
9364                    scale = [h / svgh, h / svgh];
9365                }
9366            }
9367
9368            var i,
9369                l,
9370                tmp,
9371                linesargs,
9372                items = svgnode.childNodes;
9373            for (i = 0, l = items.length; i < l; i++) {
9374                tmp = items[i];
9375                if (tmp.tagName && tmp.tagName.toUpperCase() === 'PATH') {
9376                    linesargs = convertPathToPDFLinesArgs(tmp.getAttribute("d").split(' '));
9377                    // path start x coordinate
9378                    linesargs[0] = linesargs[0] * scale[0] + x; // where x is upper left X of image
9379                    // path start y coordinate
9380                    linesargs[1] = linesargs[1] * scale[1] + y; // where y is upper left Y of image
9381                    // the rest of lines are vectors. these will adjust with scale value auto.
9382                    this.lines.call(this, linesargs[2] // lines
9383                        , linesargs[0] // starting x
9384                        , linesargs[1] // starting y
9385                        , scale);
9386                }
9387            }
9388
9389            // clean up
9390            // workernode.parentNode.removeChild(workernode)
9391
9392            return this;
9393        };
9394    })(jsPDF.API);
9395
9396    /** ====================================================================
9397     * jsPDF total_pages plugin
9398     * Copyright (c) 2013 Eduardo Menezes de Morais, [email protected]
9399     *
9400     *
9401     * ====================================================================
9402     */
9403
9404    (function (jsPDFAPI) {
9405        'use strict';
9406
9407        jsPDFAPI.putTotalPages = function (pageExpression) {
9408            'use strict';
9409
9410            var replaceExpression = new RegExp(pageExpression, 'g');
9411            for (var n = 1; n <= this.internal.getNumberOfPages(); n++) {
9412                for (var i = 0; i < this.internal.pages[n].length; i++) {
9413                    this.internal.pages[n][i] = this.internal.pages[n][i].replace(replaceExpression, this.internal.getNumberOfPages());
9414                }
9415            }
9416            return this;
9417        };
9418    })(jsPDF.API);
9419
9420    /** ====================================================================
9421     * jsPDF XMP metadata plugin
9422     * Copyright (c) 2016 Jussi Utunen, [email protected]
9423     *
9424     *
9425     * ====================================================================
9426     */
9427
9428    /*global jsPDF */
9429
9430    /**
9431     * Adds XMP formatted metadata to PDF
9432     *
9433     * @param {String} metadata The actual metadata to be added. The metadata shall be stored as XMP simple value. Note that if the metadata string contains XML markup characters "<", ">" or "&", those characters should be written using XML entities.
9434     * @param {String} namespaceuri Sets the namespace URI for the metadata. Last character should be slash or hash.
9435     * @function
9436     * @returns {jsPDF}
9437     * @methodOf jsPDF#
9438     * @name addMetadata
9439     */
9440
9441    (function (jsPDFAPI) {
9442        'use strict';
9443
9444        var xmpmetadata = "";
9445        var xmpnamespaceuri = "";
9446        var metadata_object_number = "";
9447
9448        jsPDFAPI.addMetadata = function (metadata, namespaceuri) {
9449            xmpnamespaceuri = namespaceuri || "http://jspdf.default.namespaceuri/"; //The namespace URI for an XMP name shall not be empty
9450            xmpmetadata = metadata;
9451            this.internal.events.subscribe('postPutResources', function () {
9452                if (!xmpmetadata) {
9453                    metadata_object_number = "";
9454                } else {
9455                    var xmpmeta_beginning = '<x:xmpmeta xmlns:x="adobe:ns:meta/">';
9456                    var rdf_beginning = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="" xmlns:jspdf="' + xmpnamespaceuri + '"><jspdf:metadata>';
9457                    var rdf_ending = '</jspdf:metadata></rdf:Description></rdf:RDF>';
9458                    var xmpmeta_ending = '</x:xmpmeta>';
9459                    var utf8_xmpmeta_beginning = unescape(encodeURIComponent(xmpmeta_beginning));
9460                    var utf8_rdf_beginning = unescape(encodeURIComponent(rdf_beginning));
9461                    var utf8_metadata = unescape(encodeURIComponent(xmpmetadata));
9462                    var utf8_rdf_ending = unescape(encodeURIComponent(rdf_ending));
9463                    var utf8_xmpmeta_ending = unescape(encodeURIComponent(xmpmeta_ending));
9464
9465                    var total_len = utf8_rdf_beginning.length + utf8_metadata.length + utf8_rdf_ending.length + utf8_xmpmeta_beginning.length + utf8_xmpmeta_ending.length;
9466
9467                    metadata_object_number = this.internal.newObject();
vendor: 9,917 bytes, lines 9468-9709
9468                    this.internal.write('<< /Type /Metadata /Subtype /XML /Length ' + total_len + ' >>');
9469                    this.internal.write('stream');
9470                    this.internal.write(utf8_xmpmeta_beginning + utf8_rdf_beginning + utf8_metadata + utf8_rdf_ending + utf8_xmpmeta_ending);
9471                    this.internal.write('endstream');
9472                    this.internal.write('endobj');
9473                }
9474            });
9475            this.internal.events.subscribe('putCatalog', function () {
9476                if (metadata_object_number) {
9477                    this.internal.write('/Metadata ' + metadata_object_number + ' 0 R');
9478                }
9479            });
9480            return this;
9481        };
9482    })(jsPDF.API);
9483
9484    /* Blob.js
9485   * A Blob implementation.
9486   * 2014-07-24
9487   *
9488   * By Eli Grey, http://eligrey.com
9489   * By Devin Samarin, https://github.com/dsamarin
9490   * License: X11/MIT
9491   *   See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
9492   */
9493
9494    /*global self, unescape */
9495    /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
9496    plusplus: true */
9497
9498    /*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
9499
9500    (function (view) {
9501        "use strict";
9502
9503        view.URL = view.URL || view.webkitURL;
9504
9505        if (view.Blob && view.URL) {
9506            try {
9507                new Blob;
9508                return;
9509            } catch (e) {}
9510        }
9511
9512        // Internally we use a BlobBuilder implementation to base Blob off of
9513        // in order to support older browsers that only have BlobBuilder
9514        var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
9515            var
9516                get_class = function(object) {
9517                    return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
9518                }
9519                , FakeBlobBuilder = function BlobBuilder() {
9520                    this.data = [];
9521                }
9522                , FakeBlob = function Blob(data, type, encoding) {
9523                    this.data = data;
9524                    this.size = data.length;
9525                    this.type = type;
9526                    this.encoding = encoding;
9527                }
9528                , FBB_proto = FakeBlobBuilder.prototype
9529                , FB_proto = FakeBlob.prototype
9530                , FileReaderSync = view.FileReaderSync
9531                , FileException = function(type) {
9532                    this.code = this[this.name = type];
9533                }
9534                , file_ex_codes = (
9535                    "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
9536                    + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
9537                ).split(" ")
9538                , file_ex_code = file_ex_codes.length
9539                , real_URL = view.URL || view.webkitURL || view
9540                , real_create_object_URL = real_URL.createObjectURL
9541                , real_revoke_object_URL = real_URL.revokeObjectURL
9542                , URL = real_URL
9543                , btoa = view.btoa
9544                , atob = view.atob
9545
9546                , ArrayBuffer = view.ArrayBuffer
9547                , Uint8Array = view.Uint8Array
9548
9549                , origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/
9550            ;
9551            FakeBlob.fake = FB_proto.fake = true;
9552            while (file_ex_code--) {
9553                FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
9554            }
9555            // Polyfill URL
9556            if (!real_URL.createObjectURL) {
9557                URL = view.URL = function(uri) {
9558                    var
9559                        uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
9560                        , uri_origin
9561                    ;
9562                    uri_info.href = uri;
9563                    if (!("origin" in uri_info)) {
9564                        if (uri_info.protocol.toLowerCase() === "data:") {
9565                            uri_info.origin = null;
9566                        } else {
9567                            uri_origin = uri.match(origin);
9568                            uri_info.origin = uri_origin && uri_origin[1];
9569                        }
9570                    }
9571                    return uri_info;
9572                };
9573            }
9574            URL.createObjectURL = function(blob) {
9575                var
9576                    type = blob.type
9577                    , data_URI_header
9578                ;
9579                if (type === null) {
9580                    type = "application/octet-stream";
9581                }
9582                if (blob instanceof FakeBlob) {
9583                    data_URI_header = "data:" + type;
9584                    if (blob.encoding === "base64") {
9585                        return data_URI_header + ";base64," + blob.data;
9586                    } else if (blob.encoding === "URI") {
9587                        return data_URI_header + "," + decodeURIComponent(blob.data);
9588                    } if (btoa) {
9589                        return data_URI_header + ";base64," + btoa(blob.data);
9590                    } else {
9591                        return data_URI_header + "," + encodeURIComponent(blob.data);
9592                    }
9593                } else if (real_create_object_URL) {
9594                    return real_create_object_URL.call(real_URL, blob);
9595                }
9596            };
9597            URL.revokeObjectURL = function(object_URL) {
9598                if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
9599                    real_revoke_object_URL.call(real_URL, object_URL);
9600                }
9601            };
9602            FBB_proto.append = function(data/*, endings*/) {
9603                var bb = this.data;
9604                // decode data to a binary string
9605                if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
9606                    var
9607                        str = ""
9608                        , buf = new Uint8Array(data)
9609                        , i = 0
9610                        , buf_len = buf.length
9611                    ;
9612                    for (; i < buf_len; i++) {
9613                        str += String.fromCharCode(buf[i]);
9614                    }
9615                    bb.push(str);
9616                } else if (get_class(data) === "Blob" || get_class(data) === "File") {
9617                    if (FileReaderSync) {
9618                        var fr = new FileReaderSync;
9619                        bb.push(fr.readAsBinaryString(data));
9620                    } else {
9621                        // async FileReader won't work as BlobBuilder is sync
9622                        throw new FileException("NOT_READABLE_ERR");
9623                    }
9624                } else if (data instanceof FakeBlob) {
9625                    if (data.encoding === "base64" && atob) {
9626                        bb.push(atob(data.data));
9627                    } else if (data.encoding === "URI") {
9628                        bb.push(decodeURIComponent(data.data));
9629                    } else if (data.encoding === "raw") {
9630                        bb.push(data.data);
9631                    }
9632                } else {
9633                    if (typeof data !== "string") {
9634                        data += ""; // convert unsupported types to strings
9635                    }
9636                    // decode UTF-16 to binary string
9637                    bb.push(unescape(encodeURIComponent(data)));
9638                }
9639            };
9640            FBB_proto.getBlob = function(type) {
9641                if (!arguments.length) {
9642                    type = null;
9643                }
9644                return new FakeBlob(this.data.join(""), type, "raw");
9645            };
9646            FBB_proto.toString = function() {
9647                return "[object BlobBuilder]";
9648            };
9649            FB_proto.slice = function(start, end, type) {
9650                var args = arguments.length;
9651                if (args < 3) {
9652                    type = null;
9653                }
9654                return new FakeBlob(
9655                    this.data.slice(start, args > 1 ? end : this.data.length)
9656                    , type
9657                    , this.encoding
9658                );
9659            };
9660            FB_proto.toString = function() {
9661                return "[object Blob]";
9662            };
9663            FB_proto.close = function() {
9664                this.size = 0;
9665                delete this.data;
9666            };
9667            return FakeBlobBuilder;
9668        }(view));
9669
9670        view.Blob = function(blobParts, options) {
9671            var type = options ? (options.type || "") : "";
9672            var builder = new BlobBuilder();
9673            if (blobParts) {
9674                for (var i = 0, len = blobParts.length; i < len; i++) {
9675                    if (Uint8Array && blobParts[i] instanceof Uint8Array) {
9676                        builder.append(blobParts[i].buffer);
9677                    }
9678                    else {
9679                        builder.append(blobParts[i]);
9680                    }
9681                }
9682            }
9683            var blob = builder.getBlob(type);
9684            if (!blob.slice && blob.webkitSlice) {
9685                blob.slice = blob.webkitSlice;
9686            }
9687            return blob;
9688        };
9689
9690        var getPrototypeOf = Object.getPrototypeOf || function(object) {
9691            return object.__proto__;
9692        };
9693        view.Blob.prototype = getPrototypeOf(new view.Blob());
9694    }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined.content || undefined));
9695
9696    /* FileSaver.js
9697   * A saveAs() FileSaver implementation.
9698   * 1.1.20151003
9699   *
9700   * By Eli Grey, http://eligrey.com
9701   * License: MIT
9702   *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
9703   */
9704
9705    /*global self */
9706    /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
9707
9708    /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
9709
9710    var saveAs = saveAs || (function(view) {
9711        "use strict";
9712        // IE <10 is explicitly unsupported
9713        if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
9714            return;
9715        }
9716        var
9717            doc = view.document
9718            // only get URL when necessary in case Blob.js hasn't overridden it yet
9719            , get_URL = function() {
9720                return view.URL || view.webkitURL || view;
9721            }
9722            , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
9723            , can_use_save_link = "download" in save_link
9724            , click = function(node) {
9725                var event = new MouseEvent("click");
9726                node.dispatchEvent(event);
9727            }
9728            , is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent)
9729            , webkit_req_fs = view.webkitRequestFileSystem
9730            , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
9731            , throw_outside = function(ex) {
9732                (view.setImmediate || view.setTimeout)(function() {
9733                    throw ex;
9734                }, 0);
9735            }
9736            , force_saveable_type = "application/octet-stream"
9737            , fs_min_size = 0
9738            // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and
9739            // https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047
9740            // for the reasoning behind the timeout and revocation flow
9741            , arbitrary_revoke_timeout = 500 // in ms
9742            , revoke = function(file) {
9743                var revoker = function() {
9744                    if (typeof file === "string") { // file is an object URL
9745                        get_URL().revokeObjectURL(file);
9746                    } else { // file is a File
9747                        file.remove();
9748                    }
9749                };
9750                if (view.chrome) {
9751                    revoker();
9752                } else {
9753                    setTimeout(revoker, arbitrary_revoke_timeout);
9754                }
9755            }
9756            , dispatch = function(filesaver, event_types, event) {
9757                event_types = [].concat(event_types);
9758                var i = event_types.length;
9759                while (i--) {
9760                    var listener = filesaver["on" + event_types[i]];
9761                    if (typeof listener === "function") {
9762                        try {
9763                            listener.call(filesaver, event || filesaver);
9764                        } catch (ex) {
9765                            throw_outside(ex);
9766                        }
9767                    }
9768                }
9769            }
9770            , auto_bom = function(blob) {
9771                // prepend BOM for UTF-8 XML and text/* types (including HTML)
9772                if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
9773                    return new Blob(["\ufeff", blob], {type: blob.type});
9774                }
9775                return blob;
9776            }
9777            , FileSaver = function(blob, name, no_auto_bom) {
9778                if (!no_auto_bom) {
9779                    blob = auto_bom(blob);
9780                }
9781                // First try a.download, then web filesystem, then object URLs
9782                var
9783                    filesaver = this
9784                    , type = blob.type
9785                    , blob_changed = false
9786                    , object_url
9787                    , target_view
9788                    , dispatch_all = function() {
9789                        dispatch(filesaver, "writestart progress write writeend".split(" "));
9790                    }
9791                    // on any filesys errors revert to saving with object URLs
9792                    , fs_error = function() {
9793                        if (target_view && is_safari && typeof FileReader !== "undefined") {
9794                            // Safari doesn't allow downloading of blob urls
9795                            var reader = new FileReader();
9796                            reader.onloadend = function() {
9797                                var base64Data = reader.result;
9798                                target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
9799                                filesaver.readyState = filesaver.DONE;
9800                                dispatch_all();
9801                            };
9802                            reader.readAsDataURL(blob);
9803                            filesaver.readyState = filesaver.INIT;
9804                            return;
9805                        }
9806                        // don't create more object URLs than needed
9807                        if (blob_changed || !object_url) {
9808                            object_url = get_URL().createObjectURL(blob);
9809                        }
9810                        if (target_view) {
9811                            target_view.location.href = object_url;
9812                        } else {
9813                            var new_tab = view.open(object_url, "_blank");
9814                            if (new_tab == undefined && is_safari) {
9815                                //Apple do not allow window.open, see http://bit.ly/1kZffRI
9816                                view.location.href = object_url
9817                            }
9818                        }
9819                        filesaver.readyState = filesaver.DONE;
9820                        dispatch_all();
9821                        revoke(object_url);
9822                    }
9823                    , abortable = function(func) {
9824                        return function() {
9825                            if (filesaver.readyState !== filesaver.DONE) {
9826                                return func.apply(this, arguments);
9827                            }
9828                        };
9829                    }
9830                    , create_if_not_found = {create: true, exclusive: false}
9831                    , slice
9832                ;
9833                filesaver.readyState = filesaver.INIT;
9834                if (!name) {
9835                    name = "download";
9836                }
9837                if (can_use_save_link) {
9838                    object_url = get_URL().createObjectURL(blob);
9839                    setTimeout(function() {
9840                        save_link.href = object_url;
9841                        save_link.download = name;
9842                        click(save_link);
9843                        dispatch_all();
9844                        revoke(object_url);
9845                        filesaver.readyState = filesaver.DONE;
9846                    });
9847                    return;
9848                }
9849                // Object and web filesystem URLs have a problem saving in Google Chrome when
9850                // viewed in a tab, so I force save with application/octet-stream
9851                // http://code.google.com/p/chromium/issues/detail?id=91158
9852                // Update: Google errantly closed 91158, I submitted it again:
9853                // https://code.google.com/p/chromium/issues/detail?id=389642
9854                if (view.chrome && type && type !== force_saveable_type) {
9855                    slice = blob.slice || blob.webkitSlice;
9856                    blob = slice.call(blob, 0, blob.size, force_saveable_type);
9857                    blob_changed = true;
9858                }
9859                // Since I can't be sure that the guessed media type will trigger a download
9860                // in WebKit, I append .download to the filename.
9861                // https://bugs.webkit.org/show_bug.cgi?id=65440
9862                if (webkit_req_fs && name !== "download") {
9863                    name += ".download";
9864                }
9865                if (type === force_saveable_type || webkit_req_fs) {
9866                    target_view = view;
9867                }
9868                if (!req_fs) {
9869                    fs_error();
9870                    return;
9871                }
9872                fs_min_size += blob.size;
9873                req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
9874                    fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
9875                        var save = function() {
9876                            dir.getFile(name, create_if_not_found, abortable(function(file) {
9877                                file.createWriter(abortable(function(writer) {
9878                                    writer.onwriteend = function(event) {
9879                                        target_view.location.href = file.toURL();
9880                                        filesaver.readyState = filesaver.DONE;
9881                                        dispatch(filesaver, "writeend", event);
9882                                        revoke(file);
9883                                    };
9884                                    writer.onerror = function() {
9885                                        var error = writer.error;
9886                                        if (error.code !== error.ABORT_ERR) {
9887                                            fs_error();
9888                                        }
9889                                    };
9890                                    "writestart progress write abort".split(" ").forEach(function(event) {
9891                                        writer["on" + event] = filesaver["on" + event];
9892                                    });
9893                                    writer.write(blob);
9894                                    filesaver.abort = function() {
9895                                        writer.abort();
9896                                        filesaver.readyState = filesaver.DONE;
9897                                    };
9898                                    filesaver.readyState = filesaver.WRITING;
9899                                }), fs_error);
9900                            }), fs_error);
9901                        };
9902                        dir.getFile(name, {create: false}, abortable(function(file) {
9903                            // delete file if it already exists
9904                            file.remove();
9905                            save();
9906                        }), abortable(function(ex) {
9907                            if (ex.code === ex.NOT_FOUND_ERR) {
9908                                save();
9909                            } else {
9910                                fs_error();
9911                            }
9912                        }));
9913                    }), fs_error);
9914                }), fs_error);
9915            }
9916            , FS_proto = FileSaver.prototype
9917            , saveAs = function(blob, name, no_auto_bom) {
9918                return new FileSaver(blob, name, no_auto_bom);
9919            }
9920        ;
9921        // IE 10+ (native saveAs)
9922        if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
9923            return function(blob, name, no_auto_bom) {
9924                if (!no_auto_bom) {
9925                    blob = auto_bom(blob);
9926                }
9927                return navigator.msSaveOrOpenBlob(blob, name || "download");
9928            };
9929        }
9930
9931        FS_proto.abort = function() {
9932            var filesaver = this;
9933            filesaver.readyState = filesaver.DONE;
9934            dispatch(filesaver, "abort");
9935        };
9936        FS_proto.readyState = FS_proto.INIT = 0;
9937        FS_proto.WRITING = 1;
9938        FS_proto.DONE = 2;
9939
9940        FS_proto.error =
9941            FS_proto.onwritestart =
9942                FS_proto.onprogress =
9943                    FS_proto.onwrite =
9944                        FS_proto.onabort =
9945                            FS_proto.onerror =
9946                                FS_proto.onwriteend =
9947                                    null;
9948
9949        return saveAs;
9950    }(
9951        typeof self !== "undefined" && self
9952        || typeof window !== "undefined" && window
9953        || undefined.content
9954    ));
9955    // `self` is undefined in Firefox for Android content script context
9956    // while `this` is nsIContentFrameMessageManager
9957    // with an attribute `content` that corresponds to the window
9958
9959    if (typeof module !== "undefined" && module.exports) {
9960        module.exports.saveAs = saveAs;
9961    } else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
9962        define([], function() {
9963            return saveAs;
9964        });
9965    }
9966
9967    /*
9968   * Copyright (c) 2012 chick307 <[email protected]>
9969   *
9970   * Licensed under the MIT License.
9971   * http://opensource.org/licenses/mit-license
9972   */
9973
9974    void function(global, callback) {
9975        if (typeof module === 'object') {
9976            module.exports = callback();
9977        } else if (typeof define === 'function') {
9978            define(callback);
9979        } else {
9980            global.adler32cs = callback();
9981        }
9982    }(jsPDF, function() {
9983        var _hasArrayBuffer = typeof ArrayBuffer === 'function' &&
9984            typeof Uint8Array === 'function';
9985
9986        var _Buffer = null, _isBuffer = (function() {
9987            if (!_hasArrayBuffer)
9988                return function _isBuffer() { return false };
9989
9990            try {
9991                var buffer = {};
9992                if (typeof buffer.Buffer === 'function')
9993                    _Buffer = buffer.Buffer;
9994            } catch (error) {}
9995
9996            return function _isBuffer(value) {
9997                return value instanceof ArrayBuffer ||
9998                    _Buffer !== null && value instanceof _Buffer;
9999            };
10000        }());
10001
10002        var _utf8ToBinary = (function() {
10003            if (_Buffer !== null) {
10004                return function _utf8ToBinary(utf8String) {
10005                    return new _Buffer(utf8String, 'utf8').toString('binary');
10006                };
10007            } else {
10008                return function _utf8ToBinary(utf8String) {
10009                    return unescape(encodeURIComponent(utf8String));
10010                };
10011            }
10012        }());
10013
10014        var MOD = 65521;
10015
10016        var _update = function _update(checksum, binaryString) {
10017            var a = checksum & 0xFFFF, b = checksum >>> 16;
10018            for (var i = 0, length = binaryString.length; i < length; i++) {
10019                a = (a + (binaryString.charCodeAt(i) & 0xFF)) % MOD;
10020                b = (b + a) % MOD;
10021            }
10022            return (b << 16 | a) >>> 0;
10023        };
10024
10025        var _updateUint8Array = function _updateUint8Array(checksum, uint8Array) {
10026            var a = checksum & 0xFFFF, b = checksum >>> 16;
10027            for (var i = 0, length = uint8Array.length, x; i < length; i++) {
10028                a = (a + uint8Array[i]) % MOD;
10029                b = (b + a) % MOD;
10030            }
10031            return (b << 16 | a) >>> 0
10032        };
10033
10034        var exports = {};
10035
10036        var Adler32 = exports.Adler32 = (function() {
10037            var ctor = function Adler32(checksum) {
10038                if (!(this instanceof ctor)) {
10039                    throw new TypeError(
10040                        'Constructor cannot called be as a function.');
10041                }
10042                if (!isFinite(checksum = checksum == null ? 1 : +checksum)) {
10043                    throw new Error(
10044                        'First arguments needs to be a finite number.');
10045                }
10046                this.checksum = checksum >>> 0;
10047            };
10048
10049            var proto = ctor.prototype = {};
10050            proto.constructor = ctor;
10051
10052            ctor.from = function(from) {
10053                from.prototype = proto;
10054                return from;
10055            }(function from(binaryString) {
10056                if (!(this instanceof ctor)) {
10057                    throw new TypeError(
10058                        'Constructor cannot called be as a function.');
10059                }
10060                if (binaryString == null)
10061                    throw new Error('First argument needs to be a string.');
10062                this.checksum = _update(1, binaryString.toString());
10063            });
10064
10065            ctor.fromUtf8 = function(fromUtf8) {
10066                fromUtf8.prototype = proto;
10067                return fromUtf8;
10068            }(function fromUtf8(utf8String) {
10069                if (!(this instanceof ctor)) {
10070                    throw new TypeError(
10071                        'Constructor cannot called be as a function.');
10072                }
10073                if (utf8String == null)
10074                    throw new Error('First argument needs to be a string.');
10075                var binaryString = _utf8ToBinary(utf8String.toString());
10076                this.checksum = _update(1, binaryString);
10077            });
10078
10079            if (_hasArrayBuffer) {
10080                ctor.fromBuffer = function(fromBuffer) {
10081                    fromBuffer.prototype = proto;
10082                    return fromBuffer;
10083                }(function fromBuffer(buffer) {
10084                    if (!(this instanceof ctor)) {
10085                        throw new TypeError(
10086                            'Constructor cannot called be as a function.');
10087                    }
10088                    if (!_isBuffer(buffer))
10089                        throw new Error('First argument needs to be ArrayBuffer.');
10090                    var array = new Uint8Array(buffer);
10091                    return this.checksum = _updateUint8Array(1, array);
10092                });
10093            }
10094
10095            proto.update = function update(binaryString) {
10096                if (binaryString == null)
10097                    throw new Error('First argument needs to be a string.');
10098                binaryString = binaryString.toString();
10099                return this.checksum = _update(this.checksum, binaryString);
10100            };
10101
10102            proto.updateUtf8 = function updateUtf8(utf8String) {
10103                if (utf8String == null)
10104                    throw new Error('First argument needs to be a string.');
10105                var binaryString = _utf8ToBinary(utf8String.toString());
10106                return this.checksum = _update(this.checksum, binaryString);
10107            };
10108
10109            if (_hasArrayBuffer) {
10110                proto.updateBuffer = function updateBuffer(buffer) {
10111                    if (!_isBuffer(buffer))
10112                        throw new Error('First argument needs to be ArrayBuffer.');
10113                    var array = new Uint8Array(buffer);
10114                    return this.checksum = _updateUint8Array(this.checksum, array);
10115                };
10116            }
10117
10118            proto.clone = function clone() {
10119                return new Adler32(this.checksum);
10120            };
10121
10122            return ctor;
10123        }());
10124
10125        exports.from = function from(binaryString) {
10126            if (binaryString == null)
10127                throw new Error('First argument needs to be a string.');
10128            return _update(1, binaryString.toString());
10129        };
10130
10131        exports.fromUtf8 = function fromUtf8(utf8String) {
10132            if (utf8String == null)
10133                throw new Error('First argument needs to be a string.');
10134            var binaryString = _utf8ToBinary(utf8String.toString());
10135            return _update(1, binaryString);
10136        };
10137
10138        if (_hasArrayBuffer) {
10139            exports.fromBuffer = function fromBuffer(buffer) {
10140                if (!_isBuffer(buffer))
10141                    throw new Error('First argument need to be ArrayBuffer.');
10142                var array = new Uint8Array(buffer);
10143                return _updateUint8Array(1, array);
10144            };
10145        }
10146
10147        return exports;
10148    });
10149
10150    /**
10151     * CssColors
10152     * Copyright (c) 2014 Steven Spungin (TwelveTone LLC)  [email protected]
10153     *
10154     * Licensed under the MIT License.
10155     * http://opensource.org/licenses/mit-license
10156     */
10157
10158    /**
10159     * Usage CssColors('red');
10160     * Returns RGB hex color with '#' prefix
10161     */
10162
10163    var CssColors = {};
10164    CssColors._colorsTable = {
10165        "aliceblue" : "#f0f8ff",
10166        "antiquewhite" : "#faebd7",
10167        "aqua" : "#00ffff",
10168        "aquamarine" : "#7fffd4",
10169        "azure" : "#f0ffff",
10170        "beige" : "#f5f5dc",
10171        "bisque" : "#ffe4c4",
10172        "black" : "#000000",
10173        "blanchedalmond" : "#ffebcd",
10174        "blue" : "#0000ff",
10175        "blueviolet" : "#8a2be2",
10176        "brown" : "#a52a2a",
10177        "burlywood" : "#deb887",
10178        "cadetblue" : "#5f9ea0",
10179        "chartreuse" : "#7fff00",
10180        "chocolate" : "#d2691e",
10181        "coral" : "#ff7f50",
10182        "cornflowerblue" : "#6495ed",
10183        "cornsilk" : "#fff8dc",
10184        "crimson" : "#dc143c",
10185        "cyan" : "#00ffff",
10186        "darkblue" : "#00008b",
10187        "darkcyan" : "#008b8b",
10188        "darkgoldenrod" : "#b8860b",
10189        "darkgray" : "#a9a9a9",
10190        "darkgreen" : "#006400",
10191        "darkkhaki" : "#bdb76b",
10192        "darkmagenta" : "#8b008b",
10193        "darkolivegreen" : "#556b2f",
10194        "darkorange" : "#ff8c00",
10195        "darkorchid" : "#9932cc",
10196        "darkred" : "#8b0000",
10197        "darksalmon" : "#e9967a",
10198        "darkseagreen" : "#8fbc8f",
10199        "darkslateblue" : "#483d8b",
10200        "darkslategray" : "#2f4f4f",
10201        "darkturquoise" : "#00ced1",
10202        "darkviolet" : "#9400d3",
10203        "deeppink" : "#ff1493",
10204        "deepskyblue" : "#00bfff",
10205        "dimgray" : "#696969",
10206        "dodgerblue" : "#1e90ff",
10207        "firebrick" : "#b22222",
10208        "floralwhite" : "#fffaf0",
10209        "forestgreen" : "#228b22",
10210        "fuchsia" : "#ff00ff",
10211        "gainsboro" : "#dcdcdc",
10212        "ghostwhite" : "#f8f8ff",
10213        "gold" : "#ffd700",
10214        "goldenrod" : "#daa520",
10215        "gray" : "#808080",
10216        "green" : "#008000",
10217        "greenyellow" : "#adff2f",
10218        "honeydew" : "#f0fff0",
10219        "hotpink" : "#ff69b4",
10220        "indianred " : "#cd5c5c",
10221        "indigo" : "#4b0082",
10222        "ivory" : "#fffff0",
10223        "khaki" : "#f0e68c",
10224        "lavender" : "#e6e6fa",
10225        "lavenderblush" : "#fff0f5",
10226        "lawngreen" : "#7cfc00",
10227        "lemonchiffon" : "#fffacd",
10228        "lightblue" : "#add8e6",
10229        "lightcoral" : "#f08080",
10230        "lightcyan" : "#e0ffff",
10231        "lightgoldenrodyellow" : "#fafad2",
10232        "lightgrey" : "#d3d3d3",
10233        "lightgreen" : "#90ee90",
10234        "lightpink" : "#ffb6c1",
10235        "lightsalmon" : "#ffa07a",
10236        "lightseagreen" : "#20b2aa",
10237        "lightskyblue" : "#87cefa",
10238        "lightslategray" : "#778899",
10239        "lightsteelblue" : "#b0c4de",
10240        "lightyellow" : "#ffffe0",
10241        "lime" : "#00ff00",
10242        "limegreen" : "#32cd32",
10243        "linen" : "#faf0e6",
10244        "magenta" : "#ff00ff",
10245        "maroon" : "#800000",
10246        "mediumaquamarine" : "#66cdaa",
10247        "mediumblue" : "#0000cd",
10248        "mediumorchid" : "#ba55d3",
10249        "mediumpurple" : "#9370d8",
10250        "mediumseagreen" : "#3cb371",
10251        "mediumslateblue" : "#7b68ee",
10252        "mediumspringgreen" : "#00fa9a",
10253        "mediumturquoise" : "#48d1cc",
10254        "mediumvioletred" : "#c71585",
10255        "midnightblue" : "#191970",
10256        "mintcream" : "#f5fffa",
10257        "mistyrose" : "#ffe4e1",
10258        "moccasin" : "#ffe4b5",
10259        "navajowhite" : "#ffdead",
10260        "navy" : "#000080",
10261        "oldlace" : "#fdf5e6",
10262        "olive" : "#808000",
10263        "olivedrab" : "#6b8e23",
10264        "orange" : "#ffa500",
10265        "orangered" : "#ff4500",
10266        "orchid" : "#da70d6",
10267        "palegoldenrod" : "#eee8aa",
10268        "palegreen" : "#98fb98",
10269        "paleturquoise" : "#afeeee",
10270        "palevioletred" : "#d87093",
10271        "papayawhip" : "#ffefd5",
10272        "peachpuff" : "#ffdab9",
10273        "peru" : "#cd853f",
10274        "pink" : "#ffc0cb",
10275        "plum" : "#dda0dd",
10276        "powderblue" : "#b0e0e6",
10277        "purple" : "#800080",
10278        "red" : "#ff0000",
10279        "rosybrown" : "#bc8f8f",
10280        "royalblue" : "#4169e1",
10281        "saddlebrown" : "#8b4513",
10282        "salmon" : "#fa8072",
10283        "sandybrown" : "#f4a460",
10284        "seagreen" : "#2e8b57",
10285        "seashell" : "#fff5ee",
10286        "sienna" : "#a0522d",
10287        "silver" : "#c0c0c0",
10288        "skyblue" : "#87ceeb",
10289        "slateblue" : "#6a5acd",
10290        "slategray" : "#708090",
10291        "snow" : "#fffafa",
10292        "springgreen" : "#00ff7f",
10293        "steelblue" : "#4682b4",
10294        "tan" : "#d2b48c",
10295        "teal" : "#008080",
10296        "thistle" : "#d8bfd8",
10297        "tomato" : "#ff6347",
10298        "turquoise" : "#40e0d0",
10299        "violet" : "#ee82ee",
10300        "wheat" : "#f5deb3",
10301        "white" : "#ffffff",
10302        "whitesmoke" : "#f5f5f5",
10303        "yellow" : "#ffff00",
10304        "yellowgreen" : "#9acd32"
10305    };
10306
10307    CssColors.colorNameToHex = function(color) {
10308        color = color.toLowerCase();
10309        if (typeof this._colorsTable[color] != 'undefined')
10310            return this._colorsTable[color];
10311
10312        return false;
10313    };
10314
10315    /*
10316   Deflate.js - https://github.com/gildas-lormeau/zip.js
10317   Copyright (c) 2013 Gildas Lormeau. All rights reserved.
10318
10319   Redistribution and use in source and binary forms, with or without
10320   modification, are permitted provided that the following conditions are met:
10321
10322   1. Redistributions of source code must retain the above copyright notice,
10323   this list of conditions and the following disclaimer.
10324
10325   2. Redistributions in binary form must reproduce the above copyright
10326   notice, this list of conditions and the following disclaimer in
10327   the documentation and/or other materials provided with the distribution.
10328
10329   3. The names of the authors may not be used to endorse or promote products
10330   derived from this software without specific prior written permission.
10331
10332   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
10333   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
10334   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
10335   INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
10336   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10337   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
10338   OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
10339   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
10340   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
10341   EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10342   */
10343
10344    /*
10345   * This program is based on JZlib 1.0.2 ymnk, JCraft,Inc.
10346   * JZlib is based on zlib-1.1.3, so all credit should go authors
10347   * Jean-loup Gailly([email protected]) and Mark Adler([email protected])
10348   * and contributors of zlib.
10349   */
10350
10351    var Deflater = (function(obj) {
10352
10353        // Global
10354
10355        var MAX_BITS = 15;
10356        var D_CODES = 30;
10357        var BL_CODES = 19;
10358
10359        var LENGTH_CODES = 29;
10360        var LITERALS = 256;
10361        var L_CODES = (LITERALS + 1 + LENGTH_CODES);
10362        var HEAP_SIZE = (2 * L_CODES + 1);
10363
10364        var END_BLOCK = 256;
10365
10366        // Bit length codes must not exceed MAX_BL_BITS bits
10367        var MAX_BL_BITS = 7;
10368
10369        // repeat previous bit length 3-6 times (2 bits of repeat count)
10370        var REP_3_6 = 16;
10371
10372        // repeat a zero length 3-10 times (3 bits of repeat count)
10373        var REPZ_3_10 = 17;
10374
10375        // repeat a zero length 11-138 times (7 bits of repeat count)
10376        var REPZ_11_138 = 18;
10377
10378        // The lengths of the bit length codes are sent in order of decreasing
10379        // probability, to avoid transmitting the lengths for unused bit
10380        // length codes.
10381
10382        var Buf_size = 8 * 2;
10383
10384        // JZlib version : "1.0.2"
10385        var Z_DEFAULT_COMPRESSION = -1;
10386
10387        // compression strategy
10388        var Z_FILTERED = 1;
10389        var Z_HUFFMAN_ONLY = 2;
10390        var Z_DEFAULT_STRATEGY = 0;
10391
10392        var Z_NO_FLUSH = 0;
10393        var Z_PARTIAL_FLUSH = 1;
10394        var Z_FULL_FLUSH = 3;
10395        var Z_FINISH = 4;
10396
10397        var Z_OK = 0;
10398        var Z_STREAM_END = 1;
10399        var Z_NEED_DICT = 2;
10400        var Z_STREAM_ERROR = -2;
10401        var Z_DATA_ERROR = -3;
10402        var Z_BUF_ERROR = -5;
10403
10404        // Tree
10405
10406        // see definition of array dist_code below
10407        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,
10408            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,
10409            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,
10410            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,
10411            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,
10412            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,
10413            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,
10414            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,
10415            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,
10416            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,
10417            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,
10418            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,
10419            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,
10420            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 ];
10421
10422        function Tree() {
10423            var that = this;
10424
10425            // dyn_tree; // the dynamic tree
10426            // max_code; // largest code with non zero frequency
10427            // stat_desc; // the corresponding static tree
10428
10429            // Compute the optimal bit lengths for a tree and update the total bit
10430            // length
10431            // for the current block.
10432            // IN assertion: the fields freq and dad are set, heap[heap_max] and
10433            // above are the tree nodes sorted by increasing frequency.
10434            // OUT assertions: the field len is set to the optimal bit length, the
10435            // array bl_count contains the frequencies for each bit length.
10436            // The length opt_len is updated; static_len is also updated if stree is
10437            // not null.
10438            function gen_bitlen(s) {
10439                var tree = that.dyn_tree;
10440                var stree = that.stat_desc.static_tree;
10441                var extra = that.stat_desc.extra_bits;
10442                var base = that.stat_desc.extra_base;
10443                var max_length = that.stat_desc.max_length;
10444                var h; // heap index
10445                var n, m; // iterate over the tree elements
10446                var bits; // bit length
10447                var xbits; // extra bits
10448                var f; // frequency
10449                var overflow = 0; // number of elements with bit length too large
10450
10451                for (bits = 0; bits <= MAX_BITS; bits++)
10452                    s.bl_count[bits] = 0;
10453
10454                // In a first pass, compute the optimal bit lengths (which may
10455                // overflow in the case of the bit length tree).
10456                tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
10457
10458                for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
10459                    n = s.heap[h];
10460                    bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
10461                    if (bits > max_length) {
10462                        bits = max_length;
10463                        overflow++;
10464                    }
10465                    tree[n * 2 + 1] = bits;
10466                    // We overwrite tree[n*2+1] which is no longer needed
10467
10468                    if (n > that.max_code)
10469                        continue; // not a leaf node
10470
10471                    s.bl_count[bits]++;
10472                    xbits = 0;
10473                    if (n >= base)
10474                        xbits = extra[n - base];
10475                    f = tree[n * 2];
10476                    s.opt_len += f * (bits + xbits);
10477                    if (stree)
10478                        s.static_len += f * (stree[n * 2 + 1] + xbits);
10479                }
10480                if (overflow === 0)
10481                    return;
10482
10483                // This happens for example on obj2 and pic of the Calgary corpus
10484                // Find the first bit length which could increase:
10485                do {
10486                    bits = max_length - 1;
10487                    while (s.bl_count[bits] === 0)
10488                        bits--;
10489                    s.bl_count[bits]--; // move one leaf down the tree
10490                    s.bl_count[bits + 1] += 2; // move one overflow item as its brother
10491                    s.bl_count[max_length]--;
10492                    // The brother of the overflow item also moves one step up,
10493                    // but this does not affect bl_count[max_length]
10494                    overflow -= 2;
10495                } while (overflow > 0);
10496
10497                for (bits = max_length; bits !== 0; bits--) {
10498                    n = s.bl_count[bits];
10499                    while (n !== 0) {
10500                        m = s.heap[--h];
10501                        if (m > that.max_code)
10502                            continue;
10503                        if (tree[m * 2 + 1] != bits) {
10504                            s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2];
10505                            tree[m * 2 + 1] = bits;
10506                        }
10507                        n--;
10508                    }
10509                }
10510            }
10511
10512            // Reverse the first len bits of a code, using straightforward code (a
10513            // faster
10514            // method would use a table)
10515            // IN assertion: 1 <= len <= 15
10516            function bi_reverse(code, // the value to invert
10517                                len // its bit length
10518            ) {
10519                var res = 0;
10520                do {
10521                    res |= code & 1;
10522                    code >>>= 1;
10523                    res <<= 1;
10524                } while (--len > 0);
10525                return res >>> 1;
10526            }
10527
10528            // Generate the codes for a given tree and bit counts (which need not be
10529            // optimal).
10530            // IN assertion: the array bl_count contains the bit length statistics for
10531            // the given tree and the field len is set for all tree elements.
10532            // OUT assertion: the field code is set for all tree elements of non
10533            // zero code length.
10534            function gen_codes(tree, // the tree to decorate
10535                               max_code, // largest code with non zero frequency
10536                               bl_count // number of codes at each bit length
10537            ) {
10538                var next_code = []; // next code value for each
10539                // bit length
10540                var code = 0; // running code value
10541                var bits; // bit index
10542                var n; // code index
10543                var len;
10544
10545                // The distribution counts are first used to generate the code values
10546                // without bit reversal.
10547                for (bits = 1; bits <= MAX_BITS; bits++) {
10548                    next_code[bits] = code = ((code + bl_count[bits - 1]) << 1);
10549                }
10550
10551                // Check that the bit counts in bl_count are consistent. The last code
10552                // must be all ones.
10553                // Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
10554                // "inconsistent bit counts");
10555                // Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
10556
10557                for (n = 0; n <= max_code; n++) {
10558                    len = tree[n * 2 + 1];
10559                    if (len === 0)
10560                        continue;
10561                    // Now reverse the bits
10562                    tree[n * 2] = bi_reverse(next_code[len]++, len);
10563                }
10564            }
10565
10566            // Construct one Huffman tree and assigns the code bit strings and lengths.
10567            // Update the total bit length for the current block.
10568            // IN assertion: the field freq is set for all tree elements.
10569            // OUT assertions: the fields len and code are set to the optimal bit length
10570            // and corresponding code. The length opt_len is updated; static_len is
10571            // also updated if stree is not null. The field max_code is set.
10572            that.build_tree = function(s) {
10573                var tree = that.dyn_tree;
10574                var stree = that.stat_desc.static_tree;
10575                var elems = that.stat_desc.elems;
10576                var n, m; // iterate over heap elements
10577                var max_code = -1; // largest code with non zero frequency
10578                var node; // new node being created
10579
10580                // Construct the initial heap, with least frequent element in
10581                // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
10582                // heap[0] is not used.
10583                s.heap_len = 0;
10584                s.heap_max = HEAP_SIZE;
10585
10586                for (n = 0; n < elems; n++) {
10587                    if (tree[n * 2] !== 0) {
10588                        s.heap[++s.heap_len] = max_code = n;
10589                        s.depth[n] = 0;
10590                    } else {
10591                        tree[n * 2 + 1] = 0;
10592                    }
10593                }
10594
10595                // The pkzip format requires that at least one distance code exists,
10596                // and that at least one bit should be sent even if there is only one
10597                // possible code. So to avoid special checks later on we force at least
10598                // two codes of non zero frequency.
10599                while (s.heap_len < 2) {
10600                    node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0;
10601                    tree[node * 2] = 1;
10602                    s.depth[node] = 0;
10603                    s.opt_len--;
10604                    if (stree)
10605                        s.static_len -= stree[node * 2 + 1];
10606                    // node is 0 or 1 so it does not have extra bits
10607                }
10608                that.max_code = max_code;
10609
10610                // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
10611                // establish sub-heaps of increasing lengths:
10612
10613                for (n = Math.floor(s.heap_len / 2); n >= 1; n--)
10614                    s.pqdownheap(tree, n);
10615
10616                // Construct the Huffman tree by repeatedly combining the least two
10617                // frequent nodes.
10618
10619                node = elems; // next internal node of the tree
10620                do {
10621                    // n = node of least frequency
10622                    n = s.heap[1];
10623                    s.heap[1] = s.heap[s.heap_len--];
10624                    s.pqdownheap(tree, 1);
10625                    m = s.heap[1]; // m = node of next least frequency
10626
10627                    s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
10628                    s.heap[--s.heap_max] = m;
10629
10630                    // Create a new node father of n and m
10631                    tree[node * 2] = (tree[n * 2] + tree[m * 2]);
10632                    s.depth[node] = Math.max(s.depth[n], s.depth[m]) + 1;
10633                    tree[n * 2 + 1] = tree[m * 2 + 1] = node;
10634
10635                    // and insert the new node in the heap
10636                    s.heap[1] = node++;
10637                    s.pqdownheap(tree, 1);
10638                } while (s.heap_len >= 2);
10639
10640                s.heap[--s.heap_max] = s.heap[1];
10641
10642                // At this point, the fields freq and dad are set. We can now
10643                // generate the bit lengths.
10644
10645                gen_bitlen(s);
10646
10647                // The field len is now set, we can generate the bit codes
10648                gen_codes(tree, that.max_code, s.bl_count);
10649            };
10650
10651        }
10652
10653        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,
10654            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,
10655            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,
10656            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,
10657            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,
10658            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,
10659            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 ];
10660
10661        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 ];
10662
10663        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,
10664            24576 ];
10665
10666        // Mapping from a distance to a distance code. dist is the distance - 1 and
10667        // must not have side effects. _dist_code[256] and _dist_code[257] are never
10668        // used.
10669        Tree.d_code = function(dist) {
10670            return ((dist) < 256 ? _dist_code[dist] : _dist_code[256 + ((dist) >>> 7)]);
10671        };
10672
10673        // extra bits for each length code
10674        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 ];
10675
10676        // extra bits for each distance code
10677        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 ];
10678
10679        // extra bits for each bit length code
10680        Tree.extra_blbits = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 ];
10681
10682        Tree.bl_order = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
10683
10684        // StaticTree
10685
10686        function StaticTree(static_tree, extra_bits, extra_base, elems, max_length) {
10687            var that = this;
10688            that.static_tree = static_tree;
10689            that.extra_bits = extra_bits;
10690            that.extra_base = extra_base;
10691            that.elems = elems;
10692            that.max_length = max_length;
10693        }
10694
10695        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,
10696            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,
10697            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,
10698            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,
10699            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,
10700            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,
10701            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,
10702            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
107025, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9,
10703            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,
10704            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,
10705            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,
10706            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,
10707            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,
10708            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,
10709            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,
10710            99, 8, 227, 8 ];
10711
10712        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,
10713            25, 5, 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 ];
10714
10715        StaticTree.static_l_desc = new StaticTree(StaticTree.static_ltree, Tree.extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
10716
10717        StaticTree.static_d_desc = new StaticTree(StaticTree.static_dtree, Tree.extra_dbits, 0, D_CODES, MAX_BITS);
10718
10719        StaticTree.static_bl_desc = new StaticTree(null, Tree.extra_blbits, 0, BL_CODES, MAX_BL_BITS);
10720
10721        // Deflate
10722
10723        var MAX_MEM_LEVEL = 9;
10724        var DEF_MEM_LEVEL = 8;
10725
10726        function Config(good_length, max_lazy, nice_length, max_chain, func) {
10727            var that = this;
10728            that.good_length = good_length;
10729            that.max_lazy = max_lazy;
10730            that.nice_length = nice_length;
10731            that.max_chain = max_chain;
10732            that.func = func;
10733        }
10734
10735        var STORED = 0;
10736        var FAST = 1;
10737        var SLOW = 2;
10738        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),
10739            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),
10740            new Config(32, 128, 258, 1024, SLOW), new Config(32, 258, 258, 4096, SLOW) ];
10741
10742        var z_errmsg = [ "need dictionary", // Z_NEED_DICT
10743            // 2
10744            "stream end", // Z_STREAM_END 1
10745            "", // Z_OK 0
10746            "", // Z_ERRNO (-1)
10747            "stream error", // Z_STREAM_ERROR (-2)
10748            "data error", // Z_DATA_ERROR (-3)
10749            "", // Z_MEM_ERROR (-4)
10750            "buffer error", // Z_BUF_ERROR (-5)
10751            "",// Z_VERSION_ERROR (-6)
10752            "" ];
10753
10754        // block not completed, need more input or more output
10755        var NeedMore = 0;
10756
10757        // block flush performed
10758        var BlockDone = 1;
10759
10760        // finish started, need only more output at next deflate
10761        var FinishStarted = 2;
10762
10763        // finish done, accept no more input or output
10764        var FinishDone = 3;
10765
10766        // preset dictionary flag in zlib header
10767        var PRESET_DICT = 0x20;
10768
10769        var INIT_STATE = 42;
10770        var BUSY_STATE = 113;
10771        var FINISH_STATE = 666;
10772
10773        // The deflate compression method
10774        var Z_DEFLATED = 8;
10775
10776        var STORED_BLOCK = 0;
10777        var STATIC_TREES = 1;
10778        var DYN_TREES = 2;
10779
10780        var MIN_MATCH = 3;
10781        var MAX_MATCH = 258;
10782        var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
10783
10784        function smaller(tree, n, m, depth) {
10785            var tn2 = tree[n * 2];
10786            var tm2 = tree[m * 2];
10787            return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m]));
10788        }
10789
10790        function Deflate() {
10791
10792            var that = this;
10793            var strm; // pointer back to this zlib stream
10794            var status; // as the name implies
10795            // pending_buf; // output still pending
10796            var pending_buf_size; // size of pending_buf
10797            // pending_out; // next pending byte to output to the stream
10798            // pending; // nb of bytes in the pending buffer
10799            var method; // STORED (for zip only) or DEFLATED
10800            var last_flush; // value of flush param for previous deflate call
10801
10802            var w_size; // LZ77 window size (32K by default)
10803            var w_bits; // log2(w_size) (8..16)
10804            var w_mask; // w_size - 1
10805
10806            var window;
10807            // Sliding window. Input bytes are read into the second half of the window,
10808            // and move to the first half later to keep a dictionary of at least wSize
10809            // bytes. With this organization, matches are limited to a distance of
10810            // wSize-MAX_MATCH bytes, but this ensures that IO is always
10811            // performed with a length multiple of the block size. Also, it limits
10812            // the window size to 64K, which is quite useful on MSDOS.
10813            // To do: use the user input buffer as sliding window.
10814
10815            var window_size;
10816            // Actual size of window: 2*wSize, except when the user input buffer
10817            // is directly used as sliding window.
10818
10819            var prev;
10820            // Link to older string with same hash index. To limit the size of this
10821            // array to 64K, this link is maintained only for the last 32K strings.
10822            // An index in this array is thus a window index modulo 32K.
10823
10824            var head; // Heads of the hash chains or NIL.
10825
10826            var ins_h;
10826 // hash index of string to be inserted
10827            var hash_size; // number of elements in hash table
10828            var hash_bits; // log2(hash_size)
10829            var hash_mask; // hash_size-1
10830
10831            // Number of bits by which ins_h must be shifted at each input
10832            // step. It must be such that after MIN_MATCH steps, the oldest
10833            // byte no longer takes part in the hash key, that is:
10834            // hash_shift * MIN_MATCH >= hash_bits
10835            var hash_shift;
10836
10837            // Window position at the beginning of the current output block. Gets
10838            // negative when the window is moved backwards.
10839
10840            var block_start;
10841
10842            var match_length; // length of best match
10843            var prev_match; // previous match
10844            var match_available; // set if previous match exists
10845            var strstart; // start of string to insert
10846            var match_start; // start of matching string
10847            var lookahead; // number of valid bytes ahead in window
10848
10849            // Length of the best match at previous step. Matches not greater than this
10850            // are discarded. This is used in the lazy match evaluation.
10851            var prev_length;
10852
10853            // To speed up deflation, hash chains are never searched beyond this
10854            // length. A higher limit improves compression ratio but degrades the speed.
10855            var max_chain_length;
10856
10857            // Attempt to find a better match only when the current match is strictly
10858            // smaller than this value. This mechanism is used only for compression
10859            // levels >= 4.
10860            var max_lazy_match;
10861
10862            // Insert new strings in the hash table only if the match length is not
10863            // greater than this length. This saves time but degrades compression.
10864            // max_insert_length is used only for compression levels <= 3.
10865
10866            var level; // compression level (1..9)
10867            var strategy; // favor or force Huffman coding
10868
10869            // Use a faster search when the previous match is longer than this
10870            var good_match;
10871
10872            // Stop searching when current match exceeds this
10873            var nice_match;
10874
10875            var dyn_ltree; // literal and length tree
10876            var dyn_dtree; // distance tree
10877            var bl_tree; // Huffman tree for bit lengths
10878
10879            var l_desc = new Tree(); // desc for literal tree
10880            var d_desc = new Tree(); // desc for distance tree
10881            var bl_desc = new Tree(); // desc for bit length tree
10882
10883            // that.heap_len; // number of elements in the heap
10884            // that.heap_max; // element of largest frequency
10885            // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
10886            // The same heap array is used to build all trees.
10887
10888            // Depth of each subtree used as tie breaker for trees of equal frequency
10889            that.depth = [];
10890
10891            var l_buf; // index for literals or lengths */
10892
10893            // Size of match buffer for literals/lengths. There are 4 reasons for
10894            // limiting lit_bufsize to 64K:
10895            // - frequencies can be kept in 16 bit counters
10896            // - if compression is not successful for the first block, all input
10897            // data is still in the window so we can still emit a stored block even
10898            // when input comes from standard input. (This can also be done for
10899            // all blocks if lit_bufsize is not greater than 32K.)
10900            // - if compression is not successful for a file smaller than 64K, we can
10901            // even emit a stored file instead of a stored block (saving 5 bytes).
10902            // This is applicable only for zip (not gzip or zlib).
10903            // - creating new Huffman trees less frequently may not provide fast
10904            // adaptation to changes in the input data statistics. (Take for
10905            // example a binary file with poorly compressible code followed by
10906            // a highly compressible string table.) Smaller buffer sizes give
10907            // fast adaptation but have of course the overhead of transmitting
10908            // trees more frequently.
10909            // - I can't count above 4
10910            var lit_bufsize;
10911
10912            var last_lit; // running index in l_buf
10913
10914            // Buffer for distances. To simplify the code, d_buf and l_buf have
10915            // the same number of elements. To use different lengths, an extra flag
10916            // array would be necessary.
10917
10918            var d_buf; // index of pendig_buf
10919
10920            // that.opt_len; // bit length of current block with optimal trees
10921            // that.static_len; // bit length of current block with static trees
10922            var matches; // number of string matches in current block
10923            var last_eob_len; // bit length of EOB code for last block
10924
10925            // Output buffer. bits are inserted starting at the bottom (least
10926            // significant bits).
10927            var bi_buf;
10928
10929            // Number of valid bits in bi_buf. All bits above the last valid bit
10930            // are always zero.
10931            var bi_valid;
10932
10933            // number of codes at each bit length for an optimal tree
10934            that.bl_count = [];
10935
10936            // heap used to build the Huffman trees
10937            that.heap = [];
10938
10939            dyn_ltree = [];
10940            dyn_dtree = [];
10941            bl_tree = [];
10942
10943            function lm_init() {
10944                var i;
10945                window_size = 2 * w_size;
10946
10947                head[hash_size - 1] = 0;
10948                for (i = 0; i < hash_size - 1; i++) {
10949                    head[i] = 0;
10950                }
10951
10952                // Set the default configuration parameters:
10953                max_lazy_match = config_table[level].max_lazy;
10954                good_match = config_table[level].good_length;
10955                nice_match = config_table[level].nice_length;
10956                max_chain_length = config_table[level].max_chain;
10957
10958                strstart = 0;
10959                block_start = 0;
10960                lookahead = 0;
10961                match_length = prev_length = MIN_MATCH - 1;
10962                match_available = 0;
10963                ins_h = 0;
10964            }
10965
10966            function init_block() {
10967                var i;
10968                // Initialize the trees.
10969                for (i = 0; i < L_CODES; i++)
10970                    dyn_ltree[i * 2] = 0;
10971                for (i = 0; i < D_CODES; i++)
10972                    dyn_dtree[i * 2] = 0;
10973                for (i = 0; i < BL_CODES; i++)
10974                    bl_tree[i * 2] = 0;
10975
10976                dyn_ltree[END_BLOCK * 2] = 1;
10977                that.opt_len = that.static_len = 0;
10978                last_lit = matches = 0;
10979            }
10980
10981            // Initialize the tree data structures for a new zlib stream.
10982            function tr_init() {
10983
10984                l_desc.dyn_tree = dyn_ltree;
10985                l_desc.stat_desc = StaticTree.static_l_desc;
10986
10987                d_desc.dyn_tree = dyn_dtree;
10988                d_desc.stat_desc = StaticTree.static_d_desc;
10989
10990                bl_desc.dyn_tree = bl_tree;
10991                bl_desc.stat_desc = StaticTree.static_bl_desc;
10992
10993                bi_buf = 0;
10994                bi_valid = 0;
10995                last_eob_len = 8; // enough lookahead for inflate
10996
10997                // Initialize the first block of the first file:
10998                init_block();
10999            }
11000
11001            // Restore the heap property by moving down the tree starting at node k,
11002            // exchanging a node with the smallest of its two sons if necessary,
11003            // stopping
11004            // when the heap property is re-established (each father smaller than its
11005            // two sons).
11006            that.pqdownheap = function(tree, // the tree to restore
11007                                       k // node to move down
11008            ) {
11009                var heap = that.heap;
11010                var v = heap[k];
11011                var j = k << 1; // left son of k
11012                while (j <= that.heap_len) {
11013                    // Set j to the smallest of the two sons:
11014                    if (j < that.heap_len && smaller(tree, heap[j + 1], heap[j], that.depth)) {
11015                        j++;
11016                    }
11017                    // Exit if v is smaller than both sons
11018                    if (smaller(tree, v, heap[j], that.depth))
11019                        break;
11020
11021                    // Exchange v with the smallest son
11022                    heap[k] = heap[j];
11023                    k = j;
11024                    // And continue down the tree, setting j to the left son of k
11025                    j <<= 1;
11026                }
11027                heap[k] = v;
11028            };
11029
11030            // Scan a literal or distance tree to determine the frequencies of the codes
11031            // in the bit length tree.
11032            function scan_tree(tree,// the tree to be scanned
11033                               max_code // and its largest code of non zero frequency
11034            ) {
11035                var n; // iterates over all tree elements
11036                var prevlen = -1; // last emitted length
11037                var curlen; // length of current code
11038                var nextlen = tree[0 * 2 + 1]; // length of next code
11039                var count = 0; // repeat count of the current code
11040                var max_count = 7; // max repeat count
11041                var min_count = 4; // min repeat count
11042
11043                if (nextlen === 0) {
11044                    max_count = 138;
11045                    min_count = 3;
11046                }
11047                tree[(max_code + 1) * 2 + 1] = 0xffff; // guard
11048
11049                for (n = 0; n <= max_code; n++) {
11050                    curlen = nextlen;
11051                    nextlen = tree[(n + 1) * 2 + 1];
11052                    if (++count < max_count && curlen == nextlen) {
11053                        continue;
11054                    } else if (count < min_count) {
11055                        bl_tree[curlen * 2] += count;
11056                    } else if (curlen !== 0) {
11057                        if (curlen != prevlen)
11058                            bl_tree[curlen * 2]++;
11059                        bl_tree[REP_3_6 * 2]++;
11060                    } else if (count <= 10) {
11061                        bl_tree[REPZ_3_10 * 2]++;
11062                    } else {
11063                        bl_tree[REPZ_11_138 * 2]++;
11064                    }
11065                    count = 0;
11066                    prevlen = curlen;
11067                    if (nextlen === 0) {
11068                        max_count = 138;
11069                        min_count = 3;
11070                    } else if (curlen == nextlen) {
11071                        max_count = 6;
11072                        min_count = 3;
11073                    } else {
11074                        max_count = 7;
11075                        min_count = 4;
11076                    }
11077                }
11078            }
11079
11080            // Construct the Huffman tree for the bit lengths and return the index in
11081            // bl_order of the last bit length code to send.
11082            function build_bl_tree() {
11083                var max_blindex; // index of last bit length code of non zero freq
11084
11085                // Determine the bit length frequencies for literal and distance trees
11086                scan_tree(dyn_ltree, l_desc.max_code);
11087                scan_tree(dyn_dtree, d_desc.max_code);
11088
11089                // Build the bit length tree:
11090                bl_desc.build_tree(that);
11091                // opt_len now includes the length of the tree representations, except
11092                // the lengths of the bit lengths codes and the 5+5+4 bits for the
11093                // counts.
11094
11095                // Determine the number of bit length codes to send. The pkzip format
11096                // requires that at least 4 bit length codes be sent. (appnote.txt says
11097                // 3 but the actual value used is 4.)
11098                for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
11099                    if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] !== 0)
11100                        break;
11101                }
11102                // Update opt_len to include the bit length tree and counts
11103                that.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
11104
11105                return max_blindex;
11106            }
11107
11108            // Output a byte on the stream.
11109            // IN assertion: there is enough room in pending_buf.
11110            function put_byte(p) {
11111                that.pending_buf[that.pending++] = p;
11112            }
11113
11114            function put_short(w) {
11115                put_byte(w & 0xff);
11116                put_byte((w >>> 8) & 0xff);
11117            }
11118
11119            function putShortMSB(b) {
11120                put_byte((b >> 8) & 0xff);
11121                put_byte((b & 0xff) & 0xff);
11122            }
11123
11124            function send_bits(value, length) {
11125                var val, len = length;
11126                if (bi_valid > Buf_size - len) {
11127                    val = value;
11128                    // bi_buf |= (val << bi_valid);
11129                    bi_buf |= ((val << bi_valid) & 0xffff);
11130                    put_short(bi_buf);
11131                    bi_buf = val >>> (Buf_size - bi_valid);
11132                    bi_valid += len - Buf_size;
11133                } else {
11134                    // bi_buf |= (value) << bi_valid;
11135                    bi_buf |= (((value) << bi_valid) & 0xffff);
11136                    bi_valid += len;
11137                }
11138            }
11139
11140            function send_code(c, tree) {
11141                var c2 = c * 2;
11142                send_bits(tree[c2] & 0xffff, tree[c2 + 1] & 0xffff);
11143            }
11144
11145            // Send a literal or distance tree in compressed form, using the codes in
11146            // bl_tree.
11147            function send_tree(tree,// the tree to be sent
11148                               max_code // and its largest code of non zero frequency
11149            ) {
11150                var n; // iterates over all tree elements
11151                var prevlen = -1; // last emitted length
11152                var curlen; // length of current code
11153                var nextlen = tree[0 * 2 + 1]; // length of next code
11154                var count = 0; // repeat count of the current code
11155                var max_count = 7; // max repeat count
11156                var min_count = 4; // min repeat count
11157
11158                if (nextlen === 0) {
11159                    max_count = 138;
11160                    min_count = 3;
11161                }
11162
11163                for (n = 0; n <= max_code; n++) {
11164                    curlen = nextlen;
11165                    nextlen = tree[(n + 1) * 2 + 1];
11166                    if (++count < max_count && curlen == nextlen) {
11167                        continue;
11168                    } else if (count < min_count) {
11169                        do {
11170                            send_code(curlen, bl_tree);
11171                        } while (--count !== 0);
11172                    } else if (curlen !== 0) {
11173                        if (curlen != prevlen) {
11174                            send_code(curlen, bl_tree);
11175                            count--;
11176                        }
11177                        send_code(REP_3_6, bl_tree);
11178                        send_bits(count - 3, 2);
11179                    } else if (count <= 10) {
11180                        send_code(REPZ_3_10, bl_tree);
11181                        send_bits(count - 3, 3);
11182                    } else {
11183                        send_code(REPZ_11_138, bl_tree);
11184                        send_bits(count - 11, 7);
11185                    }
11186                    count = 0;
11187                    prevlen = curlen;
11188                    if (nextlen === 0) {
11189                        max_count = 138;
11190                        min_count = 3;
11191                    } else if (curlen == nextlen) {
11192                        max_count = 6;
11193                        min_count = 3;
11194                    } else {
11195                        max_count = 7;
11196                        min_count = 4;
11197                    }
11198                }
11199            }
11200
11201            // Send the header for a block using dynamic Huffman trees: the counts, the
11202            // lengths of the bit length codes, the literal tree and the distance tree.
11203            // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
11204            function send_all_trees(lcodes, dcodes, blcodes) {
11205                var rank; // index in bl_order
11206
11207                send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt
11208                send_bits(dcodes - 1, 5);
11209                send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt
11210                for (rank = 0; rank < blcodes; rank++) {
11211                    send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3);
11212                }
11213                send_tree(dyn_ltree, lcodes - 1); // literal tree
11214                send_tree(dyn_dtree, dcodes - 1); // distance tree
11215            }
11216
11217            // Flush the bit buffer, keeping at most 7 bits in it.
11218            function bi_flush() {
11219                if (bi_valid == 16) {
11220                    put_short(bi_buf);
11221                    bi_buf = 0;
11222                    bi_valid = 0;
11223                } else if (bi_valid >= 8) {
11224                    put_byte(bi_buf & 0xff);
11225                    bi_buf >>>= 8;
11226                    bi_valid -= 8;
11227                }
11228            }
11229
11230            // Send one empty static block to give enough lookahead for inflate.
11231            // This takes 10 bits, of which 7 may remain in the bit buffer.
11232            // The current inflate code requires 9 bits of lookahead. If the
11233            // last two codes for the previous block (real code plus EOB) were coded
11234            // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
11235            // the last real code. In this case we send two empty static blocks instead
11236            // of one. (There are no problems if the previous block 
11236is stored or fixed.)
11237            // To simplify the code, we assume the worst case of last real code encoded
11238            // on one bit only.
11239            function _tr_align() {
11240                send_bits(STATIC_TREES << 1, 3);
11241                send_code(END_BLOCK, StaticTree.static_ltree);
11242
11243                bi_flush();
11244
11245                // Of the 10 bits for the empty block, we have already sent
11246                // (10 - bi_valid) bits. The lookahead for the last real code (before
11247                // the EOB of the previous block) was thus at least one plus the length
11248                // of the EOB plus what we have just sent of the empty static block.
11249                if (1 + last_eob_len + 10 - bi_valid < 9) {
11250                    send_bits(STATIC_TREES << 1, 3);
11251                    send_code(END_BLOCK, StaticTree.static_ltree);
11252                    bi_flush();
11253                }
11254                last_eob_len = 7;
11255            }
11256
11257            // Save the match info and tally the frequency counts. Return true if
11258            // the current block must be flushed.
11259            function _tr_tally(dist, // distance of matched string
11260                               lc // match length-MIN_MATCH or unmatched char (if dist==0)
11261            ) {
11262                var out_length, in_length, dcode;
11263                that.pending_buf[d_buf + last_lit * 2] = (dist >>> 8) & 0xff;
11264                that.pending_buf[d_buf + last_lit * 2 + 1] = dist & 0xff;
11265
11266                that.pending_buf[l_buf + last_lit] = lc & 0xff;
11267                last_lit++;
11268
11269                if (dist === 0) {
11270                    // lc is the unmatched char
11271                    dyn_ltree[lc * 2]++;
11272                } else {
11273                    matches++;
11274                    // Here, lc is the match length - MIN_MATCH
11275                    dist--; // dist = match distance - 1
11276                    dyn_ltree[(Tree._length_code[lc] + LITERALS + 1) * 2]++;
11277                    dyn_dtree[Tree.d_code(dist) * 2]++;
11278                }
11279
11280                if ((last_lit & 0x1fff) === 0 && level > 2) {
11281                    // Compute an upper bound for the compressed length
11282                    out_length = last_lit * 8;
11283                    in_length = strstart - block_start;
11284                    for (dcode = 0; dcode < D_CODES; dcode++) {
11285                        out_length += dyn_dtree[dcode * 2] * (5 + Tree.extra_dbits[dcode]);
11286                    }
11287                    out_length >>>= 3;
11288                    if ((matches < Math.floor(last_lit / 2)) && out_length < Math.floor(in_length / 2))
11289                        return true;
11290                }
11291
11292                return (last_lit == lit_bufsize - 1);
11293                // We avoid equality with lit_bufsize because of wraparound at 64K
11294                // on 16 bit machines and because stored blocks are restricted to
11295                // 64K-1 bytes.
11296            }
11297
11298            // Send the block data compressed using the given Huffman trees
11299            function compress_block(ltree, dtree) {
11300                var dist; // distance of matched string
11301                var lc; // match length or unmatched char (if dist === 0)
11302                var lx = 0; // running index in l_buf
11303                var code; // the code to send
11304                var extra; // number of extra bits to send
11305
11306                if (last_lit !== 0) {
11307                    do {
11308                        dist = ((that.pending_buf[d_buf + lx * 2] << 8) & 0xff00) | (that.pending_buf[d_buf + lx * 2 + 1] & 0xff);
11309                        lc = (that.pending_buf[l_buf + lx]) & 0xff;
11310                        lx++;
11311
11312                        if (dist === 0) {
11313                            send_code(lc, ltree); // send a literal byte
11314                        } else {
11315                            // Here, lc is the match length - MIN_MATCH
11316                            code = Tree._length_code[lc];
11317
11318                            send_code(code + LITERALS + 1, ltree); // send the length
11319                            // code
11320                            extra = Tree.extra_lbits[code];
11321                            if (extra !== 0) {
11322                                lc -= Tree.base_length[code];
11323                                send_bits(lc, extra); // send the extra length bits
11324                            }
11325                            dist--; // dist is now the match distance - 1
11326                            code = Tree.d_code(dist);
11327
11328                            send_code(code, dtree); // send the distance code
11329                            extra = Tree.extra_dbits[code];
11330                            if (extra !== 0) {
11331                                dist -= Tree.base_dist[code];
11332                                send_bits(dist, extra); // send the extra distance bits
11333                            }
11334                        } // literal or match pair ?
11335
11336                        // Check that the overlay between pending_buf and d_buf+l_buf is
11337                        // ok:
11338                    } while (lx < last_lit);
11339                }
11340
11341                send_code(END_BLOCK, ltree);
11342                last_eob_len = ltree[END_BLOCK * 2 + 1];
11343            }
11344
11345            // Flush the bit buffer and align the output on a byte boundary
11346            function bi_windup() {
11347                if (bi_valid > 8) {
11348                    put_short(bi_buf);
11349                } else if (bi_valid > 0) {
11350                    put_byte(bi_buf & 0xff);
11351                }
11352                bi_buf = 0;
11353                bi_valid = 0;
11354            }
11355
11356            // Copy a stored block, storing first the length and its
11357            // one's complement if requested.
11358            function copy_block(buf, // the input data
11359                                len, // its length
11360                                header // true if block header must be written
11361            ) {
11362                bi_windup(); // align on byte boundary
11363                last_eob_len = 8; // enough lookahead for inflate
11364
11365                if (header) {
11366                    put_short(len);
11367                    put_short(~len);
11368                }
11369
11370                that.pending_buf.set(window.subarray(buf, buf + len), that.pending);
11371                that.pending += len;
11372            }
11373
11374            // Send a stored block
11375            function _tr_stored_block(buf, // input block
11376                                      stored_len, // length of input block
11377                                      eof // true if this is the last block for a file
11378            ) {
11379                send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type
11380                copy_block(buf, stored_len, true); // with header
11381            }
11382
11383            // Determine the best encoding for the current block: dynamic trees, static
11384            // trees or store, and output the encoded block to the zip file.
11385            function _tr_flush_block(buf, // input block, or NULL if too old
11386                                     stored_len, // length of input block
11387                                     eof // true if this is the last block for a file
11388            ) {
11389                var opt_lenb, static_lenb;// opt_len and static_len in bytes
11390                var max_blindex = 0; // index of last bit length code of non zero freq
11391
11392                // Build the Huffman trees unless a stored block is forced
11393                if (level > 0) {
11394                    // Construct the literal and distance trees
11395                    l_desc.build_tree(that);
11396
11397                    d_desc.build_tree(that);
11398
11399                    // At this point, opt_len and static_len are the total bit lengths
11400                    // of
11401                    // the compressed block data, excluding the tree representations.
11402
11403                    // Build the bit length tree for the above two trees, and get the
11404                    // index
11405                    // in bl_order of the last bit length code to send.
11406                    max_blindex = build_bl_tree();
11407
11408                    // Determine the best encoding. Compute first the block length in
11409                    // bytes
11410                    opt_lenb = (that.opt_len + 3 + 7) >>> 3;
11411                    static_lenb = (that.static_len + 3 + 7) >>> 3;
11412
11413                    if (static_lenb <= opt_lenb)
11414                        opt_lenb = static_lenb;
11415                } else {
11416                    opt_lenb = static_lenb = stored_len + 5; // force a stored block
11417                }
11418
11419                if ((stored_len + 4 <= opt_lenb) && buf != -1) {
11420                    // 4: two words for the lengths
11421                    // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
11422                    // Otherwise we can't have processed more than WSIZE input bytes
11423                    // since
11424                    // the last block flush, because compression would have been
11425                    // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
11426                    // transform a block into a stored block.
11427                    _tr_stored_block(buf, stored_len, eof);
11428                } else if (static_lenb == opt_lenb) {
11429                    send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3);
11430                    compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
11431                } else {
11432                    send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3);
11433                    send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1);
11434                    compress_block(dyn_ltree, dyn_dtree);
11435                }
11436
11437                // The above check is made mod 2^32, for files larger than 512 MB
11438                // and uLong implemented on 32 bits.
11439
11440                init_block();
11441
11442                if (eof) {
11443                    bi_windup();
11444                }
11445            }
11446
11447            function flush_block_only(eof) {
11448                _tr_flush_block(block_start >= 0 ? block_start : -1, strstart - block_start, eof);
11449                block_start = strstart;
11450                strm.flush_pending();
11451            }
11452
11453            // Fill the window when the lookahead becomes insufficient.
11454            // Updates strstart and lookahead.
11455            //
11456            // IN assertion: lookahead < MIN_LOOKAHEAD
11457            // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
11458            // At least one byte has been read, or avail_in === 0; reads are
11459            // performed for at least two bytes (required for the zip translate_eol
11460            // option -- not supported here).
11461            function fill_window() {
11462                var n, m;
11463                var p;
11464                var more; // Amount of free space at the end of the window.
11465
11466                do {
11467                    more = (window_size - lookahead - strstart);
11468
11469                    // Deal with !@#$% 64K limit:
11470                    if (more === 0 && strstart === 0 && lookahead === 0) {
11471                        more = w_size;
11472                    } else if (more == -1) {
11473                        // Very unlikely, but possible on 16 bit machine if strstart ==
11474                        // 0
11475                        // and lookahead == 1 (input done one byte at time)
11476                        more--;
11477
11478                        // If the window is almost full and there is insufficient
11479                        // lookahead,
11480                        // move the upper half to the lower one to make room in the
11481                        // upper half.
11482                    } else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) {
11483                        window.set(window.subarray(w_size, w_size + w_size), 0);
11484
11485                        match_start -= w_size;
11486                        strstart -= w_size; // we now have strstart >= MAX_DIST
11487                        block_start -= w_size;
11488
11489                        // Slide the hash table (could be avoided with 32 bit values
11490                        // at the expense of memory usage). We slide even when level ==
11491                        // 0
11492                        // to keep the hash table consistent if we switch back to level
11493                        // > 0
11494                        // later. (Using level 0 permanently is not an optimal usage of
11495                        // zlib, so we don't care about this pathological case.)
11496
11497                        n = hash_size;
11498                        p = n;
11499                        do {
11500                            m = (head[--p] & 0xffff);
11501                            head[p] = (m >= w_size ? m - w_size : 0);
11502                        } while (--n !== 0);
11503
11504                        n = w_size;
11505                        p = n;
11506                        do {
11507                            m = (prev[--p] & 0xffff);
11508                            prev[p] = (m >= w_size ? m - w_size : 0);
11509                            // If n is not on any hash chain, prev[n] is garbage but
11510                            // its value will never be used.
11511                        } while (--n !== 0);
11512                        more += w_size;
11513                    }
11514
11515                    if (strm.avail_in === 0)
11516                        return;
11517
11518                    // If there was no sliding:
11519                    // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
11520                    // more == window_size - lookahead - strstart
11521                    // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
11522                    // => more >= window_size - 2*WSIZE + 2
11523                    // In the BIG_MEM or MMAP case (not yet supported),
11524                    // window_size == input_size + MIN_LOOKAHEAD &&
11525                    // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
11526                    // Otherwise, window_size == 2*WSIZE so more >= 2.
11527                    // If there was sliding, more >= WSIZE. So in all cases, more >= 2.
11528
11529                    n = strm.read_buf(window, strstart + lookahead, more);
11530                    lookahead += n;
11531
11532                    // Initialize the hash value now that we have some input
11532:
11533                    if (lookahead >= MIN_MATCH) {
11534                        ins_h = window[strstart] & 0xff;
11535                        ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
11536                    }
11537                    // If the whole input has less than MIN_MATCH bytes, ins_h is
11538                    // garbage,
11539                    // but this is not important since only literal bytes will be
11540                    // emitted.
11541                } while (lookahead < MIN_LOOKAHEAD && strm.avail_in !== 0);
11542            }
11543
11544            // Copy without compression as much as possible from the input stream,
11545            // return
11546            // the current block state.
11547            // This function does not insert new strings in the dictionary since
11548            // uncompressible data is probably not useful. This function is used
11549            // only for the level=0 compression option.
11550            // NOTE: this function should be optimized to avoid extra copying from
11551            // window to pending_buf.
11552            function deflate_stored(flush) {
11553                // Stored blocks are limited to 0xffff bytes, pending_buf is limited
11554                // to pending_buf_size, and each stored block has a 5 byte header:
11555
11556                var max_block_size = 0xffff;
11557                var max_start;
11558
11559                if (max_block_size > pending_buf_size - 5) {
11560                    max_block_size = pending_buf_size - 5;
11561                }
11562
11563                // Copy as much as possible from input to output:
11564                while (true) {
11565                    // Fill the window as much as possible:
11566                    if (lookahead <= 1) {
11567                        fill_window();
11568                        if (lookahead === 0 && flush == Z_NO_FLUSH)
11569                            return NeedMore;
11570                        if (lookahead === 0)
11571                            break; // flush the current block
11572                    }
11573
11574                    strstart += lookahead;
11575                    lookahead = 0;
11576
11577                    // Emit a stored block if pending_buf will be full:
11578                    max_start = block_start + max_block_size;
11579                    if (strstart === 0 || strstart >= max_start) {
11580                        // strstart === 0 is possible when wraparound on 16-bit machine
11581                        lookahead = (strstart - max_start);
11582                        strstart = max_start;
11583
11584                        flush_block_only(false);
11585                        if (strm.avail_out === 0)
11586                            return NeedMore;
11587
11588                    }
11589
11590                    // Flush if we may have to slide, otherwise block_start may become
11591                    // negative and the data will be gone:
11592                    if (strstart - block_start >= w_size - MIN_LOOKAHEAD) {
11593                        flush_block_only(false);
11594                        if (strm.avail_out === 0)
11595                            return NeedMore;
11596                    }
11597                }
11598
11599                flush_block_only(flush == Z_FINISH);
11600                if (strm.avail_out === 0)
11601                    return (flush == Z_FINISH) ? FinishStarted : NeedMore;
11602
11603                return flush == Z_FINISH ? FinishDone : BlockDone;
11604            }
11605
11606            function longest_match(cur_match) {
11607                var chain_length = max_chain_length; // max hash chain length
11608                var scan = strstart; // current string
11609                var match; // matched string
11610                var len; // length of current match
11611                var best_len = prev_length; // best match length so far
11612                var limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0;
11613                var _nice_match = nice_match;
11614
11615                // Stop when cur_match becomes <= limit. To simplify the code,
11616                // we prevent matches with the string of window index 0.
11617
11618                var wmask = w_mask;
11619
11620                var strend = strstart + MAX_MATCH;
11621                var scan_end1 = window[scan + best_len - 1];
11622                var scan_end = window[scan + best_len];
11623
11624                // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of
11625                // 16.
11626                // It is easy to get rid of this optimization if necessary.
11627
11628                // Do not waste too much time if we already have a good match:
11629                if (prev_length >= good_match) {
11630                    chain_length >>= 2;
11631                }
11632
11633                // Do not look for matches beyond the end of the input. This is
11634                // necessary
11635                // to make deflate deterministic.
11636                if (_nice_match > lookahead)
11637                    _nice_match = lookahead;
11638
11639                do {
11640                    match = cur_match;
11641
11642                    // Skip to next match if the match length cannot increase
11643                    // or if the match length is less than 2:
11644                    if (window[match + best_len] != scan_end || window[match + best_len - 1] != scan_end1 || window[match] != window[scan]
11645                        || window[++match] != window[scan + 1])
11646                        continue;
11647
11648                    // The check at best_len-1 can be removed because it will be made
11649                    // again later. (This heuristic is not always a win.)
11650                    // It is not necessary to compare scan[2] and match[2] since they
11651                    // are always equal when the other bytes match, given that
11652                    // the hash keys are equal and that HASH_BITS >= 8.
11653                    scan += 2;
11654                    match++;
11655
11656                    // We check for insufficient lookahead only every 8th comparison;
11657                    // the 256th check will be made at strstart+258.
11658                    do {
11659                    } while (window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match]
11660                    && window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match]
11661                    && window[++scan] == window[++match] && window[++scan] == window[++match] && scan < strend);
11662
11663                    len = MAX_MATCH - (strend - scan);
11664                    scan = strend - MAX_MATCH;
11665
11666                    if (len > best_len) {
11667                        match_start = cur_match;
11668                        best_len = len;
11669                        if (len >= _nice_match)
11670                            break;
11671                        scan_end1 = window[scan + best_len - 1];
11672                        scan_end = window[scan + best_len];
11673                    }
11674
11675                } while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length !== 0);
11676
11677                if (best_len <= lookahead)
11678                    return best_len;
11679                return lookahead;
11680            }
11681
11682            // Compress as much as possible from the input stream, return the current
11683            // block state.
11684            // This function does not perform lazy evaluation of matches and inserts
11685            // new strings in the dictionary only for unmatched strings or for short
11686            // matches. It is used only for the fast compression options.
11687            function deflate_fast(flush) {
11688                // short hash_head = 0; // head of the hash chain
11689                var hash_head = 0; // head of the hash chain
11690                var bflush; // set if current block must be flushed
11691
11692                while (true) {
11693                    // Make sure that we always have enough lookahead, except
11694                    // at the end of the input file. We need MAX_MATCH bytes
11695                    // for the next match, plus MIN_MATCH bytes to insert the
11696                    // string following the next match.
11697                    if (lookahead < MIN_LOOKAHEAD) {
11698                        fill_window();
11699                        if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
11700                            return NeedMore;
11701                        }
11702                        if (lookahead === 0)
11703                            break; // flush the current block
11704                    }
11705
11706                    // Insert the string window[strstart .. strstart+2] in the
11707                    // dictionary, and set hash_head to the head of the hash chain:
11708                    if (lookahead >= MIN_MATCH) {
11709                        ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
11710
11711                        // prev[strstart&w_mask]=hash_head=head[ins_h];
11712                        hash_head = (head[ins_h] & 0xffff);
11713                        prev[strstart & w_mask] = head[ins_h];
11714                        head[ins_h] = strstart;
11715                    }
11716
11717                    // Find the longest match, discarding those <= prev_length.
11718                    // At this point we have always match_length < MIN_MATCH
11719
11720                    if (hash_head !== 0 && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
11721                        // To simplify the code, we prevent matches with the string
11722                        // of window index 0 (in particular we have to avoid a match
11723                        // of the string with itself at the start of the input file).
11724                        if (strategy != Z_HUFFMAN_ONLY) {
11725                            match_length = longest_match(hash_head);
11726                        }
11727                        // longest_match() sets match_start
11728                    }
11729                    if (match_length >= MIN_MATCH) {
11730                        // check_match(strstart, match_start, match_length);
11731
11732                        bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH);
11733
11734                        lookahead -= match_length;
11735
11736                        // Insert new strings in the hash table only if the match length
11737                        // is not too large. This saves time but degrades compression.
11738                        if (match_length <= max_lazy_match && lookahead >= MIN_MATCH) {
11739                            match_length--; // string at strstart already in hash table
11740                            do {
11741                                strstart++;
11742
11743                                ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
11744                                // prev[strstart&w_mask]=hash_head=head[ins_h];
11745                                hash_head = (head[ins_h] & 0xffff);
11746                                prev[strstart & w_mask] = head[ins_h];
11747                                head[ins_h] = strstart;
11748
11749                                // strstart never exceeds WSIZE-MAX_MATCH, so there are
11750                                // always MIN_MATCH bytes ahead.
11751                            } while (--match_length !== 0);
11752                            strstart++;
11753                        } else {
11754                            strstart += match_length;
11755                            match_length = 0;
11756                            ins_h = window[strstart] & 0xff;
11757
11758                            ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
11759                            // If lookahead < MIN_MATCH, ins_h is garbage, but it does
11760                            // not
11761                            // matter since it will be recomputed at next deflate call.
11762                        }
11763                    } else {
11764                        // No match, output a literal byte
11765
11766                        bflush = _tr_tally(0, window[strstart] & 0xff);
11767                        lookahead--;
11768                        strstart++;
11769                    }
11770                    if (bflush) {
11771
11772                        flush_block_only(false);
11773                        if (strm.avail_out === 0)
11774                            return NeedMore;
11775                    }
11776                }
11777
11778                flush_block_only(flush == Z_FINISH);
11779                if (strm.avail_out === 0) {
11780                    if (flush == Z_FINISH)
11781                        return FinishStarted;
11782                    else
11783                        return NeedMore;
11784                }
11785                return flush == Z_FINISH ? FinishDone : BlockDone;
11786            }
11787
11788            // Same as above, but achieves better compression. We use a lazy
11789            // evaluation for matches: a match is finally adopted only if there is
11790            // no better match at the next window position.
11791            function deflate_slow(flush) {
11792                // short hash_head = 0; // head of hash chain
11793                var hash_head = 0; // head of hash chain
11794                var bflush; // set if current block must be flushed
11795                var max_insert;
11796
11797                // Process the input block.
11798                while (true) {
11799                    // Make sure that we always have enough lookahead, except
11800                    // at the end of the input file. We need MAX_MATCH bytes
11801                    // for the next match, plus MIN_MATCH bytes to insert the
11802                    // string following the next match.
11803
11804                    if (lookahead < MIN_LOOKAHEAD) {
11805                        fill_window();
11806                        if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
11807                            return NeedMore;
11808                        }
11809                        if (lookahead === 0)
11810                            break; // flush the current block
11811                    }
11812
11813                    // Insert the string window[strstart .. strstart+2] in the
11814                    // dictionary, and set hash_head to the head of the hash chain:
11815
11816                    if (lookahead >= MIN_MATCH) {
11817                        ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
11818                        // prev[strstart&w_mask]=hash_head=head[ins_h];
11819                        hash_head = (head[ins_h] & 0xffff);
11820                        prev[strstart & w_mask] = head[ins_h];
11821                        head[ins_h] = strstart;
11822                    }
11823
11824                    // Find the longest match, discarding those <= prev_length.
11825                    prev_length = match_length;
11826                    prev_match = match_start;
11827                    match_length = MIN_MATCH - 1;
11828
11829                    if (hash_head !== 0 && prev_length < max_lazy_match && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
11830                        // To simplify the code, we prevent matches with the string
11831                        // of window index 0 (in particular we have to avoid a match
11832                        // of the string with itself at the start of the input file).
11833
11834                        if (strategy != Z_HUFFMAN_ONLY) {
11835                            match_length = longest_match(hash_head);
11836                        }
11837                        // longest_match() sets match_start
11838
11839                        if (match_length <= 5 && (strategy == Z_FILTERED || (match_length == MIN_MATCH && strstart - match_start > 4096))) {
11840
11841                            // If prev_match is also MIN_MATCH, match_start is garbage
11842                            // but we will ignore the current match anyway.
11843                            match_length = MIN_MATCH - 1;
11844                        }
11845                    }
11846
11847                    // If there was a match at the previous step and the current
11848                    // match is not better, output the previous match:
11849                    if (prev_length >= MIN_MATCH && match_length <= prev_length) {
11850                        max_insert = strstart + lookahead - MIN_MATCH;
11851                        // Do not insert strings in hash table beyond this.
11852
11853                        // check_match(strstart-1, prev_match, prev_length);
11854
11855                        bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH);
11856
11857                        // Insert in hash table all strings up to the end of the match.
11858                        // strstart-1 and strstart are already inserted. If there is not
11859                        // enough lookahead, the last two strings are not inserted in
11860                        // the hash table.
11861                        lookahead -= prev_length - 1;
11862                        prev_length -= 2;
11863                        do {
11864                            if (++strstart <= max_insert) {
11865                                ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
11866                                // prev[strstart&w_mask]=hash_head=head[ins_h];
11867                                hash_head = (head[ins_h] & 0xffff);
11868                                prev[strstart & w_mask] = head[ins_h];
11869                                head[ins_h] = strstart;
11870                            }
11871                        } while (--prev_length !== 0);
11872                        match_available = 0;
11873                        match_length = MIN_MATCH - 1;
11874                        strstart++;
11875
11876                        if (bflush) {
11877                            flush_block_only(false);
11878                            if (strm.avail_out === 0)
11879                                return NeedMore;
11880                        }
11881                    } else if (match_available !== 0) {
11882
11883                        // If there was no match at the previous position, output a
11884                        // single literal. If there was a match but the current match
11885                        // is longer, truncate the previous match to a single literal.
11886
11887                        bflush = _tr_tally(0, window[strstart - 1] & 0xff);
11888
11889                        if (bflush) {
11890                            flush_block_only(false);
11891                        }
11892                        strstart++;
11893                        lookahead--;
11894                        if (strm.avail_out === 0)
11895                            return NeedMore;
11896                    } else {
11897                        // There is no previous match to compare with, wait for
11898                        // the next step to decide.
11899
11900                        match_available = 1;
11901                        strstart++;
11902                        lookahead--;
11903                    }
11904                }
11905
11906                if (match_available !== 0) {
11907                    bflush = _tr_tally(0, window[strstart - 1] & 0xff);
11908                    match_available = 0;
11909                }
11910                flush_block_only(flush == Z_FINISH);
11911
11912                if (strm.avail_out === 0) {
11913                    if (flush == Z_FINISH)
11914                        return FinishStarted;
11915                    else
11916                        return NeedMore;
11917                }
11918
11919                return flush == Z_FINISH ? FinishDone : BlockDone;
11920            }
11921
11922            function deflateReset(strm) {
11923                strm.total_in = strm.total_out = 0;
11924                strm.msg = null; //
11925
11926                that.pending = 0;
11927                that.pending_out = 0;
11928
11929                status = BUSY_STATE;
11930
11931                last_flush = Z_NO_FLUSH;
11932
11933                tr_init();
11934                lm_init();
11935                return Z_OK;
11936            }
11937
11938            that.deflateInit = function(strm, _level, bits, _method, memLevel, _strategy) {
11939                if (!_method)
11940                    _method = Z_DEFLATED;
11941                if (!memLevel)
11942                    memLevel = DEF_MEM_LEVEL;
11943                if (!_strategy)
11944                    _strategy = Z_DEFAULT_STRATEGY;
11945
11946                // byte[] my_version=ZLIB_VERSION;
11947
11948                //
11949                // if (!version || version[0] != my_version[0]
11950                // || stream_size != sizeof(z_stream)) {
11951                // return Z_VERSION_ERROR;
11952                // }
11953
11954                strm.msg = null;
11955
11956                if (_level == Z_DEFAULT_COMPRESSION)
11957                    _level = 6;
11958
11959                if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || _method != Z_DEFLATED || bits < 9 || bits > 15 || _level < 0 || _level > 9 || _strategy < 0
11960                    || _strategy > Z_HUFFMAN_ONLY) {
11961                    return Z_STREAM_ERROR;
11962                }
11963
11964                strm.dstate = that;
11965
11966                w_bits = bits;
11967                w_size = 1 << w_bits;
11968                w_mask = w_size - 1;
11969
11970                hash_bits = memLevel + 7;
11971                hash_size = 1 << hash_bits;
11972                hash_mask = hash_size - 1;
11973                hash_shift = Math.floor((hash_bits + MIN_MATCH - 1) / MIN_MATCH);
11974
11975                window = new Uint8Array(w_size * 2);
11976                prev = [];
11977                head = [];
11978
11979                lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
11980
11981                // We overlay pending_buf and d_buf+l_buf. This works since the average
11982                // output size for (length,distance) codes is <= 24 bits.
11983                that.pending_buf = new Uint8Array(lit_bufsize * 4);
11984                pending_buf_size = lit_bufsize * 4;
11985
11986                d_buf = Math.floor(lit_bufsize / 2);
11987                l_buf = (1 + 2) * lit_bufsize;
11988
11989                level = _level;
11990
11991                strategy = _strategy;
11992                method = _method & 0xff;
11993
11994                return deflateReset(strm);
11995            };
11996
11997            that.deflateEnd = function() {
11998                if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) {
11999                    return Z_STREAM_ERROR;
12000                }
12001                // Deallocate in reverse order of allocations:
12002                that.pending_buf = null;
12003                head = null;
12004                prev = null;
12005                window = null;
12006                // free
12007                that.dstate = null;
12008                return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
12009            };
12010
12011            that.deflateParams = function(strm, _level, _strategy) {
12012                var err = Z_OK;
12013
12014                if (_level == Z_DEFAULT_COMPRESSION) {
12015                    _level = 6;
12016                }
12017                if (_level < 0 || _level > 9 || _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
12018                    return Z_STREAM_ERROR;
12019                }
12020
12021                if (config_table[level].func != config_table[_level].func && strm.total_in !== 0) {
12022                    // Flush the last buffer:
12023                    err = strm.deflate(Z_PARTIAL_FLUSH);
12024                }
12025
12026                if (level != _level) {
12027                    level = _level;
12028                    max_lazy_match = config_table[level].max_lazy;
12029                    good_match = config_table[level].good_length;
12030                    nice_match = config_table[level].nice_length;
12031                    max_chain_length = config_table[level].max_chain;
12032                }
12033                strategy = _strategy;
12034                return err;
12035            };
12036
12037            that.deflateSetDictionary = function(strm, dictionary, dictLength) {
12038                var length = dictLength;
12039                var n, index = 0;
12040
12041                if (!dictionary || status != INIT_STATE)
12042                    return Z_STREAM_ERROR;
12043
12044                if (length < MIN_MATCH)
12045                    return Z_OK;
12046                if (length > w_size - MIN_LOOKAHEAD) {
12047                    length = w_size - MIN_LOOKAHEAD;
12048                    index = dictLength - length; // use the tail of the dictionary
12049                }
12050                window.set(dictionary.subarray(index, index + length), 0);
12051
12052                strstart = length;
12053                block_start = length;
12054
12055                // Insert all strings in the hash table (except for the last two bytes).
12056                // s->lookahead stays null, so s->ins_h will be recomputed at the next
12057                // call of fill_window.
12058
12059                ins_h = window[0] & 0xff;
12060                ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask;
12061
12062                for (n = 0; n <= length - MIN_MATCH; n++) {
12063                    ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
12064                    prev[n & w_mask] = head[ins_h];
12065                    head[ins_h] = n;
12066                }
12067                return Z_OK;
12068            };
12069
12070            that.deflate = function(_strm, flush) {
12071                var i, header, level_flags, old_flush, bstate;
12072
12073                if (flush > Z_FINISH || flush < 0) {
12074                    return Z_STREAM_ERROR;
12075                }
12076
12077                if (!_strm.next_out || (!_strm.next_in && _strm.avail_in !== 0) || (status == FINISH_STATE && flush != Z_FINISH)) {
12078                    _strm.msg = z_errmsg[Z_NEED_DICT - (Z_STREAM_ERROR)];
12079                    return Z_STREAM_ERROR;
12080                }
12081                if (_strm.avail_out === 0) {
12082                    _strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
12083                    return Z_BUF_ERROR;
12084                }
12085
12086                strm = _strm; // just in case
12087                old_flush = last_flush;
12088                last_flush = flush;
12089
12090                // Write the zlib header
12091                if (status == INIT_STATE) {
12092                    header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8;
12093                    level_flags = ((level - 1) & 0xff) >> 1;
12094
12095                    if (level_flags > 3)
12096                        level_flags = 3;
12097                    header |= (level_flags << 6);
12098                    if (strstart !== 0)
12099                        header |= PRESET_DICT;
12100                    header += 31 - (header % 31);
12101
12102                    status = BUSY_STATE;
12103                    putShortMSB(header);
12104                }
12105
12106                // Flush as much pending output as possible
12107                if (that.pending !== 0) {
12108                    strm.flush_pending();
12109                    if (strm.avail_out === 0) {
12110                        // console.log(" avail_out==0");
12111                        // Since avail_out is 0, deflate will be called again with
12112                        // more output space, but possibly with both pending and
12113                        // avail_in equal to zero. There won't be anything to do,
12114                        // but this is not an error situation so make sure we
12115                        // return OK instead of BUF_ERROR at next call of deflate:
12116                        last_flush = -1;
12117                        return Z_OK;
12118                    }
12119
12120                    // Make sure there is something to do and avoid duplicate
12121                    // consecutive
12122                    // flushes. For repeated and useless calls with Z_FINISH, we keep
12123                    // returning Z_STREAM_END instead of Z_BUFF_ERROR.
12124                } else if (strm.avail_in === 0 && flush <= old_flush && flush != Z_FINISH) {
12125                    strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
12126                    return Z_BUF_ERROR;
12127                }
12128
12129                // User must not provide more input after the first FINISH:
12130                if (status == FINISH_STATE && strm.avail_in !== 0) {
12131                    _strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
12132                    return Z_BUF_ERROR;
12133                }
12134
12135                // Start a new block or continue the current one.
12136                if (strm.avail_in !== 0 || lookahead !== 0 || (flush != Z_NO_FLUSH && status != FINISH_STATE)) {
12137                    bstate = -1;
12138                    switch (config_table[level].func) {
12139                        case STORED:
12140                            bstate = deflate_stored(flush);
12141                            break;
12142                        case FAST:
12143                            bstate = deflate_fast(flush);
12144                            break;
12145                        case SLOW:
12146                            bstate = deflate_slow(flush);
12147                            break;
12148                        default:
12149                    }
12150
12151                    if (bstate == FinishStarted || bstate == FinishDone) {
12152                        status = FINISH_STATE;
12153                    }
12154                    if (bstate == NeedMore || bstate == FinishStarted) {
12155                        if (strm.avail_out === 0) {
12156                            last_flush = -1; // avoid BUF_ERROR next call, see above
12157                        }
12158                        return Z_OK;
12159                        // If flush != Z_NO_FLUSH && avail_out === 0, the next call
12160                        // of deflate should use the same flush parameter to make sure
12161                        // that the flush is complete. So we don't have to output an
12162                        // empty block here, this will be done at next call. This also
12163                        // ensures that for a very small output buffer, we emit at most
12164                        // one empty block.
12165                    }
12166
12167                    if (bstate == BlockDone) {
12168                        if (flush == Z_PARTIAL_FLUSH) {
12169                            _tr_align();
12170                        } else { // FULL_FLUSH or SYNC_FLUSH
12171                            _tr_stored_block(0, 0, false);
12172                            // For a full flush, this empty block will be recognized
12173                            // as a special marker by inflate_sync().
12174                            if (flush == Z_FULL_FLUSH) {
12175                                // state.head[s.hash_size-1]=0;
12176                                for (i = 0; i < hash_size/*-1*/; i++)
12177                                    // forget history
12178                                    head[i] = 0;
12179                            }
12180                        }
12181                        strm.flush_pending();
12182                        if (strm.avail_out === 0) {
12183                            last_flush = -1; // avoid BUF_ERROR at next call, see above
12184                            return Z_OK;
12185                        }
12186                    }
12187                }
12188
12189                if (flush != Z_FINISH)
12190                    return Z_OK;
12191                return Z_STREAM_END;
12192            };
12193        }
12194
12195        // ZStream
12196
12197        function ZStream() {
12198            var that = this;
12199            that.next_in_index = 0;
12200            that.next_out_index = 0;
12201            // that.next_in; // next input byte
12202            that.avail_in = 0; // number of bytes available at next_in
12203            that.total_in = 0; // total nb of input bytes read so far
12204            // that.next_out; // next output byte should be put there
12205            that.avail_out = 0; // remaining free space at next_out
12206            that.total_out = 0; // total nb of bytes output so far
12207            // that.msg;
12208            // that.dstate;
12209        }
12210
12211        ZStream.prototype = {
12212            deflateInit : function(level, bits) {
12213                var that = this;
12214                that.dstate = new Deflate();
12215                if (!bits)
12216                    bits = MAX_BITS;
12217                return that.dstate.deflateInit(that, level, bits);
12218            },
12219
12220            deflate : function(flush) {
12221                var that = this;
12222                if (!that.dstate) {
12223                    return Z_STREAM_ERROR;
12224                }
12225                return that.dstate.deflate(that, flush);
12226            },
12227
12228            deflateEnd : function() {
12229                var that = this;
12230                if (!that.dstate)
12231                    return Z_STREAM_ERROR;
12232                var ret = that.dstate.deflateEnd();
12233                that.dstate = null;
12234                return ret;
12235            },
12236
12237            deflateParams : function(level, strategy) {
12238                var that = this;
12239                if (!that.dstate)
12240                    return Z_STREAM_ERROR;
12241                return that.dstate.deflateParams(that, level, strategy);
12242            },
12243
12244            deflateSetDictionary : function(dictionary, dictLength) {
12245                var that = this;
12246                if (!that.dstate)
12247                    return Z_STREAM_ERROR;
12248                return that.dstate.deflateSetDictionary(that, dictionary, dictLength);
12249            },
12250
12251            // Read a new buffer from the current input stream, update the
12252            // total number of bytes read. All deflate() input goes through
12253            // this function so some applications may wish to modify it to avoid
12254            // allocating a large strm->next_in buffer and copying from it.
12255            // (See also flush_pending()).
12256            read_buf : function(buf, start, size) {
12257                var that = this;
12258                var len = that.avail_in;
12259                if (len > size)
12260                    len = size;
12261                if (len === 0)
12262                    return 0;
12263                that.avail_in -= len;
12264                buf.set(that.next_in.subarray(that.next_in_index, that.next_in_index + len), start);
12265                that.next_in_index += len;
12266                that.total_in += len;
12267                return len;
12268            },
12269
12270            // Flush as much pending output as possible. All deflate() output goes
12271            // through this function so some applications may wish to modify it
12272            // to avoid allocating a large strm->next_out buffer and copying into it.
12273            // (See also read_buf()).
12274            flush_pending : function() {
12275                var that = this;
12276                var len = that.dstate.pending;
12277
12278                if (len > that.avail_out)
12279                    len = that.avail_out;
12280                if (len === 0)
12281                    return;
12282
12283                // if (that.dstate.pending_buf.length <= that.dstate.pending_out || that.next_out.length <= that.next_out_index
12284                // || that.dstate.pending_buf.length < (that.dstate.pending_out + len) || that.next_out.length < (that.next_out_index +
12285                // len)) {
12286                // console.log(that.dstate.pending_buf.length + ", " + that.dstate.pending_out + ", " + that.next_out.length + ", " +
12287                // that.next_out_index + ", " + len);
12288                // console.log("avail_out=" + that.avail_out);
12289                // }
12290
12291                that.next_out.set(that.dstate.pending_buf.subarray(that.dstate.pending_out, that.dstate.pending_out + len), that.next_out_index);
12292
12293                that.next_out_index += len;
12294                that.dstate.pending_out += len;
12295                that.total_out += len;
12296                that.avail_out -= len;
12297                that.dstate.pending -= len;
12298                if (that.dstate.pending === 0) {
12299                    that.dstate.pending_out = 0;
12300                }
12301            }
12302        };
12303
12304        // Deflater
12305
12306        return function Deflater(level) {
12307            var that = this;
12308            var z = new ZStream();
12309            var bufsize = 512;
12310            var flush = Z_NO_FLUSH;
12311            var buf = new Uint8Array(bufsize);
12312
12313            if (typeof level == "undefined")
12314                level = Z_DEFAULT_COMPRESSION;
12315            z.deflateInit(level);
12316            z.next_out = buf;
12317
12318            that.append = function(data, onprogress) {
12319                var err, buffers = [], lastIndex = 0, bufferIndex = 0, bufferSize = 0, array;
12320                if (!data.length)
12321                    return;
12322                z.next_in_index = 0;
12323                z.next_in = data;
12324                z.avail_in = data.length;
12325                do {
12326                    z.next_out_index = 0;
12327                    z.avail_out = bufsize;
12328                    err = z.deflate(flush);
12329                    if (err != Z_OK)
12330                        throw "deflating: " + z.msg;
12331                    if (z.next_out_index)
12332                        if (z.next_out_index == bufsize)
12333                            buffers.push(new Uint8Array(buf));
12334                        else
12335                            buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
12336                    bufferSize += z.next_out_index;
12337                    if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) {
12338                        onprogress(z.next_in_index);
12339                        lastIndex = z.next_in_index;
12340                    }
12341                } while (z.avail_in > 0 || z.avail_out === 0);
12342                array = new Uint8Array(bufferSize);
12343                buffers.forEach(function(chunk) {
12344                    array.set(chunk, bufferIndex);
12345                    bufferIndex += chunk.length;
12346                });
12347                return array;
12348            };
12349            that.flush = function() {
12350                var err, buffers = [], bufferIndex = 0, bufferSize = 0, array;
12351                do {
12352                    z.next_out_index = 0;
12353                    z.avail_out = bufsize;
12354                    err = z.deflate(Z_FINISH);
12355                    if (err != Z_STREAM_END && err != Z_OK)
12356                        throw "deflating: " + z.msg;
12357                    if (bufsize - z.avail_out > 0)
12358                        buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
12359                    bufferSize += z.next_out_index;
12360                } while (z.avail_in > 0 || z.avail_out === 0);
12361                z.deflateEnd();
12362                array = new Uint8Array(bufferSize);
12363                buffers.forEach(function(chunk) {
12364                    array.set(chunk, bufferIndex);
12365                    bufferIndex += chunk.length;
12366                });
12367                return array;
12368            };
12369        };
12370    })(undefined);
12371
12372
12373    /*
12374    html2canvas 0.5.0-beta3 <http://html2canvas.hertzen.com>
12375    Copyright (c) 2016 Niklas von Hertzen
12376
12377    Released under  License
12378  */
12379
12380    !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.html2canvas=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
12381            (function (global){
12382                /*! http://mths.be/punycode v1.2.4 by @mathias */
12383                ;(function(root) {
12384
12385                    /** Detect free variables */
12386                    var freeExports = typeof exports == 'object' && exports;
12387                    var freeModule = typeof module == 'object' && module &&
12388                        module.exports == freeExports && module;
12389                    var freeGlobal = typeof global == 'object' && global;
12390                    if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
12391                        root = freeGlobal;
12392                    }
12393
12394                    /**
12395                     * The `punycode` object.
12396                     * @name punycode
12397                     * @type Object
12398                     */
12399                    var punycode,
12400
12401                        /** Highest positive signed 32-bit float value */
12402                        maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
12403
12404                        /** Bootstring parameters */
12405                        base = 36,
12406                        tMin = 1,
12407                        tMax = 26,
12408                        skew = 38,
12409                        damp = 700,
12410                        initialBias = 72,
12411                        initialN = 128, // 0x80
12412                        delimiter = '-', // '\x2D'
12413
12414                        /** Regular expressions */
12415                        regexPunycode = /^xn--/,
12416                        regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars
12417                        regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators
12418
12419                        /** Error messages */
12420                        errors = {
12421                            'overflow': 'Overflow: input needs wider integers to process',
12422                            'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
12423                            'invalid-input': 'Invalid input'
12424                        },
12425
12426                        /** Convenience shortcuts */
12427                        baseMinusTMin = base - tMin,
12428                        floor = Math.floor,
12429                        stringFromCharCode = String.fromCharCode,
12430
12431                        /** Temporary variable */
12432                        key;
12433
12434                    /*--------------------------------------------------------------------------*/
12435
12436                    /**
12437                     * A generic error utility function.
12438                     * @private
12439                     * @param {String} type The error type.
12440                     * @returns {Error} Throws a `RangeError` with the applicable error message.
12441                     */
12442                    function error(type) {
12443                        throw RangeError(errors[type]);
12444                    }
12445
12446                    /**
12447                     * A generic `Array#map` utility function.
12448                     * @private
12449                     * @param {Array} array The array to iterate over.
12450                     * @param {Function} callback The function that gets called for every array
12451                     * item.
12452                     * @returns {Array} A new array of values returned by the callback function.
12453                     */
12454                    function map(array, fn) {
12455                        var length = array.length;
12456                        while (length--) {
12457                            array[length] = fn(array[length]);
12458                        }
12459                        return array;
12460                    }
12461
12462                    /**
12463                     * A simple `Array#map`-like wrapper to work with domain name strings.
12464                     * @private
12465                     * @param {String} domain The domain name.
12466                     * @param {Function} callback The function that gets called for every
12467                     * character.
12468                     * @returns {Array} A new string of characters returned by the callback
12469                     * function.
12470                     */
12471                    function mapDomain(string, fn) {
12472                        return map(string.split(regexSeparators), fn).join('.');
12473                    }
12474
12475                    /**
12476                     * Creates an array containing the numeric code points of each Unicode
12477                     * character in the string. While JavaScript uses UCS-2 internally,
12478                     * this function will convert a pair of surrogate halves (each of which
12479                     * UCS-2 exposes as separate characters) into a single code point,
12480                     * matching UTF-16.
12481                     * @see `punycode.ucs2.encode`
12482                     * @see <http://mathiasbynens.be/notes/javascript-encoding>
12483                     * @memberOf punycode.ucs2
12484                     * @name decode
12485                     * @param {String} string The Unicode input string (UCS-2).
12486                     * @returns {Array} The new array of code points.
12487                     */
12488                    function ucs2decode(string) {
12489                        var output = [],
12490                            counter = 0,
12491                            length = string.length,
12492                            value,
12493                            extra;
12494                        while (counter < length) {
12495                            value = string.charCodeAt(counter++);
12496                            if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
12497                                // high surrogate, and there is a next character
12498                                extra = string.charCodeAt(counter++);
12499                                if ((extra & 0xFC00) == 0xDC00) { // low surrogate
12500                                    output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
12501                                } else {
12502                                    // unmatched surrogate; only append this code unit, in case the next
12503                                    // code unit is the high surrogate of a surrogate pair
12504                                    output.push(value);
12505                                    counter--;
12506                                }
12507                            } else {
12508                                output.push(value);
12509                            }
12510                        }
12511                        return output;
12512                    }
12513
12514                    /**
12515                     * Creates a string based on an array of numeric code points.
12516                     * @see `punycode.ucs2.decode`
12517                     * @memberOf punycode.ucs2
12518                     * @name encode
12519                     * @param {Array} codePoints The array of numeric code points.
12520                     * @returns {String} The new Unicode string (UCS-2).
12521                     */
12522                    function ucs2encode(array) {
12523                        return map(array, function(value) {
12524                            var output = '';
12525                            if (value > 0xFFFF) {
12526                                value -= 0x10000;
12527                                output += stringFromCharCode(value >>>
vendor: 14,930 bytes, lines 12527-12844
12527 10 & 0x3FF | 0xD800);
12528                                value = 0xDC00 | value & 0x3FF;
12529                            }
12530                            output += stringFromCharCode(value);
12531                            return output;
12532                        }).join('');
12533                    }
12534
12535                    /**
12536                     * Converts a basic code point into a digit/integer.
12537                     * @see `digitToBasic()`
12538                     * @private
12539                     * @param {Number} codePoint The basic numeric code point value.
12540                     * @returns {Number} The numeric value of a basic code point (for use in
12541                     * representing integers) in the range `0` to `base - 1`, or `base` if
12542                     * the code point does not represent a value.
12543                     */
12544                    function basicToDigit(codePoint) {
12545                        if (codePoint - 48 < 10) {
12546                            return codePoint - 22;
12547                        }
12548                        if (codePoint - 65 < 26) {
12549                            return codePoint - 65;
12550                        }
12551                        if (codePoint - 97 < 26) {
12552                            return codePoint - 97;
12553                        }
12554                        return base;
12555                    }
12556
12557                    /**
12558                     * Converts a digit/integer into a basic code point.
12559                     * @see `basicToDigit()`
12560                     * @private
12561                     * @param {Number} digit The numeric value of a basic code point.
12562                     * @returns {Number} The basic code point whose value (when used for
12563                     * representing integers) is `digit`, which needs to be in the range
12564                     * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
12565                     * used; else, the lowercase form is used. The behavior is undefined
12566                     * if `flag` is non-zero and `digit` has no uppercase form.
12567                     */
12568                    function digitToBasic(digit, flag) {
12569                        //  0..25 map to ASCII a..z or A..Z
12570                        // 26..35 map to ASCII 0..9
12571                        return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
12572                    }
12573
12574                    /**
12575                     * Bias adaptation function as per section 3.4 of RFC 3492.
12576                     * http://tools.ietf.org/html/rfc3492#section-3.4
12577                     * @private
12578                     */
12579                    function adapt(delta, numPoints, firstTime) {
12580                        var k = 0;
12581                        delta = firstTime ? floor(delta / damp) : delta >> 1;
12582                        delta += floor(delta / numPoints);
12583                        for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
12584                            delta = floor(delta / baseMinusTMin);
12585                        }
12586                        return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
12587                    }
12588
12589                    /**
12590                     * Converts a Punycode string of ASCII-only symbols to a string of Unicode
12591                     * symbols.
12592                     * @memberOf punycode
12593                     * @param {String} input The Punycode string of ASCII-only symbols.
12594                     * @returns {String} The resulting string of Unicode symbols.
12595                     */
12596                    function decode(input) {
12597                        // Don't use UCS-2
12598                        var output = [],
12599                            inputLength = input.length,
12600                            out,
12601                            i = 0,
12602                            n = initialN,
12603                            bias = initialBias,
12604                            basic,
12605                            j,
12606                            index,
12607                            oldi,
12608                            w,
12609                            k,
12610                            digit,
12611                            t,
12612                            /** Cached calculation results */
12613                            baseMinusT;
12614
12615                        // Handle the basic code points: let `basic` be the number of input code
12616                        // points before the last delimiter, or `0` if there is none, then copy
12617                        // the first basic code points to the output.
12618
12619                        basic = input.lastIndexOf(delimiter);
12620                        if (basic < 0) {
12621                            basic = 0;
12622                        }
12623
12624                        for (j = 0; j < basic; ++j) {
12625                            // if it's not a basic code point
12626                            if (input.charCodeAt(j) >= 0x80) {
12627                                error('not-basic');
12628                            }
12629                            output.push(input.charCodeAt(j));
12630                        }
12631
12632                        // Main decoding loop: start just after the last delimiter if any basic code
12633                        // points were copied; start at the beginning otherwise.
12634
12635                        for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
12636
12637                            // `index` is the index of the next character to be consumed.
12638                            // Decode a generalized variable-length integer into `delta`,
12639                            // which gets added to `i`. The overflow checking is easier
12640                            // if we increase `i` as we go, then subtract off its starting
12641                            // value at the end to obtain `delta`.
12642                            for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
12643
12644                                if (index >= inputLength) {
12645                                    error('invalid-input');
12646                                }
12647
12648                                digit = basicToDigit(input.charCodeAt(index++));
12649
12650                                if (digit >= base || digit > floor((maxInt - i) / w)) {
12651                                    error('overflow');
12652                                }
12653
12654                                i += digit * w;
12655                                t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
12656
12657                                if (digit < t) {
12658                                    break;
12659                                }
12660
12661                                baseMinusT = base - t;
12662                                if (w > floor(maxInt / baseMinusT)) {
12663                                    error('overflow');
12664                                }
12665
12666                                w *= baseMinusT;
12667
12668                            }
12669
12670                            out = output.length + 1;
12671                            bias = adapt(i - oldi, out, oldi == 0);
12672
12673                            // `i` was supposed to wrap around from `out` to `0`,
12674                            // incrementing `n` each time, so we'll fix that now:
12675                            if (floor(i / out) > maxInt - n) {
12676                                error('overflow');
12677                            }
12678
12679                            n += floor(i / out);
12680                            i %= out;
12681
12682                            // Insert `n` at position `i` of the output
12683                            output.splice(i++, 0, n);
12684
12685                        }
12686
12687                        return ucs2encode(output);
12688                    }
12689
12690                    /**
12691                     * Converts a string of Unicode symbols to a Punycode string of ASCII-only
12692                     * symbols.
12693                     * @memberOf punycode
12694                     * @param {String} input The string of Unicode symbols.
12695                     * @returns {String} The resulting Punycode string of ASCII-only symbols.
12696                     */
12697                    function encode(input) {
12698                        var n,
12699                            delta,
12700                            handledCPCount,
12701                            basicLength,
12702                            bias,
12703                            j,
12704                            m,
12705                            q,
12706                            k,
12707                            t,
12708                            currentValue,
12709                            output = [],
12710                            /** `inputLength` will hold the number of code points in `input`. */
12711                            inputLength,
12712                            /** Cached calculation results */
12713                            handledCPCountPlusOne,
12714                            baseMinusT,
12715                            qMinusT;
12716
12717                        // Convert the input in UCS-2 to Unicode
12718                        input = ucs2decode(input);
12719
12720                        // Cache the length
12721                        inputLength = input.length;
12722
12723                        // Initialize the state
12724                        n = initialN;
12725                        delta = 0;
12726                        bias = initialBias;
12727
12728                        // Handle the basic code points
12729                        for (j = 0; j < inputLength; ++j) {
12730                            currentValue = input[j];
12731                            if (currentValue < 0x80) {
12732                                output.push(stringFromCharCode(currentValue));
12733                            }
12734                        }
12735
12736                        handledCPCount = basicLength = output.length;
12737
12738                        // `handledCPCount` is the number of code points that have been handled;
12739                        // `basicLength` is the number of basic code points.
12740
12741                        // Finish the basic string - if it is not empty - with a delimiter
12742                        if (basicLength) {
12743                            output.push(delimiter);
12744                        }
12745
12746                        // Main encoding loop:
12747                        while (handledCPCount < inputLength) {
12748
12749                            // All non-basic code points < n have been handled already. Find the next
12750                            // larger one:
12751                            for (m = maxInt, j = 0; j < inputLength; ++j) {
12752                                currentValue = input[j];
12753                                if (currentValue >= n && currentValue < m) {
12754                                    m = currentValue;
12755                                }
12756                            }
12757
12758                            // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
12759                            // but guard against overflow
12760                            handledCPCountPlusOne = handledCPCount + 1;
12761                            if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
12762                                error('overflow');
12763                            }
12764
12765                            delta += (m - n) * handledCPCountPlusOne;
12766                            n = m;
12767
12768                            for (j = 0; j < inputLength; ++j) {
12769                                currentValue = input[j];
12770
12771                                if (currentValue < n && ++delta > maxInt) {
12772                                    error('overflow');
12773                                }
12774
12775                                if (currentValue == n) {
12776                                    // Represent delta as a generalized variable-length integer
12777                                    for (q = delta, k = base; /* no condition */; k += base) {
12778                                        t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
12779                                        if (q < t) {
12780                                            break;
12781                                        }
12782                                        qMinusT = q - t;
12783                                        baseMinusT = base - t;
12784                                        output.push(
12785                                            stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
12786                                        );
12787                                        q = floor(qMinusT / baseMinusT);
12788                                    }
12789
12790                                    output.push(stringFromCharCode(digitToBasic(q, 0)));
12791                                    bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
12792                                    delta = 0;
12793                                    ++handledCPCount;
12794                                }
12795                            }
12796
12797                            ++delta;
12798                            ++n;
12799
12800                        }
12801                        return output.join('');
12802                    }
12803
12804                    /**
12805                     * Converts a Punycode string representing a domain name to Unicode. Only the
12806                     * Punycoded parts of the domain name will be converted, i.e. it doesn't
12807                     * matter if you call it on a string that has already been converted to
12808                     * Unicode.
12809                     * @memberOf punycode
12810                     * @param {String} domain The Punycode domain name to convert to Unicode.
12811                     * @returns {String} The Unicode representation of the given Punycode
12812                     * string.
12813                     */
12814                    function toUnicode(domain) {
12815                        return mapDomain(domain, function(string) {
12816                            return regexPunycode.test(string)
12817                                ? decode(string.slice(4).toLowerCase())
12818                                : string;
12819                        });
12820                    }
12821
12822                    /**
12823                     * Converts a Unicode string representing a domain name to Punycode. Only the
12824                     * non-ASCII parts of the domain name will be converted, i.e. it doesn't
12825                     * matter if you call it with a domain that's already in ASCII.
12826                     * @memberOf punycode
12827                     * @param {String} domain The domain name to convert, as a Unicode string.
12828                     * @returns {String} The Punycode representation of the given domain name.
12829                     */
12830                    function toASCII(domain) {
12831                        return mapDomain(domain, function(string) {
12832                            return regexNonASCII.test(string)
12833                                ? 'xn--' + encode(string)
12834                                : string;
12835                        });
12836                    }
12837
12838                    /*--------------------------------------------------------------------------*/
12839
12840                    /** Define the public API */
12841                    punycode = {
12842                        /**
12843                         * A string representing the current Punycode.js version number.
12844                         * @memberOf punycode
12845                         * @type String
12846                         */
12847                        'version': '1.2.4',
12848                        /**
12849                         * An object of methods to convert from JavaScript's internal character
12850                         * representation (UCS-2) to Unicode code points, and back.
12851                         * @see <http://mathiasbynens.be/notes/javascript-encoding>
12852                         * @memberOf punycode
12853                         * @type Object
12854                         */
12855                        'ucs2': {
12856                            'decode': ucs2decode,
12857                            'encode': ucs2encode
12858                        },
12859                        'decode': decode,
12860                        'encode': encode,
12861                        'toASCII': toASCII,
12862                        'toUnicode': toUnicode
12863                    };
12864
12865                    /** Expose `punycode` */
12866                    // Some AMD build optimizers, like r.js, check for specific condition patterns
12867                    // like the following:
12868                    if (
12869                        typeof define == 'function' &&
12870                        typeof define.amd == 'object' &&
12871                        define.amd
12872                    ) {
12873                        define('punycode', function() {
12874                            return punycode;
12875                        });
12876                    } else if (freeExports && !freeExports.nodeType) {
12877                        if (freeModule) { // in Node.js or RingoJS v0.8.0+
12878                            freeModule.exports = punycode;
12879                        } else { // in Narwhal or RingoJS v0.7.0-
12880                            for (key in punycode) {
12881                                punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
12882                            }
12883                        }
12884                    } else { // in Rhino or a web browser
12885                        root.punycode = punycode;
12886                    }
12887
12888                }(this));
12889
12890            }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
12891        },{}],2:[function(_dereq_,module,exports){
12892            var log = _dereq_('./log');
12893
12894            function restoreOwnerScroll(ownerDocument, x, y) {
12895                if (ownerDocument.defaultView && (x !== ownerDocument.defaultView.pageXOffset || y !== ownerDocument.defaultView.pageYOffset)) {
12896                    ownerDocument.defaultView.scrollTo(x, y);
12897                }
12898            }
12899
12900            function cloneCanvasContents(canvas, clonedCanvas) {
12901                try {
12902                    if (clonedCanvas) {
12903                        clonedCanvas.width = canvas.width;
12904                        clonedCanvas.height = canvas.height;
12905                        clonedCanvas.getContext("2d").putImageData(canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height), 0, 0);
12906                    }
12907                } catch(e) {
12908                    log("Unable to copy canvas content from", canvas, e);
12909                }
12910            }
12911
12912            function cloneNode(node, javascriptEnabled) {
12913                var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);
12914
12915                var child = node.firstChild;
12916                while(child) {
12917                    if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
12918                        clone.appendChild(cloneNode(child, javascriptEnabled));
12919                    }
12920                    child = child.nextSibling;
12921                }
12922
12923                if (node.nodeType === 1) {
12924                    clone._scrollTop = node.scrollTop;
12925                    clone._scrollLeft = node.scrollLeft;
12926                    if (node.nodeName === "CANVAS") {
12927                        cloneCanvasContents(node, clone);
12928                    } else if (node.nodeName === "TEXTAREA" || node.nodeName === "SELECT") {
12929                        clone.value = node.value;
12930                    }
12931                }
12932
12933                return clone;
12934            }
12935
12936            function initNode(node) {
12937                if (node.nodeType === 1) {
12938                    node.scrollTop = node._scrollTop;
12939                    node.scrollLeft = node._scrollLeft;
12940
12941                    var child = node.firstChild;
12942                    while(child) {
12943                        initNode(child);
12944                        child = child.nextSibling;
12945                    }
12946                }
12947            }
12948
12949            module.exports = function(ownerDocument, containerDocument, width, height, options, x ,y) {
12950                var documentElement = cloneNode(ownerDocument.documentElement, options.javascriptEnabled);
12951                var container = containerDocument.createElement("iframe");
12952
12953                container.className = "html2canvas-container";
12954                container.style.visibility = "hidden";
12955                container.style.position = "fixed";
12956                container.style.left = "-10000px";
12957                container.style.top = "0px";
12958                container.style.border = "0";
12959                container.width = width;
12960                container.height = height;
12961                container.scrolling = "no"; // ios won't scroll without it
12962                containerDocument.body.appendChild(container);
12963
12964                return new Promise(function(resolve) {
12965                    var documentClone = container.contentWindow.document;
12966
12967                    /* Chrome doesn't detect relative background-images assigned in inline <style> sheets when fetched through getComputedStyle
12968           if window url is about:blank, we can assign the url to current by writing onto the document
12969           */
12970                    container.contentWindow.onload = container.onload = function() {
12971                        var interval = setInterval(function() {
12972                            if (documentClone.body.childNodes.length > 0) {
12973                                initNode(documentClone.documentElement);
12974                                clearInterval(interval);
12975                                if (options.type === "view") {
12976                                    container.contentWindow.scrollTo(x, y);
12977                                    if ((/(iPad|iPhone|iPod)/g).test(navigator.userAgent) && (container.contentWindow.scrollY !== y || container.contentWindow.scrollX !== x)) {
12978                                        documentClone.documentElement.style.top = (-y) + "px";
12979                                        documentClone.documentElement.style.left = (-x) + "px";
12980                                        documentClone.documentElement.style.position = 'absolute';
12981                                    }
12982                                }
12983                                resolve(container);
12984                            }
12985                        }, 50);
12986                    };
12987
12988                    documentClone.open();
12989                    documentClone.write("<!DOCTYPE html><html></html>");
12990                    // Chrome scrolls the parent document for some reason after the write to the cloned window???
12991                    restoreOwnerScroll(ownerDocument, x, y);
12992                    documentClone.replaceChild(documentClone.adoptNode(documentElement), documentClone.documentElement);
12993                    documentClone.close();
12994                });
12995            };
12996
12997        },{"./log":13}],3:[function(_dereq_,module,exports){
12998            // http://dev.w3.org/csswg/css-color/
12999
13000            function Color(value) {
13001                this.r = 0;
13002                this.g = 0;
13003                this.b = 0;
13004                this.a = null;
13005                var result = this.fromArray(value) ||
13006                    this.namedColor(value) ||
13007                    this.rgb(value) ||
13008                    this.rgba(value) ||
13009                    this.hex6(value) ||
13010                    this.hex3(value);
13011            }
13012
13013            Color.prototype.darken = function(amount) {
13014                var a = 1 - amount;
13015                return  new Color([
13016                    Math.round(this.r * a),
13017                    Math.round(this.g * a),
13018                    Math.round(this.b * a),
13019                    this.a
13020                ]);
13021            };
13022
13023            Color.prototype.isTransparent = function() {
13024                return this.a === 0;
13025            };
13026
13027            Color.prototype.isBlack = function() {
13028                return this.r === 0 && this.g === 0 && this.b === 0;
13029            };
13030
13031            Color.prototype.fromArray = function(array) {
13032                if (Array.isArray(array)) {
13033                    this.r = Math.min(array[0], 255);
13034                    this.g = Math.min(array[1], 255);
13035                    this.b = Math.min(array[2], 255);
13036                    if (array.length > 3) {
13037                        this.a = array[3];
13038                    }
13039                }
13040
13041                return (Array.isArray(array));
13042            };
13043
13044            var _hex3 = /^#([a-f0-9]{3})$/i;
13045
13046            Color.prototype.hex3 = function(value) {
13047                var match = null;
13048                if ((match = value.match(_hex3)) !== null) {
13049                    this.r = parseInt(match[1][0] + match[1][0], 16);
13050                    this.g = parseInt(match[1][1] + match[1][1], 16);
13051                    this.b = parseInt(match[1][2] + match[1][2], 16);
13052                }
13053                return match !== null;
13054            };
13055
13056            var _hex6 = /^#([a-f0-9]{6})$/i;
13057
13058            Color.prototype.hex6 = function(value) {
13059                var match = null;
13060                if ((match = value.match(_hex6)) !== null) {
13061                    this.r = parseInt(match[1].substring(0, 2), 16);
13062                    this.g = parseInt(match[1].substring(2, 4), 16);
13063                    this.b = parseInt(match[1].substring(4, 6), 16);
13064                }
13065                return match !== null;
13066            };
13067
13068
13069            var _rgb = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/;
13070
13071            Color.prototype.rgb = function(value) {
13072                var match = null;
13073                if ((match = value.match(_rgb)) !== null) {
13074                    this.r = Number(match[1]);
13075                    this.g = Number(match[2]);
13076                    this.b = Number(match[3]);
13077                }
13078                return match !== null;
13079            };
13080
13081            var _rgba = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d?\.?\d+)\s*\)$/;
13082
13083            Color.prototype.rgba = function(value) {
13084                var match = null;
13085                if ((match = value.match(_rgba)) !== null) {
13086                    this.r = Number(match[1]);
13087                    this.g = Number(match[2]);
13088                    this.b = Number(match[3]);
13089                    this.a = Number(match[4]);
13090                }
13091                return match !== null;
13092            };
13093
13094            Color.prototype.toString = function() {
13095                return this.a !== null && this.a !== 1 ?
13096                    "rgba(" + [this.r, this.g, this.b, this.a].join(",") + ")" :
13097                    "rgb(" + [this.r, this.g, this.b].join(",") + ")";
13098            };
13099
13100            Color.prototype.namedColor = function(value) {
13101                value = value.toLowerCase();
13102                var color = colors[value];
13103                if (color) {
13104                    this.r = color[0];
13105                    this.g = color[1];
13106                    this.b = color[2];
13107                } else if (value === "transparent") {
13108                    this.r = this.g = this.b = this.a = 0;
13109                    return true;
13110                }
13111
13112                return !!color;
13113            };
13114
13115            Color.prototype.isColor = true;
13116
13117            // JSON.stringify([].slice.call($$('.named-color-table tr'), 1).map(function(row) { return [row.childNodes[3].textContent, row.childNodes[5].textContent.trim().split(",").map(Number)] }).reduce(function(data, row) {data[row[0]] = row[1]; return data}, {}))
13118            var colors = {
13119                "aliceblue": [240, 248, 255],
13120                "antiquewhite": [250, 235, 215],
13121                "aqua": [0, 255, 255],
13122                "aquamarine": [127, 255, 212],
13123                "azure": [240, 255, 255],
13124                "beige": [245, 245, 220],
13125                "bisque": [255, 228, 196],
13126                "black": [0, 0, 0],
13127                "blanchedalmond": [255, 235, 205],
13128                "blue": [0, 0, 255],
13129                "blueviolet": [138, 43, 226],
13130                "brown": [165, 42, 42],
13131                "burlywood": [222, 184, 135],
13132                "cadetblue": [95, 158, 160],
13133                "chartreuse": [127, 255, 0],
13134                "chocolate": [210, 105, 30],
13135                "coral": [255, 127, 80],
13136                "cornflowerblue": [100, 149, 237],
13137                "cornsilk": [255, 248, 220],
13138                "crimson": [220, 20, 60],
13139                "cyan": [0, 255, 255],
13140                "darkblue": [0, 0, 139],
13141                "darkcyan": [0, 139, 139],
13142                "darkgoldenrod": [184, 134, 11],
13143                "darkgray": [169, 169, 169],
13144                "darkgreen": [0, 100, 0],
13145                "darkgrey": [169, 169, 169],
13146                "darkkhaki": [189, 183, 107],
13147                "darkmagenta": [139, 0, 139],
13148                "darkolivegreen": [85, 107, 47],
13149                "darkorange": [255, 140, 0],
13150                "darkorchid": [153, 50, 204],
13151                "darkred": [139, 0, 0],
13152                "darksalmon": [233, 150, 122],
13153                "darkseagreen": [143, 188, 143],
13154                "darkslateblue": [72, 61, 139],
13155                "darkslategray": [47, 79, 79],
13156                "darkslategrey": [47, 79, 79],
13157                "darkturquoise": [0, 206, 209],
13158                "darkviolet": [148, 0, 211],
13159                "deeppink": [255, 20, 147],
13160                "deepskyblue": [0, 191, 255],
13161                "dimgray": [105, 105, 105],
13162                "dimgrey": [105, 105, 105],
13163                "dodgerblue": [30, 144, 255],
13164                "firebrick": [178, 34, 34],
13165                "floralwhite": [255, 250, 240],
13166                "forestgreen": [34, 139, 34],
13167                "fuchsia": [255, 0, 255],
13168                "gainsboro": [220, 220, 220],
13169                "ghostwhite": [248, 248, 255],
13170                "gold": [255, 215, 0],
13171                "goldenrod": [218, 165, 32],
13172                "gray": [128, 128, 128],
13173                "green": [0, 128, 0],
13174                "greenyellow": [173, 255, 47],
13175                "grey": [128, 128, 128],
13176                "honeydew": [240, 255, 240],
13177                "hotpink": [255, 105, 180],
13178                "indianred": [205, 92, 92],
13179                "indigo": [75, 0, 130],
13180                "ivory": [255, 255, 240],
13181                "khaki": [240, 230, 140],
13182                "lavender": [230, 230, 250],
13183                "lavenderblush": [255, 240, 245],
13184                "lawngreen": [124, 252, 0],
13185                "lemonchiffon": [255, 250, 205],
13186                "lightblue": [173, 216, 230],
13187                "lightcoral": [240, 128, 128],
13188                "lightcyan": [224, 255, 255],
13189                "lightgoldenrodyellow": [250, 250, 210],
13190                "lightgray": [211, 211, 211],
13191                "lightgreen": [144, 238, 144],
13192                "lightgrey": [211, 211, 211],
13193                "lightpink": [255, 182, 193],
13194                "lightsalmon": [255, 160, 122],
13195                "lightseagreen": [32, 178, 170],
13196                "lightskyblue": [135, 206, 250],
13197                "lightslategray": [119, 136, 153],
13198                "lightslategrey": [119, 136, 153],
13199                "lightsteelblue": [176, 196, 222],
13200                "lightyellow": [255, 255, 224],
13201                "lime": [0, 255, 0],
13202                "limegreen": [50, 205, 50],
13203                "linen": [250, 240, 230],
13204                "magenta": [255, 0, 255],
13205                "maroon": [128, 0, 0],
13206                "mediumaquamarine": [102, 205, 170],
13207                "mediumblue": [0, 0, 205],
13208                "mediumorchid": [186, 85, 211],
13209                "mediumpurple": [147, 112, 219],
13210                "mediumseagreen": [60, 179, 113],
13211                "mediumslateblue": [123, 104, 238],
13212                "mediumspringgreen": [0, 250, 154],
13213                "mediumturquoise": [72, 209, 204],
13214                "mediumvioletred": [199, 21, 133],
13215                "midnightblue": [25, 25, 112],
13216                "mintcream": [245, 255, 250],
13217                "mistyrose": [255, 228, 225],
13218                "moccasin": [255, 228, 181],
13219                "navajowhite": [255, 222, 173],
13220                "navy": [0, 0, 128],
13221                "oldlace": [253, 245, 230],
13222                "olive": [128, 128, 0],
13223                "olivedrab": [107, 142, 35],
13224                "orange": [255, 165, 0],
13225                "orangered": [255, 69, 0],
13226                "orchid": [218, 112, 214],
13227                "palegoldenrod": [238, 232, 170],
13228                "palegreen": [152, 251, 152],
13229                "paleturquoise": [175, 238, 238],
13230                "palevioletred": [219, 112, 147],
13231                "papayawhip": [255, 239, 213],
13232                "peachpuff": [255, 218, 185],
13233                "peru": [205, 133, 63],
13234                "pink": [255, 192, 203],
13235                "plum": [221, 160, 221],
13236                "powderblue": [176, 224, 230],
13237                "purple": [128, 0, 128],
13238                "rebeccapurple": [102, 51, 153],
13239                "red": [255, 0, 0],
13240                "rosybrown": [188, 143, 143],
13241                "royalblue": [65, 105, 225],
13242                "saddlebrown": [139, 69, 19],
13243                "salmon": [250, 128, 114],
13244                "sandybrown": [244, 164, 96],
13245                "seagreen": [46, 139, 87],
13246                "seashell": [255, 245, 238],
13247                "sienna": [160, 82, 45],
13248                "silver": [192, 192, 192],
13249                "skyblue": [135, 206, 235],
13250                "slateblue": [106, 90, 205],
13251                "slategray": [112, 128, 144],
13252                "slategrey": [112, 128, 144],
13253                "snow": [255, 250, 250],
13254                "springgreen": [0, 255, 127],
13255                "steelblue": [70, 130, 180],
13256                "tan": [210, 180, 140],
13257                "teal": [0, 128, 128],
13258                "thistle": [216, 191, 216],
13259                "tomato": [255, 99, 71],
13260                "turquoise": [64, 224, 208],
13261                "violet": [238, 130, 238],
13262                "wheat": [245, 222, 179],
13263                "white": [255, 255, 255],
13264                "whitesmoke": [245, 245, 245],
13265                "yellow": [255, 255, 0],
13266                "yellowgreen": [154, 205, 50]
13267            };
13268
13269            module.exports = Color;
13270
13271        },{}],4:[function(_dereq_,module,exports){
13272            var Support = _dereq_('./support');
13273            var CanvasRenderer = _dereq_('./renderers/canvas');
13274            var ImageLoader = _dereq_('./imageloader');
13275            var NodeParser = _dereq_('./nodeparser');
13276            var NodeContainer = _dereq_('./nodecontainer');
13277            var log = _dereq_('./log');
13278            var utils = _dereq_('./utils');
13279            var createWindowClone = _dereq_('./clone');
13280            var loadUrlDocument = _dereq_('./proxy').loadUrlDocument;
13281            var getBounds = utils.getBounds;
13282
13283            var html2canvasNodeAttribute = "data-html2canvas-node";
13284            var html2canvasCloneIndex = 0;
13285
13286            function html2canvas(nodeList, options) {
13287                var index = html2canvasCloneIndex++;
13288                options = options || {};
13289                if (options.logging) {
13290                    log.options.logging = true;
13291                    log.options.start = Date.now();
13292                }
13293
13294                options.async = typeof(options.async) === "undefined" ? true : options.async;
13295                options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint;
13296                options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer;
13297                options.javascriptEnabled = typeof(options.javascriptEnabled) === "undefined" ? false : options.javascriptEnabled;
13298                options.imageTimeout = typeof(options.imageTimeout) === "undefined" ? 10000 : options.imageTimeout;
13299                options.renderer = typeof(options.renderer) === "function" ? options.renderer : CanvasRenderer;
13300                options.strict = !!options.strict;
13301
13302                if (typeof(nodeList) === "string") {
13303                    if (typeof(options.proxy) !== "string") {
13304                        return Promise.reject("Proxy must be used when rendering url");
13305                    }
13306                    var width = options.width != null ? options.width : window.innerWidth;
13307                    var height = options.height != null ? options.height : window.innerHeight;
13308                    return loadUrlDocument(absoluteUrl(nodeList), options.proxy, document, width, height, options).then(function(container) {
13309                        return renderWindow(container.contentWindow.document.documentElement, container, options, width, height);
13310                    });
13311                }
13312
13313                var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0];
13314                node.setAttribute(html2canvasNodeAttribute + index, index);
13315                return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {
13316                    if (typeof(options.onrendered) === "function") {
13317                        log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas");
13318                        options.onrendered(canvas);
13319                    }
13320                    return canvas;
13321                });
13322            }
13323
13324            html2canvas.CanvasRenderer = CanvasRenderer;
13325            html2canvas.NodeContainer = NodeContainer;
13326            html2canvas.log = log;
13327            html2canvas.utils = utils;
13328
13329            var html2canvasExport = (typeof(document) === "undefined" || typeof(Object.create) !== "function" || typeof(document.createElement("canvas").getContext) !== "function") ? function() {
13330                return Promise.reject("No canvas support");
13331            } : html2canvas;
13332
13333            module.exports = html2canvasExport;
13334
13335            if (typeof(define) === 'function' && define.amd) {
13336                define('html2canvas', [], function() {
13337                    return html2canvasExport;
13338                });
13339            }
13340
13341            function renderDocument(document, options, windowWidth, windowHeight, html2canvasIndex) {
13342                return createWindowClone(document, document, windowWidth, windowHeight, options, document.defaultView.pageXOffset, document.defaultView.pageYOffset).then(function(container) {
13343                    log("Document cloned");
13344                    var attributeName = html2canvasNodeAttribute + html2canvasIndex;
13345                    var selector = "[" + attributeName + "='" + html2canvasIndex + "']";
13346                    document.querySelector(selector).removeAttribute(attributeName);
13347                    var clonedWindow = container.contentWindow;
13348                    var node = clonedWindow.document.querySelector(selector);
13349                    var oncloneHandler = (typeof(options.onclone) 
13349=== "function") ? Promise.resolve(options.onclone(clonedWindow.document)) : Promise.resolve(true);
13350                    return oncloneHandler.then(function() {
13351                        return renderWindow(node, container, options, windowWidth, windowHeight);
13352                    });
13353                });
13354            }
13355
13356            function renderWindow(node, container, options, windowWidth, windowHeight) {
13357                var clonedWindow = container.contentWindow;
13358                var support = new Support(clonedWindow.document);
13359                var imageLoader = new ImageLoader(options, support);
13360                var bounds = getBounds(node);
13361                var width = options.type === "view" ? windowWidth : documentWidth(clonedWindow.document);
13362                var height = options.type === "view" ? windowHeight : documentHeight(clonedWindow.document);
13363                var renderer = new options.renderer(width, height, imageLoader, options, document);
13364                var parser = new NodeParser(node, renderer, support, imageLoader, options);
13365                return parser.ready.then(function() {
13366                    log("Finished rendering");
13367                    var canvas;
13368
13369                    if (options.type === "view") {
13370                        canvas = crop(renderer.canvas, {width: renderer.canvas.width, height: renderer.canvas.height, top: 0, left: 0, x: 0, y: 0});
13371                    } else if (node === clonedWindow.document.body || node === clonedWindow.document.documentElement || options.canvas != null) {
13372                        canvas = renderer.canvas;
13373                    } else {
13374                        canvas = crop(renderer.canvas, {width:  options.width != null ? options.width : bounds.width, height: options.height != null ? options.height : bounds.height, top: bounds.top, left: bounds.left, x: 0, y: 0});
13375                    }
13376
13377                    cleanupContainer(container, options);
13378                    return canvas;
13379                });
13380            }
13381
13382            function cleanupContainer(container, options) {
13383                if (options.removeContainer) {
13384                    container.parentNode.removeChild(container);
13385                    log("Cleaned up container");
13386                }
13387            }
13388
13389            function crop(canvas, bounds) {
13390                var croppedCanvas = document.createElement("canvas");
13391                var x1 = Math.min(canvas.width - 1, Math.max(0, bounds.left));
13392                var x2 = Math.min(canvas.width, Math.max(1, bounds.left + bounds.width));
13393                var y1 = Math.min(canvas.height - 1, Math.max(0, bounds.top));
13394                var y2 = Math.min(canvas.height, Math.max(1, bounds.top + bounds.height));
13395                croppedCanvas.width = bounds.width;
13396                croppedCanvas.height =  bounds.height;
13397                var width = x2-x1;
13398                var height = y2-y1;
13399                log("Cropping canvas at:", "left:", bounds.left, "top:", bounds.top, "width:", width, "height:", height);
13400                log("Resulting crop with width", bounds.width, "and height", bounds.height, "with x", x1, "and y", y1);
13401                croppedCanvas.getContext("2d").drawImage(canvas, x1, y1, width, height, bounds.x, bounds.y, width, height);
13402                return croppedCanvas;
13403            }
13404
13405            function documentWidth (doc) {
13406                return Math.max(
13407                    Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),
13408                    Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),
13409                    Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)
13410                );
13411            }
13412
13413            function documentHeight (doc) {
13414                return Math.max(
13415                    Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),
13416                    Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),
13417                    Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)
13418                );
13419            }
13420
13421            function absoluteUrl(url) {
13422                var link = document.createElement("a");
13423                link.href = url;
13424                link.href = link.href;
13425                return link;
13426            }
13427
13428        },{"./clone":2,"./imageloader":11,"./log":13,"./nodecontainer":14,"./nodeparser":15,"./proxy":16,"./renderers/canvas":20,"./support":22,"./utils":26}],5:[function(_dereq_,module,exports){
13429            var log = _dereq_('./log');
13430            var smallImage = _dereq_('./utils').smallImage;
13431
13432            function DummyImageContainer(src) {
13433                this.src = src;
13434                log("DummyImageContainer for", src);
13435                if (!this.promise || !this.image) {
13436                    log("Initiating DummyImageContainer");
13437                    DummyImageContainer.prototype.image = new Image();
13438                    var image = this.image;
13439                    DummyImageContainer.prototype.promise = new Promise(function(resolve, reject) {
13440                        image.onload = resolve;
13441                        image.onerror = reject;
13442                        image.src = smallImage();
13443                        if (image.complete === true) {
13444                            resolve(image);
13445                        }
13446                    });
13447                }
13448            }
13449
13450            module.exports = DummyImageContainer;
13451
13452        }
13452,{"./log":13,"./utils":26}],6:[function(_dereq_,module,exports){
13453            var smallImage = _dereq_('./utils').smallImage;
13454
13455            function Font(family, size) {
13456                var container = document.createElement('div'),
13457                    img = document.createElement('img'),
13458                    span = document.createElement('span'),
13459                    sampleText = 'Hidden Text',
13460                    baseline,
13461                    middle;
13462
13463                container.style.visibility = "hidden";
13464                container.style.fontFamily = family;
13465                container.style.fontSize = size;
13466                container.style.margin = 0;
13467                container.style.padding = 0;
13468
13469                document.body.appendChild(container);
13470
13471                img.src = smallImage();
13472                img.width = 1;
13473                img.height = 1;
13474
13475                img.style.margin = 0;
13476                img.style.padding = 0;
13477                img.style.verticalAlign = "baseline";
13478
13479                span.style.fontFamily = family;
13480                span.style.fontSize = size;
13481                span.style.margin = 0;
13482                span.style.padding = 0;
13483
13484                span.appendChild(document.createTextNode(sampleText));
13485                container.appendChild(span);
13486                container.appendChild(img);
13487                baseline = (img.offsetTop - span.offsetTop) + 1;
13488
13489                container.removeChild(span);
13490                container.appendChild(document.createTextNode(sampleText));
13491
13492                container.style.lineHeight = "normal";
13493                img.style.verticalAlign = "super";
13494
13495                middle = (img.offsetTop-container.offsetTop) + 1;
13496
13497                document.body.removeChild(container);
13498
13499                this.baseline = baseline;
13500                this.lineWidth = 1;
13501                this.middle = middle;
13502            }
13503
13504            module.exports = Font;
13505
13506        },{"./utils":26}],7:[function(_dereq_,module,exports){
13507            var Font = _dereq_('./font');
13508
13509            function FontMetrics() {
13510                this.data = {};
13511            }
13512
13513            FontMetrics.prototype.getMetrics = function(family, size) {
13514                if (this.data[family + "-" + size] === undefined) {
13515                    this.data[family + "-" + size] = new Font(family, size);
13516                }
13517                return this.data[family + "-" + size];
13518            };
13519
13520            module.exports = FontMetrics;
13521
13522        },{"./font":6}],8:[function(_dereq_,module,exports){
13523            var utils = _dereq_('./utils');
13524            var getBounds = utils.getBounds;
13525            var loadUrlDocument = _dereq_('./proxy').loadUrlDocument;
13526
13527            function FrameContainer(container, sameOrigin, options) {
13528                this.image = null;
13529                this.src = container;
13530                var self = this;
13531                var bounds = getBounds(container);
13532                this.promise = (!sameOrigin ? this.proxyLoad(options.proxy, bounds, options) : new Promise(function(resolve) {
13533                    if (container.contentWindow.document.URL === "about:blank" || container.contentWindow.document.documentElement == null) {
13534                        container.contentWindow.onload = container.onload = function() {
13535                            resolve(container);
13536                        };
13537                    } else {
13538                        resolve(container);
13539                    }
13540                })).then(function(container) {
13541                    var html2canvas = _dereq_('./core');
13542                    return html2canvas(container.contentWindow.document.documentElement, {type: 'view', width: container.width, height: container.height, proxy: options.proxy, javascriptEnabled: options.javascriptEnabled, removeContainer: options.removeContainer, allowTaint: options.allowTaint, imageTimeout: options.imageTimeout / 2});
13543                }).then(function(canvas) {
13544                    return self.image = canvas;
13545                });
13546            }
13547
13548            FrameContainer.prototype.proxyLoad = function(proxy, bounds, options) {
13549                var container = this.src;
13550                return loadUrlDocument(container.src, proxy, container.ownerDocument, bounds.width, bounds.height, options);
13551            };
13552
13553            module.exports = FrameContainer;
13554
13555        },{"./core":4,"./proxy":16,"./utils":26}],9:[function(_dereq_,module,exports){
13556            function GradientContainer(imageData) {
13557                this.src = imageData.value;
13558                this.colorStops = [];
13559                this.type = null;
13560                this.x0 = 0.5;
13561                this.y0 = 0.5;
13562                this.x1 = 0.5;
13563                this.y1 = 0.5;
13564                this.promise = Promise.resolve(true);
13565            }
13566
13567            GradientContainer.TYPES = {
13568                LINEAR: 1,
13569                RADIAL: 2
13570            };
13571
13572            // TODO: support hsl[a], negative %/length values
13573            // TODO: support <angle> (e.g. -?\d{1,3}(?:\.\d+)deg, etc. : https://developer.mozilla.org/docs/Web/CSS/angle )
13574            GradientContainer.REGEXP_COLORSTOP = /^\s*(rgba?\(\s*\d{1,3},\s*\d{1,3},\s*\d{1,3}(?:,\s*[0-9\.]+)?\s*\)|[a-z]{3,20}|#[a-f0-9]{3,6})(?:\s+(\d{1,3}(?:\.\d+)?)(%|px)?)?(?:\s|$)/i;
13575
13576            module.exports = GradientContainer;
13577
13578        },{}],10:[function(_dereq_,module,exports){
13579            function ImageContainer(src, cors) {
13580                this.src = src;
13581                this.image = new Image();
13582                var self = this;
13583                this.tainted = null;
13584                this.promise = new Promise(function(resolve, reject) {
13585                    self.image.onload = resolve;
13586                    self.image.onerror = reject;
13587                    if (cors) {
13588                        self.image.crossOrigin = "anonymous";
13589                    }
13590                    self.image.src = src;
13591                    if (self.image.complete === true) {
13592                        resolve(self.image);
13593                    }
13594                });
13595            }
13596
13597            module.exports = ImageContainer;
13598
13599        },{}],11:[function(_dereq_,module,exports){
13600            var log = _dereq_('./log');
13601            var ImageContainer = _dereq_('./imagecontainer');
13602            var DummyImageContainer = _dereq_('./dummyimagecontainer');
13603            var ProxyImageContainer = _dereq_('./proxyimagecontainer');
13604            var FrameContainer = _dereq_('./framecontainer');
13605            var SVGContainer = _dereq_('./svgcontainer');
13606            var SVGNodeContainer = _dereq_('./svgnodecontainer');
13607            var LinearGradientContainer = _dereq_('./lineargradientcontainer');
13608            var WebkitGradientContainer = _dereq_('./webkitgradientcontainer');
13609            var bind = _dereq_('./utils').bind;
13610
13611            function ImageLoader(options, support) {
13612                this.link = null;
13613                this.options = options;
13614                this.support = support;
13615                this.origin = this.getOrigin(window.location.href);
13616            }
13617
13618            ImageLoader.prototype.findImages = function(nodes) {
13619                var images = [];
13620                nodes.reduce(function(imageNodes, container) {
13621                    switch(container.node.nodeName) {
13622                        case "IMG":
13623                            return imageNodes.concat([{
13624                                args: [container.node.src],
13625                                method: "url"
13626                            }]);
13627                        case "svg":
13628                        case "IFRAME":
13629                            return imageNodes.concat([{
13630                                args: [container.node],
13631                                method: container.node.nodeName
13632                            }]);
13633                    }
13634                    return imageNodes;
13635                }
13635, []).forEach(this.addImage(images, this.loadImage), this);
13636                return images;
13637            };
13638
13639            ImageLoader.prototype.findBackgroundImage = function(images, container) {
13640                container.parseBackgroundImages().filter(this.hasImageBackground).forEach(this.addImage(images, this.loadImage), this);
13641                return images;
13642            };
13643
13644            ImageLoader.prototype.addImage = function(images, callback) {
13645                return function(newImage) {
13646                    newImage.args.forEach(function(image) {
13647                        if (!this.imageExists(images, image)) {
13648                            images.splice(0, 0, callback.call(this, newImage));
13649                            log('Added image #' + (images.length), typeof(image) === "string" ? image.substring(0, 100) : image);
13650                        }
13651                    }, this);
13652                };
13653            };
13654
13655            ImageLoader.prototype.hasImageBackground = function(imageData) {
13656                return imageData.method !== "none";
13657            };
13658
13659            ImageLoader.prototype.loadImage = function(imageData) {
13660                if (imageData.method === "url") {
13661                    var src = imageData.args[0];
13662                    if (this.isSVG(src) && !this.support.svg && !this.options.allowTaint) {
13663                        return new SVGContainer(src);
13664                    } else if (src.match(/data:image\/.*;base64,/i)) {
13665                        return new ImageContainer(src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''), false);
13666                    } else if (this.isSameOrigin(src) || this.options.allowTaint === true || this.isSVG(src)) {
13667                        return new ImageContainer(src, false);
13668                    } else if (this.support.cors && !this.options.allowTaint && this.options.useCORS) {
13669                        return new ImageContainer(src, true);
13670                    } else if (this.options.proxy) {
13671                        return new ProxyImageContainer(src, this.options.proxy);
13672                    } else {
13673                        return new DummyImageContainer(src);
13674                    }
13675                } else if (imageData.method === "linear-gradient") {
13676                    return new LinearGradientContainer(imageData);
13677                } else if (imageData.method === "gradient") {
13678                    return new WebkitGradientContainer(imageData);
13679                } else if (imageData.method === "svg") {
13680                    return new SVGNodeContainer(imageData.args[0], this.support.svg);
13681                } else if (imageData.method === "IFRAME") {
13682                    return new FrameContainer(imageData.args[0], this.isSameOrigin(imageData.args[0].src), this.options);
13683                } else {
13684                    return new DummyImageContainer(imageData);
13685                }
13686            };
13687
13688            ImageLoader.prototype.isSVG = function(src) {
13689                return src.substring(src.length - 3).toLowerCase() === "svg" || SVGContainer.prototype.isInline(src);
13690            };
13691
13692            ImageLoader.prototype.imageExists = function(images, src) {
13693                return images.some(function(image) {
13694                    return image.src === src;
13695                });
13696            };
13697
13698            ImageLoader.prototype.isSameOrigin = function(url) {
13699                return (this.getOrigin(url) === this.origin);
13700            };
13701
13702            ImageLoader.prototype.getOrigin = function(url) {
13703                var link = this.link || (this.link = document.createElement("a"));
13704                link.href = url;
13705                link.href = link.href; // IE9, LOL! - http://jsfiddle.net/niklasvh/2e48b/
13706                return link.protocol + link.hostname + link.port;
13707            };
13708
13709            ImageLoader.prototype.getPromise = function(container) {
13710                return this.timeout(container, this.options.imageTimeout)['catch'](function() {
13711                    var dummy = new DummyImageContainer(container.src);
13712                    return dummy.promise.then(function(image) {
13713                        container.image = image;
13714                    });
13715                });
13716            };
13717
13718            ImageLoader.prototype.get = function(src) {
13719                var found = null;
13720                return this.images.some(function(img) {
13721                    return (found = img).src === src;
13722                }) ? found : null;
13723            };
13724
13725            ImageLoader.prototype.fetch = function(nodes) {
13726                this.images = nodes.reduce(bind(this.findBackgroun
13726dImage, this), this.findImages(nodes));
13727                this.images.forEach(function(image, index) {
13728                    image.promise.then(function() {
13729                        log("Succesfully loaded image #"+ (index+1), image);
13730                    }, function(e) {
13731                        log("Failed loading image #"+ (index+1), image, e);
13732                    });
13733                });
13734                this.ready = Promise.all(this.images.map(this.getPromise, this));
13735                log("Finished searching images");
13736                return this;
13737            };
13738
13739            ImageLoader.prototype.timeout = function(container, timeout) {
13740                var timer;
13741                var promise = Promise.race([container.promise, new Promise(function(res, reject) {
13742                    timer = setTimeout(function() {
13743                        log("Timed out loading image", container);
13744                        reject(container);
13745                    }, timeout);
13746                })]).then(function(container) {
13747                    clearTimeout(timer);
13748                    return container;
13749                });
13750                promise['catch'](function() {
13751                    clearTimeout(timer);
13752                });
13753                return promise;
13754            };
13755
13756            module.exports = ImageLoader;
13757
13758        },{"./dummyimagecontainer":5,"./framecontainer":8,"./imagecontainer":10,"./lineargradientcontainer":12,"./log":13,"./proxyimagecontainer":17,"./svgcontainer":23,"./svgnodecontainer":24,"./utils":26,"./webkitgradientcontainer":27}],12:[function(_dereq_,module,exports){
13759            var GradientContainer = _dereq_('./gradientcontainer');
13760            var Color = _dereq_('./color');
13761
13762            function LinearGradientContainer(imageData) {
13763                GradientContainer.apply(this, arguments);
13764                this.type = GradientContainer.TYPES.LINEAR;
13765
13766                var hasDirection = LinearGradientContainer.REGEXP_DIRECTION.test( imageData.args[0] ) ||
13767                    !GradientContainer.REGEXP_COLORSTOP.test( imageData.args[0] );
13768
13769                if (hasDirection) {
13770                    imageData.args[0].split(/\s+/).reverse().forEach(function(position, index) {
13771                        switch(position) {
13772                            case "left":
13773                                this.x0 = 0;
13774                                this.x1 = 1;
13775                                break;
13776                            case "top":
13777                                this.y0 = 0;
13778                                this.y1 = 1;
13779                                break;
13780                            case "right":
13781                                this.x0 = 1;
13782                                this.x1 = 0;
13783                                break;
13784                            case "bottom":
13785                                this.y0 = 1;
13786                                this.y1 = 0;
13787                                break;
13788                            case "to":
13789                                var y0 = this.y0;
13790                                var x0 = this.x0;
13791                                this.y0 = this.y1;
13792                                this.x0 = this.x1;
13793                                this.x1 = x0;
13794                                this.y1 = y0;
13795                                break;
13796                            case "center":
13797                                break; // centered by default
13798                            // Firefox internally converts position keywords to percentages:
13799                            // http://www.w3.org/TR/2010/WD-CSS2-20101207/colors.html#propdef-background-position
13800                            default: // percentage or absolute length
13801                                // TODO: support absolute start point positions (e.g., use bounds to convert px to a ratio)
13802                                var ratio = parseFloat(position, 10) * 1e-2;
13803                                if (isNaN(ratio)) { // invalid or unhandled value
13804                                    break;
13805                                }
13806                                if (index === 0) {
13807                                    this.y0 = ratio;
13808                                    this.y1 = 1 - this.y0;
13809                                } else {
13810                                    this.x0 = ratio;
13811                                    this.x1 = 1 - this.x0;
13812                                }
13813                                break;
13814                        }
13815                    }, this);
13816                } else {
13817                    this.y0 = 0;
13818                    this.y1 = 1;
13819                }
13820
13821                this.colorStops = imageData.args.slice(hasDirection ? 1 : 0).map(function(colorStop) {
13822                    var colorStopMatch = colorStop.match(GradientContainer.REGEXP_COLORSTOP);
13823                    var value = +colorStopMatch[2];
13824                    var unit = value === 0 ? "%" : colorStopMatch[3]; // treat "0" as "0%"
13825                    return {
13826                        color: new Color(colorStopMatch[1]),
13827                        // TODO: support absolute stop positions (e.g., compute gradient line length & convert px to ratio)
13828                        stop: unit === "%" ? value / 100 : null
13829                    };
13830                });
13831
13832                if (this.colorStops[0].stop === null) {
13833                    this.colorStops[0].stop = 0;
13834                }
13835
13836                if (this.colorStops[this.colorStops.length - 1].stop === null) {
13837                    this.colorStops[this.colorStops.length - 1].stop = 1;
13838                }
13839
13840                // calculates and fills-in explicit stop positions when omitted from rule
13841                this.colorStops.forEach(function(colorStop, index) {
13842                    if (colorStop.stop === null) {
13843                        this.colorStops.slice(index).some(function(find, count) {
13844                            if (find.stop !== null) {
13845                                colorStop.stop = ((find.stop - this.colorStops[index - 1].stop) / (count + 1)) + this.colorStops[index - 1].stop;
13846                                return true;
13847                            } else {
13848                                return false;
13849                            }
13850                        }, this);
13851                    }
13852                }, this);
13853            }
13854
13855            LinearGradientContainer.prototype = Object.create(GradientContainer.prototype);
13856
13857            // TODO: support <angle> (e.g. -?\d{1,3}(?:\.\d+)deg, etc. : https://developer.mozilla.org/docs/Web/CSS/angle )
13858            LinearGradientContainer.REGEXP_DIRECTION = /^\s*(?:to|left|right|top|bottom|center|\d{1,3}(?:\.\d+)?%?)(?:\s|$)/i;
13859
13860            module.exports = LinearGradientContainer;
13861
13862        },{"./color":3,"./gradientcontainer":9}],13:[function(_dereq_,module,exports){
13863            var logger = function() {
13864                if (logger.options.logging && window.console && window.console.log) {
13865                    Function.prototype.bind.call(window.console.log, (window.console)).apply(window.console, [(Date.now() - logger.options.start) + "ms", "html2canvas:"].concat([].slice.call(arguments, 0)));
13866                }
13867            };
13868
13869            logger.options = {logging: false};
13870            module.exports = logger;
13871
13872        },{}],14:[function(_dereq_,module,exports){
13873            var Color = _dereq_('./color');
13874            var utils = _dereq_('./utils');
13875            var getBounds = utils.getBounds;
13876            var parseBackgrounds = utils.parseBackgrounds;
13877            var offsetBounds = utils.offsetBounds;
13878
13879            function NodeContainer(node, parent) {
13880                this.node = node;
13881                this.parent = parent;
13882                this.stack = null;
13883                this.bounds = null;
13884                this.borders = null;
13885                this.clip = [];
13886                this.backgroundClip = [];
13887                this.offsetBounds = null;
13888                this.visible = null;
13889                this.computedStyles = null;
13890                this.colors = {};
13891                this.styles = {};
13892                this.backgroundImages = null;
13893                this.transformData = null;
13894                this.transformMatrix = null;
13895                this.isPseudoElement = false;
13896                this.opacity = null;
13897            }
13898
13899            NodeContainer.prototype.cloneTo = function(stack) {
13900                stack.visible = this.visible;
13901                stack.borders = this.borders;
13902                stack.bounds = this.bounds;
13903                stack.clip = this.clip;
13904                stack.backgroundClip = this.backgroundClip;
13905                stack.computedStyles = this.computedStyles;
13906                stack.styles = this.styles;
13907                stack.backgroundImages = this.backgroundImages;
13908                stack.opacity = this.opacity;
13909            };
13910
13911            NodeContainer.prototype.getOpacity = function() {
13912                return this.opacity === null ? (this.opacity = this.cssFloat('opacity')) : this.opacity;
13913            };
13914
13915            NodeContainer.prototype.assignStack = function(stack) {
13916                this.stack = stack;
13917                stack.children.push(this);
13918            };
13919
13920            NodeContainer.prototype.isElementVisible = function() {
13921                return this.node.nodeType === Node.TEXT_NODE ? this.parent.visible : (
13922                    this.css('display') !== "none" &&
13923                    this.css('visibility') !== "hidden" &&
13924                    !this.node.hasAttribute("data-html2canvas-ignore") &&
13925                    (this.node.nodeName !== "INPUT" || this.node.getAttribute("type") !== "hidden")
13926                );
13927            };
13928
13929            NodeContainer.prototype.css = function(attribute) {
13930                if (!this.computedStyles) {
13931                    this.computedStyles = this.isPseudoElement ? this.parent.computedStyle(this.before ? ":before" : ":after") : this.computedStyle(null);
13932                }
13933
13934                return this.styles[attribute] || (this.styles[attribute] = this.computedStyles[attribute]);
13935            };
13936
13937            NodeContainer.prototype.prefixedCss = function(attribute) {
13938                var prefixes = ["webkit", "moz", "ms", "o"];
13939                var value = this.css(attribute);
13940                if (value === undefined) {
13941                    prefixes.some(function(prefix) {
13942                        value = this.css(prefix + attribute.substr(0, 1).toUpperCase() + attribute.substr(1));
13943                        return value !== undefined;
13944                    }, this);
13945                }
13946                return value === undefined ? null : value;
13947            };
13948
13949            NodeContainer.prototype.computedStyle = function(type) {
13950                return this.node.ownerDocument.defaultView.getComputedStyle(this.node, type);
13951            };
13952
13953            NodeContainer.prototype.cssInt = function(attribute) {
13954                var value = parseInt(this.css(attribute), 10);
13955                return (isNaN(value)) ? 0 : value; // borders in old IE are throwing 'medium' for demo.html
13956            };
13957
13958            NodeContainer.prototype.color = function(attribute) {
13959                return this.colors[attribute] || (this.colors[attribute] = new Color(this.css(attribute)));
13960            };
13961
13962            NodeContainer.prototype.cssFloat = function(attribute) {
13963                var value = parseFloat(this.css(attribute));
13964                return (isNaN(value)) ? 0 : value;
13965            };
13966
13967            NodeContainer.prototype.fontWeight = function() {
13968                var weight = this.css("fontWeight");
13969                switch(parseInt(weight, 10)){
13970                    case 401:
13971                        weight = "bold";
13972                        break;
13973                    case 400:
13974                        weight = "normal";
13975                        break;
13976                }
13977                return weight;
13978            };
13979
13980            NodeContainer.prototype.parseClip = function() {
13981                var matches = this.css('clip').match(this.CLIP);
13982                if (matches) {
13983                    return {
13984                        top: parseInt(matches[1], 10),
13985                        right: parseInt(matches[2], 10),
13986                        bottom: parseInt(matches[3], 10),
13987                        left: parseInt(matches[4], 10)
13988                    };
13989                }
13990                return null;
13991            };
13992
13993            NodeContainer.prototype.parseBackgroundImages = function() {
13994                return this.backgroundImages || (this.backgroundImages = parseBackgrounds(this.css("backgroundImage")));
13995            };
13996
13997            NodeContainer.prototype.cssList = function(property, index) {
13998                var value = (this.css(property) || '').split(',');
13999                value = value[index || 0] || value[0] || 'auto';
14000                value = value.trim().split(' ');
14001                if (value.length === 1) {
14002                    value = [value[0], isPercentage(value[0]) ? 'auto' : value[0]];
14003                }
14004                return value;
14005            };
14006
14007            NodeContainer.prototype.parseBackgroundSize = function(bounds, image, index) {
14008                var size = this.cssList("backgroundSize", index);
14009                var width, height;
14010
14011                if (isPercentage(size[0])) {
14012                    width = bounds.width * parseFloat(size[0]) / 100;
14013                } else if (/contain|cover/.test(size[0])) {
14014                    var targetRatio = bounds.width / bounds.height, currentRatio = image.width / image.height;
14015                    return (targetRatio < currentRatio ^ size[0] === 'contain') ?  {width: bounds.height * currentRatio, height: bounds.height} : {width: bounds.width, height: bounds.width / currentRatio};
14016                } else {
14017                    width = parseInt(size[0], 10);
14018                }
14019
14020                if (size[0] === 'auto' && size[1] === 'auto') {
14021                    height = image.height;
14022                } else if (size[1] === 'auto') {
14023                    height = width / image.width * image.height;
14024                } else if (isPercentage(size[1])) {
14025                    height =  bounds.height * parseFloat(size[1]) / 100;
14026                } else {
14027                    height = parseInt(size[1], 10);
14028                }
14029
14030                if (size[0] === 'auto') {
14031                    width = height / image.height * image.width;
14032                }
14033
14034                return {width: width, height: height};
14035            };
14036
14037            NodeContainer.prototype.parseBackgroundPosition = function(bounds, image, index, backgroundSize) {
14038                var position = this.cssList('backgroundPosition', index);
14039                var left, top;
14040
14041                if (isPercentage(position[0])){
14042                    left = (bounds.width - (backgroundSize || image).width) * (parseFloat(position[0]) / 100);
14043                } else {
14044                    left = parseInt(position[0], 10);
14045                }
14046
14047                if (position[1] === 'auto') {
14048                    top = left / image.width * image.height;
14049                } else if (isPercentage(position[1])){
14050                    top =  (bounds.height - (backgroundSize || image).height) * parseFloat(position[1]) / 100;
14051                } else {
14052                    top = parseInt(position[1], 10);
14053                }
14054
14055                if (position[0] === 'auto') {
14056                    left = top / image.height * image.width;
14057                }
14058
14059                return {left: left, top: top};
14060            };
14061
14062            NodeContainer.prototype.parseBackgroundRepeat = function(index) {
14063                return this.cssList("backgroundRepeat", index)[0];
14064            };
14065
14066            NodeContainer.prototype.parseTextShadows = function() {
14067                var textShadow = this.css("textShadow");
14068                var results = [];
14069
14070                if (textShadow && textShadow !== 'none') {
14071                    var shadows = textShadow.match(this.TEXT_SHADOW_PROPERTY);
14072                    for (var i = 0; shadows && (i < shadows.length); i++) {
14073                        var s = shadows[i].match(this.TEXT_SHADOW_VALUES);
14074                        results.push({
14075                            color: new Color(s[0]),
14076                            offsetX: s[1] ? parseFloat(s[1].replace('px', '')) : 0,
14077                            offsetY: s[2] ? parseFloat(s[2].replace('px', '')) : 0,
14078                            blur: s[3] ? s[3].replace('px', '') : 0
14079                        });
14080                    }
14081                }
14082                return results;
14083            };
14084
14085            NodeContainer.prototype.parseTransform = function() {
14086                if (!this.transformData) {
14087                    if (this.hasTransform()) {
14088                        var offset = this.parseBounds();
14089                        var origin = this.prefixedCss("transformOrigin").split(" ").map(removePx).map(asFloat);
14090                        origin[0] += offset.left;
14091                        origin[1] += offset.top;
14092                        this.transformData = {
14093                            origin: origin,
14094                            matrix: this.parseTransformMatrix()
14095                        };
14096                    } else {
14097                        this.transformData = {
14098                            origin: [0, 0],
14099                            matrix: [1, 0, 0, 1, 0, 0]
14100                        };
14101                    }
14102                }
14103                return this.transformData;
14104            };
14105
14106            NodeContainer.prototype.parseTransformMatrix = function() {
14107                if (!this.transformMatrix) {
14108                    var transform = this.prefixedCss("transform");
14109                    var matrix = transform ? parseMatrix(transform.match(this.MATRIX_PROPERTY)) : null;
14110                    this.transformMatrix = matrix ? matrix : [1, 0, 0, 1, 0, 0];
14111                }
14112                return this.transformMatrix;
14113            };
14114
14115            NodeContainer.prototype.parseBounds = function() {
14116                return this.bounds || (this.bounds = this.hasTransform() ? offsetBounds(this.node) : getBounds(this.node));
14117            };
14118
14119            NodeContainer.prototype.hasTransform = function() {
14120                return this.parseTransformMatrix().join(",") !== "1,0,0,1,0,0" || (this.parent && this.parent.hasTransform());
14121            };
14122
14123            NodeContainer.prototype.getValue = function() {
14124                var value = this.node.value || "";
14125                if (this.node.tagName === "SELECT") {
14126                    value = selectionValue(this.node);
14127                } else if (this.node.type === "password") {
14128                    value = Array(value.length + 1).join('\u2022'); // jshint ignore:line
14129                }
14130                return value.length === 0 ? (this.node.placeholder || "") : value;
14131            };
14132
14133            NodeContainer.prototype.MATRIX_PROPERTY = /(matrix|matrix3d)\((.+)\)/;
14134            NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g;
14135            NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;
14136            NodeContainer.prototype.CLIP = /^rect\((\d+)px,? (\d+)px,? (\d+)px,? (\d+)px\)$/;
14137
14138            function selectionValue(node) {
14139                var option = node.options[node.selectedIndex || 0];
14140                return option ? (option.text || "") : "";
14141            }
14142
14143            function parseMatrix(match) {
14144                if (match && match[1] === "matrix") {
14145                    return match[2].split(",").map(function(s) {
14146                        return parseFloat(s.trim());
14147                    });
14148                } else if (match && match[1] === "matrix3d") {
14149                    var matrix3d = match[2].split(",").map(function(s) {
14150                        return parseFloat(s.trim());
14151                    });
14152                    return [matrix3d[0], matrix3d[1], matrix3d[4], matrix3d[5], matrix3d[12], matrix3d[13]];
14153                }
14154            }
14155
14156            function isPercentage(value) {
14157                return value.toString().indexOf("%") !== -1;
14158            }
14159
14160            function removePx(str) {
14161                return str.replace("px", "");
14162            }
14163
14164            function asFloat(str) {
14165                return parseFloat(str);
14166            }
14167
14168            module.exports = NodeContainer;
14169
14170        },{"./color":3,"./utils":26}],15:[function(_dereq_,module,exports){
14171            var log = _dereq_('./log');
14172            var punycode = _dereq_('punycode');
14173            var NodeContainer = _dereq_('./nodecontainer');
14174            var TextContainer = _dereq_('./textcontainer');
14175            var PseudoElementContainer = _dereq_('./pseudoelementcontainer');
14176            var FontMetrics = _dereq_('./fontmetrics');
14177            var Color = _dereq_('./color');
14178            var StackingContext = _dereq_('./stackingcontext');
14179            var utils = _dereq_('./utils');
14180            var bind = utils.bind;
14181            var getBounds = utils.getBounds;
14182            var parseBackgrounds = utils.parseBackgrounds;
14183            var offsetBounds = utils.offsetBounds;
14184
14185            function NodeParser(element, renderer, support, imageLoader, options) {
14186                log("Starting NodeParser");
14187                this.renderer = renderer;
14188                this.options = options;
14189                this.range = null;
14190                this.support = support;
14191                this.renderQueue = [];
14192                this.stack = new StackingContext(true, 1, element.ownerDocument, null);
14193                var parent = new NodeContainer(element, null);
14194                if (options.background) {
14195                    renderer.rectangle(0, 0, renderer.width, renderer.height, new Color(options.background));
14196                }
14197                if (element === element.ownerDocument.documentElement) {
14198                    // http://www.w3.org/TR/css3-background/#special-backgrounds
14199                    var canvasBackground = new NodeContainer(parent.color('backgroundColor').isTransparent() ? element.ownerDocument.body : element.ownerDocument.documentElement, null);
14200                    renderer.rectangle(0, 0, renderer.width, renderer.height, canvasBackground.color('backgroundColor'));
14201                }
14202                parent.visibile = parent.isElementVisible();
14203                this.createPseudoHideStyles(element.ownerDocument);
14204                this.disableAnimations(element.ownerDocument);
14205                this.nodes = flatten([parent].concat(this.getChildren(parent)).filter(function(container) {
14206                    return container.visible = container.isElementVisible();
14207                }).map(this.getPseudoElements, this));
14208                this.fontMetrics = new FontMetrics();
14209                log("Fetched nodes, total:", this.nodes.length);
14210                log("Calculate overflow clips");
14211                this.calculateOverflowClips();
14212                log("Start fetching images");
14213                this.images = imageLoader.fetch(this.nodes.filter(isElement));
14214                this.ready = this.images.ready.then(bind(function() {
14215                    log("Images loaded, starting parsing");
14216                    log("Creating stacking contexts");
14217                    this.createStackingContexts();
14218                    log("Sorting stacking contexts");
14219                    this.sortStackingContexts(this.stack);
14220                    this.parse(this.stack);
14221                    log("Render queue created with " + this.renderQueue.length + " items");
14222                    return new Promise(bind(function(resolve) {
14223                        if (!options.async) {
14224                            this.renderQueue.forEach(this.paint, this);
14225                            resolve();
14226                        } else if (typeof(options.async) === "function") {
14227                            options.async.call(this, this.renderQueue, resolve);
14228                        } else if (this.renderQueue.length > 0){
14229                            this.renderIndex = 0;
14230                            this.asyncRenderer(this.renderQueue, resolve);
14231                        } else {
14232                            resolve();
14233                        }
14234                    }, this));
14235                }, this));
14236            }
14237
14238            NodeParser.prototype.calculateOverflowClips = function() {
14239                this.nodes.forEach(function(container) {
14240                    if (isElement(container)) {
14241                        if (isPseudoElement(container)) {
14242                            container.appendToDOM();
14243                        }
14244                        container.borders = this.parseBorders(container);
14245                        var clip = (container.css('overflow') === "hidden") ? [container.borders.clip] : [];
14246                        var cssClip = container.parseClip();
14247                        if (cssClip && ["absolute", "fixed"].indexOf(container.css('position')) !== -1) {
14248                            clip.push([["rect",
14249                                container.bounds.left + cssClip.left,
14250                                container.bounds.top + cssClip.top,
14251                                cssClip.right - cssClip.left,
14252                                cssClip.bottom - cssClip.top
14253                            ]]);
14254                        }
14255                        container.clip = hasParentClip(container) ? container.parent.clip.concat(clip) : clip;
14256                        container.backgroundClip = (container.css('overflow') !== "hidden") ? c
14256ontainer.clip.concat([container.borders.clip]) : container.clip;
14257                        if (isPseudoElement(container)) {
14258                            container.cleanDOM();
14259                        }
14260                    } else if (isTextNode(container)) {
14261                        container.clip = hasParentClip(container) ? container.parent.clip : [];
14262                    }
14263                    if (!isPseudoElement(container)) {
14264                        container.bounds = null;
14265                    }
14266                }, this);
14267            };
14268
14269            function hasParentClip(container) {
14270                return container.parent && container.parent.clip.length;
14271            }
14272
14273            NodeParser.prototype.asyncRenderer = function(queue, resolve, asyncTimer) {
14274                asyncTimer = asyncTimer || Date.now();
14275                this.paint(queue[this.renderIndex++]);
14276                if (queue.length === this.renderIndex) {
14277                    resolve();
14278                } else if (asyncTimer + 20 > Date.now()) {
14279                    this.asyncRenderer(queue, resolve, asyncTimer);
14280                } else {
14281                    setTimeout(bind(function() {
14282                        this.asyncRenderer(queue, resolve);
14283                    }, this), 0);
14284                }
14285            };
14286
14287            NodeParser.prototype.createPseudoHideStyles = function(document) {
14288                this.createStyles(document, '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + ':before { content: "" !important; display: none !important; }' +
14289                    '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER + ':after { content: "" !important; display: none !important; }');
14290            };
14291
14292            NodeParser.prototype.disableAnimations = function(document) {
14293                this.createStyles(document, '* { -webkit-animation: none !important; -moz-animation: none !important; -o-animation: none !important; animation: none !important; ' +
14294                    '-webkit-transition: none !important; -moz-transition: none !important; -o-transition: none !important; transition: none !important;}');
14295            };
14296
14297            NodeParser.prototype.createStyles = function(document, styles) {
14298                var hidePseudoElements = document.createElement('style');
14299                hidePseudoElements.innerHTML = styles;
14300                document.body.appendChild(hidePseudoElements);
14301            };
14302
14303            NodeParser.prototype.getPseudoElements = function(container) {
14304                var nodes = [[container]];
14305                if (container.node.nodeType === Node.ELEMENT_NODE) {
14306                    var before = this.getPseudoElement(container, ":before");
14307                    var after = this.getPseudoElement(container, ":after");
14308
14309                    if (before) {
14310                        nodes.push(before);
14311                    }
14312
14313                    if (after) {
14314                        nodes.push(after);
14315                    }
14316                }
14317                return flatten(nodes);
14318            };
14319
14320            function toCamelCase(str) {
14321                return str.replace(/(\-[a-z])/g, function(match){
14322                    return match.toUpperCase().replace('-','');
14323                });
14324            }
14325
14326            NodeParser.prototype.getPseudoElement = function(container, type) {
14327                var style = container.computedStyle(type);
14328                if(!style || !style.content || style.content === "none" || style.content === "-moz-alt-content" || style.display === "none") {
14329                    return null;
14330                }
14331
14332                var content = stripQuotes(style.content);
14333                var isImage = content.substr(0, 3) === 'url';
14334                var pseudoNode = document.createElement(isImage ? 'img' : 'html2canvaspseudoelement');
14335                var pseudoContainer = new PseudoElementContainer(pseudoNode, container, type);
14336
14337                for (var i = style.length-1; i >= 0; i--) {
14338                    var property = toCamelCase(style.item(i));
14339                    pseudoNode.style[property] = style[property];
14340                }
14341
14342                pseudoNode.className = PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + " " + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER;
14343
14344                if (isImage) {
14345                    pseudoNode.src = parseBackgrounds(content)[0].args[0];
14346                    return [pseudoContainer];
14347                } else {
14348                    var text = document.createTextNode(content);
14349                    pseudoNode.appendChild(text);
14350                    return [pseudoContainer, new TextContainer(text, pseudoContainer)];
14351                }
14352            };
14353
14354
14355            NodeParser.prototype.getChildren = function(parentContainer) {
14356                return flatten([].filter.call(parentContainer.node.childNodes, renderableNode).map(function(node) {
14357                    var container = [node.nodeType === Node.TEXT_NODE ? new TextContainer(node, parentContainer) : new NodeContainer(node, parentContainer)].filter(nonIgnoredElement);
14358                    return node.nodeType === Node.ELEMENT_NODE && container.length && node.tagName !== "TEXTAREA" ? (container[0].isElementVisible() ? container.concat(this.getChildren(container[0])) : []) : container;
14359                }, this));
14360            };
14361
14362            NodeParser.prototype.newStackingContext = function(container, hasOwnStacking) {
14363                var stack = new StackingContext(hasOwnStacking, container.getOpacity(), container.node, container.parent);
14364                container.cloneTo(stack);
14365                var parentStack = hasOwnStacking ? stack.getParentStack(this) : stack.parent.stack;
14366                parentStack.contexts.push(stack);
14367                container.stack = stack;
14368            };
14369
14370            NodeParser.prototype.createStackingContexts = function() {
14371                this.nodes.forEach(function(container) {
14372                    if (isElement(container) && (this.isRootElement(container) || hasOpacity(container) || isPositionedForStacking(container) || this.isBodyWithTransparentRoot(container) || container.hasTransform())) {
14373                        this.newStackingContext(container, true);
14374                    } else if (isElement(container) && ((isPositioned(container) && zIndex0(container)) || isInlineBlock(container) || isFloating(container))) {
14375                        this.newStackingContext(container, false);
14376                    } else {
14377                        container.assignStack(container.parent.stack);
14378                    }
14379                }, this);
14380            };
14381
14382            NodeParser.prototype.isBodyWithTransparentRoot = function(container) {
14383                return container.node.nodeName === "BODY" && container.parent.color('backgroundColor').isTransparent();
14384            };
14385
14386            NodeParser.prototype.isRootElement = function(container) {
14387                return container.parent === null;
14388            };
14389
14390            NodeParser.prototype.sortStackingContexts = function(stack) {
14391                stack.contexts.sort(zIndexSort(stack.contexts.slice(0)));
14392                stack.contexts.forEach(this.sortStackingContexts, this);
14393            };
14394
14395            NodeParser.prototype.parseTextBounds = function(container) {
14396                return function(text, index, textList) {
14397                    if (container.parent.css("textDecoration").substr(0, 4) !== "none" || text.trim().length !== 0) {
14398                        if (this.support.rangeBounds && !container.parent.hasTransform()) {
14399                            var offset = textList.slice(0, index).join("").length;
14400                            return this.getRangeBounds(container.node, offset, text.length);
14401                        } else if (container.node && typeof(container.node.data) === "string") {
14402                            var replacementNode = container.node.splitText(text.length);
14403                            var bounds = this.getWrapperBounds(container.node, container.parent.hasTransform());
14404                            container.node = replacementNode;
14405                            return bounds;
14406                        }
14407                    } else if(!this.support.rangeBounds || container.parent.hasTransform()){
14408                        container.node = container.node.splitText(text.length);
14409                    }
14410                    return {};
14411                };
14412            };
14413
14414            NodeParser.prototype.getWrapperBounds = function(node, transform) {
14415                var wrapper = node.ownerDocument.createElement('html2canvaswrapper');
14416                var parent = node.parentNode,
14417                    backupText = node.cloneNode(true);
14418
14419                wrapper.appendChild(node.cloneNode(true));
14420                parent.replaceChild(wrapper, node);
14421                var bounds = transform ? offsetBounds(wrapper) : getBounds(wrapper);
14422                parent.replaceChild(backupText, wrapper);
14423                return bounds;
14424            };
14425
14426            NodeParser.prototype.getRangeBounds = function(node, offset, length) {
14427                var range = this.range || (this.range = node.ownerDocument.createRange());
14428                range.setStart(node, offset);
14429                range.setEnd(node, offset + length);
14430                return range.getBoundingClientRect();
14431            };
14432
14433            function ClearTransform() {}
14434
14435            NodeParser.prototype.parse = function(stack) {
14436                // http://www.w3.org/TR/CSS21/visuren.html#z-index
14437                var negativeZindex = stack.contexts.filter(negativeZIndex); // 2. the child stacking contexts with negative stack levels (most negative first).
14438                var descendantElements = stack.children.filter(isElement);
14439                var descendantNonFloats = descendantElements.filter(not(isFloating));
14440                var nonInlineNonPositionedDescendants = descendantNonFloats.filter(not(isPositioned)).filter(not(inlineLevel)); // 3 the in-flow, non-inline-level, non-positioned descendants.
14441                var nonPositionedFloats = descendantElements.filter(not(isPositioned)).filter(isFloating); // 4. the non-positioned floats.
14442                var inFlow = descendantNonFloats.filter(not(isPositioned)).filter(inlineLevel); // 5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
14443                var stackLevel0 = stack.contexts.concat(descendantNonFloats.filter(isPositioned)).filter(zIndex0); // 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
14444                var text = stack.children.filter(isTextNode).filter(hasText);
14445                var positiveZindex = stack.contexts.filter(positiveZIndex); // 7. the child stacking contexts with positive stack levels (least positive first).
14446                negativeZindex.concat(nonInlineNonPositionedDescendants).concat(nonPositionedFloats)
14447                    .concat(inFlow).concat(stackLevel0).concat(text).concat(positiveZindex).forEach(function(container) {
14448                    this.renderQueue.push(container);
14449                    if (isStackingContext(container)) {
14450                        this.parse(container);
14451                        this.renderQueue.push(new ClearTransform());
14452                    }
14453                }, this);
14454            };
14455
14456            NodeParser.prototype.paint = function(container) {
14457                try {
14458                    if (container instanceof ClearTransform) {
14459                        this.renderer.ctx.restore();
14460                    } else if (isTextNode(container)) {
14461                        if (isPseudoElement(container.parent)) {
14462                            container.parent.appendToDOM();
14463                        }
14464                        this.paintText(container);
14465                        if (isPseudoElement(container.parent)) {
14466                            container.parent.cleanDOM();
14467                        }
14468                    } else {
14469                        this.paintNode(container);
14470                    }
14471                } catch(e) {
14472                    log(e);
14473                    if (this.options.strict) {
14474                        throw e;
14475                    }
14476                }
14477            };
14478
14479            NodeParser.prototype.paintNode = function(container) {
14480                if (isStackingContext(container)) {
14481                    this.renderer.setOpacity(container.opacity);
14482                    this.renderer.ctx.save();
14483                    if (container.hasTransform()) {
14484                        this.renderer.setTransform(container.parseTransform());
14485                    }
14486                }
14487
14488                if (container.node.nodeName === "INPUT" && container.node.type === "checkbox") {
14489                    this.paintCheckbox(container);
14490                } else if (container.node.nodeName === "INPUT" && container.node.type === "radio") {
14491                    this.paintRadio(container);
14492                } else {
14493                    this.paintElement(container);
14494                }
14495            };
14496
14497            NodeParser.prototype.paintElement = function(container) {
14498                var bounds = container.parseBounds();
14499                this.renderer.clip(container.backgroundClip, function() {
14500                    this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth));
14501                }, this);
14502
14503                this.renderer.clip(container.clip, function() {
14504                    this.renderer.renderBorders(container.borders.borders);
14505                }, this);
14506
14507                this.renderer.clip(container.backgroundClip, function() {
14508                    switch (container.node.nodeName) {
14509                        case "svg":
14510                        case "IFRAME":
14511                            var imgContainer = this.images.get(container.node);
14512                            if (imgContainer) {
14513                                this.renderer.renderImage(container, bounds, container.borders, imgContainer);
14514                            } else {
14515                                log("Error loading <" + container.node.nodeName + ">", container.node);
14516                            }
14517                            break;
14518                        case "IMG":
14519                            var imageContainer = this.images.get(container.node.src);
14520                            if (imageContainer) {
14521                                this.renderer.renderImage(container, bounds, container.borders, imageContainer);
14522                            } else {
14523                                log("Error loading <img>", container.node.src);
14524                            }
14525                            break;
14526                        case "CANVAS":
14527                            this.renderer.renderImage(container, bounds, container.borders, {image: container.node});
14528                            break;
14529                        case "SELECT":
14530                        case "INPUT":
14531                        case "TEXTAREA":
14532                            this.paintFormValue(container);
14533                            break;
14534                    }
14535                }, this);
14536            };
14537
14538            NodeParser.prototype.paintCheckbox = function(container) {
14539                var b = container.parseBounds();
14540
14541                var size = Math.min(b.width, b.height);
14542                var bounds = {width: size - 1, height: size - 1, top: b.top, left: b.left};
14543                var r = [3, 3];
14544                var radius = [r, r, r, r];
14545                var borders = [1,1,1,1].map(function(w) {
14546                    return {color: new Color('#A5A5A5'), width: w};
14547                });
14548
14549                var borderPoints = calculateCurvePoints(bounds, radius, borders);
14550
14551                this.renderer.clip(container.backgroundClip, function() {
14552                    this.renderer.rectangle(bounds.left + 1, bounds.top + 1, bounds.width - 2, bounds.height - 2, new Color("#DEDEDE"));
14553                    this.renderer.renderBorders(calculateBorders(borders, bounds, borderPoints, radius));
14554                    if (container.node.checked) {
14555                        this.renderer.font(new Color('#424242'), 'normal', 'normal', 'bold', (size - 3) + "px", 'arial');
14556                        this.renderer.text("\u2714", bounds.left + size / 6, bounds.top + size - 1);
14557                    }
14558                }, this);
14559            };
14560
14561            NodeParser.prototype.paintRadio = function(container) {
14562                var bounds = container.parseBounds();
14563
14564                var size = Math.min(bounds.width, bounds.height) - 2;
14565
14566                this.renderer.clip(container.backgroundClip, function() {
14567                    this.renderer.circleStroke(bounds.left + 1, bounds.top + 1, size, new Color('#DEDEDE'), 1, new Color('#A5A5A5'));
14568                    if (container.node.checked) {
14569                        this.renderer.circle(Math.ceil(bounds.left + size / 4) + 1, Math.ceil(bounds.top + size / 4) + 1, Math.floor(size / 2), new Color('#424242'));
14570                    }
14571                }, this);
14572            };
14573
14574            NodeParser.prototype.paintFormValue = function(container) {
14575                var value = container.getValue();
14576                if (value.length > 0) {
14577                    var document = container.node.ownerDocument;
14578                    var wrapper = document.createElement('html2canvaswrapper');
14579                    var properties = ['lineHeight', 'textAlign', 'fontFamily', 'fontWeight', 'fontSize', 'color',
14580                        'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom',
14581                        'width', 'height', 'borderLeftStyle', 'borderTopStyle', 'borderLeftWidth', 'borderTopWidth',
14582                        'boxSizing', 'whiteSpace', 'wordWrap'];
14583
14584                    properties.forEach(function(property) {
14585                        try {
14586                            wrapper.style[property] = container.css(property);
14587                        } catch(e) {
14588                            // Older IE has issues with "border"
14589                            log("html2canvas: Parse: Exception caught in renderFormValue: " + e.message);
14590                        }
14591                    });
14592                    var bounds = container.parseBounds();
14593                    wrapper.style.position = "fixed";
14594                    wrapper.style.left = bounds.left + "px";
14595                    wrapper.style.top = bounds.top + "px";
14596                    wrapper.textContent = value;
14597                    document.body.appendChild(wrapper);
14598                    this.paintText(new TextContainer(wrapper.firstChild, container));
14599                    document.body.removeChild(wrapper);
14600                }
14601            };
14602
14603            NodeParser.prototype.paintText = function(container) {
14604                container.applyTextTransform();
14605                var characters = punycode.ucs2.decode(container.node.data);
14606                var textList = (!this.options.letterRendering || noLetterSpacing(container)) && !hasUnicode(container.node.data) ? getWords(characters) : characters.map(function(character) {
14607                    return punycode.ucs2.encode([character]);
14608                });
14609
14610                var weight = container.parent.fontWeight();
14611                var size = container.parent.css('fontSize');
14612                var family = container.parent.css('fontFamily');
14613                var shadows = container.parent.parseTextShadows();
14614
14615                this.renderer.font(container.parent.color('color'), container.parent.css('fontStyle'), container.parent.css('fontVariant'), weight, size, family);
14616                if (shadows.length) {
14617                    // TODO: support multiple text shadows
14618                    this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur);
14619                } else {
14620                    this.renderer.clearShadow();
14621                }
14622
14623                this.renderer.clip(container.parent.clip, function() {
14624                    textList.map(this.parseTextBounds(container), this).forEach(function(bounds, index) {
14625                        if (bounds) {
14626                            this.renderer.text(textList[index], bounds.left, bounds.bottom);
14627                            this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));
14628                        }
14629                    }, this);
14630                }, this);
14631            };
14632
14633            NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) {
14634                switch(container.css("textDecoration").split(" ")[0]) {
14635                    case "underline":
14636                        // Draws a line at the baseline of the font
14637                        // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size
14638                        this.renderer.rectangle(bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, container.color("color"));
14639                        break;
14640                    case "overline":
14641                        this.renderer.rectangle(bounds.left, Math.round(bounds.top), bounds.width, 1, container.color("color"));
14642                        break;
14643                    case "line-through":
14644                        // TODO try and find exact position for line-through
14645                        this.renderer.rectangle(bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, container.color("color"));
14646                        break;
14647                }
14648            };
14649
14650            var borderColorTransforms = {
14651                inset: [
14652                    ["darken", 0.60],
14653                    ["darken", 0.10],
14654                    ["darken", 0.10],
14655                    ["darken", 0.60]
14656                ]
14657            };
14658
14659            NodeParser.prototype.parseBorders = function(container) {
14660                var nodeBounds = container.parseBounds();
14661                var radius = getBorderRadiusData(container);
14662                var borders = ["Top", "Right", "Bottom", "Left"].map(function(side, index) {
14663                    var style = container.css('border' + side + 'Style');
14664                    var color = container.color('border' + side + 'Color');
14665                    if (style === "inset" && color.isBlack()) {
14666                        color = new Color([255, 255, 255, color.a]); // this is wrong, but
14667                    }
14668                    var colorTransform = borderColorTransforms[style] ? borderColorTransforms[style][index] : null;
14669                    return {
14670                        width: container.cssInt('border' + side + 'Width'),
14671                        color: colorTransform ? color[colorTransform[0]](colorTransform[1]) : color,
14672                        args: null
14673                    };
14674                });
14675                var borderPoints = calculateCurvePoints(nodeBounds, radius, borders);
14676
14677                return {
14678                    clip: this.parseBackgroundClip(container, borderPoints, borders, radius, nodeBounds),
14679                    borders: calculateBorders(borders, nodeBounds, borderPoints, radius)
14680                };
14681            };
14682
14683            function calculateBorders(borders, nodeBounds, borderPoints, radius) {
14684                return borders.map(function(border, borderSide) {
14685                    if (border.width > 0) {
14686                        var bx = nodeBounds.left;
14687                        var by = nodeBounds.top;
14688                        var bw = nodeBounds.width;
14689                        var bh = nodeBounds.height - (borders[2].width);
14690
14691                        switch(borderSide) {
14692                            case 0:
14693                                // top border
14694                                bh = borders[0].width;
14695                                border.args = drawSide({
14696                                        c1: [bx, by],
14697                                        c2: [bx + bw, by],
14698                                        c3: [bx + bw - borders[1].width, by + bh],
14699                                        c4: [bx + borders[3].width, by + bh]
14700                                    }, radius[0], radius[1],
14701                                    borderPoints.topLeftOuter, borderPoints.topLeftInner, borderPoints.topRightOuter, borderPoints.topRightInner);
14702                                break;
14703                            case 1:
14704                                // right border
14705                                bx = nodeBounds.left + nodeBounds.width - (borders[1].width);
14706                                bw = borders[1].width;
14707
14708                                border.args = drawSide({
14709                                        c1: [bx + bw, by],
14710                                        c2: [bx + bw, by + bh + borders[2].width],
14711                                        c3: [bx, by + bh],
14712                                        c4: [bx, by + borders[0].width]
14713                                    }, radius[1], radius[2],
14714                                    borderPoints.topRightOuter, borderPoints.topRightInner, borderPoints.bottomRightOuter, borderPoints.bottomRightInner);
14715                                break;
14716                            case 2:
14717                                // bottom border
14718                                by = (by + nodeBounds.height) - (borders[2].width);
14719                                bh = borders[2].width;
14720                                border.args = drawSide({
14721                                        c1: [bx + bw, by + bh],
14722                                        c2: [bx, by + bh],
14723                                        c3: [bx + borders[3].width, by],
14724                                        c4: [bx + bw - borders[3].width, by]
14725                                    }, radius[2], radius[3],
14726                                    borderPoints.bottomRightOuter, borderPoints.bottomRightInner, borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner);
14727                                break;
14728                            case 3:
14729                                // left border
14730                                bw = borders[3].width;
14731                                border.args = drawSide({
14732                                        c1: [bx, by + bh + borders[2].width],
14733                                        c2: [bx, by],
14734                                        c3: [bx + bw, by + borders[0].width],
14735                                        c4: [bx + bw, by + bh]
14736                                    }, radius[3], radius[0],
14737                                    borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner, borderPoints.topLeftOuter, borderPoints.topLeftInner);
14738                                break;
14739                        }
14740                    }
14741                    return border;
14742                });
14743            }
14744
14745            NodeParser.prototype.parseBackgroundClip = function(container, borderPoints, borders, radius, bounds) {
14746                var backgroundClip = container.css('backgroundClip'),
14747                    borderArgs = [];
14748
14749                switch(backgroundClip) {
14750                    case "content-box":
14751                    case "padding-box":
14752                        parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftInner, borderPoints.topRightInner, bounds.left + borders[3].width, bounds.top + borders[0].width);
14753                        parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightInner, borderPoints.bottomRightInner, bounds.left + bounds.width - borders[1].width, bounds.top + borders[0].width);
14754                        parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightInner, borderPoints.bottomLeftInner, bounds.left + bounds.width - borders[1].width, bounds.top + bounds.height - borders[2].width);
14755                        parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftInner, borderPoints.topLeftInner, bounds.left + borders[3].width, bounds.top + bounds.height - borders[2].width);
14756                        break;
14757
14758                    default:
14759                        parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftOuter, borderPoints.topRightOuter, bounds.left, bounds.top);
14760                        parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightOuter, borderPoints.bottomRightOuter, bounds.left + bounds.width, bounds.top);
14761                        parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightOuter, borderPoints.bottomLeftOuter, bounds.left + bounds.width, bounds.top + bounds.height);
14762                        parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftOuter, borderPoints.topLeftOuter, bounds.left, bounds.top + bounds.height);
14763                        break;
14764                }
14765
14766                return borderArgs;
14767            };
14768
14769            function getCurvePoints(x, y, r1, r2) {
14770                var kappa = 4 * ((Math.sqrt(2) - 1) / 3);
14771                var ox = (r1) * kappa, // control point offset horizontal
14772                    oy = (r2) * kappa, // control point offset vertical
14773                    xm = x + r1, // x-middle
14774                    ym = y + r2; // y-middle
14775                return {
14776                    topLeft: bezierCurve({x: x, y: ym}, {x: x, y: ym - oy}, {x: xm - ox, y: y}, {x: xm, y: y}),
14777                    topRight: bezierCurve({x: x, y: y}, {x: x + ox,y: y}, {x: xm, y: ym - oy}, {x: xm, y: ym}),
14778                    bottomRight: bezierCurve({x: xm, y: y}, {x: xm, y: y + oy}, {x: x + ox, y: ym}, {x: x, y: ym}),
14779                    bottomLeft: bezierCurve({x: xm, y: ym}, {x: xm - ox, y: ym}, {x: x, y: y + oy}, {x: x, y:y})
14780                };
14781            }
14782
14783            function calculateCurvePoints(bounds, borderRadius, borders) {
14784                var x = bounds.left,
14785                    y = bounds.top,
14786                    width = bounds.width,
14787                    height = bounds.height,
14788
14789                    tlh = borderRadius[0][0] < width / 2 ? borderRadius[0][0] : width / 2,
14790                    tlv = borderRadius[0][1] < height / 2 ? borderRadius[0][1] : height / 2,
14791                    trh = borderRadius[1][0] < width / 2 ? borderRadius[1][0] : width / 2,
14792                    trv = borderRadius[1][1] < height / 2 ? borderRadius[1][1] : height / 2,
14793                    brh = borderRadius[2][0] < width / 2 ? borderRadius[2][0] : width / 2,
14794                    brv = borderRadius[2][1] < height / 2 ? borderRadius[2][1] : height / 2,
14795                    blh = borderRadius[3][0] < width / 2 ? borderRadius[3][0] : width / 2,
14796                    blv = borderRadius[3][1] < height / 2 ? borderRadius[3][1] : height / 2;
14797
14798                var topWidth = width - trh,
14799                    rightHeight = height - brv,
14800                    bottomWidth = width - brh,
14801                    leftHeight = height - blv;
14802
14803                return {
14804                    topLeftOuter: getCurvePoints(x, y, tlh, tlv).topLeft.subdivide(0.5),
14805                    topLeftInner: getCurvePoints(x + borders[3].width, y + borders[0].width, Math.max(0, tlh - borders[3].width), Math.max(0, tlv - borders[0].width)).topLeft.subdivide(0.5),
14806                    topRightOuter: getCurvePoints(x + topWidth, y, trh, trv).topRight.subdivide(0.5),
14807                    topRightInner: getCurvePoints(x + Math.min(topWidth, width + borders[3].width), y + borders[0].width, (topWidth > width + borders[3].width) ? 0 :trh - borders[3].width, trv - borders[0].width).topRight.subdivide(0.5),
14808                    bottomRightOuter: getCurvePoints(x + bottomWidth, y + rightHeight, brh, brv).bottomRight.subdivide(0.5),
14809                    bottomRightInner: getCurvePoints(x + Math.min(bottomWidth, width - borders[3].width), y + Math.min(rightHeight, height + borders[0].width), Math.max(0, brh - borders[1].width),  brv - borders[2].width).bottomRight.subdivide(0.5),
14810                    bottomLeftOuter: getCurvePoints(x, y + leftHeight, blh, blv).bottomLeft.subdivide(0.5),
14811                    bottomLeftInner: getCurvePoints(x + borders[3].width, y + leftHeight, Math.max(0, blh - borders[3].width), blv - borders[2].width).bottomLeft.subdivide(0.5)
14812                };
14813            }
14814
14815            function bezierCurve(start, startControl, endControl, end) {
14816                var lerp = function (a, b, t) {
14817                    return {
14818                        x: a.x + (b.x - a.x) * t,
14819                        y: a.y + (b.y - a.y) * t
14820                    };
14821                };
14822
14823                return {
14824                    start: start,
14825                    startControl: startControl,
14826                    endControl: endControl,
14827                    end: end,
14828                    subdivide: function(t) {
14829                        var ab = lerp(start, startControl, t),
14830                            bc = lerp(startControl, endControl, t),
14831                            cd = lerp(endControl, end, t),
14832                            abbc = lerp(ab, bc, t),
14833                            bccd = lerp(bc, cd, t),
14834                            dest = lerp(abbc, bccd, t);
14835                        return [bezierCurve(start, ab, abbc, dest), bezierCurve(dest, bccd, cd, end)];
14836                    },
14837                    curveTo: function(borderArgs) {
14838                        borderArgs.push(["bezierCurve", startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y]);
14839                    },
14840                    curveToReversed: function(borderArgs) {
14841                        borderArgs.push(["bezierCurve", endControl.x, endControl.y, startControl.x, startControl.y, start.x, start.y]);
14842                    }
14843                };
14844            }
14845
14846            function drawSide(borderData, radius1, radius2, outer1, inner1, outer2, inner2) {
14847                var borderArgs = [];
14848
14849                if (radius1[0] > 0 || radius1[1] > 0) {
14850                    borderArgs.push(["line", outer1[1].start.x, outer1[1].start.y]);
14851                    outer1[1].curveTo(borderArgs);
14852                } else {
14853                    borderArgs.push([ "line", borderData.c1[0], borderData.c1[1]]);
14854                }
14855
14856                if (radius2[0] > 0 || radius2[1] > 0) {
14857                    borderArgs.push(["line", outer2[0].start.x, outer2[0].start.y]);
14858                    outer2[0].curveTo(borderArgs);
14859                    borderArgs.push(["line", inner2[0].end.x, inner2[0].end.y]);
14860                    inner2[0].curveToReversed(borderArgs);
14861                } else {
14862                    borderArgs.push(["line", borderData.c2[0], borderData.c2[1]]);
14863                    borderArgs.push(["line", borderData.c3[0], borderData.c3[1]]);
14864                }
14865
14866                if (radius1[0] > 0 || radius1[1] > 0) {
14867                    borderArgs.push(["line", inner1[1].end.x, inner1[1].end.y]);
14868                    inner1[1].curveToReversed(borderArgs);
14869                } else {
14870                    borderArgs.push(["line", borderData.c4[0], borderData.c4[1]]);
14871                }
14872
14873                return borderArgs;
14874            }
14875
14876            function parseCorner(borderArgs, radius1, radius2, corner1, corner2, x, y) {
14877                if (radius1[0] > 0 || radius1[1] > 0) {
14878                    borderArgs.push(["line", corner1[0].start.x, c
14878orner1[0].start.y]);
14879                    corner1[0].curveTo(borderArgs);
14880                    corner1[1].curveTo(borderArgs);
14881                } else {
14882                    borderArgs.push(["line", x, y]);
14883                }
14884
14885                if (radius2[0] > 0 || radius2[1] > 0) {
14886                    borderArgs.push(["line", corner2[0].start.x, corner2[0].start.y]);
14887                }
14888            }
14889
14890            function negativeZIndex(container) {
14891                return container.cssInt("zIndex") < 0;
14892            }
14893
14894            function positiveZIndex(container) {
14895                return container.cssInt("zIndex") > 0;
14896            }
14897
14898            function zIndex0(container) {
14899                return container.cssInt("zIndex") === 0;
14900            }
14901
14902            function inlineLevel(container) {
14903                return ["inline", "inline-block", "inline-table"].indexOf(container.css("display")) !== -1;
14904            }
14905
14906            function isStackingContext(container) {
14907                return (container instanceof StackingContext);
14908            }
14909
14910            function hasText(container) {
14911                return container.node.data.trim().length > 0;
14912            }
14913
14914            function noLetterSpacing(container) {
14915                return (/^(normal|none|0px)$/.test(container.parent.css("letterSpacing")));
14916            }
14917
14918            function getBorderRadiusData(container) {
14919                return ["TopLeft", "TopRight", "BottomRight", "BottomLeft"].map(function(side) {
14920                    var value = container.css('border' + side + 'Radius');
14921                    var arr = value.split(" ");
14922                    if (arr.length <= 1) {
14923                        arr[1] = arr[0];
14924                    }
14925                    return arr.map(asInt);
14926                });
14927            }
14928
14929            function renderableNode(node) {
14930                return (node.nodeType === Node.TEXT_NODE || node.nodeType === Node.ELEMENT_NODE);
14931            }
14932
14933            function isPositionedForStacking(container) {
14934                var position = container.css("position");
14935                var zIndex = (["absolute", "relative", "fixed"].indexOf(position) !== -1) ? container.css("zIndex") : "auto";
14936                return zIndex !== "auto";
14937            }
14938
14939            function isPositioned(container) {
14940                return container.css("position") !== "static";
14941            }
14942
14943            function isFloating(container) {
14944                return container.css("float") !== "none";
14945            }
14946
14947            function isInlineBlock(container) {
14948                return ["inline-block", "inline-table"].indexOf(container.css("display")) !== -1;
14949            }
14950
14951            function not(callback) {
14952                var context = this;
14953                return function() {
14954                    return !callback.apply(context, arguments);
14955                };
14956            }
14957
14958            function isElement(container) {
14959                return container.node.nodeType === Node.ELEMENT_NODE;
14960            }
14961
14962            function isPseudoElement(container) {
14963                return container.isPseudoElement === true;
14964            }
14965
14966            function isTextNode(container) {
14967                return container.node.nodeType === Node.TEXT_NODE;
14968            }
14969
14970            function zIndexSort(contexts) {
14971                return function(a, b) {
14972                    return (a.cssInt("zIndex") + (contexts.indexOf(a) / contexts.length)) - (b.cssInt("zIndex") + (contexts.indexOf(b) / contexts.length));
14973                };
14974            }
14975
14976            function hasOpacity(container) {
14977                return container.getOpacity() < 1;
14978            }
14979
14980            function asInt(value) {
14981                return parseInt(value, 10);
14982            }
14983
14984            function getWidth(border) {
14985                return border.width;
14986            }
14987
14988            function nonIgnoredElement(nodeContainer) {
14989                return (nodeContainer.node.nodeType !== Node.ELEMENT_NODE || ["SCRIPT", "HEAD", "TITLE", "OBJECT", "BR", "OPTION"].indexOf(nodeContainer.node.nodeName) === -1);
14990            }
14991
14992            function flatten(arrays) {
14993                return [].concat.apply([], arrays);
14994            }
14995
14996            function stripQuotes(content) {
14997                var first = content.substr(0, 1);
14998                return (first === content.substr(content.length - 1) && first.match(/'|"/)) ? content.substr(1, content.length - 2) : content;
14999            }
15000
15001            function getWords(characters) {
15002                var words = [], i = 0, onWordBoundary = false, word;
15003                while(characters.length) {
15004                    if (isWordBoundary(characters[i]) === onWordBoundary) {
15005                        word = characters.splice(0, i);
15006                        if (word.length) {
15007                            words.push(punycode.ucs2.encode(word));
15008                        }
15009                        onWordBoundary =! onWordBoundary;
15010                        i = 0;
15011                    } else {
15012                        i++;
15013                    }
15014
15015                    if (i >= characters.length) {
15016                        word = characters.splice(0, i);
15017                        if (word.length) {
15018                            words.push(punycode.ucs2.encode(word));
15019                        }
15020                    }
15021                }
15022                return words;
15023            }
15024
15025            function isWordBoundary(characterCode) {
15026                return [
15027                    32, // <space>
15028                    13, // \r
15029                    10, // \n
15030                    9, // \t
15031                    45 // -
15032                ].indexOf(characterCode) !== -1;
15033            }
15034
15035            function hasUnicode(string) {
15036                return (/[^\u0000-\u00ff]/).test(string);
15037            }
15038
15039            module.exports = NodeParser;
15040
15041        },{"./color":3,"./fontmetrics":7,"./log":13,"./nodecontainer":14,"./pseudoelementcontainer":18,"./stackingcontext":21,"./textcontainer":25,"./utils":26,"pu
15041nycode":1}],16:[function(_dereq_,module,exports){
15042            var XHR = _dereq_('./xhr');
15043            var utils = _dereq_('./utils');
15044            var log = _dereq_('./log');
15045            var createWindowClone = _dereq_('./clone');
15046            var decode64 = utils.decode64;
15047
15048            function Proxy(src, proxyUrl, document) {
15049                var supportsCORS = ('withCredentials' in new XMLHttpRequest());
15050                if (!proxyUrl) {
15051                    return Promise.reject("No proxy configured");
15052                }
15053                var callback = createCallback(supportsCORS);
15054                var url = createProxyUrl(proxyUrl, src, callback);
15055
15056                return supportsCORS ? XHR(url) : (jsonp(document, url, callback).then(function(response) {
15057                    return decode64(response.content);
15058                }));
15059            }
15060            var proxyCount = 0;
15061
15062            function ProxyURL(src, proxyUrl, document) {
15063                var supportsCORSImage = ('crossOrigin' in new Image());
15064                var callback = createCallback(supportsCORSImage);
15065                var url = createProxyUrl(proxyUrl, src, callback);
15066                return (supportsCORSImage ? Promise.resolve(url) : jsonp(document, url, callback).then(function(response) {
15067                    return "data:" + response.type + ";base64," + response.content;
15068                }));
15069            }
15070
15071            function jsonp(document, url, callback) {
15072                return new Promise(function(resolve, reject) {
15073                    var s = document.createElement("script");
15074                    var cleanup = function() {
15075                        delete window.html2canvas.proxy[callback];
15076                        document.body.removeChild(s);
15077                    };
15078                    window.html2canvas.proxy[callback] = function(response) {
15079                        cleanup();
15080                        resolve(response);
15081                    };
15082                    s.src = url;
15083                    s.onerror = function(e) {
15084                        cleanup();
15085                        reject(e);
15086                    };
15087                    document.body.appendChild(s);
15088                });
15089            }
15090
15091            function createCallback(useCORS) {
15092                return !useCORS ? "html2canvas_" + Date.now() + "_" + (++proxyCount) + "_" + Math.round(Math.random() * 100000) : "";
15093            }
15094
15095            function createProxyUrl(proxyUrl, src, callback) {
15096                return proxyUrl + "?url=" + encodeURIComponent(src) + (callback.length ? "&callback=html2canvas.proxy." + callback : "");
15097            }
15098
15099            function documentFromHTML(src) {
15100                return function(html) {
15101                    var parser = new DOMParser(), doc;
15102                    try {
15103                        doc = parser.parseFromString(html, "text/html");
15104                    } catch(e) {
15105                        log("DOMParser not supported, falling back to createHTMLDocument");
15106                        doc = document.implementation.createHTMLDocument("");
15107                        try {
15108                            doc.open();
15109                            doc.write(html);
15110                            doc.close();
15111                        } catch(ee) {
15112                            log("createHTMLDocument write not supported, falling back to document.body.innerHTML");
15113                            doc.body.innerHTML = html; // ie9 doesnt support writing to documentElement
15114                        }
15115                    }
15116
15117                    var b = doc.querySelector("base");
15118                    if (!b || !b.href.host) {
15119                        var base = doc.createElement("base");
15120                        base.href = src;
15121                        doc.head.insertBefore(base, doc.head.firstChild);
15122                    }
15123
15124                    return doc;
15125                };
15126            }
15127
15128            function loadUrlDocument(src, proxy, document, width, height, options) {
15129                return new Proxy(src, proxy, window.document).then(documentFromHTML(src)).then(function(doc) {
15130                    return createWindowClone(doc, document, width, height, options, 0, 0);
15131                });
15132            }
15133
15134            exports.Proxy = Proxy;
15135            exports.ProxyURL = ProxyURL;
15136            exports.loadUrlDocument = loadUrlDocument;
15137
15138        }
15138,{"./clone":2,"./log":13,"./utils":26,"./xhr":28}],17:[function(_dereq_,module,exports){
15139            var ProxyURL = _dereq_('./proxy').ProxyURL;
15140
15141            function ProxyImageContainer(src, proxy) {
15142                var link = document.createElement("a");
15143                link.href = src;
15144                src = link.href;
15145                this.src = src;
15146                this.image = new Image();
15147                var self = this;
15148                this.promise = new Promise(function(resolve, reject) {
15149                    self.image.crossOrigin = "Anonymous";
15150                    self.image.onload = resolve;
15151                    self.image.onerror = reject;
15152
15153                    new ProxyURL(src, proxy, document).then(function(url) {
15154                        self.image.src = url;
15155                    })['catch'](reject);
15156                });
15157            }
15158
15159            module.exports = ProxyImageContainer;
15160
15161        },{"./proxy":16}],18:[function(_dereq_,module,exports){
15162            var NodeContainer = _dereq_('./nodecontainer');
15163
15164            function PseudoElementContainer(node, parent, type) {
15165                NodeContainer.call(this, node, parent);
15166                this.isPseudoElement = true;
15167                this.before = type === ":before";
15168            }
15169
15170            PseudoElementContainer.prototype.cloneTo = function(stack) {
15171                PseudoElementContainer.prototype.cloneTo.call(this, stack);
15172                stack.isPseudoElement = true;
15173                stack.before = this.before;
15174            };
15175
15176            PseudoElementContainer.prototype = Object.create(NodeContainer.prototype);
15177
15178            PseudoElementContainer.prototype.appendToDOM = function() {
15179                if (this.before) {
15180                    this.parent.node.insertBefore(this.node, this.parent.node.firstChild);
15181                } else {
15182                    this.parent.node.appendChild(this.node);
15183                }
15184                this.parent.node.className += " " + this.getHideClass();
15185            };
15186
15187            PseudoElementContainer.prototype.cleanDOM = function() {
15188                this.node.parentNode.removeChild(this.node);
15189                this.parent.node.className = this.parent.node.className.replace(this.getHideClass(), "");
15190            };
15191
15192            PseudoElementContainer.prototype.getHideClass = function() {
15193                return this["PSEUDO_HIDE_ELEMENT_CLASS_" + (this.before ? "BEFORE" : "AFTER")];
15194            };
15195
15196            PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE = "___html2canvas___pseudoelement_before";
15197            PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER = "___html2canvas___pseudoelement_after";
15198
15199            module.exports = PseudoElementContainer;
15200
15201        },{"./nodecontainer":14}],19:[function(_dereq_,module,exports){
15202            var log = _dereq_('./log');
15203
15204            function Renderer(width, height, images, options, document) {
15205                this.width = width;
15206                this.height = height;
15207                this.images = images;
15208                this.options = options;
15209                this.document = document;
15210            }
15211
15212            Renderer.prototype.renderImage = function(container, bounds, borderData, imageContainer) {
15213                var paddingLeft = container.cssInt('paddingLeft'),
15214                    paddingTop = container.cssInt('paddingTop'),
15215                    paddingRight = container.cssInt('paddingRight'),
15216                    paddingBottom = container.cssInt('paddingBottom'),
15217                    borders = borderData.borders;
15218
15219                var width = bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight);
15220                var height = bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom);
15221                this.drawImage(
15222                    imageContainer,
15223                    0,
15224                    0,
15225                    imageContainer.image.width || width,
15226                    imageContainer.image.height || height,
15227                    bounds.left + paddingLeft + borders[3].width,
15228                    bounds.top + paddingTop + borders[0].width,
15229                    width,
15230                    height
15231                );
15232            };
15233
15234            Renderer.prototype.renderBackground = function(container, bounds, borderData) {
15235                if (bounds.height > 0 && bounds.width > 0) {
15236                    this.renderBackgroundColor(container, bounds);
15237                    this.renderBackgroundImage(container, bounds, borderData);
15238                }
15239            };
15240
15241            Renderer.prototype.renderBackgroundColor = function(container, bounds) {
15242                var color = container.color("backgroundColor");
15243                if (!color.isTransparent()) {
15244                    this.rectangle(bounds.left, bounds.top, bounds.width, bounds.height, color);
15245                }
15246            };
15247
15248            Renderer.prototype.renderBorders = function(borders) {
15249                borders.forEach(this.renderBorder, this);
15250            };
15251
15252            Renderer.prototype.renderBorder = function(data) {
15253                if (!data.color.isTransparent() && data.args !== null) {
15254                    this.drawShape(data.args, data.color);
15255                }
15256            };
15257
15258            Renderer.prototype.renderBackgroundImage = function(container, bounds, borderData) {
15259                var backgroundImages = container.parseBackgroundImages();
15260                backgroundImages.reverse().forEach(function(backgroundImage, index, arr) {
15261                    switch(backgroundImage.method) {
15262                        case "url":
15263                            var image = this.images.get(backgroundImage.args[0]);
15264                            if (image) {
15265                                this.renderBackgroundRepeating(container, bounds, image, arr.length - (index+1), borderData);
15266                            } else {
15267                                log("Error loading background-image", backgroundImage.args[0]);
15268                            }
15269                            break;
15270                        case "linear-gradient":
15271                        case "gradient":
15272                            var gradientImage = this.images.get(backgroundImage.value);
15273                            if (gradientImage) {
15274                                this.renderBackgroundGradient(gradientImage, bounds, borderData);
15275                            } else {
15276                                log("Error loading background-image", backgroundImage.args[0]);
15277                            }
15278                            break;
15279                        case "none":
15280                            break;
15281                        default:
15282                            log("Unknown background-image type", backgroundImage.args[0]);
15283                    }
15284                }, this);
15285            };
15286
15287            Renderer.prototype.renderBackgroundRepeating = function(container, bounds, imageContainer, index, borderData) {
15288                var size = container.parseBackgroundSize(bounds, imageContainer.image, index);
15289                var position = container.parseBackgroundPosition(bounds, imageContainer.image, index, size);
15290                var repeat = container.parseBackgroundRepeat(index);
15291                switch (repeat) {
15292                    case "repeat-x":
15293                    case "repeat no-repeat":
15294                        this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + borderData[3], bounds.top + position.top + borderData[0], 99999, size.height, borderData);
15295                        break;
15296                    case "repeat-y":
15297                    case "no-repeat repeat":
15298                        this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + position.left + borderData[3], bounds.top + borderData[0], size.width, 99999, borderData);
15299                        break;
15300                    case "no-repeat":
15301                        this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + position.left + borderData[3], bounds.top + position.top + borderData[0], size.width, size.height, borderData);
15302                        break;
15303                    default:
15304                        this.renderBackgroundRepeat(imageContainer, position, size, {top: bounds.top, left: bounds.left}, borderData[3], borderData[0]);
15305                        break;
15306                }
15307            };
15308
15309            module.exports = Renderer;
15310
15311        },{"./log":13}],20:[function(_dereq_,module,exports){
15312            var Renderer = _dereq_('../renderer');
15313            var LinearGradientContainer = _dereq_('../lineargradientcontainer');
15314            var log = _dereq_('../log');
15315
15316            function CanvasRenderer(width, height) {
15317                Renderer.apply(this, arguments);
15318                this.canvas = this.options.canvas || this.document.createElement("canvas");
15319                if (!this.options.canvas) {
15320                    this.canvas.width = width;
15321                    this.canvas.height = height;
15322                }
15323                this.ctx = this.canvas.getContext("2d");
15324                this.taintCtx = this.document.createElement("canvas").getContext("2d");
15325                this.ctx.textBaseline = "bottom";
15326                this.variables = {};
15327                log("Initialized CanvasRenderer with size", width, "x", height);
15328            }
15329
15330            CanvasRenderer.prototype = Object.create(Renderer.prototype);
15331
15332            CanvasRenderer.prototype.setFillStyle = function(fillStyle) {
15333                this.ctx.fillStyle = typeof(fillStyle) === "object" && !!fillStyle.isColor ? fillStyle.toString() : fillStyle;
15334                return this.ctx;
15335            };
15336
15337            CanvasRenderer.prototype.rectangle = function(left, top, width, height, color) {
15338                this.setFillStyle(color).fillRect(left, top, width, height);
15339            };
15340
15341            CanvasRenderer.prototype.circle = function(left, top, size, color) {
15342                this.setFillStyle(color);
15343                this.ctx.beginPath();
15344                this.ctx.arc(left + size / 2, top + size / 2, size / 2, 0, Math.PI*2, true);
15345                this.ctx.closePath();
15346                this.ctx.fill();
15347            };
15348
15349            CanvasRenderer.prototype.circleStroke = function(left, top, size, color, stroke, strokeColor) {
15350                this.circle(left, top, size, color);
15351                this.ctx.strokeStyle = strokeColor.toString();
15352                this.ctx.stroke();
15353            };
15354
15355            CanvasRenderer.prototype.drawShape = function(shape, color) {
15356                this.shape(shape);
15357                this.setFillStyle(color).fill();
15358            };
15359
15360            CanvasRenderer.prototype.taints = function(imageContainer) {
15361                if (imageContainer.tainted === null) {
15362                    this.taintCtx.drawImage(imageContainer.image, 0, 0);
15363                    try {
15364                        this.taintCtx.getImageData(0, 0, 1, 1);
15365                        imageContainer.tainted = false;
15366                    } catch(e) {
15367                        this.taintCtx = document.createElement("canvas").getContext("2d");
15368                        imageContainer.tainted = true;
15369                    }
15370                }
15371
15372                return imageContainer.tainted;
15373            };
15374
15375            CanvasRenderer.prototype.drawImage = function(imageContainer, sx, sy, sw, sh, dx, dy, dw, dh) {
15376                if (!this.taints(imageContainer) || this.options.allowTaint) {
15377                    this.ctx.drawImage(imageContainer.image, sx, sy, sw, sh, dx, dy, dw, dh);
15378                }
15379            };
15380
15381            CanvasRenderer.prototype.clip = function(shapes, callback, context) {
15382                this.ctx.save();
15383                shapes.filter(hasEntries).forEach(function(shape) {
15384                    this.shape(shape).clip();
15385                }, this);
15386                callback.call(context);
15387                this.ctx.restore();
15388            };
15389
15390            CanvasRenderer.prototype.shape = function(shape) {
15391                this.ctx.beginPath();
15392                shape.forEach(function(point, index) {
15393                    if (point[0] === "rect") {
15394                        this.ctx.rect.apply(this.ctx, point.slice(1));
15395                    } else {
15396                        this.ctx[(index === 0) ? "moveTo" : point[0] + "To" ].apply(this.ctx, point.slice(1));
15397                    }
15398                }, this);
15399                this.ctx.closePath();
15400                return this.ctx;
15401            };
15402
15403            CanvasRenderer.prototype.font = function(color, style, variant, weight, size, family) {
15404                this.setFillStyle(color).font = [style, variant, weight, size, family].join(" ").split(",")[0];
15405            };
15406
15407            CanvasRenderer.prototype.fontShadow = function(color, offsetX, offsetY, blur) {
15408                this.setVariable("shadowColor", color.toString())
15409                    .setVariable("shadowOffsetY", offsetX)
15410                    .setVariable("shadowOffsetX", offsetY)
15411                    .setVariable("shadowBlur", blur);
15412            };
15413
15414            CanvasRenderer.prototype.clearShadow = function() {
15415                this.setVariable("shadowColor", "rgba(0,0,0,0)");
15416            };
15417
15418            CanvasRenderer.prototype.setOpacity = function(opacity) {
15419                this.ctx.globalAlpha = opacity;
15420            };
15421
15422            CanvasRenderer.prototype.setTransform = function(transform) {
15423                this.ctx.translate(transform.origin[0], transform.origin[1]);
15424                this.ctx.transform.apply(this.ctx, transform.matrix);
15425                this.ctx.translate(-transform.origin[0], -transform.origin[1]);
15426            };
15427
15428            CanvasRenderer.prototype.setVariable = function(property, value) {
15429                if (this.variables[property] !== value) {
15430                    this.variables[property] = this.ctx[property] = value;
15431                }
15432
15433                return this;
15434            };
15435
15436            CanvasRenderer.prototype.text = function(text, left, bottom) {
15437                this.ctx.fillText(text, left, bottom);
15438            };
15439
15440            CanvasRenderer.prototype.backgroundRepeatShape = function(imageContainer, backgroundPosition, size, bounds, left, top, width, height, borderData) {
15441                var shape = [
15442                    ["line", Math.round(left), Math.round(top)],
15443                    ["line", Math.round(left + width), Math.round(top)],
15444                    ["line", Math.round(left + width), Math.round(height + top)],
15445                    ["line", Math.round(left), Math.round(height + top)]
15446                ];
15447                this.clip([shape], function() {
15448                    this.renderBackgroundRepeat(imageContainer, backgroundPosition, size, bounds, borderData[3], borderData[0]);
15449                }, this);
15450            };
15451
15452            CanvasRenderer.prototype.renderBackgroundRepeat = function(imageContainer, backgroundPosition, size, bounds, borderLeft, borderTop) {
15453                var offsetX = Math.round(bounds.left + backgroundPosition.left + borderLeft), offsetY = Math.round(bounds.top + backgroundPosition.top + borderTop);
15454                this.setFillStyle(this.ctx.createPattern(this.resizeImage(imageContainer, size), "repeat"));
15455                this.ctx.translate(offsetX, offsetY);
15456                this.ctx.fill();
15457                this.ctx.translate(-offsetX, -offsetY);
15458            };
15459
15460            CanvasRenderer.prototype.renderBackgroundGradient = function(gradientImage, bounds) {
15461                if (gradientImage instanceof LinearGradientContainer) {
15462                    var gradient = this.ctx.createLinearGradient(
15463                        bounds.left + bounds.width * gradientImage.x0,
15464                        bounds.top + bounds.height * gradientImage.y0,
15465                        bounds.left +  bounds.width * gradientImage.x1,
15466                        bounds.top +  bounds.height * gradientImage.y1);
15467                    gradientImage.colorStops.forEach(function(colorStop) {
15468                        gradient.addColorStop(colorStop.stop, colorStop.color.toString());
15469                    });
15470                    this.rectangle(bounds.left, bounds.top, bounds.width, bounds.height, gradient);
15471                }
15472            };
15473
15474            CanvasRenderer.prototype.resizeImage = function(imageContainer, size) {
15475                var image = imageContainer.image;
15476                if(image.width === size.width && image.height === size.height) {
15477                    return image;
15478                }
15479
15480                var ctx, canvas = document.createElement('canvas');
15481                canvas.width = size.width;
15482                canvas.height = size.height;
15483                ctx = canvas.getContext("2d");
15484                ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, size.width, size.height );
15485                return canvas;
15486            };
15487
15488            function hasEntries(array) {
15489                return array.length > 0;
15490            }
15491
15492            module.exports = CanvasRenderer;
15493
15494        },{"../lineargradientcontainer":12,"../log":13,"../renderer":19}],21:[function(_dereq_,module,exports){
15495            var NodeContainer = _dereq_('./nodecontainer');
15496
15497            function StackingContext(hasOwnStacking, opacity, element, parent) {
15498                NodeContainer.call(this, element, parent);
15499                this.ownStacking = hasOwnStacking;
15500                this.contexts = [];
15501                this.children = [];
15502                this.opacity = (this.parent ? this.parent.stack.opacity : 1) * opacity;
15503            }
15504
15505            StackingContext.prototype = Object.create(NodeContainer.prototype);
15506
15507            StackingContext.prototype.getParentStack = function(context) {
15508                var parentStack = (this.parent) ? this.parent.stack : null;
15509                return parentStack ? (parentStack.ownStacking ? parentStack : parentStack.getParentStack(context)) : context.stack;
15510            };
15511
15512            module.exports = StackingContext;
15513
15514        },{"./nodecontainer":14}],22:[function(_dereq_,module,exports){
15515            function Support(document) {
15516                this.rangeBounds = this.testRangeBounds(document);
15517                this.cors = this.testCORS();
15518                this.svg = this.testSVG();
15519            }
15520
15521            Support.prototype.testRangeBounds = function(document) {
15522                var range, testElement, rangeBounds, rangeHeight, support = false;
15523
15524                if (document.createRange) {
15525                    range = document.createRange();
15526                    if (range.getBoundingClientRect) {
15527                        testElement = document.createElement('boundtest');
15528                        testElement.style.height = "123px";
15529                        testElement.style.display = "block";
15530                        document.body.appendChild(testElement);
15531
15532                        range.selectNode(testElement);
15533                        rangeBounds = range.getBoundingClientRect();
15534                        rangeHeight = rangeBounds.height;
15535
15536                        if (rangeHeight === 123) {
15537                            support = true;
15538                        }
15539                        document.body.removeChild(testElement);
15540                    }
15541                }
15542
15543                return support;
15544            };
15545
15546            Support.prototype.testCORS = function() {
15547                return typeof((new Image()).crossOrigin) !== "undefined";
15548            };
15549
15550            Support.prototype.testSVG = function() {
15551                var img = new Image();
15552                var canvas = document.createElement("canvas");
15553                var ctx =  canvas.getContext("2d");
15554                img.src = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>";
15555
15556                try {
15557                    ctx.drawImage(img, 0, 0);
15558                    canvas.toDataURL();
15559                } catch(e) {
15560                    return false;
15561                }
15562                return true;
15563            };
15564
15565            module.exports = Support;
15566
15567        },{}],23:[function(_dereq_,module,exports){
15568            var XHR = _dereq_('./xhr');
15569            var decode64 = _dereq_('./utils').decode64;
15570
15571            function SVGContainer(src) {
15572                this.src = src;
15573                this.image = null;
15574                var self = this;
15575
15576                this.promise = this.hasFabric().then(function() {
15577                    return (self.isInline(src) ? Promise.resolve(self.inlineFormatting(src)) : XHR(src));
15578                }).then(function(svg) {
15579                    return new Promise(function(resolve) {
15580                        window.html2canvas.svg.fabric.loadSVGFromString(svg, self.createCanvas.call(self, resolve));
15581                    });
15582                });
15583            }
15584
15585            SVGContainer.prototype.hasFabric = function() {
15586                return !window.html2canvas.svg || !window.html2canvas.svg.fabric ? Promise.reject(new Error("html2canvas.svg.js is not loaded, cannot render svg")) : Promise.resolve();
15587            };
15588
15589            SVGContainer.prototype.inlineFormatting = function(src) {
15590                return (/^data:image\/svg\+xml;base64,/.test(src)) ? this.decode64(this.removeContentType(src)) : this.removeContentType(src);
15591            };
15592
15593            SVGContainer.prototype.removeContentType = function(src) {
15594                return src.replace(/^data:image\/svg\+xml(;base64)?,/,'');
15595            };
15596
15597            SVGContainer.prototype.isInline = function(src) {
15598                return (/^data:image\/svg\+xml/i.test(src));
15599            };
15600
15601            SVGContainer.prototype.createCanvas = function(resolve) {
15602                var self = this;
15603                return function (objects, options) {
15604                    var canvas = new window.html2canvas.svg.fabric.StaticCanvas('c');
15605                    self.image = canvas.lowerCanvasEl;
15606                    canvas
15607                        .setWidth(options.width)
15608                        .setHeight(options.height)
15609                        .add(window.html2canvas.svg.fabric.util.groupSVGElements(objects, options))
15610                        .renderAll();
15611                    resolve(canvas.lowerCanvasEl);
15612                };
15613            };
15614
15615            SVGContainer.prototype.decode64 = function(str) {
15616                return (typeof(window.atob) === "function") ? window.atob(str) : decode64(str);
15617            };
15618
15619            module.exports = SVGContainer;
15620
15621        },{"./utils":26,"./xhr":28}],24:[function(_dereq_,module,exports){
15622            var SVGContainer = _dereq_('./svgcontainer');
15623
15624            function SVGNodeContainer(node, _native) {
15625                this.src = node;
15626                this.image = null;
15627                var self = this;
15628
15629                this.promise = _native ? new Promise(function(resolve, reject) {
15630                    self.image = new Image();
15631                    self.image.onload = resolve;
15632                    self.image.onerror = reject;
15633                    self.image.src = "data:image/svg+xml," + (ne
15633w XMLSerializer()).serializeToString(node);
15634                    if (self.image.complete === true) {
15635                        resolve(self.image);
15636                    }
15637                }) : this.hasFabric().then(function() {
15638                    return new Promise(function(resolve) {
15639                        window.html2canvas.svg.fabric.parseSVGDocument(node, self.createCanvas.call(self, resolve));
15640                    });
15641                });
15642            }
15643
15644            SVGNodeContainer.prototype = Object.create(SVGContainer.prototype);
15645
15646            module.exports = SVGNodeContainer;
15647
15648        },{"./svgcontainer":23}],25:[function(_dereq_,module,exports){
15649            var NodeContainer = _dereq_('./nodecontainer');
15650
15651            function TextContainer(node, parent) {
15652                NodeContainer.call(this, node, parent);
15653            }
15654
15655            TextContainer.prototype = Object.create(NodeContainer.prototype);
15656
15657            TextContainer.prototype.applyTextTransform = function() {
15658                this.node.data = this.transform(this.parent.css("textTransform"));
15659            };
15660
15661            TextContainer.prototype.transform = function(transform) {
15662                var text = this.node.data;
15663                switch(transform){
15664                    case "lowercase":
15665                        return text.toLowerCase();
15666                    case "capitalize":
15667                        return text.replace(/(^|\s|:|-|\(|\))([a-z])/g, capitalize);
15668                    case "uppercase":
15669                        return text.toUpperCase();
15670                    default:
15671                        return text;
15672                }
15673            };
15674
15675            function capitalize(m, p1, p2) {
15676                if (m.length > 0) {
15677                    return p1 + p2.toUpperCase();
15678                }
15679            }
15680
15681            module.exports = TextContainer;
15682
15683        },{"./nodecontainer":14}],26:[function(_dereq_,module,exports){
15684            exports.smallImage = function smallImage() {
15685                return "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
15686            };
15687
15688            exports.bind = function(callback, context) {
15689                return function() {
15690                    return callback.apply(context, arguments);
15691                };
15692            };
15693
15694            /*
15695   * base64-arraybuffer
15696   * https://github.com/niklasvh/base64-arraybuffer
15697   *
15698   * Copyright (c) 2012 Niklas von Hertzen
15699   * Licensed under the MIT license.
15700   */
15701
15702            exports.decode64 = function(base64) {
15703                var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
15704                var len = base64.length, i, encoded1, encoded2, encoded3, encoded4, byte1, byte2, byte3;
15705
15706                var output = "";
15707
15708                for (i = 0; i < len; i+=4) {
15709                    encoded1 = chars.indexOf(base64[i]);
15710                    encoded2 = chars.indexOf(base64[i+1]);
15711                    encoded3 = chars.indexOf(base64[i+2]);
15712                    encoded4 = chars.indexOf(base64[i+3]);
15713
15714                    byte1 = (encoded1 << 2) | (encoded2 >> 4);
15715                    byte2 = ((encoded2 & 15) << 4) | (encoded3 >> 2);
15716                    byte3 = ((encoded3 & 3) << 6) | encoded4;
15717                    if (encoded3 === 64) {
15718                        output += String.fromCharCode(byte1);
15719                    } else if (encoded4 === 64 || encoded4 === -1) {
15720                        output += String.fromCharCode(byte1, byte2);
15721                    } else{
15722                        output += String.fromCharCode(byte1, byte2, byte3);
15723                    }
15724                }
15725
15726                return output;
15727            };
15728
15729            exports.getBounds = function(node) {
15730                if (node.getBoundingClientRect) {
15731                    var clientRect = node.getBoundingClientRect();
15732                    var width = node.offsetWidth == null ? clientRect.width : node.offsetWidth;
15733                    return {
15734                        top: clientRect.top,
15735                        bottom: clientRect.bottom || (clientRect.top + clientRect.height),
15736                        right: clientRect.left + width,
15737                        left: clientRect.left,
15738                        width:  width,
15739                        height: node.offsetHeight == null ? clientRect.height : node.offsetHeight
15740                    };
15741                }
15742                return {};
15743            };
15744
15745            exports.offsetBounds = function(node) {
15746                var parent = node.offsetParent ? exports.offsetBounds(node.offsetParent) : {top: 0, left: 0};
15747
15748                return {
15749                    top: node.offsetTop + parent.top,
15750                    bottom: node.offsetTop + node.offsetHeight + parent.top,
15751                    right: node.offsetLeft + parent.left + node.offsetWidth,
15752                    left: node.offsetLeft + parent.left,
15753                    width: node.offsetWidth,
15754                    height: node.offsetHeight
15755                };
15756            };
15757
15758            exports.parseBackgrounds = function(backgroundImage) {
15759                var whitespace = ' \r\n\t',
15760                    method, definition, prefix, prefix_i, block, results = [],
15761                    mode = 0, numParen = 0, quote, args;
15762                var appendResult = function() {
15763                    if(method) {
15764                        if (definition.substr(0, 1) === '"') {
15765                            definition = definition.substr(1, definition.length - 2);
15766                        }
15767                        if (definition) {
15768                            args.push(definition);
15769                        }
15770                        if (method.substr(0, 1) === '-' && (prefix_i = method.indexOf('-', 1 ) + 1) > 0) {
15771                            prefix = method.substr(0, prefix_i);
15772                            method = method.substr(prefix_i);
15773                        }
15774                        results.push({
15775                            prefix: prefix,
15776                            method: method.toLowerCase(),
15777                            value: block,
15778                            args: args,
15779                            image: null
15780                        });
15781                    }
15782                    args = [];
15783                    method = prefix = definition = block = '';
15784                };
15785                args = [];
15786                method = prefix = definition = block = '';
15787                backgroundImage.split("").forEach(function(c) {
15788                    if (mode === 0 && whitespace.indexOf(c) > -1) {
15789                        return;
15790                    }
15791                    switch(c) {
15792                        case '"':
15793                            if(!quote) {
15794                                quote = c;
15795                            } else if(quote === c) {
15796                                quote = null;
15797                            }
15798                            break;
15799                        case '(':
15800                            if(quote) {
15801                                break;
15802                            } else if(mode === 0) {
15803                                mode = 1;
15804                                block += c;
15805                                return;
15806                            } else {
15807                                numParen++;
15808                            }
15809                            break;
15810                        case ')':
15811                            if (quote) {
15812                                break;
15813                            } else if(mode === 1) {
15814                                if(numParen === 0) {
15815                                    mode = 0;
15816                                    block += c;
15817                                    appendResult();
15818                                    return;
15819                                } else {
15820                                    numParen--;
15821                                }
15822                            }
15823                            break;
15824
15825                        case ',':
15826                            if (quote) {
15827                                break;
15828                            } else if(mode === 0) {
15829                                appendResult();
15830                                return;
15831                            } else if (mode === 1) {
15832                                if (numParen === 0 && !method.match(/^url$/i)) {
15833                                    args.push(definition);
15834                                    definition = '';
15835                                    block += c;
15836                                    return;
15837                                }
15838                            }
15839                            break;
15840                    }
15841
15842                    block += c;
15843                    if (mode === 0) {
15844                        method += c;
15845                    } else {
15846                        definition += c;
15847                    }
15848                });
15849
15850                appendResult();
15851                return results;
15852            };
15853
15854        },{}],27:[function(_dereq_,module,exports){
15855            var GradientContainer = _dereq_('./gradientcontainer');
15856
15857            function WebkitGradientContainer(imageData) {
15858                GradientContainer.apply(this, arguments);
15859                this.type = imageData.args[0] === "linear" ? GradientContainer.TYPES.LINEAR 
15859: GradientContainer.TYPES.RADIAL;
15860            }
15861
15862            WebkitGradientContainer.prototype = Object.create(GradientContainer.prototype);
15863
15864            module.exports = WebkitGradientContainer;
15865
15866        },{"./gradientcontainer":9}],28:[function(_dereq_,module,exports){
15867            function XHR(url) {
15868                return new Promise(function(resolve, reject) {
15869                    var xhr = new XMLHttpRequest();
15870                    xhr.open('GET', url);
15871
15872                    xhr.onload = function() {
15873                        if (xhr.status === 200) {
15874                            resolve(xhr.responseText);
15875                        } else {
15876                            reject(new Error(xhr.statusText));
15877                        }
15878                    };
15879
15880                    xhr.onerror = function() {
15881                        reject(new Error("Network Error"));
15882                    };
15883
15884                    xhr.send();
15885                });
15886            }
15887
15888            module.exports = XHR;
15889
15890        },{}]},{},[4])(4)
15891    });
15892
15893    // Generated by CoffeeScript 1.4.0
15894
15895    /*
15896  # PNG.js
15897  # Copyright (c) 2011 Devon Govett
15898  # MIT LICENSE
15899  #
15900  #
15901  */
15902
15903
15904    (function(global) {
15905        var PNG;
15906
15907        PNG = (function() {
15908            var APNG_BLEND_OP_OVER, APNG_BLEND_OP_SOURCE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_NONE, APNG_DISPOSE_OP_PREVIOUS, makeImage, scratchCanvas, scratchCtx;
15909
15910            PNG.load = function(url, canvas, callback) {
15911                var xhr,
15912                    _this = this;
15913                if (typeof canvas === 'function') {
15914                    callback = canvas;
15915                }
15916                xhr = new XMLHttpRequest;
15917                xhr.open("GET", url, true);
15918                xhr.responseType = "arraybuffer";
15919                xhr.onload = function() {
15920                    var data, png;
15921                    data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
15922                    png = new PNG(data);
15923                    if (typeof (canvas != null ? canvas.getContext : void 0) === 'function') {
15924                        png.render(canvas);
15925                    }
15926                    return typeof callback === "function" ? callback(png) : void 0;
15927                };
15928                return xhr.send(null);
15929            };
15930
15931            APNG_DISPOSE_OP_NONE = 0;
15932
15933            APNG_DISPOSE_OP_BACKGROUND = 1;
15934
15935            APNG_DISPOSE_OP_PREVIOUS = 2;
15936
15937            APNG_BLEND_OP_SOURCE = 0;
15938
15939            APNG_BLEND_OP_OVER = 1;
15940
15941            function PNG(data) {
15942                var chunkSize, colors, palLen, delayDen, delayNum, frame, i, index, key, section, palShort, text, _i, _j, _ref;
15943                this.data = data;
15944                this.pos = 8;
15945                this.palette = [];
15946                this.imgData = [];
15947                this.transparency = {};
15948                this.animation = null;
15949                this.text = {};
15950                frame = null;
15951                while (true) {
15952                    chunkSize = this.readUInt32();
15953                    section = ((function() {
15954                        var _i, _results;
15955                        _results = [];
15956                        for (i = _i = 0; _i < 4; i = ++_i) {
15957                            _results.push(String.fromCharCode(this.data[this.pos++]));
15958                        }
15959                        return _results;
15960                    }).call(this)).join('');
15961                    switch (section) {
15962                        case 'IHDR':
15963                            this.width = this.readUInt32();
15964                            this.height = this.readUInt32();
15965                            this.bits = this.data[this.pos++];
15966                            this.colorType = this.data[this.pos++];
15967                            this.compressionMethod = this.data[this.pos++];
15968                            this.filterMethod = this.data[this.pos++];
15969                            this.interlaceMethod = this.data[this.pos++];
15970                            break;
15971                        case 'acTL':
15972                            this.animation = {
15973                                numFrames: this.readUInt32(),
15974                                numPlays: this.readUInt32() || Infinity,
15975                                frames: []
15976                            };
15977                            break;
15978                        case 'PLTE':
15979                            this.palette = this.read(chunkSize);
15980                            break;
15981                        case 'fcTL':
15982                            if (frame) {
15983                                this.animation.frames.push(frame);
15984                            }
15985                            this.pos += 4;
15986                            frame = {
15987                                width: this.readUInt32(),
15988                                height: this.readUInt32(),
15989                                xOffset: this.readUInt32(),
15990                                yOffset: this.readUInt32()
15991                            };
15992                            delayNum = this.readUInt16();
15993                            delayDen = this.readUInt16() || 100;
15994                            frame.delay = 1000 * delayNum / delayDen;
15995                            frame.disposeOp = this.data[this.pos++];
15996                            frame.blendOp = this.data[this.pos++];
15997                            frame.data = [];
15998                            break;
15999                        case 'IDAT':
16000                        case 'fdAT':
16001                            if (section === 'fdAT') {
16002                                this.pos += 4;
16003                                chunkSize -= 4;
16004                            }
16005                            data = (frame != null ? frame.data : void 0) || this.imgData;
16006                            for (i = _i = 0; 0 <= chunkSize ? _i < chunkSize : _i > chunkSize; i = 0 <= chunkSize ? ++_i : --_i) {
16007                                data.push(this.data[this.pos++]);
16008                            }
16009                            break;
16010                        case 'tRNS':
16011                            this.transparency = {};
16012                            switch (this.colorType) {
16013                                case 3:
16014                                    palLen = this.palette.length/3;
16015                                    this.transparency.indexed = this.read(chunkSize);
16016                                    if(this.transparency.indexed.length > palLen)
16017                                        throw new Error('More transparent colors than palette size');
16018                                    /*
16019                   * According to the PNG spec trns should be increased to the same size as palette if shorter
16020                   */
16021                                    //palShort = 255 - this.transparency.indexed.length;
16022                                    palShort = palLen - this.transparency.indexed.length;
16023                                    if (palShort > 0) {
16024                                        for (i = _j = 0; 0 <= palShort ? _j < palShort : _j > palShort; i = 0 <= palShort ? ++_j : --_j) {
16025                                            this.transparency.indexed.push(255);
16026                                        }
16027                                    }
16028                                    break;
16029                                case 0:
16030                                    this.transparency.grayscale = this.read(chunkSize)[0];
16031                                    break;
16032                                case 2:
16033                                    this.transparency.rgb = this.read(chunkSize);
16034                            }
16035                            break;
16036                        case 'tEXt':
16037                            text = this.read(chunkSize);
16038                            index = text.indexOf(0);
16039                            key = String.fromCharCode.apply(String, text.slice(0, index));
16040                            this.text[key] = String.fromCharCode.apply(String, text.slice(index + 1));
16041                            break;
16042                        case 'IEND':
16043                            if (frame) {
16044                                this.animation.frames.push(frame);
16045                            }
16046                            this.colors = (function() {
16047                                switch (this.colorType) {
16048                                    case 0:
16049                                    case 3:
16050                                    case 4:
16051                                        return 1;
16052                                    case 2:
16053                                    case 6:
16054                                        return 3;
16055                                }
16056                            }).call(this);
16057                            this.hasAlphaChannel = (_ref = this.colorType) === 4 || _ref === 6;
16058                            colors = this.colors + (this.hasAlphaChannel ? 1 : 0);
16059                            this.pixelBitlength = this.bits * colors;
16060                            this.colorSpace = (function() {
16061                                switch (this.colors) {
16062                                    case 1:
16063                                        return 'DeviceGray';
16064                                    case 3:
16065                                        return 'DeviceRGB';
16066                                }
16067                            }).call(this);
16068                            this.imgData = new Uint8Array(this.imgData);
16069                            return;
16070                        default:
16071                            this.pos += chunkSize;
16072                    }
16073                    this.pos += 4;
16074                    if (this.pos > this.data.length) {
16075                        throw new Error("Incomplete or corrupt PNG file");
16076                    }
16077                }
16078                return;
16079            }
16080
16081            PNG.prototype.read = function(bytes) {
16082                var i, _i, _results;
16083                _results = [];
16084                for (i = _i = 0; 0 <= bytes ? _i < bytes : _i > bytes; i = 0 <= bytes ? ++_i : --_i) {
16085                    _results.push(this.data[this.pos++]);
16086                }
16087                return _results;
16088            };
16089
16090            PNG.prototype.readUInt32 = function() {
16091                var b1, b2, b3, b4;
16092                b1 = this.data[this.pos++] << 24;
16093                b2 = this.data[this.pos++] << 16;
16094                b3 = this.data[this.pos++] << 8;
16095                b4 = this.data[this.pos++];
16096                return b1 | b2 | b3 | b4;
16097            };
16098
16099            PNG.prototype.readUInt16 = function() {
16100                var b1, b2;
16101                b1 = this.data[this.pos++] << 8;
16102                b2 = this.data[this.pos++];
16103                return b1 | b2;
16104            };
16105
16106            PNG.prototype.decodePixels = function(data) {
16107                var abyte, c, col, i, left, length, p, pa, paeth, pb, pc, pixelBytes, pixels, pos, row, scanlineLength, upper, upperLeft, _i, _j, _k, _l, _m;
16108                if (data == null) {
16109                    data = this.imgData;
16110                }
16111                if (data.length === 0) {
16112                    return new Uint8Array(0);
16113                }
16114                data = new FlateStream(data);
16115                data = data.getBytes();
16116                pixelBytes = this.pixelBitlength / 8;
16117                scanlineLength = pixelBytes * this.width;
16118                pixels = new Uint8Array(scanlineLength * this.height);
16119                length = data.length;
16120                row = 0;
16121                pos = 0;
16122                c = 0;
16123                while (pos < length) {
16124                    switch (data[pos++]) {
16125                        case 0:
16126                            for (i = _i = 0; _i < scanlineLength; i = _i += 1) {
16127                                pixels[c++] = data[pos++];
16128                            }
16129                            break;
16130                        case 1:
16131                            for (i = _j = 0; _j < scanlineLength; i = _j += 1) {
16132                                abyte = data[pos++];
16133                                left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
16134                                pixels[c++] = (abyte + left) % 256;
16135                            }
16136                            break;
16137                        case 2:
16138                            for (i = _k = 0; _k < scanlineLength; i = _k += 1) {
16139                                abyte = data[pos++];
16140                                col = (i - (i % pixelBytes)) / pixelBytes;
16141                                upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
16142                                pixels[c++] = (upper + abyte) % 256;
16143                            }
16144                            break;
16145                        case 3:
16146                            for (i = _l = 0; _l < scanlineLength; i = _l += 1) {
16147                                abyte = data[pos++];
16148                                col = (i - (i % pixelBytes)) / pixelBytes;
16149                                left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
16150                                upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
16151                                pixels[c++] = (abyte + Math.floor((left + upper) / 2)) % 256;
16152                            }
16153                            break;
16154                        case 4:
16155                            for (i = _m = 0; _m < scanlineLength; i = _m += 1) {
16156                                abyte = data[pos++];
16157                                col = (i - (i % pixelBytes)) / pixelBytes;
16158                                left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
16159                                if (row === 0) {
16160                                    upper = upperLeft = 0;
16161                                } else {
16162                                    upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
16163                                    upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)];
16164                                }
16165                                p = left + upper - upperLeft;
16166                                pa = Math.abs(p - left);
16167                                pb = Math.abs(p - upper);
16168                                pc = Math.abs(p - upperLeft);
16169                                if (pa <= pb && pa <= pc) {
16170                                    paeth = left;
16171                                } else if (pb <= pc) {
16172                                    paeth = upper;
16173                                } else {
16174                                    paeth = upperLeft;
16175                                }
16176                                pixels[c++] = (abyte + paeth) % 256;
16177                            }
16178                            break;
16179                        default:
16180                            throw new Error("Invalid filter algorithm: " + data[pos - 1]);
16181                    }
16182                    row++;
16183                }
16184                return pixels;
16185            };
16186
16187            PNG.prototype.decodePalette = function() {
16188                var c, i, length, palette, pos, ret, transparency, _i, _ref, _ref1;
16189                palette = this.palette;
16190                transparency = this.transparency.indexed || [];
16191                ret = new Uint8Array((transparency.length || 0) + palette.length);
16192                pos = 0;
16193                length = palette.length;
16194                c = 0;
16195                for (i = _i = 0, _ref = palette.length; _i < _ref; i = _i += 3) {
16196                    ret[pos++] = palette[i];
16197                    ret[pos++] = palette[i + 1];
16198                    ret[pos++] = palette[i + 2];
16199                    ret[pos++] = (_ref1 = transparency[c++]) != null ? _ref1 : 255;
16200                }
16201                return ret;
16202            };
16203
16204            PNG.prototype.copyToImageData = function(imageData, pixels) {
16205                var alpha, colors, data, i, input, j, k, length, palette, v, _ref;
16206                colors = this.colors;
16207                palette = null;
16208                alpha = this.hasAlphaChannel;
16209                if (this.palette.length) {
16210                    palette = (_ref = this._decodedPalette) != null ? _ref : this._decodedPalette = this.decodePalette();
16211                    colors = 4;
16212                    alpha = true;
16213                }
16214                data = imageData.data || imageData;
16215                length = data.length;
16216                input = palette || pixels;
16217                i = j = 0;
16218                if (colors === 1) {
16219                    while (i < length) {
16220                        k = palette ? pixels[i / 4] * 4 : j;
16221                        v = input[k++];
16222                        data[i++] = v;
16223                        data[i++] = v;
16224                        data[i++] = v;
16225                        data[i++] = alpha ? input[k++] : 255;
16226                        j = k;
16227                    }
16228                } else {
16229                    while (i < length) {
16230                        k = palette ? pixels[i / 4] * 4 : j;
16231                        data[i++] = input[k++];
16232                        data[i++] = input[k++];
16233                        data[i++] = input[k++];
16234                        data[i++] = alpha ? input[k++] : 255;
16235                        j = k;
16236                    }
16237                }
16238            };
16239
16240            PNG.prototype.decode = function() {
16241                var ret;
16242                ret = new Uint8Array(this.width * this.height * 4);
16243                this.copyToImageData(ret, this.decodePixels());
16244                return ret;
16245            };
16246
16247            try {
16248                scratchCanvas = global.document.createElement('canvas');
16249                scratchCtx = scratchCanvas.getContext('2d');
16250            } catch(e) {
16251                return -1;
16252            }
16253
16254            makeImage = function(imageData) {
16255                var img;
16256                scratchCtx.width = imageData.width;
16257                scratchCtx.height = imageData.height;
16258                scratchCtx.clearRect(0, 0, imageData.width, imageData.height);
16259                scratchCtx.putImageData(imageData, 0, 0);
16260                img = new Image;
16261                img.src = scratchCanvas.toDataURL();
16262                return img;
16263            };
16264
16265            PNG.prototype.decodeFrames = function(ctx) {
16266                var frame, i, imageData, pixels, _i, _len, _ref, _results;
16267                if (!this.animation) {
16268                    return;
16269                }
16270                _ref = this.animation.frames;
16271                _results = [];
16272                for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
16273                    frame = _ref[i];
16274                    imageData = ctx.createImageData(frame.width, frame.height);
16275                    pixels = this.decodePixels(new Uint8Array(frame.data));
16276                    this.copyToImageData(imageData, pixels);
16277                    frame.imageData = imageData;
16278                    _results.push(frame.image = makeImage(imageData));
16279                }
16280                return _results;
16281            };
16282
16283            PNG.prototype.renderFrame = function(ctx, number) {
16284                var frame, frames, prev;
16285                frames = this.animation.frames;
16286                frame = frames[number];
16287                prev = frames[number - 1];
16288                if (number === 0) {
16289                    ctx.clearRect(0, 0, this.width, this.height);
16290                }
16291                if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_BACKGROUND) {
16292                    ctx.clearRect(prev.xOffset, prev.yOffset, prev.width, prev.height);
16293                } else if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_PREVIOUS) {
16294                    ctx.putImageData(prev.imageData, prev.xOffset, prev.yOffset);
16295                }
16296                if (frame.blendOp === APNG_BLEND_OP_SOURCE) {
16297                    ctx.clearRect(frame.xOffset, frame.yOffset, frame.width, frame.height);
16298                }
16299                return ctx.drawImage(frame.image, frame.xOffset, frame.yOffset);
16300            };
16301
16302            PNG.prototype.animate = function(ctx) {
16303                var doFrame, frameNumber, frames, numFrames, numPlays, _ref,
16304                    _this = this;
16305                frameNumber = 0;
16306                _ref = this.animation, numFrames = _ref.numFrames, frames = _ref.frames, numPlays = _ref.numPlays;
16307                return (doFrame = function() {
16308                    var f, frame;
16309                    f = frameNumber++ % numFrames;
16310                    frame = frames[f];
16311                    _this.renderFrame(ctx, f);
16312                    if (numFrames > 1 && frameNumber / numFrames < numPlays) {
16313                        return _this.animation._timeout = setTimeout(doFrame, frame.delay);
16314                    }
16315                })();
16316            };
16317
16318            PNG.prototype.stopAnimation = function() {
16319                var _ref;
16320                return clearTimeout((_ref = this.animation) != null ? _ref._timeout : void 0);
16321            };
16322
16323            PNG.prototype.render = function(canvas) {
16324                var ctx, data;
16325                if (canvas._png) {
16326                    canvas._png.stopAnimation();
16327                }
16328                canvas._png = this;
16329                canvas.width = this.width;
16330                canvas.height = this.height;
16331                ctx = canvas.getContext("2d");
16332                if (this.animation) {
16333                    this.decodeFrames(ctx);
16334                    return this.animate(ctx);
16335                } else {
16336                    data = ctx.createImageData(this.width, this.height);
16337                    this.copyToImageData(data, this.decodePixels());
16338                    return ctx.putImageData(data, 0, 0);
16339                }
16340            };
16341
16342            return PNG;
16343
16344        })();
16345
16346        global.PNG = PNG;
16347
16348    })(typeof window !== "undefined" && window || undefined);
16349
16350    /*
16351   * Extracted from pdf.js
16352   * https://github.com/andreasgal/pdf.js
16353   *
16354   * Copyright (c) 2011 Mozilla Foundation
16355   *
16356   * Contributors: Andreas Gal <[email protected]>
16357   *               Chris G Jones <[email protected]>
16358   *               Shaon Barman <[email protected]>
16359   *               Vivien Nicolas <[email protected]>
16360   *               Justin D'Arcangelo <[email protected]>
16361   *               Yury Delendik
16362   *
16363   *
16364   */
16365
16366    var DecodeStream = (function() {
16367        function constructor() {
16368            this.pos = 0;
16369            this.bufferLength = 0;
16370            this.eof = false;
16371            this.buffer = null;
16372        }
16373
16374        constructor.prototype = {
16375            ensureBuffer: function decodestream_ensureBuffer(requested) {
16376                var buffer = this.buffer;
16377                var current = buffer ? buffer.byteLength : 0;
16378                if (requested < current)
16379                    return buffer;
16380                var size = 512;
16381                while (size < requested)
16382                    size <<= 1;
16383                var buffer2 = new Uint8Array(size);
16384                for (var i = 0; i < current; ++i)
16385                    buffer2[i] = buffer[i];
16386                return this.buffer = buffer2;
16387            },
16388            getByte: function decodestream_getByte() {
16389                var pos = this.pos;
16390                while (this.bufferLength <= pos) {
16391                    if (this.eof)
16392                        return null;
16393                    this.readBlock();
16394                }
16395                return this.buffer[this.pos++];
16396            },
16397            getBytes: function decodestream_getBytes(length) {
16398                var pos = this.pos;
16399
16400                if (length) {
16401                    this.ensureBuffer(pos + length);
16402                    var end = pos + length;
16403
16404                    while (!this.eof && this.bufferLength < end)
16405                        this.readBlock();
16406
16407                    var bufEnd = this.bufferLength;
16408                    if (end > bufEnd)
16409                        end = bufEnd;
16410                } else {
16411                    while (!this.eof)
16412                        this.readBlock();
16413
16414                    var end = this.bufferLength;
16415                }
16416
16417                this.pos = end;
16418                return this.buffer.subarray(pos, end);
16419            },
16420            lookChar: function decodestream_lookChar() {
16421                var pos = this.pos;
16422                while (this.bufferLength <= pos) {
16423                    if (this.eof)
16424                        return null;
16425                    this.readBlock();
16426                }
16427                return String.fromCharCode(this.buffer[this.pos]);
16428            },
16429            getChar: function decodestream_getChar() {
16430                var pos = this.pos;
16431                while (this.bufferLength <= pos) {
16432                    if (this.eof)
16433                        return null;
16434                    this.readBlock();
16435                }
16436                return String.fromCharCode(this.buffer[this.pos++]);
16437            },
16438            makeSubStream: function decodestream_makeSubstream(start, length, dict) {
16439                var end = start + length;
16440                while (this.bufferLength <= end && !this.eof)
16441                    this.readBlock();
16442                return new Stream(this.buffer, start, length, dict);
16443            },
16444            skip: function decodestream_skip(n) {
16445                if (!n)
16446                    n = 1;
16447                this.pos += n;
16448            },
16449            reset: function decodestream_reset() {
16450                this.pos = 0;
16451            }
16452        };
16453
16454        return constructor;
16455    })();
16456
16457    var FlateStream = (function() {
16458        if (typeof Uint32Array === 'undefined') {
16459            return undefined;
16460        }
16461        var codeLenCodeMap = new Uint32Array([
16462            16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
16463        ]);
16464
16465        var lengthDecode = new Uint32Array([
16466            0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,
16467            0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,
16468            0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073,
16469            0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102
16470        ]);
16471
16472        var distDecode = new Uint32Array([
16473            0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,
16474            0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,
16475            0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01,
16476            0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001
16477        ]);
16478
16479        var fixedLitCodeTab = [new Uint32Array([
16480            0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,
16481            0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,
16482            0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0,
16483            0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0,
16484            0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8,
16485            0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8,
16486            0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8,
16487            0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8,
16488            0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4,
16489            0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4,
16490            0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4,
16491            0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4,
16492            0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc,
16493            0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec,
16494            0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc,
16495            0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc,
16496            0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2,
16497            0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2,
16498            0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2,
16499            0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2,
16500            0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca,
16501            0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea,
16502            0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da,
16503            0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa,
16504            0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6,
16505            0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6,
16506            0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6,
16507            0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6,
16508            0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce,
16509            0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee,
16510            0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de,
16511            0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe,
16512            0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1,
16513            0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1,
16514            0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1,
16515            0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1,
16516            0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9,
16517            0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9,
16518            0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9,
16519            0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9,
16520            0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5,
16521            0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5,
16522            0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5,
16523            0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5,
16524            0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd,
16525            0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed,
16526            0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd,
16527            0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd,
16528            0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3,
16529            0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3,
16530            0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3,
16531            0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3,
16532            0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb,
16533            0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb,
16534            0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db,
16535            0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb,
16536            0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7,
16537            0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7,
16538            0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7,
16539            0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 
165390x900f7,
16540            0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf,
16541            0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef,
16542            0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df,
16543            0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff
16544        ]), 9];
16545
16546        var fixedDistCodeTab = [new Uint32Array([
16547            0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,
16548            0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,
16549            0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d,
16550            0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
16551        ]), 5];
16552
16553        function error(e) {
16554            throw new Error(e)
16555        }
16556
16557        function constructor(bytes) {
16558            //var bytes = stream.getBytes();
16559            var bytesPos = 0;
16560
16561            var cmf = bytes[bytesPos++];
16562            var flg = bytes[bytesPos++];
16563            if (cmf == -1 || flg == -1)
16564                error('Invalid header in flate stream');
16565            if ((cmf & 0x0f) != 0x08)
16566                error('Unknown compression method in flate stream');
16567            if ((((cmf << 8) + flg) % 31) != 0)
16568                error('Bad FCHECK in flate stream');
16569            if (flg & 0x20)
16570                error('FDICT bit set in flate stream');
16571
16572            this.bytes = bytes;
16573            this.bytesPos = bytesPos;
16574
16575            this.codeSize = 0;
16576            this.codeBuf = 0;
16577
16578            DecodeStream.call(this);
16579        }
16580
16581        constructor.prototype = Object.create(DecodeStream.prototype);
16582
16583        constructor.prototype.getBits = function(bits) {
16584            var codeSize = this.codeSize;
16585            var codeBuf = this.codeBuf;
16586            var bytes = this.bytes;
16587            var bytesPos = this.bytesPos;
16588
16589            var b;
16590            while (codeSize < bits) {
16591                if (typeof (b = bytes[bytesPos++]) == 'undefined')
16592                    error('Bad encoding in flate stream');
16593                codeBuf |= b << codeSize;
16594                codeSize += 8;
16595            }
16596            b = codeBuf & ((1 << bits) - 1);
16597            this.codeBuf = codeBuf >> bits;
16598            this.codeSize = codeSize -= bits;
16599            this.bytesPos = bytesPos;
16600            return b;
16601        };
16602
16603        constructor.prototype.getCode = function(table) {
16604            var codes = table[0];
16605            var maxLen = table[1];
16606            var codeSize = this.codeSize;
16607            var codeBuf = this.codeBuf;
16608            var bytes = this.bytes;
16609            var bytesPos = this.bytesPos;
16610
16611            while (codeSize < maxLen) {
16612                var b;
16613                if (typeof (b = bytes[bytesPos++]) == 'undefined')
16614                    error('Bad encoding in flate stream');
16615                codeBuf |= (b << codeSize);
16616                codeSize += 8;
16617            }
16618            var code = codes[codeBuf & ((1 << maxLen) - 1)];
16619            var codeLen = code >> 16;
16620            var codeVal = code & 0xffff;
16621            if (codeSize == 0 || codeSize < codeLen || codeLen == 0)
16622                error('Bad encoding in flate stream');
16623            this.codeBuf = (codeBuf >> codeLen);
16624            this.codeSize = (codeSize - codeLen);
16625            this.bytesPos = bytesPos;
16626            return codeVal;
16627        };
16628
16629        constructor.prototype.generateHuffmanTable = function(lengths) {
16630            var n = lengths.length;
16631
16632            // find max code length
16633            var maxLen = 0;
16634            for (var i = 0; i < n; ++i) {
16635                if (lengths[i] > maxLen)
16636                    maxLen = lengths[i];
16637            }
16638
16639            // build the table
16640            var size = 1 << maxLen;
16641            var codes = new Uint32Array(size);
16642            for (var len = 1, code = 0, skip = 2;
16643                 len <= maxLen;
16644                 ++len, code <<= 1, skip <<= 1) {
16645                for (var val = 0; val < n; ++val) {
16646                    if (lengths[val] == len) {
16647                        // bit-reverse the code
16648                        var code2 = 0;
16649                        var t = code;
16650                        for (var i = 0; i < len; ++i) {
16651                            code2 = (code2 << 1) | (t & 1);
16652                            t >>= 1;
16653                        }
16654
16655                        // fill the table entries
16656                        for (var i = code2; i < size; i += skip)
16657                            codes[i] = (len << 16) | val;
16658
16659                        ++code;
16660                    }
16661                }
16662            }
16663
16664            return [codes, maxLen];
16665        };
16666
16667        constructor.prototype.readBlock = function() {
16668            function repeat(stream, array, len, offset, what) {
16669                var repeat = stream.getBits(len) + offset;
16670                while (repeat-- > 0)
16671                    array[i++] = what;
16672            }
16673
16674            // read block header
16675            var hdr = this.getBits(3);
16676            if (hdr & 1)
16677                this.eof = true;
16678            hdr >>= 1;
16679
16680            if (hdr == 0) { // uncompressed block
16681                var bytes = this.bytes;
16682                var bytesPos = this.bytesPos;
16683                var b;
16684
16685                if (typeof (b = bytes[bytesPos++]) == 'undefined')
16686                    error('Bad block header in flate stream');
16687                var blockLen = b;
16688                if (typeof (b = bytes[bytesPos++]) == 'undefined')
16689                    error('Bad block header in flate stream');
16690                blockLen |= (b << 8);
16691                if (typeof (b = bytes[bytesPos++]) == 'undefined')
16692                    error('Bad block header in flate stream');
16693                var check = b;
16694                if (typeof (b = bytes[bytesPos++]) == 'undefined')
16695                    error('Bad block header in flate stream');
16696                check |= (b << 8);
16697                if (check != (~blockLen & 0xffff))
16698                    error('Bad uncompressed block length in flate stream');
16699
16700                this.codeBuf = 0;
16701                this.codeSize = 0;
16702
16703                var bufferLength = this.bufferLength;
16704                var buffer = this.ensureBuffer(bufferLength + blockLen);
16705                var end = bufferLength + blockLen;
16706                this.bufferLength = end;
16707                for (var n = bufferLength; n < end; ++n) {
16708                    if (typeof (b = bytes[bytesPos++]) == 'undefined') {
16709                        this.eof = true;
16710                        break;
16711                    }
16712                    buffer[n] = b;
16713                }
16714                this.bytesPos = bytesPos;
16715                return;
16716            }
16717
16718            var litCodeTable;
16719            var distCodeTable;
16720            if (hdr == 1) { // compressed block, fixed codes
16721                litCodeTable = fixedLitCodeTab;
16722                distCodeTable = fixedDistCodeTab;
16723            } else if (hdr == 2) { // compressed block, dynamic codes
16724                var numLitCodes = this.getBits(5) + 257;
16725                var numDistCodes = this.getBits(5) + 1;
16726                var numCodeLenCodes = this.getBits(4) + 4;
16727
16728                // build the code lengths code table
16729                var codeLenCodeLengths = Array(codeLenCodeMap.length);
16730                var i = 0;
16731                while (i < numCodeLenCodes)
16732                    codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3);
16733                var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
16734
16735                // build the literal and distance code tables
16736                var len = 0;
16737                var i = 0;
16738                var codes = numLitCodes + numDistCodes;
16739                var codeLengths = new Array(codes);
16740                while (i < codes) {
16741                    var code = this.getCode(codeLenCodeTab);
16742                    if (code == 16) {
16743                        repeat(this, codeLengths, 2, 3, len);
16744                    } else if (code == 17) {
16745                        repeat(this, codeLengths, 3, 3, len = 0);
16746                    } else if (code == 18) {
16747                        repeat(this, codeLengths, 7, 11, len = 0);
16748                    } else {
16749                        codeLengths[i++] = len = code;
16750                    }
16751                }
16752
16753                litCodeTable =
16754                    this.generateHuffmanTable(codeLengths.slice(0, numLitCodes));
16755                distCodeTable =
16756                    this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes));
16757            } else {
16758                error('Unknown block type in flate stream');
16759            }
16760
16761            var buffer = this.buffer;
16762            var limit = buffer ? buffer.length : 0;
16763            var pos = this.bufferLength;
16764            while (true) {
16765                var code1 = this.getCode(litCodeTable);
16766                if (code1 < 256) {
16767                    if (pos + 1 >= limit) {
16768                        buffer = this.ensureBuffer(pos + 1);
16769                        limit = buffer.length;
16770                    }
16771                    buffer[pos++] = code1;
16772                    continue;
16773                }
16774                if (code1 == 256) {
16775                    this.bufferLength = pos;
16776                    return;
16777                }
16778                code1 -= 257;
16779                code1 = lengthDecode[code1];
16780                var code2 = code1 >> 16;
16781                if (code2 > 0)
16782                    code2 = this.getBits(code2);
16783                var len = (code1 & 0xffff) + code2;
16784                code1 = this.getCode(distCodeTable);
16785                code1 = distDecode[code1];
16786                code2 = code1 >> 16;
16787                if (code2 > 0)
16788                    code2 = this.getBits(code2);
16789                var dist = (code1 & 0xffff) + code2;
16790                if (pos + len >= limit) {
16791                    buffer = this.ensureBuffer(pos + len);
16792                    limit = buffer.length;
16793                }
16794                for (var k = 0; k < len; ++k, ++pos)
16795                    buffer[pos] = buffer[pos - dist];
16796            }
16797        };
16798
16799        return constructor;
16800    })();
16801
16802    /**
16803     * JavaScript Polyfill functions for jsPDF
16804     * Collected from public resources by
16805     * https://github.com/diegocr
16806     */
16807
16808    (function (global) {
16809        var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
16810
16811        if (typeof global.btoa === 'undefined') {
16812            global.btoa = function(data) {
16813                //  discuss at: http://phpjs.org/functions/base64_encode/
16814                // original by: Tyler Akins (http://rumkin.com)
16815                // improved by: Bayron Guevara
16816                // improved by: Thunder.m
16817                // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
16818                // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
16819                // improved by: Rafal Kukawski (http://kukawski.pl)
16820                // bugfixed by: Pellentesque Malesuada
16821                //   example 1: base64_encode('Kevin van Zonneveld');
16822                //   returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
16823
16824                var o1,o2,o3,h1,h2,h3,h4,bits,i = 0,ac = 0,enc = '',tmp_arr = [];
16825
16826                if (!data) {
16827                    return data;
16828                }
16829
16830                do { // pack three octets into four hexets
16831                    o1 = data.charCodeAt(i++);
16832                    o2 = data.charCodeAt(i++);
16833                    o3 = data.charCodeAt(i++);
16834
16835                    bits = o1 << 16 | o2 << 8 | o3;
16836
16837                    h1 = bits >> 18 & 0x3f;
16838                    h2 = bits >> 12 & 0x3f;
16839                    h3 = bits >> 6 & 0x3f;
16840                    h4 = bits & 0x3f;
16841
16842                    // use hexets to index into b64, and append result to encoded string
16843                    tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
16844                } while (i < data.length);
16845
16846                enc = tmp_arr.join('');
16847
16848                var r = data.length % 3;
16849
16850                return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
16851            };
16852        }
16853
16854        if (typeof global.atob === 'undefined') {
16855            global.atob = function(data) {
16856                //  discuss at: http://phpjs.org/functions/base64_decode/
16857                // original by: Tyler Akins (http://rumkin.com)
16858                // improved by: Thunder.m
16859                // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
16860                // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
16861                //    input by: Aman Gupta
16862                //    input by: Brett Zamir (http://brett-zamir.me)
16863                // bugfixed by: Onno Marsman
16864                // bugfixed by: Pellentesque Malesuada
16865                // bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
16866                //   example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
16867                //   returns 1: 'Kevin van Zonneveld'
16868
16869                var o1,o2,o3,h1,h2,h3,h4,bits,i = 0,ac = 0,dec = '',tmp_arr = [];
16870
16871                if (!data) {
16872                    return data;
16873                }
16874
16875                data += '';
16876
16877                do { // unpack four hexets into three octets using index points in b64
16878                    h1 = b64.indexOf(data.charAt(i++));
16879                    h2 = b64.indexOf(data.charAt(i++));
16880                    h3 = b64.indexOf(data.charAt(i++));
16881                    h4 = b64.indexOf(data.charAt(i++));
16882
16883                    bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
16884
16885                    o1 = bits >> 16 & 0xff;
16886                    o2 = bits >> 8 & 0xff;
16887                    o3 = bits & 0xff;
16888
16889                    if (h3 == 64) {
16890                        tmp_arr[ac++] = String.fromCharCode(o1);
16891                    } else if (h4 == 64) {
16892                        tmp_arr[ac++] = String.fromCharCode(o1, o2);
16893                    } else {
16894                        tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
16895                    }
16896                } while (i < data.length);
16897
16898                dec = tmp_arr.join('');
16899
16900                return dec;
16901            };
16902        }
16903
16904        if (!Array.prototype.map) {
16905            Array.prototype.map = function(fun /*, thisArg */) {
16906                if (this === void 0 || this === null || typeof fun !== "function")
16907                    throw new TypeError();
16908
16909                var t = Object(this), len = t.length >>> 0, res = new Array(len);
16910                var thisArg = arguments.length > 1 ? arguments[1] : void 0;
16911                for (var i = 0; i < len; i++) {
16912                    // NOTE: Absolute correctness would demand Object.defineProperty
16913                    //       be used.  But this method is fairly new, and failure is
16914                    //       possible only if Object.prototype or Array.prototype
16915                    //       has a property |i| (very unlikely), so use a less-correct
16916                    //       but more portable alternative.
16917                    if (i in t)
16918                        res[i] = fun.call(thisArg, t[i], i, t);
16919                }
16920
16921                return res;
16922            };
16923        }
16924
16925
16926        if(!Array.isArray) {
16927            Array.isArray = function(arg) {
16928                return Object.prototype.toString.call(arg) === '[object Array]';
16929            };
16930        }
16931
16932        if (!Array.prototype.forEach) {
16933            Array.prototype.forEach = function(fun, thisArg) {
16934                "use strict";
16935
16936                if (this === void 0 || this === null || typeof fun !== "function")
16937                    throw new TypeError();
16938
16939                var t = Object(this), len = t.length >>> 0;
16940                for (var i = 0; i < len; i++) {
16941                    if (i in t)
16942                        fun.call(thisArg, t[i], i, t);
16943                }
16944            };
16945        }
16946
16947        if (!Object.keys) {
16948            Object.keys = (function () {
16949                'use strict';
16950
16951                var hasOwnProperty = Object.prototype.hasOwnProperty,
16952                    hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
16953                    dontEnums = ['toString','toLocaleString','valueOf','hasOwnProperty',
16954                        'isPrototypeOf','propertyIsEnumerable','constructor'],
16955                    dontEnumsLength = dontEnums.length;
16956
16957                return function (obj) {
16958                    if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
16959                        throw new TypeError();
16960                    }
16961                    var result = [], prop, i;
16962
16963                    for (prop in obj) {
16964                        if (hasOwnProperty.call(obj, prop)) {
16965                            result.push(prop);
16966                        }
16967                    }
16968
16969                    if (hasDontEnumBug) {
16970                        for (i = 0; i < dontEnumsLength; i++) {
16971                            if (hasOwnProperty.call(obj, dontEnums[i])) {
16972                                result.push(dontEnums[i]);
16973                            }
16974                        }
16975                    }
16976                    return result;
16977                };
16978            }());
16979        }
16980
16981        if (!String.prototype.trim) {
16982            String.prototype.trim = function () {
16983                return this.replace(/^\s+|\s+$/g, '');
16984            };
16985        }
16986        if (!String.prototype.trimLeft) {
16987            String.prototype.trimLeft = function() {
16988                return this.replace(/^\s+/g, "");
16989            };
16990        }
16991        if (!String.prototype.trimRight) {
16992            String.prototype.trimRight = function() {
16993                return this.replace(/\s+$/g, "");
16994            };
16995        }
16996
16997    })(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined);
16998
16999    var jsPDF = jsPDF;
17000
17001    return jsPDF;
17002
17003}
vendor: 4 bytes, line 17003
17003));

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.