PageSourceSearch

https://www.cfxway.com/wp-content/plugins/cfx-connect//scripts/jspdf.debug.js

js cfxway.com collected 2026-10-09 21:40:40 UTC 602,210 bytes, 17,364 lines download raw bytes

vendor: 5,244 bytes, lines 1-227
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
7var _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 && obj !== Symbol.prototype ? "symbol" : typeof obj;
11};
12
13
14
15
16
17var asyncGenerator = function () {
18  function AwaitValue(value) {
19    this.value = value;
20  }
21
22  function AsyncGenerator(gen) {
23    var front, back;
24
25    function send(key, arg) {
26      return new Promise(function (resolve, reject) {
27        var request = {
28          key: key,
29          arg: arg,
30          resolve: resolve,
31          reject: reject,
32          next: null
33        };
34
35        if (back) {
36          back = back.next = request;
37        } else {
38          front = back = request;
39          resume(key, arg);
40        }
41      });
42    }
43
44    function resume(key, arg) {
45      try {
46        var result = gen[key](arg);
47        var value = result.value;
48
49        if (value instanceof AwaitValue) {
50          Promise.resolve(value.value).then(function (arg) {
51            resume("next", arg);
52          }, function (arg) {
53            resume("throw", arg);
54          });
55        } else {
56          settle(result.done ? "return" : "normal", result.value);
57        }
58      } catch (err) {
59        settle("throw", err);
60      }
61    }
62
63    function settle(type, value) {
64      switch (type) {
65        case "return":
66          front.resolve({
67            value: value,
68            done: true
69          });
70          break;
71
72        case "throw":
73          front.reject(value);
74          break;
75
76        default:
77          front.resolve({
78            value: value,
79            done: false
80          });
81          break;
82      }
83
84      front = front.next;
85
86      if (front) {
87        resume(front.key, front.arg);
88      } else {
89        back = null;
90      }
91    }
92
93    this._invoke = send;
94
95    if (typeof gen.return !== "function") {
96      this.return = undefined;
97    }
98  }
99
100  if (typeof Symbol === "function" && Symbol.asyncIterator) {
101    AsyncGenerator.prototype[Symbol.asyncIterator] = function () {
102      return this;
103    };
104  }
105
106  AsyncGenerator.prototype.next = function (arg) {
107    return this._invoke("next", arg);
108  };
109
110  AsyncGenerator.prototype.throw = function (arg) {
111    return this._invoke("throw", arg);
112  };
113
114  AsyncGenerator.prototype.return = function (arg) {
115    return this._invoke("return", arg);
116  };
117
118  return {
119    wrap: function (fn) {
120      return function () {
121        return new AsyncGenerator(fn.apply(this, arguments));
122      };
123    },
124    await: function (value) {
125      return new AwaitValue(value);
126    }
127  };
128}();
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144var get$1 = function get$1(object, property, receiver) {
145  if (object === null) object = Function.prototype;
146  var desc = Object.getOwnPropertyDescriptor(object, property);
147
148  if (desc === undefined) {
149    var parent = Object.getPrototypeOf(object);
150
151    if (parent === null) {
152      return undefined;
153    } else {
154      return get$1(parent, property, receiver);
155    }
156  } else if ("value" in desc) {
157    return desc.value;
158  } else {
159    var getter = desc.get;
160
161    if (getter === undefined) {
162      return undefined;
163    }
164
165    return getter.call(receiver);
166  }
167};
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185var set$1 = function set$1(object, property, value, receiver) {
186  var desc = Object.getOwnPropertyDescriptor(object, property);
187
188  if (desc === undefined) {
189    var parent = Object.getPrototypeOf(object);
190
191    if (parent !== null) {
192      set$1(parent, property, value, receiver);
193    }
194  } else if ("value" in desc && desc.writable) {
195    desc.value = value;
196  } else {
197    var setter = desc.set;
198
199    if (setter !== undefined) {
200      setter.call(receiver, value);
201    }
202  }
203
204  return value;
205};
206
207/** @preserve
208 * jsPDF - PDF Document creation from JavaScript
209 * Version 1.3.3 Built on 2017-02-23T15:31:28.692Z
210 *                           CommitID c2fa0d3c14
211 *
212 * Copyright (c) 2010-2016 James Hall <[email protected]>, https://github.com/MrRio/jsPDF
213 *               2010 Aaron Spike, https://github.com/acspike
214 *               2012 Willow Systems Corporation, willow-systems.com
215 *               2012 Pablo Hess, https://github.com/pablohess
216 *               2012 Florian Jenett, https://github.com/fjenett
217 *               2013 Warren Weckesser, https://github.com/warrenweckesser
218 *               2013 Youssef Beddad, https://github.com/lifof
219 *               2013 Lee Driscoll, https://github.com/lsdriscoll
220 *               2013 Stefan Slonevskiy, https://github.com/stefslon
221 *               2013 Jeremy Morel, https://github.com/jmorel
222 *               2013 Christoph Hartmann, https://github.com/chris-rock
223 *               2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
224 *               2014 James Makes, https://github.com/dollaruw
225 *               2014 Diego Casorran, https://github.com/diegocr
226 *               2014 Steven Spungin, https://github.com/Flamenco
227 *               2014 Kenneth Glassey, https://github.com/Gavver
227s
228 *
229 * Licensed under the MIT License
230 *
231 * Contributor(s):
232 *    siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,
233 *    kim3er, mfo, alnorth, Flamenco
234 */
235
236/**
237 * Creates new jsPDF document object instance.
238 *
239 * @class
240 * @param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l")
241 * @param unit        Measurement unit to be used when coordinates are specified.
242 *                    One of "pt" (points), "mm" (Default), "cm", "in"
243 * @param format      One of 'pageFormats' as shown below, default: a4
244 * @returns {jsPDF}
245 * @name jsPDF
246 */
247var jsPDF = function (global) {
248  'use strict';
249
250  var pdfVersion = '1.3',
251      pageFormats = { // Size in pt of various paper formats
252    'a0': [2383.94, 3370.39],
253    'a1': [1683.78, 2383.94],
254    'a2': [1190.55, 1683.78],
255    'a3': [841.89, 1190.55],
256    'a4': [595.28, 841.89],
257    'a5': [419.53, 595.28],
258    'a6': [297.64, 419.53],
259    'a7': [209.76, 297.64],
260    'a8': [147.40, 209.76],
261    'a9': [104.88, 147.40],
262    'a10': [73.70, 104.88],
263    'b0': [2834.65, 4008.19],
264    'b1': [2004.09, 2834.65],
265    'b2': [1417.32, 2004.09],
266    'b3': [1000.63, 1417.32],
267    'b4': [708.66, 1000.63],
268    'b5': [498.90, 708.66],
269    'b6': [354.33, 498.90],
270    'b7': [249.45, 354.33],
271    'b8': [175.75, 249.45],
272    'b9': [124.72, 175.75],
273    'b10': [87.87, 124.72],
274    'c0': [2599.37, 3676.54],
275    'c1': [1836.85, 2599.37],
276    'c2': [1298.27, 1836.85],
277    'c3': [918.43, 1298.27],
278    'c4': [649.13, 918.43],
279    'c5': [459.21, 649.13],
280    'c6': [323.15, 459.21],
281    'c7': [229.61, 323.15],
282    'c8': [161.57, 229.61],
283    'c9': [113.39, 161.57],
284    'c10': [79.37, 113.39],
285    'dl': [311.81, 623.62],
286    'letter': [612, 792],
287    'government-letter': [576, 756],
288    'legal': [612, 1008],
289    'junior-legal': [576, 360],
290    'ledger': [1224, 792],
291    'tabloid': [792, 1224],
292    'credit-card': [153, 243]
293  };
294
295  /**
296   * jsPDF's Internal PubSub Implementation.
297   * See mrrio.github.io/jsPDF/doc/symbols/PubSub.html
298   * Backward compatible rewritten on 2014 by
299   * Diego Casorran, https://github.com/diegocr
300   *
301   * @class
302   * @name PubSub
303   * @ignore This should not be in the public docs.
304   */
305  function PubSub(context) {
306    var topics = {};
307
308    this.subscribe = function (topic, callback, once) {
309      if (typeof callback !== 'function') {
310        return false;
311      }
312
313      if (!topics.hasOwnProperty(topic)) {
314        topics[topic] = {};
315      }
316
317      var id = Math.random().toString(35);
318      topics[topic][id] = [callback, !!once];
319
320      return id;
321    };
322
323    this.unsubscribe = function (token) {
324      for (var topic in topics) {
325        if (topics[topic][token]) {
326          delete topics[topic][token];
327          return true;
328        }
329      }
330      return false;
331    };
332
333    this.publish = function (topic) {
334      if (topics.hasOwnProperty(topic)) {
335        var args = Array.prototype.slice.call(arguments, 1),
336            idr = [];
337
338        for (var id in topics[topic]) {
339          var sub = topics[topic][id];
340          try {
341            sub[0].apply(context, args);
342          } catch (ex) {
343            if (global.console) {
344              console.error('jsPDF PubSub Error', ex.message, ex);
345            }
346          }
347          if (sub[1]) idr.push(id);
348        }
349        if (idr.length) idr.forEach(this.unsubscribe);
350      }
351    };
352  }
353
354  /**
355   * @constructor
356   * @private
357   */
358  function jsPDF(orientation, unit, format, compressPdf) {
359    var options = {};
360
361    if ((typeof orientation === 'undefined' ? 'undefined' : _typeof(orientation)) === 'object') {
362      options = orientation;
363
364      orientation = options.orientation;
365      unit = options.unit || unit;
366      format = options.format || format;
367      compressPdf = options.compress || options.compressPdf || compressPdf;
368    }
369
370    // Default options
371    unit = unit || 'mm';
372    format = format || 'a4';
373    orientation = ('' + (orientation || 'P')).toLowerCase();
374
375    var format_as_string = ('' + format).toLowerCase(),
376        compress = !!compressPdf && typeof Uint8Array === 'function',
377        textColor = options.textColor || '0 g',
378        drawColor = options.drawColor || '0 G',
379        activeFontSize = options.fontSize || 16,
380        lineHeightProportion = options.lineHeight || 1.15,
381        lineWidth = options.lineWidth || 0.200025,
382        // 2mm
383    objectNumber = 2,
384        // 'n' Current object number
385    outToPages = !1,
386        // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content
387    offsets = [],
388        // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes.
389    fonts = {},
390        // collection of font objects, where key is fontKey - a dynamically created label for a given font.
391    fontmap = {},
392        // mapping structure fontName > fontStyle > font key - performance layer. See addFont()
393    activeFontKey,
394        // will be string representing the KEY of the font as combination of fontName + fontStyle
395    k,
396        // Scale factor
397    tmp,
398        page = 0,
399        currentPage,
400        pages = [],
401        pagesContext = [],
402        // same index as pages and pagedim
403    pagedim = [],
404        content = [],
405        additionalObjects = [],
406        lineCapID = 0,
407        lineJoinID = 0,
408        content_length = 0,
409        pageWidth,
410        pageHeight,
411        pageMode,
412        zoomMode,
413        layoutMode,
414        documentProperties = {
415      'title': '',
416      'subject': '',
417      'author': '',
418      'keywords': '',
419      'creator': ''
420    },
421        API = {},
422        events = new PubSub(API),
423
424
425    /////////////////////
426    // Private functions
427    /////////////////////
428    f2 = function f2(number) {
429      return number.toFixed(2); // Ie, %.2f
430    },
431        f3 = function f3(number) {
432      return number.toFixed(3); // Ie, %.3f
433    },
434        padd2 = function padd2(number) {
435      return ('0' + parseInt(number)).slice(-2);
436    },
437        out = function out(string) {
438      if (outToPages) {
439        /* set by beginPage */
440        pages[currentPage].push(string);
441      } else {
442        // +1 for '\n' that will be used to join 'content'
443        content_length += string.length + 1;
444        content.push(string);
445      }
446    },
447        newObject = function newObject() {
448      // Begin a new object
449      objectNumber++;
450      offsets[objectNumber] = content_length;
451      out(objectNumber + ' 0 obj');
452      return objectNumber;
453    },
454
455    // Does not output the object until after the pages have been output.
456    // Returns an object containing the objectId and content.
457    // All pages have been added so the object ID can be estimated to start right after.
458    // This does not modify the current objectNumber;  It must be updated after the newObjects are output.
459    newAdditionalObject = function newAdditionalObject() {
460      var objId = pages.length * 2 + 1;
461      objId += additionalObjects.length;
462      var obj = {
463        objId: objId,
464        content: ''
465      };
466      additionalObjects.push(obj);
467      return obj;
468    },
469
470    // Does not output the object.  The caller must call newObjectDeferredBegin(oid) before outputing any data
471    newObjectDeferred = function newObjectDeferred() {
472      objectNumber++;
473      offsets[objectNumber] = function () {
474        return content_length;
475      };
476      return objectNumber;
477    },
478        newObjectDeferredBegin = function newObjectDeferredBegin(oid) {
479      offsets[oid] = content_length;
480    },
481        putStream = function putStream(str) {
482      out('stream');
483      out(str);
484      out('endstream');
485    },
486        putPages = function putPages() {
487      var n,
488          p,
489          arr,
490          i,
491          deflater,
492          adler32,
493          adler32cs,
494          wPt,
495          hPt,
496          pageObjectNumbers = [];
497
498      adler32cs = global.adler32cs || jsPDF.adler32cs;
499      if (compress && typeof adler32cs === 'undefined') {
500        compress = false;
501      }
502
503      // outToPages = false as set in endDocument(). out() writes to content.
504
505      for (n = 1; n <= page; n++) {
506        pageObjectNumbers.push(newObject());
507        wPt = (pageWidth = pagedim[n].width) * k;
508        hPt = (pageHeight = pagedim[n].height) * k;
509        out('<</Type /Page');
510        out('/Parent 1 0 R');
511        out('/Resources 2 0 R');
512        out('/MediaBox [0 0 ' + f2(wPt) + ' ' + f2(hPt) + ']');
513        // Added for annotation plugin
514        events.publish('putPage', {
515          pageNumber: n,
516          page: pages[n]
517        });
518        out('/Contents ' + (objectNumber + 1) + ' 0 R');
519        out('>>');
520        out('endobj');
521
522        // Page content
523        p = pages[n].join('\n');
524        newObject();
525        if (compress) {
526          arr = [];
527          i = p.length;
528          while (i--) {
529            arr[i] = p.charCodeAt(i);
530          }
531          adler32 = adler32cs.from(p);
532          deflater = new Deflater(6);
533          deflater.append(new Uint8Array(arr));
534          p = deflater.flush();
535          arr = new Uint8Array(p.length + 6);
536          arr.set(new Uint8Array([120, 156])), arr.set(p, 2);
537          arr.set(new Uint8Array([adler32 & 0xFF, adler32 >> 8 & 0xFF, adler32 >> 16 & 0xFF, adler32 >> 24 & 0xFF]), p.length + 2);
538          p = String.fromCharCode.apply(null, arr);
539          out('<</Length ' + p.length + ' /Filter [/FlateDecode]>>');
540        } else {
541          out('<</Length ' + p.length + '>>');
542        }
543        putStream(p);
544        out('endobj');
545      }
546      offsets[1] = content_length;
547      out('1 0 obj');
548      out('<</Type /Pages');
549      var kids = '/Kids [';
550      for (i = 0; i < page; i++) {
551        kids += pageObjectNumbers[i] + ' 0 R ';
552      }
553      out(kids + ']');
554      out('/Count ' + page);
555      out('>>');
556      out('endobj');
557      events.publish('postPutPages');
558    },
559        putFont = function putFont(font) {
560      font.objectNumber = newObject();
561      out('<</BaseFont/' + font.PostScriptName + '/Type/Font');
562      if (typeof font.encoding === 'string') {
563        out('/Encoding/' + font.encoding);
564      }
565      out('/Subtype/Type1>>');
566      out('endobj');
567    },
568        putFonts = function putFonts() {
569      for (var fontKey in fonts) {
570        if (fonts.hasOwnProperty(fontKey)) {
571          putFont(fonts[fontKey]);
572        }
573      }
574    },
575        putXobjectDict = function putXobjectDict() {
576      // Loop through images, or other data objects
577      events.publish('putXobjectDict');
578    },
579        putResourceDictionary = function putResourceDictionary() {
580      out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
581      out('/Font <<');
582
583      // Do this for each font, the '1' bit is the index of the font
584      for (var fontKey in fonts) {
585        if (fonts.hasOwnProperty(fontKey)) {
586          out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R');
587        }
588      }
589      out('>>');
590      out('/XObject <<');
591      putXobjectDict();
592      out('>>');
593    },
594        putResources = function putResources() {
595      putFonts();
596      events.publish('putResources');
597      // Resource dictionary
598      offsets[2] = content_length;
599      out('2 0 obj');
600      out('<<');
601      putResourceDictionary();
602      out('>>');
603      out('endobj');
604      events.publish('postPutResources');
605    },
606        putAdditionalObjects = function putAdditionalObjects() {
607      events.publish('putAdditionalObjects');
608      for (var i = 0; i < additionalObjects.length; i++) {
609        var obj = additionalObjects[i];
610        offsets[obj.objId] = content_length;
611        out(obj.objId + ' 0 obj');
612        out(obj.content);
613        out('endobj');
614      }
615      objectNumber += additionalObjects.length;
616      events.publish('postPutAdditionalObjects');
617    },
618        addToFontDictionary = function addToFontDictionary(fontKey, fontName, fontStyle) {
619      // this is mapping structure for quick font key lookup.
620      // returns the KEY of the font (ex: "F1") for a given
621      // pair of font name and type (ex: "Arial". "Italic")
622      if (!fontmap.hasOwnProperty(fontName)) {
623        fontmap[fontName] = {};
624      }
625      fontmap[fontName][fontStyle] = fontKey;
626    },
627
628    /**
629     * FontObject describes a particular font as member of an instnace of jsPDF
630     *
631     * It's a collection of properties like 'id' (to be used in PDF stream),
632     * 'fontName' (font's family name), 'fontStyle' (font's style variant label)
633     *
634     * @class
635     * @public
636     * @property id {String} PDF-document-instance-specific label assinged to the font.
637     * @property PostScriptName {String} PDF specification full name for the font
638     * @property encoding {Object} Encoding_name-to-Font_metrics_object mapping.
639     * @name FontObject
640     * @ignore This should not be in the public docs.
641     */
642    addFont = function addFont(PostScriptName, fontName, fontStyle, encoding) {
643      var fontKey = 'F' + (Object.keys(fonts).length + 1).toString(10),
644
645      // This is FontObject
646      font = fonts[fontKey] = {
647        'id': fontKey,
648        'PostScriptName': PostScriptName,
649        'fontName': fontName,
650        'fontStyle': fontStyle,
651        'encoding': encoding,
652        'metadata': {}
653      };
654      addToFontDictionary(fontKey, fontName, fontStyle);
655      events.publish('addFont', font);
656
657      return fontKey;
658    },
659        addFonts = function addFonts() {
660
661      var HELVETICA = "helvetica",
662          TIMES = "times",
663          COURIER = "courier",
664          NORMAL = "normal",
665          BOLD = "bold",
666          ITALIC = "italic",
667          BOLD_ITALIC = "bolditalic",
668          encoding = 'StandardEncoding',
669          ZAPF = "zapfdingbats",
670          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]];
671
672      for (var i = 0, l = standardFonts.length; i < l; i++) {
673        var fontKey = addFont(standardFonts[i][0], standardFonts[i][1], standardFonts[i][2], encoding);
674
675        // adding aliases for standard fonts, this time matching the capitalization
676        var parts = standardFonts[i][0].split('-');
677        addToFontDictionary(fontKey, parts[0], parts[1] || '');
678      }
679      events.publish('addFonts', {
680        fonts: fonts,
681        dictionary: fontmap
682      });
683    },
684        SAFE = function __safeCall(fn) {
685      fn.foo = function __safeCallWrapper() {
686        try {
687          return fn.apply(this, arguments);
688        } catch (e) {
689          var stack = e.stack || '';
690          if (~stack.indexOf(' at ')) stack = stack.split(" at ")[1];
691          var m = "Error in function " + stack.split("\n")[0].split('<')[0] + ": " + e.message;
692          if (global.console) {
693            global.console.error(m, e);
694            if (global.alert) alert(m);
695          } else {
696            throw new Error(m);
697          }
698        }
699      };
700      fn.foo.bar = fn;
701      return fn.foo;
702    },
703        to8bitStream = function to8bitStream(text, flags) {
704      /**
705       * PDF 1.3 spec:
706       * "For text strings encoded in Unicode, the first two bytes must be 254 followed by
707       * 255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts
708       * with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely
709       * to be a meaningful beginning of a word or phrase.) The remainder of the
710       * string consists of Unicode character codes, according to the UTF-16 encoding
711       * specified in the Unicode standard, version 2.0. Commonly used Unicode values
712       * are represented as 2 bytes per character, with the high-order byte appearing first
713       * in the string."
714       *
715       * In other words, if there are chars in a string with char code above 255, we
716       * recode the string to UCS2 BE - string doubles in length and BOM is prepended.
717       *
718       * HOWEVER!
719       * Actual *content* (body) text (as opposed to strings used in document properties etc)
720       * does NOT expect BOM. There, it is treated as a literal GID (Glyph ID)
721       *
722       * Because of Adobe's focus on "you subset your fonts!" you are not supposed to have
723       * a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could
724       * fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode
725       * code page. There, however, all characters in the stream are treated as GIDs,
726       * including BOM, which is the reason we need to skip BOM in content text (i.e. that
727       * that is tied to a font).
728       *
729       * To signal this "special" PDFEscape / to8bitStream handling mode,
730       * API.text() function sets (unless you overwrite it with manual values
731       * given to API.text(.., flags) )
732       * flags.autoencode = true
733       * flags.noBOM = true
734       *
735       * ===================================================================================
736       * `flags` properties relied upon:
737       *   .sourceEncoding = string with encoding label.
738       *                     "Unicode" by default. = encoding of the incoming text.
739       *                     pass some non-existing encoding name
740       *                     (ex: 'Do not touch my strings! I know what I am doing.')
741       *                     to make encoding code skip the encoding step.
742       *   .outputEncoding = Either valid PDF encoding name
743       *                     (must be supported by jsPDF font metrics, otherwise no encoding)
744       *                     or a JS object, where key = sourceCharCode, value = outputCharCode
745       *                     missing keys will be treated as: sourceCharCode === outputCharCode
746       *   .noBOM
747       *       See comment higher above for explanation for why this is important
748       *   .autoencode
749       *       See comment higher above for explanation for why this is important
750       */
751
752      var i, l, sourceEncoding, encodingBlock, outputEncoding, newtext, isUnicode, ch, bch;
753
754      flags = flags || {};
755      sourceEncoding = flags.sourceEncoding || 'Unicode';
756      outputEncoding = flags.outputEncoding;
757
758      // This 'encoding' section relies on font metrics format
759      // attached to font objects by, among others,
760      // "Willow Systems' standard_font_metrics plugin"
761      // see jspdf.plugin.standard_font_metrics.js for format
762      // of the font.metadata.encoding Object.
763      // It should be something like
764      //   .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}}
765      //   .widths = {0:width, code:width, ..., 'fof':divisor}
766      //   .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...}
767      if ((flags.autoencode || outputEncoding) && fonts[activeFontKey].metadata && fonts[activeFontKey].metadata[sourceEncoding] && fonts[activeFontKey].metadata[sourceEncoding].encoding) {
768        encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding;
769
770        // each font has default encoding. Some have it clearly defined.
771        if (!outputEncoding && fonts[activeFontKey].encoding) {
772          outputEncoding = fonts[activeFontKey].encoding;
773        }
774
775        // Hmmm, the above did not work? Let's try again, in different place.
776        if (!outputEncoding && encodingBlock.codePages) {
777          outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default
778        }
779
780        if (typeof outputEncoding === 'string') {
781          outputEncoding = encodingBlock[outputEncoding];
782        }
783        // we want output encoding to be a JS Object, where
784        // key = sourceEncoding's character code and
785        // value = outputEncoding's character code.
786        if (outputEncoding) {
787          isUnicode = false;
788          newtext = [];
789          for (i = 0, l = text.length; i < l; i++) {
790            ch = outputEncoding[text.charCodeAt(i)];
791            if (ch) {
792              newtext.push(String.fromCharCode(ch));
793            } else {
794              newtext.push(text[i]);
795            }
796
797            // since we are looping over chars anyway, might as well
798            // check for residual unicodeness
799            if (newtext[i].charCodeAt(0) >> 8) {
800              /* more than 255 */
801              isUnicode = true;
802            }
803          }
804          text = newtext.join('');
805        }
806      }
807
808      i = text.length;
809      // isUnicode may be set to false above. Hence the triple-equal to undefined
810      while (isUnicode === undefined && i !== 0) {
811        if (text.charCodeAt(i - 1) >> 8) {
812          /* more than 255 */
813          isUnicode = true;
814        }
815        i--;
816      }
817      if (!isUnicode) {
818        return text;
819      }
820
821      newtext = flags.noBOM ? [] : [254, 255];
822      for (i = 0, l = text.length; i < l; i++) {
823        ch = text.charCodeAt(i);
824        bch = ch >> 8; // divide by 256
825        if (bch >> 8) {
826          /* something left after dividing by 256 second time */
827          throw new Error("Character at position " + i + " of string '" + text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE");
828        }
829        newtext.push(bch);
830        newtext.push(ch - (bch << 8));
831      }
832      return String.fromCharCode.apply(undefined, newtext);
833    },
834        pdfEscape = function pdfEscape(text, flags) {
835      /**
836       * Replace '/', '(', and ')' with pdf-safe versions
837       *
838       * Doing to8bitStream does NOT make this PDF display unicode text. For that
839       * we also need to reference a unicode font and embed it - royal pain in the rear.
840       *
841       * There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars,
842       * which JavaScript Strings are happy to provide. So, while we still cannot display
843       * 2-byte characters property, at least CONDITIONALLY converting (entire string containing)
844       * 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF
845       * is still parseable.
846       * This will allow immediate support for unicode in document properties strings.
847       */
848      return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
849    },
850        putInfo = function putInfo() {
851      out('/Producer (jsPDF ' + jsPDF.version + ')');
852      for (var key in documentProperties) {
853        if (documentProperties.hasOwnProperty(key) && documentProperties[key]) {
854          out('/' + key.substr(0, 1).toUpperCase() + key.substr(1) + ' (' + pdfEscape(documentProperties[key]) + ')');
855        }
856      }
857      var created = new Date(),
858          tzoffset = created.getTimezoneOffset(),
859          tzsign = tzoffset < 0 ? '+' : '-',
860          tzhour = Math.floor(Math.abs(tzoffset / 60)),
861          tzmin = Math.abs(tzoffset % 60),
862          tzstr = [tzsign, padd2(tzhour), "'", padd2(tzmin), "'"].join('');
863      out(['/CreationDate (D:', created.getFullYear(), padd2(created.getMonth() + 1), padd2(created.getDate()), padd2(created.getHours()), padd2(created.getMinutes()), padd2(created.getSeconds()), tzstr, ')'].join(''));
864    },
865        putCatalog = function putCatalog() {
866      out('/Type /Catalog');
867      out('/Pages 1 0 R');
868      // PDF13ref Section 7.2.1
869      if (!zoomMode) zoomMode = 'fullwidth';
870      switch (zoomMode) {
871        case 'fullwidth':
872          out('/OpenAction [3 0 R /FitH null]');
873          break;
874        case 'fullheight':
875          out('/OpenAction [3 0 R /FitV null]');
876          break;
877        case 'fullpage':
878          out('/OpenAction [3 0 R /Fit]');
879          break;
880        case 'original':
881          out('/OpenAction [3 0 R /XYZ null null 1]');
882          break;
883        default:
884          var pcn = '' + zoomMode;
885          if (pcn.substr(pcn.length - 1) === '%') zoomMode = parseInt(zoomMode) / 100;
886          if (typeof zoomMode === 'number') {
887            out('/OpenAction [3 0 R /XYZ null null ' + f2(zoomMode) + ']');
888          }
889      }
890      if (!layoutMode) layoutMode = 'continuous';
891      switch (layoutMode) {
892        case 'continuous':
893          out('/PageLayout /OneColumn');
894          break;
895        case 'single':
896          out('/PageLayout /SinglePage');
897          break;
898        case 'two':
899        case 'twoleft':
900          out('/PageLayout /TwoColumnLeft');
901          break;
902        case 'tworight':
903          out('/PageLayout /TwoColumnRight');
904          break;
905      }
906      if (pageMode) {
907        /**
908         * A name object specifying how the document should be displayed when opened:
909         * UseNone      : Neither document outline nor thumbnail images visible -- DEFAULT
910         * UseOutlines  : Document outline visible
911         * UseThumbs    : Thumbnail images visible
912         * FullScreen   : Full-screen mode, with no menu bar, window controls, or any other window visible
913         */
914        out('/PageMode /' + pageMode);
915      }
916      events.publish('putCatalog');
917    },
918        putTrailer = function putTrailer() {
919      out('/Size ' + (objectNumber + 1));
920      out('/Root ' + objectNumber + ' 0 R');
921      out('/Info ' + (objectNumber - 1) + ' 0 R');
922    },
923        beginPage = function beginPage(width, height) {
924      // Dimensions are stored as user units and converted to points on output
925      var orientation = typeof height === 'string' && height.toLowerCase();
926      if (typeof width === 'string') {
927        var format = width.toLowerCase();
928        if (pageFormats.hasOwnProperty(format)) {
929          width = pageFormats[format][0] / k;
930          height = pageFormats[format][1] / k;
931        }
932      }
933      if (Array.isArray(width)) {
934        height = width[1];
935        width = width[0];
936      }
937      if (orientation) {
938        switch (orientation.substr(0, 1)) {
939          case 'l':
940            if (height > width) orientation = 's';
941            break;
942          case 'p':
943            if (width > height) orientation = 's';
944            break;
945        }
946        if (orientation === 's') {
947          tmp = width;
948          width = height;
949          height = tmp;
950        }
951      }
952      outToPages = true;
953      pages[++page] = [];
954      pagedim[page] = {
955        width: Number(width) || pageWidth,
956        height: Number(height) || pageHeight
957      };
958      pagesContext[page] = {};
959      _setPage(page);
960    },
961        _addPage = function _addPage() {
962      beginPage.apply(this, arguments);
963      // Set line width
964      out(f2(lineWidth * k) + ' w');
965      // Set draw color
966      out(drawColor);
967      // resurrecting non-default line caps, joins
968      if (lineCapID !== 0) {
969        out(lineCapID + ' J');
970      }
971      if (lineJoinID !== 0) {
972        out(lineJoinID + ' j');
973      }
974      events.publish('addPage', {
975        pageNumber: page
976      });
977    },
978        _deletePage = function _deletePage(n) {
979      if (n > 0 && n <= page) {
980        pages.splice(n, 1);
981        pagedim.splice(n, 1);
982        page--;
983        if (currentPage > page) {
984          currentPage = page;
985        }
986        this.setPage(currentPage);
987      }
988    },
989        _setPage = function _setPage(n) {
990      if (n > 0 && n <= page) {
991        currentPage = n;
992        pageWidth = pagedim[n].width;
993        pageHeight = pagedim[n].height;
994      }
995    },
996
997    /**
998     * Returns a document-specific font key - a label assigned to a
999     * font name + font type combination at the time the font was added
1000     * to the font inventory.
1001     *
1002     * Font key is used as label for the desired font for a block of text
1003     * to be added to the PDF document stream.
1004     * @private
1005     * @function
1006     * @param fontName {String} can be undefined on "falthy" to indicate "use current"
1007     * @param fontStyle {String} can be undefined on "falthy" to indicate "use current"
1008     * @returns {String} Font key.
1009     */
1010    _getFont = function _getFont(fontName, fontStyle) {
1011      var key;
1012
1013      fontName = fontName !== undefined ? fontName : fonts[activeFontKey].fontName;
1014      fontStyle = fontStyle !== undefined ? fontStyle : fonts[activeFontKey].fontStyle;
1015
1016      if (fontName !== undefined) {
1017        fontName = fontName.toLowerCase();
1018      }
1019      switch (fontName) {
1020        case 'sans-serif':
1021        case 'verdana':
1022        case 'arial':
1023        case 'helvetica':
1024          fontName = 'helvetica';
1025          break;
1026        case 'fixed':
1027        case 'monospace':
1028        case 'terminal':
1029        case 'courier':
1030          fontName = 'courier';
1031          break;
1032        case 'serif':
1033        case 'cursive':
1034        case 'fantasy':
1035        default:
1036          fontName = 'times';
1037          break;
1038      }
1039
1040      try {
1041        // get a string like 'F3' - the KEY corresponding tot he font + type combination.
1042        key = fontmap[fontName][fontStyle];
1043      } catch (e) {}
1044
1045      if (!key) {
1046        //throw new Error("Unable to look up font label for font '" + fontName + "', '"
1047        //+ fontStyle + "'. Refer to getFontList() for available fonts.");
1048        key = fontmap['times'][fontStyle];
1049        if (key == null) {
1050          key = fontmap['times']['normal'];
1051        }
1052      }
1053      return key;
1054    },
1055        buildDocument = function buildDocument() {
1056      outToPages = false; // switches out() to content
1057
1058      objectNumber = 2;
1059      content_length = 0;
1060      content = [];
1061      offsets = [];
1062      additionalObjects = [];
1063      // Added for AcroForm
1064      events.publish('buildDocument');
1065
1066      // putHeader()
1067      out('%PDF-' + pdfVersion);
1068
1069      putPages();
1070
1071      // Must happen after putPages
1072      // Modifies current object Id
1073      putAdditionalObjects();
1074
1075      putResources();
1076
1077      // Info
1078      newObject();
1079      out('<<');
1080      putInfo();
1081      out('>>');
1082      out('endobj');
1083
1084      // Catalog
1085      newObject();
1086      out('<<');
1087      putCatalog();
1088      out('>>');
1089      out('endobj');
1090
1091      // Cross-ref
1092      var o = content_length,
1093          i,
1094          p = "0000000000";
1095      out('xref');
1096      out('0 ' + (objectNumber + 1));
1097      out(p + ' 65535 f ');
1098      for (i = 1; i <= objectNumber; i++) {
1099        var offset = offsets[i];
1100        if (typeof offset === 'function') {
1101          out((p + offsets[i]()).slice(-10) + ' 00000 n ');
1102        } else {
1103          out((p + offsets[i]).slice(-10) + ' 00000 n ');
1104        }
1105      }
1106      // Trailer
1107      out('trailer');
1108      out('<<');
1109      putTrailer();
1110      out('>>');
1111      out('startxref');
1112      out('' + o);
1113      out('%%EOF');
1114
1115      outToPages = true;
1116
1117      return content.join('\n');
1118    },
1119        getStyle = function getStyle(style) {
1120      // see path-painting operators in PDF spec
1121      var op = 'S'; // stroke
1122      if (style === 'F') {
1123        op = 'f'; // fill
1124      } else if (style === 'FD' || style === 'DF') {
1125        op = 'B'; // both
1126      } else if (style === 'f' || style === 'f*' || style === 'B' || style === 'B*') {
1127        /*
1128         Allow direct use of these PDF path-painting operators:
1129         - f	fill using nonzero winding number rule
1130         - f*	fill using even-odd rule
1131         - B	fill then stroke with fill using non-zero winding number rule
1132         - B*	fill then stroke with fill using even-odd rule
1133         */
1134        op = style;
1135      }
1136      return op;
1137    },
1138        getArrayBuffer = function getArrayBuffer() {
1139      var data = buildDocument(),
1140          len = data.length,
1141          ab = new ArrayBuffer(len),
1142          u8 = new Uint8Array(ab);
1143
1144      while (len--) {
1145        u8[len] = data.charCodeAt(len);
1146      }return ab;
1147    },
1148        getBlob = function getBlob() {
1149      return new Blob([getArrayBuffer()], {
1150        type: "application/pdf"
1151      });
1152    },
1153
1154    /**
1155     * Generates the PDF document.
1156     *
1157     * If `type` argument is undefined, output is raw body of resulting PDF returned as a string.
1158     *
1159     * @param {String} type A string identifying one of the possible output types.
1160     * @param {Object} options An object providing some additional signalling to PDF generator.
1161     * @function
1162     * @returns {jsPDF}
1163     * @methodOf jsPDF#
1164     * @name output
1165     */
1166    _output = SAFE(function (type, options) {
1167      var datauri = ('' + type).substr(0, 6) === 'dataur' ? 'data:application/pdf;base64,' + btoa(buildDocument()) : 0;
1168
1169      switch (type) {
1170        case undefined:
1171          return buildDocument();
1172        case 'save':
1173          if (navigator.getUserMedia) {
1174            if (global.URL === undefined || global.URL.createObjectURL === undefined) {
1175              return API.output('dataurlnewwindow');
1176            }
1177          }
1178          saveAs(getBlob(), options);
1179          if (typeof saveAs.unload === 'function') {
1180            if (global.setTimeout) {
1181              setTimeout(saveAs.unload, 911);
1182            }
1183          }
1184          break;
1185        case 'arraybuffer':
1186          return getArrayBuffer();
1187        case 'blob':
1188          return getBlob();
1189        case 'bloburi':
1190        case 'bloburl':
1191          // User is responsible of calling revokeObjectURL
1192          return global.URL && global.URL.createObjectURL(getBlob()) || void 0;
1193        case 'datauristring':
1194        case 'dataurlstring':
1195          return datauri;
1196        case 'dataurlnewwindow':
1197          var nW = global.open(datauri);
1198          if (nW || typeof safari === "undefined") return nW;
1199        /* pass through */
1200        case 'datauri':
1201        case 'dataurl':
1202          return global.document.location.href = datauri;
1203        default:
1204          throw new Error('Output type "' + type + '" is not supported.');
1205      }
1206      // @TODO: Add different output options
1207    });
1208
1209    switch (unit) {
1210      case 'pt':
1211        k = 1;
1212        break;
1213      case 'mm':
1214        k = 72 / 25.4000508;
1215        break;
1216      case 'cm':
1217        k = 72 / 2.54000508;
1218        break;
1219      case 'in':
1220        k = 72;
1221        break;
1222      case 'px':
1223        k = 96 / 72;
1224        break;
1225      case 'pc':
1226        k = 12;
1227        break;
1228      case 'em':
1229        k = 12;
1230        break;
1231      case 'ex':
1232        k = 6;
1233        break;
1234      default:
1235        throw 'Invalid unit: ' + unit;
1236    }
1237
1238    //---------------------------------------
1239    // Public API
1240
1241    /**
1242     * Object exposing internal API to plugins
1243     * @public
1244     */
1245    API.internal = {
1246      'pdfEscape': pdfEscape,
1247      'getStyle': getStyle,
1248      /**
1249       * Returns {FontObject} describing a particular font.
1250       * @public
1251       * @function
1252       * @param fontName {String} (Optional) Font's family name
1253       * @param fontStyle {String} (Optional) Font's style variation name (Example:"Italic")
1254       * @returns {FontObject}
1255       */
1256      'getFont': function getFont() {
1257        return fonts[_getFont.apply(API, arguments)];
1258      },
1259      'getFontSize': function getFontSize() {
1260        return activeFontSize;
1261      },
1262      'getLineHeight': function getLineHeight() {
1263        return activeFontSize * lineHeightProportion;
1264      },
1265      'write': function write(string1 /*, string2, string3, etc */) {
1266        out(arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' '));
1267      },
1268      'getCoordinateString': function getCoordinateString(value) {
1269        return f2(value * k);
1270      },
1271      'getVerticalCoordinateString': function getVerticalCoordinateString(value) {
1272        return f2((pageHeight - value) * k);
1273      },
1274      'collections': {},
1275      'newObject': newObject,
1276      'newAdditionalObject': newAdditionalObject,
1277      'newObjectDeferred': newObjectDeferred,
1278      'newObjectDeferredBegin': newObjectDeferredBegin,
1279      'putStream': putStream,
1280      'events': events,
1281      // ratio that you use in multiplication of a given "size" number to arrive to 'point'
1282      // units of measurement.
1283      // scaleFactor is set at initialization of the document and calculated against the stated
1284      // default measurement units for the document.
1285      // If default is "mm", k is the number that will turn number in 'mm' into 'points' number.
1286      // through multiplication.
1287      'scaleFactor': k,
1288      'pageSize': {
1289        get width() {
1290          return pageWidth;
1291        },
1292        get height() {
1293          return pageHeight;
1294        }
1295      },
1296      'output': function output(type, options) {
1297        return _output(type, options);
1298      },
1299      'getNumberOfPages': function getNumberOfPages() {
1300        return pages.length - 1;
1301      },
1302      'pages': pages,
1303      'out': out,
1304      'f2': f2,
1305      'getPageInfo': function getPageInfo(pageNumberOneBased) {
1306        var objId = (pageNumberOneBased - 1) * 2 + 3;
1307        return {
1308          objId: objId,
1309          pageNumber: pageNumberOneBased,
1310          pageContext: pagesContext[pageNumberOneBased]
1311        };
1312      },
1313      'getCurrentPageInfo': function getCurrentPageInfo() {
1314        var objId = (currentPage - 1) * 2 + 3;
1315        return {
1316          objId: objId,
1317          pageNumber: currentPage,
1318          pageContext: pagesContext[currentPage]
1319        };
1320      },
1321      'getPDFVersion': function getPDFVersion() {
1322        return pdfVersion;
1323      }
1324    };
1325
1326    /**
1327     * Adds (and transfers the focus to) new page to the PDF document.
1328     * @function
1329     * @returns {jsPDF}
1330     *
1331     * @methodOf jsPDF#
1332     * @name addPage
1333     */
1334    API.addPage = function () {
1335      _addPage.apply(this, arguments);
1336      return this;
1337    };
1338    /**
1339     * Adds (and transfers the focus to) new page to the PDF document.
1340     * @function
1341     * @returns {jsPDF}
1342     *
1343     * @methodOf jsPDF#
1344     * @name setPage
1345     * @param {Number} page Switch the active page to the page number specified
1346     * @example
1347     * doc = jsPDF()
1348     * doc.addPage()
1349     * doc.addPage()
1350     * doc.text('I am on page 3', 10, 10)
1351     * doc.setPage(1)
1352     * doc.text('I am on page 1', 10, 10)
1353     */
1354    API.setPage = function () {
1355      _setPage.apply(this, arguments);
1356      return this;
1357    };
1358    API.insertPage = function (beforePage) {
1359      this.addPage();
1360      this.movePage(currentPage, beforePage);
1361      return this;
1362    };
1363    API.movePage = function (targetPage, beforePage) {
1364      if (targetPage > beforePage) {
1365        var tmpPages = pages[targetPage];
1366        var tmpPagedim = pagedim[targetPage];
1367        var tmpPagesContext = pagesContext[targetPage];
1368        for (var i = targetPage; i > beforePage; i--) {
1369          pages[i] = pages[i - 1];
1370          pagedim[i] = pagedim[i - 1];
1371          pagesContext[i] = pagesContext[i - 1];
1372        }
1373        pages[beforePage] = tmpPages;
1374        pagedim[beforePage] = tmpPagedim;
1375        pagesContext[beforePage] = tmpPagesContext;
1376        this.setPage(beforePage);
1377      } else if (targetPage < beforePage) {
1378        var tmpPages = pages[targetPage];
1379        var tmpPagedim = pagedim[targetPage];
1380        var tmpPagesContext = pagesContext[targetPage];
1381        for (var i = targetPage; i < beforePage; i++) {
1382          pages[i] = pages[i + 1];
1383          pagedim[i] = pagedim[i + 1];
1384          pagesContext[i] = pagesContext[i + 1];
1385        }
1386        pages[beforePage] = tmpPages;
1387        pagedim[beforePage] = tmpPagedim;
1388        pagesContext[beforePage] = tmpPagesContext;
1389        this.setPage(beforePage);
1390      }
1391      return this;
1392    };
1393
1394    API.deletePage = function () {
1395      _deletePage.apply(this, arguments);
1396      return this;
1397    };
1398
1399    /**
1400     * Set the display mode options of the page like zoom and layout.
1401     *
1402     * @param {integer|String} zoom   You can pass an integer or percentage as
1403     * a string. 2 will scale the document up 2x, '200%' will scale up by the
1404     * same amount. You can also set it to 'fullwidth', 'fullheight',
1405     * 'fullpage', or 'original'.
1406     *
1407     * Only certain PDF readers support this, such as Adobe Acrobat
1408     *
1409     * @param {String} layout Layout mode can be: 'continuous' - this is the
1410     * default continuous scroll. 'single' - the single page mode only shows one
1411     * page at a time. 'twoleft' - two column left mode, first page starts on
1412     * the left, and 'tworight' - pages are laid out in two columns, with the
1413     * first page on the right. This would be used for books.
1414     * @param {String} pmode 'UseOutlines' - it shows the
1415     * outline of the document on the left. 'UseThumbs' - shows thumbnails along
1416     * the left. 'FullScreen' - prompts the user to enter fullscreen mode.
1417     *
1418     * @function
1419     * @returns {jsPDF}
1420     * @name setDisplayMode
1421     */
1422    API.setDisplayMode = function (zoom, layout, pmode) {
1423      zoomMode = zoom;
1424      layoutMode = layout;
1425      pageMode = pmode;
1426
1427      var validPageModes = [undefined, null, 'UseNone', 'UseOutlines', 'UseThumbs', 'FullScreen'];
1428      if (validPageModes.indexOf(pmode) == -1) {
1429        throw new Error('Page mode must be one of UseNone, UseOutlines, UseThumbs, or FullScreen. "' + pmode + '" is not recognized.');
1430      }
1431      return this;
1432    },
1433
1434    /**
1435     * Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings.
1436     *
1437     * @function
1438     * @param {String|Array} text String or array of strings to be added to the page. Each line is shifted one line down per font, spacing settings declared before this call.
1439     * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1440     * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1441     * @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.
1442     * @returns {jsPDF}
1443     * @methodOf jsPDF#
1444     * @name text
1445     */
1446    API.text = function (text, x, y, flags, angle, align) {
1447      /**
1448       * Inserts something like this into PDF
1449       *   BT
1450       *    /F1 16 Tf  % Font name + size
1451       *    16 TL % How many units down for next line in multiline text
1452       *    0 g % color
1453       *    28.35 813.54 Td % position
1454       *    (line one) Tj
1455       *    T* (line two) Tj
1456       *    T* (line three) Tj
1457       *   ET
1458       */
1459      function ESC(s) {
1460        s = s.split("\t").join(Array(options.TabLen || 9).join(" "));
1461        return pdfEscape(s, flags);
1462      }
1463
1464      // Pre-August-2012 the order of arguments was function(x, y, text, flags)
1465      // in effort to make all calls have similar signature like
1466      //   function(data, coordinates... , miscellaneous)
1467      // this method had its args flipped.
1468      // code below allows backward compatibility with old arg order.
1469      if (typeof text === 'number') {
1470        tmp = y;
1471        y = x;
1472        x = text;
1473        text = tmp;
1474      }
1475
1476      // If there are any newlines in text, we assume
1477      // the user wanted to print multiple lines, so break the
1478      // text up into an array.  If the text is already an array,
1479      // we assume the user knows what they are doing.
1480      // Convert text into an array anyway to simplify
1481      // later code.
1482      if (typeof text === 'string') {
1483        if (text.match(/[\n\r]/)) {
1484          text = text.split(/\r\n|\r|\n/g);
1485        } else {
1486          text = [text];
1487        }
1488      }
1489      if (typeof angle === 'string') {
1490        align = angle;
1491        angle = null;
1492      }
1493      if (typeof flags === 'string') {
1494        align = flags;
1495        flags = null;
1496      }
1497      if (typeof flags === 'number') {
1498        angle = flags;
1499        flags = null;
1500      }
1501      var xtra = '',
1502          mode = 'Td',
1503          todo;
1504      if (angle) {
1505        angle *= Math.PI / 180;
1506        var c = Math.cos(angle),
1507            s = Math.sin(angle);
1508        xtra = [f2(c), f2(s), f2(s * -1), f2(c), ''].join(" ");
1509        mode = 'Tm';
1510      }
1511      flags = flags || {};
1512      if (!('noBOM' in flags)) flags.noBOM = true;
1513      if (!('autoencode' in flags)) flags.autoencode = true;
1514
1515      var strokeOption = '';
1516      var pageContext = this.internal.getCurrentPageInfo().pageContext;
1517      if (true === flags.stroke) {
1518        if (pageContext.lastTextWasStroke !== true) {
1519          strokeOption = '1 Tr\n';
1520          pageContext.lastTextWasStroke = true;
1521        }
1522      } else {
1523        if (pageContext.lastTextWasStroke) {
1524          strokeOption = '0 Tr\n';
1525        }
1526        pageContext.lastTextWasStroke = false;
1527      }
1528
1529      if (typeof this._runningPageHeight === 'undefined') {
1530        this._runningPageHeight = 0;
1531      }
1532
1533      if (typeof text === 'string') {
1534        text = ESC(text);
1535      } else if (Object.prototype.toString.call(text) === '[object Array]') {
1536        // we don't want to destroy  original text array, so cloning it
1537        var sa = text.concat(),
1538            da = [],
1539            len = sa.length;
1540        // we do array.join('text that must not be PDFescaped")
1541        // thus, pdfEscape each component separately
1542        while (len--) {
1543          da.push(ESC(sa.shift()));
1544        }
1545        var linesLeft = Math.ceil((pageHeight - y - this._runningPageHeight) * k / (activeFontSize * lineHeightProportion));
1546        if (0 <= linesLeft && linesLeft < da.length + 1) {
1547          //todo = da.splice(linesLeft-1);
1548        }
1549
1550        if (align) {
1551          var left,
1552              prevX,
1553              maxLineLength,
1554              leading = activeFontSize * lineHeightProportion,
1555              lineWidths = text.map(function (v) {
1556            return this.getStringUnitWidth(v) * activeFontSize / k;
1557          }, this);
1558          maxLineLength = Math.max.apply(Math, lineWidths);
1559          // The first line uses the "main" Td setting,
1560          // and the subsequent lines are offset by the
1561          // previous line's x coordinate.
1562          if (align === "center") {
1563            // The passed in x coordinate defines
1564            // the center point.
1565            left = x - maxLineLength / 2;
1566            x -= lineWidths[0] / 2;
1567          } else if (align === "right") {
1568            // The passed in x coordinate defines the
1569            // rightmost point of the text.
1570            left = x - maxLineLength;
1571            x -= lineWidths[0];
1572          } else {
1573            throw new Error('Unrecognized alignment option, use "center" or "right".');
1574          }
1575          prevX = x;
1576          text = da[0];
1577          for (var i = 1, len = da.length; i < len; i++) {
1578            var delta = maxLineLength - lineWidths[i];
1579            if (align === "center") delta /= 2;
1580            // T* = x-offset leading Td ( text )
1581            text += ") Tj\n" + (left - prevX + delta) + " -" + leading + " Td (" + da[i];
1582            prevX = left + delta;
1583          }
1584        } else {
1585          text = da.join(") Tj\nT* (");
1586        }
1587      } else {
1588        throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.');
1589      }
1590      // Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates
1591
1592      // BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET
1593      // if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations)
1594      // Thus, there is NO useful, *reliable* concept of "default" font for a page.
1595      // The fact that "default" (reuse font used before) font worked before in basic cases is an accident
1596      // - readers dealing smartly with brokenness of jsPDF's markup.
1597
1598      var curY;
1599
1600      if (todo) {
1601        //this.addPage();
1602        //this._runningPageHeight += y -  (activeFontSize * 1.7 / k);
1603        //curY = f2(pageHeight - activeFontSize * 1.7 /k);
1604      } else {
1605        curY = f2((pageHeight - y) * k);
1606      }
1607      //curY = f2((pageHeight - (y - this._runningPageHeight)) * k);
1608
1609      //			if (curY < 0){
1610      //				console.log('auto page break');
1611      //				this.addPage();
1612      //				this._runningPageHeight = y -  (activeFontSize * 1.7 / k);
1613      //				curY = f2(pageHeight - activeFontSize * 1.7 /k);
1614      //			}
1615
1616      out('BT\n/' + activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size
1617      activeFontSize * lineHeightProportion + ' TL\n' + // line spacing
1618      strokeOption + // stroke option
1619      textColor + '\n' + xtra + f2(x * k) + ' ' + curY + ' ' + mode + '\n(' + text + ') Tj\nET');
1620
1621      if (todo) {
1622        //this.text( todo, x, activeFontSize * 1.7 / k);
1623        //this.text( todo, x, this._runningPageHeight + (activeFontSize * 1.7 / k));
1624        this.text(todo, x, y); // + (activeFontSize * 1.7 / k));
1625      }
1626
1627      return this;
1628    };
1629
1630    /**
1631     * Letter spacing method to print text with gaps
1632     *
1633     * @function
1634     * @param {String|Array} text String to be added to the page.
1635     * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1636     * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1637     * @param {Number} spacing Spacing (in units declared at inception)
1638     * @returns {jsPDF}
1639     * @methodOf jsPDF#
1640     * @name lstext
1641     * @deprecated We'll be removing this function. It doesn't take character width into account.
1642     */
1643    API.lstext = function (text, x, y, spacing) {
1644      console.warn('jsPDF.lstext is deprecated');
1645      for (var i = 0, len = text.length; i < len; i++, x += spacing) {
1646        this.text(text[i], x, y);
1647      }return this;
1648    };
1649
1650    API.line = function (x1, y1, x2, y2) {
1651      return this.lines([[x2 - x1, y2 - y1]], x1, y1);
1652    };
1653
1654    API.clip = function () {
1655      // By patrick-roberts, github.com/MrRio/jsPDF/issues/328
1656      // Call .clip() after calling .rect() with a style argument of null
1657      out('W'); // clip
1658      out('S'); // stroke path; necessary for clip to work
1659    };
1660
1661    /**
1662     * This fixes the previous function clip(). Perhaps the 'stroke path' hack was due to the missing 'n' instruction?
1663     * We introduce the fixed version so as to not break API.
1664     * @param fillRule
1665     */
1666    API.clip_fixed = function (fillRule) {
1667      // Call .clip() after calling drawing ops with a style argument of null
1668      // W is the PDF clipping op
1669      if ('evenodd' === fillRule) {
1670        out('W*');
1671      } else {
1672        out('W');
1673      }
1674      // End the path object without filling or stroking it.
1675      // This operator is a path-painting no-op, used primarily for the side effect of changing the current clipping path
1676      // (see Section 4.4.3, “Clipping Path Operators”)
1677      out('n');
1678    };
1679
1680    /**
1681     * Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates.
1682     * All data points in `lines` are relative to last line origin.
1683     * `x`, `y` become x1,y1 for first line / curve in the set.
1684     * For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point.
1685     * 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.
1686     *
1687     * @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line
1688     * @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves).
1689     * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1690     * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1691     * @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.
1692     * @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.
1693     * @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point.
1694     * @function
1695     * @returns {jsPDF}
1696     * @methodOf jsPDF#
1697     * @name lines
1698     */
1699    API.lines = function (lines, x, y, scale, style, closed) {
1700      var scalex, scaley, i, l, leg, x2, y2, x3, y3, x4, y4;
1701
1702      // Pre-August-2012 the order of arguments was function(x, y, lines, scale, style)
1703      // in effort to make all calls have similar signature like
1704      //   function(content, coordinateX, coordinateY , miscellaneous)
1705      // this method had its args flipped.
1706      // code below allows backward compatibility with old arg order.
1707      if (typeof lines === 'number') {
1708        tmp = y;
1709        y = x;
1710        x = lines;
1711        lines = tmp;
1712      }
1713
1714      scale = scale || [1, 1];
1715
1716      // starting point
1717      out(f3(x * k) + ' ' + f3((pageHeight - y) * k) + ' m ');
1718
1719      scalex = scale[0];
1720      scaley = scale[1];
1721      l = lines.length;
1722      //, x2, y2 // bezier only. In page default measurement "units", *after* scaling
1723      //, x3, y3 // bezier only. In page default measurement "units", *after* scaling
1724      // ending point for all, lines and bezier. . In page default measurement "units", *after* scaling
1725      x4 = x; // last / ending point = starting point for first item.
1726      y4 = y; // last / ending point = starting point for first item.
1727
1728      for (i = 0; i < l; i++) {
1729        leg = lines[i];
1730        if (leg.length === 2) {
1731          // simple line
1732          x4 = leg[0] * scalex + x4; // here last x4 was prior ending point
1733          y4 = leg[1] * scaley + y4; // here last y4 was prior ending point
1734          out(f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' l');
1735        } else {
1736          // bezier curve
1737          x2 = leg[0] * scalex + x4; // here last x4 is prior ending point
1738          y2 = leg[1] * scaley + y4; // here last y4 is prior ending point
1739          x3 = leg[2] * scalex + x4; // here last x4 is prior ending point
1740          y3 = leg[3] * scaley + y4; // here last y4 is prior ending point
1741          x4 = leg[4] * scalex + x4; // here last x4 was prior ending point
1742          y4 = leg[5] * scaley + y4; // here last y4 was prior ending point
1743          out(f3(x2 * k) + ' ' + f3((pageHeight - y2) * k) + ' ' + f3(x3 * k) + ' ' + f3((pageHeight - y3) * k) + ' ' + f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' c');
1744        }
1745      }
1746
1747      if (closed) {
1748        out(' h');
1749      }
1750
1751      // stroking / filling / both the path
1752      if (style !== null) {
1753        out(getStyle(style));
1754      }
1755      return this;
1756    };
1757
1758    /**
1759     * Adds a rectangle to PDF
1760     *
1761     * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1762     * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1763     * @param {Number} w Width (in units declared at inception of PDF document)
1764     * @param {Number} h Height (in units declared at inception of PDF document)
1765     * @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.
1766     * @function
1767     * @returns {jsPDF}
1768     * @methodOf jsPDF#
1769     * @name rect
1770     */
1771    API.rect = function (x, y, w, h, style) {
1772      var op = getStyle(style);
1773      out([f2(x * k), f2((pageHeight - y) * k), f2(w * k), f2(-h * k), 're'].join(' '));
1774
1775      if (style !== null) {
1776        out(getStyle(style));
1777      }
1778
1779      return this;
1780    };
1781
1782    /**
1783     * Adds a triangle to PDF
1784     *
1785     * @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page
1786     * @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1787     * @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page
1788     * @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1789     * @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page
1790     * @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1791     * @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.
1792     * @function
1793     * @returns {jsPDF}
1794     * @methodOf jsPDF#
1795     * @name triangle
1796     */
1797    API.triangle = function (x1, y1, x2, y2, x3, y3, style) {
1798      this.lines([[x2 - x1, y2 - y1], // vector to point 2
1799      [x3 - x2, y3 - y2], // vector to point 3
1800      [x1 - x3, y1 - y3] // closing vector back to point 1
1801      ], x1, y1, // start of path
1802      [1, 1], style, true);
1803      return this;
1804    };
1805
1806    /**
1807     * Adds a rectangle with rounded corners to PDF
1808     *
1809     * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1810     * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1811     * @param {Number} w Width (in units declared at inception of PDF document)
1812     * @param {Number} h Height (in units declared at inception of PDF document)
1813     * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
1814     * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
1815     * @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.
1816     * @function
1817     * @returns {jsPDF}
1818     * @methodOf jsPDF#
1819     * @name roundedRect
1820     */
1821    API.roundedRect = function (x, y, w, h, rx, ry, style) {
1822      var MyArc = 4 / 3 * (Math.SQRT2 - 1);
1823      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
1824      [1, 1], style);
1825      return this;
1826    };
1827
1828    /**
1829     * Adds an ellipse to PDF
1830     *
1831     * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1832     * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1833     * @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
1834     * @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
1835     * @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.
1836     * @function
1837     * @returns {jsPDF}
1838     * @methodOf jsPDF#
1839     * @name ellipse
1840     */
1841    API.ellipse = function (x, y, rx, ry, style) {
1842      var lx = 4 / 3 * (Math.SQRT2 - 1) * rx,
1843          ly = 4 / 3 * (Math.SQRT2 - 1) * ry;
1844
1845      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(' '));
1846      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(' '));
1847      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(' '));
1848      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(' '));
1849
1850      if (style !== null) {
1851        out(getStyle(style));
1852      }
1853
1854      return this;
1855    };
1856
1857    /**
1858     * Adds an circle to PDF
1859     *
1860     * @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1861     * @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1862     * @param {Number} r Radius (in units declared at inception of PDF document)
1863     * @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.
1864     * @function
1865     * @returns {jsPDF}
1866     * @methodOf jsPDF#
1867     * @name circle
1868     */
1869    API.circle = function (x, y, r, style) {
1870      return this.ellipse(x, y, r, r, style);
1871    };
1872
1873    /**
1874     * Adds a properties to the PDF document
1875     *
1876     * @param {Object} A property_name-to-property_value object structure.
1877     * @function
1878     * @returns {jsPDF}
1879     * @methodOf jsPDF#
1880     * @name setProperties
1881     */
1882    API.setProperties = function (properties) {
1883      // copying only those properties we can render.
1884      for (var property in documentProperties) {
1885        if (documentProperties.hasOwnProperty(property) && properties[property]) {
1886          documentProperties[property] = properties[property];
1887        }
1888      }
1889      return this;
1890    };
1891
1892    /**
1893     * Sets font size for upcoming text elements.
1894     *
1895     * @param {Number} size Font size in points.
1896     * @function
1897     * @returns {jsPDF}
1898     * @methodOf jsPDF#
1899     * @name setFontSize
1900     */
1901    API.setFontSize = function (size) {
1902      activeFontSize = size;
1903      return this;
1904    };
1905
1906    /**
1907     * Sets text font face, variant for upcoming text elements.
1908     * See output of jsPDF.getFontList() for possible font names, styles.
1909     *
1910     * @param {String} fontName Font name or family. Example: "times"
1911     * @param {String} fontStyle Font style or variant. Example: "italic"
1912     * @function
1913     * @returns {jsPDF}
1914     * @methodOf jsPDF#
1915     * @name setFont
1916     */
1917    API.setFont = function (fontName, fontStyle) {
1918      activeFontKey = _getFont(fontName, fontStyle);
1919      // if font is not found, the above line blows up and we never go further
1920      return this;
1921    };
1922
1923    /**
1924     * Switches font style or variant for upcoming text elements,
1925     * while keeping the font face or family same.
1926     * See output of jsPDF.getFontList() for possible font names, styles.
1927     *
1928     * @param {String} style Font style or variant. Example: "italic"
1929     * @function
1930     * @returns {jsPDF}
1931     * @methodOf jsPDF#
1932     * @name setFontStyle
1933     */
1934    API.setFontStyle = API.setFontType = function (style) {
1935      activeFontKey = _getFont(undefined, style);
1936      // if font is not found, the above line blows up and we never go further
1937      return this;
1938    };
1939
1940    /**
1941     * Returns an object - a tree of fontName to fontStyle relationships available to
1942     * active PDF document.
1943     *
1944     * @public
1945     * @function
1946     * @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... }
1947     * @methodOf jsPDF#
1948     * @name getFontList
1949     */
1950    API.getFontList = function () {
1951      // TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added.
1952      var list = {},
1953          fontName,
1954          fontStyle,
1955          tmp;
1956
1957      for (fontName in fontmap) {
1958        if (fontmap.hasOwnProperty(fontName)) {
1959          list[fontName] = tmp = [];
1960          for (fontStyle in fontmap[fontName]) {
1961            if (fontmap[fontName].hasOwnProperty(fontStyle)) {
1962              tmp.push(fontStyle);
1963            }
1964          }
1965        }
1966      }
1967
1968      return list;
1969    };
1970
1971    /**
1972     * Add a custom font.
1973     *
1974     * @param {String} Postscript name of the Font.  Example: "Menlo-Regular"
1975     * @param {String} Name of font-family from @font-face definition.  Example: "Menlo Regular"
1976     * @param {String} Font style.  Example: "normal"
1977     * @function
1978     * @returns the {fontKey} (same as the internal method)
1979     * @methodOf jsPDF#
1980     * @name addFont
1981     */
1982    API.addFont = function (postScriptName, fontName, fontStyle) {
1983      addFont(postScriptName, fontName, fontStyle, 'StandardEncoding');
1984    };
1985
1986    /**
1987     * Sets line width for upcoming lines.
1988     *
1989     * @param {Number} width Line width (in units declared at inception of PDF document)
1990     * @function
1991     * @returns {jsPDF}
1992     * @methodOf jsPDF#
1993     * @name setLineWidth
1994     */
1995    API.setLineWidth = function (width) {
1996      out((width * k).toFixed(2) + ' w');
1997      return this;
1998    };
1999
2000    /**
2001     * Sets the stroke color for upcoming elements.
2002     *
2003     * Depending on the number of arguments given, Gray, RGB, or CMYK
2004     * color space is implied.
2005     *
2006     * When only ch1 is given, "Gray" color space is implied and it
2007     * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
2008     * if values are communicated as String types, or in range from 0 (black)
2009     * to 255 (white) if communicated as Number type.
2010     * The RGB-like 0-255 range is provided for backward compatibility.
2011     *
2012     * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
2013     * value must be in the range from 0.00 (minimum intensity) to to 1.00
2014     * (max intensity) if values are communicated as String types, or
2015     * from 0 (min intensity) to to 255 (max intensity) if values are communicated
2016     * as Number types.
2017     * The RGB-like 0-255 range is provided for backward compatibility.
2018     *
2019     * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
2020     * value must be a in the range from 0.00 (0% concentration) to to
2021     * 1.00 (100% concentration)
2022     *
2023     * Because JavaScript treats fixed point numbers badly (rounds to
2024     * floating point nearest to binary representation) it is highly advised to
2025     * communicate the fractional numbers as String types, not JavaScript Number type.
2026     *
2027     * @param {Number|String} ch1 Color channel value
2028     * @param {Number|String} ch2 Color channel value
2029     * @param {Number|String} ch3 Color channel value
2030     * @param {Number|String} ch4 Color channel value
2031     *
2032     * @function
2033     * @returns {jsPDF}
2034     * @methodOf jsPDF#
2035     * @name setDrawColor
2036     */
2037    API.setDrawColor = function (ch1, ch2, ch3, ch4) {
2038      var color;
2039      if (ch2 === undefined || ch4 === undefined && ch1 === ch2 === ch3) {
2040        // Gray color space.
2041        if (typeof ch1 === 'string') {
2042          color = ch1 + ' G';
2043        } else {
2044          color = f2(ch1 / 255) + ' G';
2045        }
2046      } else if (ch4 === undefined) {
2047        // RGB
2048        if (typeof ch1 === 'string') {
2049          color = [ch1, ch2, ch3, 'RG'].join(' ');
2050        } else {
2051          color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' ');
2052        }
2053      } else {
2054        // CMYK
2055        if (typeof ch1 === 'string') {
2056          color = [ch1, ch2, ch3, ch4, 'K'].join(' ');
2057        } else {
2058          color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' ');
2059        }
2060      }
2061
2062      out(color);
2063      return this;
2064    };
2065
2066    /**
2067     * Sets the fill color for upcoming elements.
2068     *
2069     * Depending on the number of arguments given, Gray, RGB, or CMYK
2070     * color space is implied.
2071     *
2072     * When only ch1 is given, "Gray" color space is implied and it
2073     * must be a value in the range from 0.00 (solid black) to to 1.00 (white)
2074     * if values are communicated as String types, or in range from 0 (black)
2075     * to 255 (white) if communicated as Number type.
2076     * The RGB-like 0-255 range is provided for backward compatibility.
2077     *
2078     * When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
2079     * value must be in the range from 0.00 (minimum intensity) to to 1.00
2080     * (max intensity) if values are communicated as String types, or
2081     * from 0 (min intensity) to to 255 (max intensity) if values are communicated
2082     * as Number types.
2083     * The RGB-like 0-255 range is provided for backward compatibility.
2084     *
2085     * When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
2086     * value must be a in the range from 0.00 (0% concentration) to to
2087     * 1.00 (100% concentration)
2088     *
2089     * Because JavaScript treats fixed point numbers badly (rounds to
2090     * floating point nearest to binary representation) it is highly advised to
2091     * communicate the fractional numbers as String types, not JavaScript Number type.
2092     *
2093     * @param {Number|String} ch1 Color channel value
2094     * @param {Number|String} ch2 Color channel value
2095     * @param {Number|String} ch3 Color channel value
2096     * @param {Number|String} ch4 Color channel value
2097     *
2098     * @function
2099     * @returns {jsPDF}
2100     * @methodOf jsPDF#
2101     * @name setFillColor
2102     */
2103    API.setFillColor = function (ch1, ch2, ch3, ch4) {
2104      var color;
2105
2106      if (ch2 === undefined || ch4 === undefined && ch1 === ch2 === ch3) {
2107        // Gray color space.
2108        if (typeof ch1 === 'string') {
2109          color = ch1 + ' g';
2110        } else {
2111          color = f2(ch1 / 255) + ' g';
2112        }
2113      } else if (ch4 === undefined || (typeof ch4 === 'undefined' ? 'undefined' : _typeof(ch4)) === 'object') {
2114        // RGB
2115        if (typeof ch1 === 'string') {
2116          color = [ch1, ch2, ch3, 'rg'].join(' ');
2117        } else {
2118          color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' ');
2119        }
2120        if (ch4 && ch4.a === 0) {
2121          //TODO Implement transparency.
2122          //WORKAROUND use white for now
2123          color = ['255', '255', '255', 'rg'].join(' ');
2124        }
2125      } else {
2126        // CMYK
2127        if (typeof ch1 === 'string') {
2128          color = [ch1, ch2, ch3, ch4, 'k'].join(' ');
2129        } else {
2130          color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' ');
2131        }
2132      }
2133
2134      out(color);
2135      return this;
2136    };
2137
2138    /**
2139     * Sets the text color for upcoming elements.
2140     * If only one, first argument is given,
2141     * treats the value as gray-scale color value.
2142     *
2143     * @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF'
2144     * @param {Number} g Green channel color value in range 0-255
2145     * @param {Number} b Blue channel color value in range 0-255
2146     * @function
2147     * @returns {jsPDF}
2148     * @methodOf jsPDF#
2149     * @name setTextColor
2150     */
2151    API.setTextColor = function (r, g, b) {
2152      if (typeof r === 'string' && /^#[0-9A-Fa-f]{6}$/.test(r)) {
2153        var hex = parseInt(r.substr(1), 16);
2154        r = hex >> 16 & 255;
2155        g = hex >> 8 & 255;
2156        b = hex & 255;
2157      }
2158
2159      if (r === 0 && g === 0 && b === 0 || typeof g === 'undefined') {
2160        textColor = f3(r / 255) + ' g';
2161      } else {
2162        textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' ');
2163      }
2164      return this;
2165    };
2166
2167    /**
2168     * Is an Object providing a mapping from human-readable to
2169     * integer flag values designating the varieties of line cap
2170     * and join styles.
2171     *
2172     * @returns {Object}
2173     * @fieldOf jsPDF#
2174     * @name CapJoinStyles
2175     */
2176    API.CapJoinStyles = {
2177      0: 0,
2178      'butt': 0,
2179      'but': 0,
2180      'miter': 0,
2181      1: 1,
2182      'round': 1,
2183      'rounded': 1,
2184      'circle': 1,
2185      2: 2,
2186      'projecting': 2,
2187      'project': 2,
2188      'square': 2,
2189      'bevel': 2
2190    };
2191
2192    /**
2193     * Sets the line cap styles
2194     * See {jsPDF.CapJoinStyles} for variants
2195     *
2196     * @param {String|Number} style A string or number identifying the type of line cap
2197     * @function
2198     * @returns {jsPDF}
2199     * @methodOf jsPDF#
2200     * @name setLineCap
2201     */
2202    API.setLineCap = function (style) {
2203      var id = this.CapJoinStyles[style];
2204      if (id === undefined) {
2205        throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
2206      }
2207      lineCapID = id;
2208      out(id + ' J');
2209
2210      return this;
2211    };
2212
2213    /**
2214     * Sets the line join styles
2215     * See {jsPDF.CapJoinStyles} for variants
2216     *
2217     * @param {String|Number} style A string or number identifying the type of line join
2218     * @function
2219     * @returns {jsPDF}
2220     * @methodOf jsPDF#
2221     * @name setLineJoin
2222     */
2223    API.setLineJoin = function (style) {
2224      var id = this.CapJoinStyles[style];
2225      if (id === undefined) {
2226        throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
2227      }
2228      lineJoinID = id;
2229      out(id + ' j');
2230
2231      return this;
2232    };
2233
2234    // Output is both an internal (for plugins) and external function
2235    API.output = _output;
2236
2237    /**
2238     * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf')
2239     * @param  {String} filename The filename including extension.
2240     *
2241     * @function
2242     * @returns {jsPDF}
2243     * @methodOf jsPDF#
2244     * @name save
2245     */
2246    API.save = function (filename) {
2247      API.output('save', filename);
2248    };
2249
2250    // applying plugins (more methods) ON TOP of built-in API.
2251    // this is intentional as we allow plugins to override
2252    // built-ins
2253    for (var plugin in jsPDF.API) {
2254      if (jsPDF.API.hasOwnProperty(plugin)) {
2255        if (plugin === 'events' && jsPDF.API.events.length) {
2256          (function (events, newEvents) {
2257
2258            // jsPDF.API.events is a JS Array of Arrays
2259            // where each Array is a pair of event name, handler
2260            // Events were added by plugins to the jsPDF instantiator.
2261            // These are always added to the new instance and some ran
2262            // during instantiation.
2263            var eventname, handler_and_args, i;
2264
2265            for (i = newEvents.length - 1; i !== -1; i--) {
2266              // subscribe takes 3 args: 'topic', function, runonce_flag
2267              // if undefined, runonce is false.
2268              // users can attach callback directly,
2269              // or they can attach an array with [callback, runonce_flag]
2270              // that's what the "apply" magic is for below.
2271              eventname = newEvents[i][0];
2272              handler_and_args = newEvents[i][1];
2273              events.subscribe.apply(events, [eventname].concat(typeof handler_and_args === 'function' ? [handler_and_args] : handler_and_args));
2274            }
2275          })(events, jsPDF.API.events);
2276        } else {
2277          API[plugin] = jsPDF.API[plugin];
2278        }
2279      }
2280    }
2281
2282    //////////////////////////////////////////////////////
2283    // continuing initialization of jsPDF Document object
2284    //////////////////////////////////////////////////////
2285    // Add the first page automatically
2286    addFonts();
2287    activeFontKey = 'F1';
2288    _addPage(format, orientation);
2289
2290    events.publish('initialized');
2291    return API;
2292  }
2293
2294  /**
2295   * jsPDF.API is a STATIC property of jsPDF class.
2296   * jsPDF.API is an object you can add methods and properties to.
2297   * The methods / properties you add will show up in new jsPDF objects.
2298   *
2299   * One property is prepopulated. It is the 'events' Object. Plugin authors can add topics,
2300   * callbacks to this object. These will be reassigned to all new instances of jsPDF.
2301   * Examples:
2302   * jsPDF.API.events['initialized'] = function(){ 'this' is API object }
2303   * jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object }
2304   *
2305   * @static
2306   * @public
2307   * @memberOf jsPDF
2308   * @name API
2309   *
2310   * @example
2311   * jsPDF.API.mymethod = function(){
2312   *   // 'this' will be ref to internal API object. see jsPDF source
2313   *   // , so you can refer to built-in methods like so:
2314   *   //     this.line(....)
2315   *   //     this.text(....)
2316   * }
2317   * var pdfdoc = new jsPDF()
2318   * pdfdoc.mymethod() // <- !!!!!!
2319   */
2320  jsPDF.API = {
2321    events: []
2322  };
2323  jsPDF.version = "1.x-master";
2324
2325  if (typeof define === 'function' && define.amd) {
2326    define('jsPDF', function () {
2327      return jsPDF;
2328    });
2329  } else if (typeof module !== 'undefined' && module.exports) {
2330    module.exports = jsPDF;
2331  } else {
2332    global.jsPDF = jsPDF;
2333  }
2334  return jsPDF;
2335}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined);
2336
2337
2338/**
2339 * jsPDF AcroForm Plugin
2340 * Copyright (c) 2016 Alexander Weidt, https://github.com/BiggA94
2341 *
2342 * Licensed under the MIT License.
2343 * http://opensource.org/licenses/mit-license
2344 */
2345
2346(window.AcroForm = function (jsPDFAPI) {
2347    'use strict';
2348
2349    var AcroForm = window.AcroForm;
2350
2351    AcroForm.scale = function (x) {
2352        return x * (acroformPlugin.internal.scaleFactor / 1); // 1 = (96 / 72)
2353    };
2354    AcroForm.antiScale = function (x) {
2355        return 1 / acroformPlugin.internal.scaleFactor * x;
2356    };
2357
2358    var acroformPlugin = {
2359        fields: [],
2360        xForms: [],
2361        /**
2362         * acroFormDictionaryRoot contains information about the AcroForm Dictionary
2363         * 0: The Event-Token, the AcroFormDictionaryCallback has
2364         * 1: The Object ID of the Root
2365         */
2366        acroFormDictionaryRoot: null,
2367        /**
2368         * After the PDF gets evaluated, the reference to the root has to be reset,
2369         * this indicates, whether the root has already been printed out
2370         */
2371        printedOut: false,
2372        internal: null
2373    };
2374
2375    jsPDF.API.acroformPlugin = acroformPlugin;
2376
2377    var annotReferenceCallback = function annotReferenceCallback() {
2378        for (var i in this.acroformPlugin.acroFormDictionaryRoot.Fields) {
2379            var formObject = this.acroformPlugin.acroFormDictionaryRoot.Fields[i];
2380            // add Annot Reference!
2381            if (formObject.hasAnnotation) {
2382                // If theres an Annotation Widget in the Form Object, put the Reference in the /Annot array
2383                createAnnotationReference.call(this, formObject);
2384            }
2385        }
2386    };
2387
2388    var createAcroForm = function createAcroForm() {
2389        if (this.acroformPlugin.acroFormDictionaryRoot) {
2390            //return;
2391            throw new Error("Exception while creating AcroformDictionary");
2392        }
2393
2394        // The Object Number of the AcroForm Dictionary
2395        this.acroformPlugin.acroFormDictionaryRoot = new AcroForm.AcroFormDictionary();
2396
2397        this.acroformPlugin.internal = this.internal;
2398
2399        // add Callback for creating the AcroForm Dictionary
2400        this.acroformPlugin.acroFormDictionaryRoot._eventID = this.internal.events.subscribe('postPutResources', AcroFormDictionaryCallback);
2401
2402        this.internal.events.subscribe('buildDocument', annotReferenceCallback); //buildDocument
2403
2404        // Register event, that is triggered when the DocumentCatalog is written, in order to add /AcroForm
2405        this.internal.events.subscribe('putCatalog', putCatalogCallback);
2406
2407        // Register event, that creates all Fields
2408        this.internal.events.subscribe('postPutPages', createFieldCallback);
2409    };
2410
2411    /**
2412     * Create the Reference to the widgetAnnotation, so that it gets referenced in the Annot[] int the+
2413     * (Requires the Annotation Plugin)
2414     */
2415    var createAnnotationReference = function createAnnotationReference(object) {
2416        var options = {
2417            type: 'reference',
2418            object: object
2419        };
2420        jsPDF.API.annotationPlugin.annotations[this.internal.getPageInfo(object.page).pageNumber].push(options);
2421    };
2422
2423    var putForm = function putForm(formObject) {
2424        if (this.acroformPlugin.printedOut) {
2425            this.acroformPlugin.printedOut = false;
2426            this.acroformPlugin.acroFormDictionaryRoot = null;
2427        }
2428        if (!this.acroformPlugin.acroFormDictionaryRoot) {
2429            createAcroForm.call(this);
2430        }
2431        this.acroformPlugin.acroFormDictionaryRoot.Fields.push(formObject);
2432    };
2433
2434    // Callbacks
2435
2436    var putCatalogCallback = function putCatalogCallback() {
2437        //Put reference to AcroForm to DocumentCatalog
2438        if (typeof this.acroformPlugin.acroFormDictionaryRoot != 'undefined') {
2439            // for safety, shouldn't normally be the case
2440            this.internal.write('/AcroForm ' + this.acroformPlugin.acroFormDictionaryRoot.objId + ' ' + 0 + ' R');
2441        } else {
2442            console.log('Root missing...');
2443        }
2444    };
2445
2446    /**
2447     * Adds /Acroform X 0 R to Document Catalog,
2448     * and creates the AcroForm Dictionary
2449     */
2450    var AcroFormDictionaryCallback = function AcroFormDictionaryCallback() {
2451        // Remove event
2452        this.internal.events.unsubscribe(this.acroformPlugin.acroFormDictionaryRoot._eventID);
2453
2454        delete this.acroformPlugin.acroFormDictionaryRoot._eventID;
2455
2456        this.acroformPlugin.printedOut = true;
2457    };
2458
2459    /**
2460     * Creates the single Fields and writes them into the Document
2461     *
2462     * If fieldArray is set, use the fields that are inside it instead of the fields from the AcroRoot
2463     * (for the FormXObjects...)
2464     */
2465    var createFieldCallback = function createFieldCallback(fieldArray) {
2466        var standardFields = !fieldArray;
2467
2468        if (!fieldArray) {
2469            // in case there is no fieldArray specified, we want to print out the Fields of the AcroForm
2470            // Print out Root
2471            this.internal.newObjectDeferredBegin(this.acroformPlugin.acroFormDictionaryRoot.objId);
2472            this.internal.out(this.acroformPlugin.acroFormDictionaryRoot.getString());
2473        }
2474
2475        var fieldArray = fieldArray || this.acroformPlugin.acroFormDictionaryRoot.Kids;
2476
2477        for (var i in fieldArray) {
2478            var key = i;
2479            var form = fieldArray[i];
2480
2481            var oldRect = form.Rect;
2482
2483            if (form.Rect) {
2484                form.Rect = AcroForm.internal.calculateCoordinates.call(this, form.Rect);
2485            }
2486
2487            // Start Writing the Object
2488            this.internal.newObjectDeferredBegin(form.objId);
2489
2490            var content = "";
2491            content += form.objId + " 0 obj\n";
2492
2493            content += "<<\n" + form.getContent();
2494
2495            form.Rect = oldRect;
2496
2497            if (form.hasAppearanceStream && !form.appearanceStreamContent) {
2498                // Calculate Appearance
2499                var appearance = AcroForm.internal.calculateAppearanceStream.call(this, form);
2500                content += "/AP << /N " + appearance + " >>\n";
2501
2502                this.acroformPlugin.xForms.push(appearance);
2503            }
2504
2505            // Assume AppearanceStreamContent is a Array with N,R,D (at least one of them!)
2506            if (form.appearanceStreamContent) {
2507                content += "/AP << ";
2508                // Iterate over N,R and D
2509                for (var k in form.appearanceStreamContent) {
2510                    var value = form.appearanceStreamContent[k];
2511                    content += "/" + k + " ";
2512                    content += "<< ";
2513                    if (Object.keys(value).length >= 1 || Array.isArray(value)) {
2514                        // appearanceStream is an Array or Object!
2515                        for (var i in value) {
2516                            var obj = value[i];
2517                            if (typeof obj === 'function') {
2518                                // if Function is referenced, call it in order to get the FormXObject
2519                                obj = obj.call(this, form);
2520                            }
2521                            content += "/" + i + " " + obj + " ";
2522
2523                            // In case the XForm is already used, e.g. OffState of CheckBoxes, don't add it
2524                            if (!(this.acroformPlugin.xForms.indexOf(obj) >= 0)) this.acroformPlugin.xForms.push(obj);
2525                        }
2526                    } else {
2527                        var obj = value;
2528                        if (typeof obj === 'function') {
2529                            // if Function is referenced, call it in order to get the FormXObject
2530                            obj = obj.call(this, form);
2531                        }
2532                        content += "/" + i + " " + obj + " \n";
2533                        if (!(this.acroformPlugin.xForms.indexOf(obj) >= 0)) this.acroformPlugin.xForms.push(obj);
2534                    }
2535                    content += " >>\n";
2536                }
2537
2538                // appearance stream is a normal Object..
2539                content += ">>\n";
2540            }
2541
2542            content += ">>\nendobj\n";
2543
2544            this.internal.out(content);
2545        }
2546        if (standardFields) {
2547            createXFormObjectCallback.call(this, this.acroformPlugin.xForms);
2548        }
2549    };
2550
2551    var createXFormObjectCallback = function createXFormObjectCallback(fieldArray) {
2552        for (var i in fieldArray) {
2553            var key = i;
2554            var form = fieldArray[i];
2555            // Start Writing the Object
2556            this.internal.newObjectDeferredBegin(form && form.objId);
2557
2558            var content = "";
2559            content += form ? form.getString() : '';
2560            this.internal.out(content);
2561
2562            delete fieldArray[key];
2563        }
2564    };
2565
2566    // Public:
2567
2568    jsPDFAPI.addField = function (fieldObject) {
2569        //var opt = parseOptions(fieldObject);
2570        if (fieldObject instanceof AcroForm.TextField) {
2571            addTextField.call(this, fieldObject);
2572        } else if (fieldObject instanceof AcroForm.ChoiceField) {
2573            addChoiceField.call(this, fieldObject);
2574        } else if (fieldObject instanceof AcroForm.Button) {
2575            addButton.call(this, fieldObject);
2576        } else if (fieldObject instanceof AcroForm.ChildClass) {
2577            putForm.call(this, fieldObject);
2578        } else if (fieldObject) {
2579            // try to put..
2580            putForm.call(this, fieldObject);
2581        }
2582        fieldObject.page = this.acroformPlugin.internal.getCurrentPageInfo().pageNumber;
2583        return this;
2584    };
2585
2586    // ############### sort in:
2587
2588    /**
2589     * Button
2590     * FT = Btn
2591     */
2592    var addButton = function addButton(options) {
2593        var options = options || new AcroForm.Field();
2594
2595        options.FT = '/Btn';
2596
2597        /**
2598         * Calculating the Ff entry:
2599         *
2600         * The Ff entry contains flags, that have to be set bitwise
2601         * In the Following the number in the Comment is the BitPosition
2602         */
2603        var flags = options.Ff || 0;
2604
2605        // 17, Pushbutton
2606        if (options.pushbutton) {
2607            // Options.pushbutton should be 1 or 0
2608            flags = AcroForm.internal.setBitPosition(flags, 17);
2609            delete options.pushbutton;
2610        }
2611
2612        //16, Radio
2613        if (options.radio) {
2614            //flags = options.Ff | options.radio << 15;
2615            flags = AcroForm.internal.setBitPosition(flags, 16);
2616            delete options.radio;
2617        }
2618
2619        // 15, NoToggleToOff (Radio buttons only
2620        if (options.noToggleToOff) {
2621            //flags = options.Ff | options.noToggleToOff << 14;
2622            flags = AcroForm.internal.setBitPosition(flags, 15);
2623            //delete options.noToggleToOff;
2624        }
2625
2626        // In case, there is no Flag set, it is a check-box
2627        options.Ff = flags;
2628
2629        putForm.call(this, options);
2630    };
2631
2632    var addTextField = function addTextField(options) {
2633        var options = options || new AcroForm.Field();
2634
2635        options.FT = '/Tx';
2636
2637        /**
2638         * Calculating the Ff entry:
2639         *
2640         * The Ff entry contains flags, that have to be set bitwise
2641         * In the Following the number in the Comment is the BitPosition
2642         */
2643
2644        var flags = options.Ff || 0;
2645
2646        // 13, multiline
2647        if (options.multiline) {
2648            // Set Flag
2649            flags = flags | 1 << 12;
2650            // Remove multiline from FieldObject
2651            //delete options.multiline;
2652        }
2653
2654        // 14, Password
2655        if (options.password) {
2656            flags = flags | 1 << 13;
2657            //delete options.password;
2658        }
2659
2660        // 21, FileSelect, PDF 1.4...
2661        if (options.fileSelect) {
2662            flags = flags | 1 << 20;
2663            //delete options.fileSelect;
2664        }
2665
2666        // 23, DoNotSpellCheck, PDF 1.4...
2667        if (options.doNotSpellCheck) {
2668            flags = flags | 1 << 22;
2669            //delete options.doNotSpellCheck;
2670        }
2671
2672        // 24, DoNotScroll, PDF 1.4...
2673        if (options.doNotScroll) {
2674            flags = flags | 1 << 23;
2675            //delete options.doNotScroll;
2676        }
2677
2678        options.Ff = options.Ff || flags;
2679
2680        // Add field
2681        putForm.call(this, options);
2682    };
2683
2684    var addChoiceField = function addChoiceField(opt) {
2685        var options = opt || new AcroForm.Field();
2686
2687        options.FT = '/Ch';
2688
2689        /**
2690         * Calculating the Ff entry:
2691         *
2692         * The Ff entry contains flags, that have to be set bitwise
2693         * In the Following the number in the Comment is the BitPosition
2694         */
2695
2696        var flags = options.Ff || 0;
2697
2698        // 18, Combo (If not set, the choiceField is a listBox!!)
2699        if (options.combo) {
2700            // Set Flag
2701            flags = AcroForm.internal.setBitPosition(flags, 18);
2702            // Remove combo from FieldObject
2703            delete options.combo;
2704        }
2705
2706        // 19, Edit
2707        if (options.edit) {
2708            flags = AcroForm.internal.setBitPosition(flags, 19);
2709            delete options.edit;
2710        }
2711
2712        // 20, Sort
2713        if (options.sort) {
2714            flags = AcroForm.internal.setBitPosition(flags, 20);
2715            delete options.sort;
2716        }
2717
2718        // 22, MultiSelect (PDF 1.4)
2719        if (options.multiSelect && this.internal.getPDFVersion() >= 1.4) {
2720            flags = AcroForm.internal.setBitPosition(flags, 22);
2721            delete options.multiSelect;
2722        }
2723
2724        // 23, DoNotSpellCheck (PDF 1.4)
2725        if (options.doNotSpellCheck && this.internal.getPDFVersion() >= 1.4) {
2726            flags = AcroForm.internal.setBitPosition(flags, 23);
2727            delete options.doNotSpellCheck;
2728        }
2729
2730        options.Ff = flags;
2731
2732        //options.hasAnnotation = true;
2733
2734        // Add field
2735        putForm.call(this, options);
2736    };
2737})(jsPDF.API);
2738
2739var AcroForm = window.AcroForm;
2740
2741AcroForm.internal = {};
2742
2743AcroForm.createFormXObject = function (formObject) {
2744    var xobj = new AcroForm.FormXObject();
2745    var height = AcroForm.Appearance.internal.getHeight(formObject) || 0;
2746    var width = AcroForm.Appearance.internal.getWidth(formObject) || 0;
2747    xobj.BBox = [0, 0, width, height];
2748    return xobj;
2749};
2750
2751// Contains Methods for creating standard appearances
2752AcroForm.Appearance = {
2753    CheckBox: {
2754        createAppearanceStream: function createAppearanceStream() {
2755            var appearance = {
2756                N: {
2757                    On: AcroForm.Appearance.CheckBox.YesNormal
2758                },
2759                D: {
2760                    On: AcroForm.Appearance.CheckBox.YesPushDown,
2761                    Off: AcroForm.Appearance.CheckBox.OffPushDown
2762                }
2763            };
2764
2765            return appearance;
2766        },
2767        /**
2768         * If any other icons are needed, the number between the brackets can be changed
2769         * @returns {string}
2770         */
2771        createMK: function createMK() {
2772            // 3-> Hook
2773            return "<< /CA (3)>>";
2774        },
2775        /**
2776         * Returns the standard On Appearance for a CheckBox
2777         * @returns {AcroForm.FormXObject}
2778         */
2779        YesPushDown: function YesPushDown(formObject) {
2780            var xobj = AcroForm.createFormXObject(formObject);
2781            var stream = "";
2782            // F13 is ZapfDingbats (Symbolic)
2783            formObject.Q = 1; // set text-alignment as centered
2784            var calcRes = AcroForm.internal.calculateX(formObject, "3", "ZapfDingbats", 50);
2785            stream += "0.749023 g\n\
2786             0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\
2787             f\n\
2788             BMC\n\
2789             q\n\
2790             0 0 1 rg\n\
2791             /F13 " + calcRes.fontSize + " Tf 0 g\n\
2792             BT\n";
2793            stream += calcRes.text;
2794            stream += "ET\n\
2795             Q\n\
2796             EMC\n";
2797            xobj.stream = stream;
2798            return xobj;
2799        },
2800
2801        YesNormal: function YesNormal(formObject) {
2802            var xobj = AcroForm.createFormXObject(formObject);
2803            var stream = "";
2804            formObject.Q = 1; // set text-alignment as centered
2805            var calcRes = AcroForm.internal.calculateX(formObject, "3", "ZapfDingbats", AcroForm.Appearance.internal.getHeight(formOb
2805ject) * 0.9);
2806            stream += "1 g\n\
28070 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\
2808f\n\
2809q\n\
28100 0 1 rg\n\
28110 0 " + (AcroForm.Appearance.internal.getWidth(formObject) - 1) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 1) + " re\n\
2812W\n\
2813n\n\
28140 g\n\
2815BT\n\
2816/F13 " + calcRes.fontSize + " Tf 0 g\n";
2817            stream += calcRes.text;
2818            stream += "ET\n\
2819             Q\n";
2820            xobj.stream = stream;
2821            return xobj;
2822        },
2823
2824        /**
2825         * Returns the standard Off Appearance for a CheckBox
2826         * @returns {AcroForm.FormXObject}
2827         */
2828        OffPushDown: function OffPushDown(formObject) {
2829            var xobj = AcroForm.createFormXObject(formObject);
2830            var stream = "";
2831            stream += "0.749023 g\n\
2832            0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\
2833            f\n";
2834            xobj.stream = stream;
2835            return xobj;
2836        }
2837    },
2838
2839    RadioButton: {
2840        Circle: {
2841            createAppearanceStream: function createAppearanceStream(name) {
2842                var appearanceStreamContent = {
2843                    D: {
2844                        'Off': AcroForm.Appearance.RadioButton.Circle.OffPushDown
2845                    },
2846                    N: {}
2847                };
2848                appearanceStreamContent.N[name] = AcroForm.Appearance.RadioButton.Circle.YesNormal;
2849                appearanceStreamContent.D[name] = AcroForm.Appearance.RadioButton.Circle.YesPushDown;
2850                return appearanceStreamContent;
2851            },
2852            createMK: function createMK() {
2853                return "<< /CA (l)>>";
2854            },
2855
2856            YesNormal: function YesNormal(formObject) {
2857                var xobj = AcroForm.createFormXObject(formObject);
2858                var stream = "";
2859                // Make the Radius of the Circle relative to min(height, width) of formObject
2860                var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formObject) / 4;
2861                // The Borderpadding...
2862                DotRadius *= 0.9;
2863                var c = AcroForm.Appearance.internal.Bezier_C;
2864                /*
2865                 The Following is a Circle created with Bezier-Curves.
2866                 */
2867                stream += "q\n\
28681 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2869" + DotRadius + " 0 m\n\
2870" + DotRadius + " " + DotRadius * c + " " + DotRadius * c + " " + DotRadius + " 0 " + DotRadius + " c\n\
2871-" + DotRadius * c + " " + DotRadius + " -" + DotRadius + " " + DotRadius * c + " -" + DotRadius + " 0 c\n\
2872-" + DotRadius + " -" + DotRadius * c + " -" + DotRadius * c + " -" + DotRadius + " 0 -" + DotRadius + " c\n\
2873" + DotRadius * c + " -" + DotRadius + " " + DotRadius + " -" + DotRadius * c + " " + DotRadius + " 0 c\n\
2874f\n\
2875Q\n";
2876                xobj.stream = stream;
2877                return xobj;
2878            },
2879            YesPushDown: function YesPushDown(formObject) {
2880                var xobj = AcroForm.createFormXObject(formObject);
2881                var stream = "";
2882                var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formObject) / 4;
2883                // The Borderpadding...
2884                DotRadius *= 0.9;
2885                // Save results for later use; no need to waste processor ticks on doing math
2886                var k = DotRadius * 2;
2887                // var c = AcroForm.Appearance.internal.Bezier_C;
2888                var kc = k * AcroForm.Appearance.internal.Bezier_C;
2889                var dc = DotRadius * AcroForm.Appearance.internal.Bezier_C;
2890                //                 stream += "0.749023 g\n\
2891                //             q\n\
2892                //           1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formOb
2892ject) / 2 + " cm\n\
2893                // " + DotRadius * 2 + " 0 m\n\
2894                // " + DotRadius * 2 + " " + DotRadius * 2 * c + " " + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 " + DotRadius * 2 + " c\n\
2895                // -" + DotRadius * 2 * c + " " + DotRadius * 2 + " -" + DotRadius * 2 + " " + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 c\n\
2896                // -" + DotRadius * 2 + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 -" + DotRadius * 2 + " c\n\
2897                // " + DotRadius * 2 * c + " -" + DotRadius * 2 + " " + DotRadius * 2 + " -" + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 c\n\
2898                //             f\n\
2899                //             Q\n\
2900                //             0 g\n\
2901                //             q\n\
2902                //             1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2903                // " + DotRadius + " 0 m\n\
2904                // " + DotRadius + " " + DotRadius * c + " " + DotRadius * c + " " + DotRadius + " 0 " + DotRadius + " c\n\
2905                // -" + DotRadius * c + " " + DotRadius + " -" + DotRadius + " " + DotRadius * c + " -" + DotRadius + " 0 c\n\
2906                // -" + DotRadius + " -" + DotRadius * c + " -" + DotRadius * c + " -" + DotRadius + " 0 -" + DotRadius + " c\n\
2907                // " + DotRadius * c + " -" + DotRadius + " " + DotRadius + " -" + DotRadius * c + " " + DotRadius + " 0 c\n\
2908                //             f\n\
2909                //             Q\n";
2910
2911                //  FASTER VERSION with less processor ticks spent on math operations
2912                stream += "0.749023 g\n\
2913            q\n\
2914           1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2915" + k + " 0 m\n\
2916" + k + " " + kc + " " + kc + " " + k + " 0 " + k + " c\n\
2917-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c\n\
2918-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c\n\
2919" + kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c\n\
2920            f\n\
2921            Q\n\
2922            0 g\n\
2923            q\n\
2924            1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2925" + DotRadius + " 0 m\n\
2926" + DotRadius + " " + dc + " " + dc + " " + DotRadius + " 0 " + DotRadius + " c\n\
2927-" + dc + " " + DotRadius + " -" + DotRadius + " " + dc + " -" + DotRadius + " 0 c\n\
2928-" + DotRadius + " -" + dc + " -" + dc + " -" + DotRadius + " 0 -" + DotRadius + " c\n\
2929" + dc + " -" + DotRadius + " " + DotRadius + " -" + dc + " " + DotRadius + " 0 c\n\
2930            f\n\
2931            Q\n";
2932                xobj.stream = stream;
2933                return xobj;
2934            },
2935            OffPushDown: function OffPushDown(formObject) {
2936                var xobj = AcroForm.createFormXObject(formObject);
2937                var stream = "";
2938                var DotRadius = AcroForm.Appearance.internal.getWidth(formObject) <= AcroForm.Appearance.internal.getHeight(formObject) ? AcroForm.Appearance.internal.getWidth(formObject) / 4 : AcroForm.Appearance.internal.getHeight(formObject) / 4;
2939                // The Borderpadding...
2940                DotRadius *= 0.9;
2941                // Save results for later use; no need to waste processor ticks on doing math
2942                var k = DotRadius * 2;
2943                // var c = AcroForm.Appearance.internal.Bezier_C;
2944                var kc = k * AcroForm.Appearance.internal.Bezier_C;
2945                //                 stream += "0.749023 g\n\
2946                //             q\n\
2947                //  1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formObject) / 2 + " cm\n\
2948                // " + DotRadius * 2 + " 0 m\n\
2949                // " + DotRadius * 2 + " " + DotRadius * 2 * c + " " + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 " + DotRadius * 2 + " c\n\
2950                // -" + DotRadius * 2 * c + " " + DotRadius * 2 + " -" + DotRadius * 2 + " " + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 c\n\
2951                // -" + DotRadius * 2 + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 * c + " -" + DotRadius * 2 + " 0 -" + DotRadius * 2 + " c\n\
2952                // " + DotRadius * 2 * c + " -" + DotRadius * 2 + " " + DotRadius * 2 + " -" + DotRadius * 2 * c + " " + DotRadius * 2 + " 0 c\n\
2953                //             f\n\
2954                //             Q\n";
2955
2956                //  FASTER VERSION with less processor ticks spent on math operations
2957                stream += "0.749023 g\n\
2958            q\n\
2959 1 0 0 1 " + AcroForm.Appearance.internal.getWidth(formObject) / 2 + " " + AcroForm.Appearance.internal.getHeight(formOb
2959ject) / 2 + " cm\n\
2960" + k + " 0 m\n\
2961" + k + " " + kc + " " + kc + " " + k + " 0 " + k + " c\n\
2962-" + kc + " " + k + " -" + k + " " + kc + " -" + k + " 0 c\n\
2963-" + k + " -" + kc + " -" + kc + " -" + k + " 0 -" + k + " c\n\
2964" + kc + " -" + k + " " + k + " -" + kc + " " + k + " 0 c\n\
2965            f\n\
2966            Q\n";
2967                xobj.stream = stream;
2968                return xobj;
2969            }
2970        },
2971
2972        Cross: {
2973            /**
2974             * Creates the Actual AppearanceDictionary-References
2975             * @param name
2976             * @returns
2977             */
2978            createAppearanceStream: function createAppearanceStream(name) {
2979                var appearanceStreamContent = {
2980                    D: {
2981                        'Off': AcroForm.Appearance.RadioButton.Cross.OffPushDown
2982                    },
2983                    N: {}
2984                };
2985                appearanceStreamContent.N[name] = AcroForm.Appearance.RadioButton.Cross.YesNormal;
2986                appearanceStreamContent.D[name] = AcroForm.Appearance.RadioButton.Cross.YesPushDown;
2987                return appearanceStreamContent;
2988            },
2989            createMK: function createMK() {
2990                return "<< /CA (8)>>";
2991            },
2992
2993            YesNormal: function YesNormal(formObject) {
2994                var xobj = AcroForm.createFormXObject(formObject);
2995                var stream = "";
2996                var cross = AcroForm.Appearance.internal.calculateCross(formObject);
2997                stream += "q\n\
2998            1 1 " + (AcroForm.Appearance.internal.getWidth(formObject) - 2) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 2) + " re\n\
2999            W\n\
3000            n\n\
3001            " + cross.x1.x + " " + cross.x1.y + " m\n\
3002            " + cross.x2.x + " " + cross.x2.y + " l\n\
3003            " + cross.x4.x + " " + cross.x4.y + " m\n\
3004            " + cross.x3.x + " " + cross.x3.y + " l\n\
3005            s\n\
3006            Q\n";
3007                xobj.stream = stream;
3008                return xobj;
3009            },
3010            YesPushDown: function YesPushDown(formObject) {
3011                var xobj = AcroForm.createFormXObject(formObject);
3012                var cross = AcroForm.Appearance.internal.calculateCross(formObject);
3013                var stream = "";
3014                stream += "0.749023 g\n\
3015            0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\
3016            f\n\
3017            q\n\
3018            1 1 " + (AcroForm.Appearance.internal.getWidth(formObject) - 2) + " " + (AcroForm.Appearance.internal.getHeight(formObject) - 2) + " re\n\
3019            W\n\
3020            n\n\
3021            " + cross.x1.x + " " + cross.x1.y + " m\n\
3022            " + cross.x2.x + " " + cross.x2.y + " l\n\
3023            " + cross.x4.x + " " + cross.x4.y + " m\n\
3024            " + cross.x3.x + " " + cross.x3.y + " l\n\
3025            s\n\
3026            Q\n";
3027                xobj.stream = stream;
3028                return xobj;
3029            },
3030            OffPushDown: function OffPushDown(formObject) {
3031                var xobj = AcroForm.createFormXObject(formObject);
3032                var stream = "";
3033                stream += "0.749023 g\n\
3034            0 0 " + AcroForm.Appearance.internal.getWidth(formObject) + " " + AcroForm.Appearance.internal.getHeight(formObject) + " re\n\
3035            f\n";
3036                xobj.stream = stream;
3037                return xobj;
3038            }
3039        }
3040    },
3041
3042    /**
3043     * Returns the standard Appearance
3044     * @returns {AcroForm.FormXObject}
3045     */
3046    createDefaultAppearanceStream: function createDefaultAppearanceStream(formObject) {
3047        var stream = "";
3048        // Set Helvetica to Standard Font (size: auto)
3049        // Color: Black
3050        stream += "/Helv 0 Tf 0 g";
3051        return stream;
3052    }
3053};
3054
3055AcroForm.Appearance.internal = {
3056    Bezier_C: 0.551915024494,
3057
3058    calculateCross: function calculateCross(formObject) {
3059        var min = function min(x, y) {
3060            return x > y ? y : x;
3061        };
3062
3063        var width = AcroForm.Appearance.internal.getWidth(formObject);
3064        var height = AcroForm.Appearance.internal.getHeight(formOb
3064ject);
3065        var a = min(width, height);
3066        var crossSize = a;
3067        var borderPadding = 2; // The Padding in px
3068
3069
3070        var cross = {
3071            x1: { // upperLeft
3072                x: (width - a) / 2,
3073                y: (height - a) / 2 + a },
3074            x2: { // lowerRight
3075                x: (width - a) / 2 + a,
3076                y: (height - a) / 2 //borderPadding
3077            },
3078            x3: { // lowerLeft
3079                x: (width - a) / 2,
3080                y: (height - a) / 2 //borderPadding
3081            },
3082            x4: { // upperRight
3083                x: (width - a) / 2 + a,
3084                y: (height - a) / 2 + a }
3085        };
3086
3087        return cross;
3088    }
3089};
3090AcroForm.Appearance.internal.getWidth = function (formObject) {
3091    return formObject.Rect[2]; //(formObject.Rect[2] - formObject.Rect[0]) || 0;
3092};
3093AcroForm.Appearance.internal.getHeight = function (formObject) {
3094    return formObject.Rect[3]; //(formObject.Rect[1] - formObject.Rect[3]) || 0;
3095};
3096
3097// ##########################
3098
3099//### For inheritance:
3100AcroForm.internal.inherit = function (child, parent) {
3101    var ObjectCreate = Object.create || function (o) {
3102        var F = function F() {};
3103        F.prototype = o;
3104        return new F();
3105    };
3106    child.prototype = Object.create(parent.prototype);
3107    child.prototype.constructor = child;
3108};
3109
3110// ### Handy Functions:
3111
3112AcroForm.internal.arrayToPdfArray = function (array) {
3113    if (Array.isArray(array)) {
3114        var content = ' [';
3115        for (var i in array) {
3116            var element = array[i].toString();
3117            content += element;
3118            content += i < array.length - 1 ? ' ' : '';
3119        }
3120        content += ']';
3121
3122        return content;
3123    }
3124};
3125
3126AcroForm.internal.toPdfString = function (string) {
3127    string = string || "";
3128
3129    // put Bracket at the Beginning of the String
3130    if (string.indexOf('(') !== 0) {
3131        string = '(' + string;
3132    }
3133
3134    if (string.substring(string.length - 1) != ')') {
3135        string += '(';
3136    }
3137    return string;
3138};
3139
3140// ##########################
3141//          Classes
3142// ##########################
3143
3144
3145AcroForm.PDFObject = function () {
3146    // The Object ID in the PDF Object Model
3147    // todo
3148    var _objId;
3149    Object.defineProperty(this, 'objId', {
3150        get: function get() {
3151            if (!_objId) {
3152                if (this.internal) {
3153                    _objId = this.internal.newObjectDeferred();
3154                } else if (jsPDF.API.acroformPlugin.internal) {
3155                    // todo - find better option, that doesn't rely on a Global Static var
3156                    _objId = jsPDF.API.acroformPlugin.internal.newObjectDeferred();
3157                }
3158            }
3159            if (!_objId) {
3160                console.log("Couldn't create Object ID");
3161            }
3162            return _objId;
3163        },
3164        configurable: false
3165    });
3166};
3167
3168AcroForm.PDFObject.prototype.toString = function () {
3169    return this.objId + " 0 R";
3170};
3171
3172AcroForm.PDFObject.prototype.getString = function () {
3173    var res = this.objId + " 0 obj\n<<";
3174    var content = this.getContent();
3175
3176    res += content + ">>\n";
3177    if (this.stream) {
3178        res += "stream\n";
3179        res += this.stream;
3180        res += "endstream\n";
3181    }
3182    res += "endobj\n";
3183    return res;
3184};
3185
3186AcroForm.PDFObject.prototype.getContent = function () {
3187    /**
3188     * Prints out all enumerable Variables from the Object
3189     * @param fieldObject
3190     * @returns {string}
3191     */
3192    var createContentFromFieldObject = function createContentFromFieldObject(fieldObject) {
3193        var content = '';
3194
3195        var keys = Object.keys(fieldObject).filter(function (key) {
3196            return key != 'content' && key != 'appearanceStreamContent' && key.substring(0, 1) != "_";
3197        });
3198
3199        for (var i in keys) {
3200            var key = keys[i];
3201            var value = fieldObject[key];
3202
3203            /*if (key == 'Rect' && value) {
3204             value = AcroForm.internal.calculateCoordinates.call(jsPDF.API.acroformPlugin.internal, value);
3205             }*/
3206
3207            if (value) {
3208                if (Array.isArray(value)) {
3209                    content += '/' + key + ' ' + AcroForm.internal.arrayToPdfArray(value) + "\n";
3210                } else if (value instanceof AcroForm.PDFObject) {
3211                    // In case it is a reference to another PDFObject, take the referennce number
3212                    content += '/' + key + ' ' + value.objId + " 0 R" + "\n";
3213                } else {
3214                    content += '/' + key + ' ' + value + '\n';
3215                }
3216            }
3217        }
3218        return content;
3219    };
3220
3221    var object = "";
3222
3223    object += createContentFromFieldObject(this);
3224    return object;
3225};
3226
3227AcroForm.FormXObject = function () {
3228    AcroForm.PDFObject.call(this);
3229    this.Type = "/XObject";
3230    this.Subtype = "/Form";
3231    this.FormType = 1;
3232    this.BBox;
3233    this.Matrix;
3234    this.Resources = "2 0 R";
3235    this.PieceInfo;
3236    var _stream;
3237    Object.defineProperty(this, 'Length', {
3238        enumerable: true,
3239        get: function get() {
3240            return _stream !== undefined ? _stream.length : 0;
3241        }
3242    });
3243    Object.defineProperty(this, 'stream', {
3244        enumerable: false,
3245        set: function set(val) {
3246            _stream = val;
3247        },
3248        get: function get() {
3249            if (_stream) {
3250                return _stream;
3251            } else {
3252                return null;
3253            }
3254        }
3255    });
3256};
3257
3258AcroForm.internal.inherit(AcroForm.FormXObject, AcroForm.PDFObject);
3259
3260AcroForm.AcroFormDictionary = function () {
3261    AcroForm.PDFObject.call(this);
3262    var _Kids = [];
3263    Object.defineProperty(this, 'Kids', {
3264        enumerable: false,
3265        configurable: true,
3266        get: function get() {
3267            if (_Kids.length > 0) {
3268                return _Kids;
3269            } else {
3270                return;
3271            }
3272        }
3273    });
3274    Object.defineProperty(this, 'Fields', {
3275        enumerable: true,
3276        configurable: true,
3277        get: function get() {
3278            return _Kids;
3279        }
3280    });
3281    // Default Appearance
3282    this.DA;
3283};
3284
3285AcroForm.internal.inherit(AcroForm.AcroFormDictionary, AcroForm.PDFObject);
3286
3287// ##### The Objects, the User can Create:
3288
3289
3290// The Field Object contains the Variables, that every Field needs
3291// Rectangle for Appearance: lower_left_X, lower_left_Y, width, height
3292AcroForm.Field = function () {
3293    'use strict';
3294
3295    AcroForm.PDFObject.call(this);
3296
3297    var _Rect;
3298    Object.defineProperty(this, 'Rect', {
3299        enumerable: true,
3300        configurable: false,
3301        get: function get() {
3302            if (!_Rect) {
3303                return;
3304            }
3305            var tmp = _Rect;
3306            //var calculatedRes = AcroForm.internal.calculateCoordinates(_Rect); // do later!
3307            return tmp;
3308        },
3309        set: function set(val) {
3310            _Rect = val;
3311        }
3312    });
3313
3314    var _FT = "";
3315    Object.defineProperty(this, 'FT', {
3316        enumerable: true,
3317        set: function set(val) {
3318            _FT = val;
3319        },
3320        get: function get() {
3321            return _FT;
3322        }
3323    });
3324    /**
3325     * The Partial name of the Field Object.
3326     * It has to be unique.
3327     */
3328    var _T;
3329
3330    Object.defineProperty(this, 'T', {
3331        enumerable: true,
3332        configurable: false,
3333        set: function set(val) {
3334            _T = val;
3335        },
3336        get: function get() {
3337            if (!_T || _T.length < 1) {
3338                if (this instanceof AcroForm.ChildClass) {
3339                    // In case of a Child from a Radio´Group, you don't need a FieldName!!!
3340                    return;
3341                }
3342                return "(FieldObject" + AcroForm.Field.FieldNum++ + ")";
3343            }
3344            if (_T.substring(0, 1) == "(" && _T.substring(_T.length - 1)) {
3345                return _T;
3346            }
3347            return "(" + _T + ")";
3348        }
3349    });
3350
3351    var _DA;
3352    // Defines the default appearance (Needed for variable Text)
3353    Object.defineProperty(this, 'DA', {
3354        enumerable: true,
3355        get: function get() {
3356            if (!_DA) {
3357                return;
3358            }
3359            return '(' + _DA + ')';
3360        },
3361        set: function set(val) {
3362            _DA = val;
3363        }
3364    });
3365
3366    var _DV;
3367    // Defines the default value
3368    Object.defineProperty(this, 'DV', {
3369        enumerable: true,
3370        configurable: true,
3371        get: function get() {
3372            if (!_DV) {
3373                return;
3374            }
3375            return _DV;
3376        },
3377        set: function set(val) {
3378            _DV = val;
3379        }
3380    });
3381
3382    //this.Type = "/Annot";
3383    //this.Subtype = "/Widget";
3384    Object.defineProperty(this, 'Type', {
3385        enumerable: true,
3386        get: function get() {
3387            return this.hasAnnotation ? "/Annot" : null;
3388        }
3389    });
3390
3391    Object.defineProperty(this, 'Subtype', {
3392        enumerable: true,
3393        get: function get() {
3394            return this.hasAnnotation ? "/Widget" : null;
3395        }
3396    });
3397
3398    /**
3399     *
3400     * @type {Array}
3401     */
3402    this.BG;
3403
3404    Object.defineProperty(this, 'hasAnnotation', {
3405        enumerable: false,
3406        get: function get() {
3407            if (this.Rect || this.BC || this.BG) {
3408                return true;
3409            }
3410            return false;
3411        }
3412    });
3413
3414    Object.defineProperty(this, 'hasAppearanceStream', {
3415        enumerable: false,
3416        configurable: true,
3417        writable: true
3418    });
3419
3420    Object.defineProperty(this, 'page', {
3421        enumerable: false,
3422        configurable: true,
3423        writable: true
3424    });
3425};
3426AcroForm.Field.FieldNum = 0;
3427
3428AcroForm.internal.inherit(AcroForm.Field, AcroForm.PDFObject);
3429
3430AcroForm.ChoiceField = function () {
3431    AcroForm.Field.call(this);
3432    // Field Type = Choice Field
3433    this.FT = "/Ch";
3434    // options
3435    this.Opt = [];
3436    this.V = '()';
3437    // Top Index
3438    this.TI = 0;
3439    /**
3440     * Defines, whether the
3441     * @type {boolean}
3442     */
3443    this.combo = false;
3444    /**
3445     * Defines, whether the Choice Field is an Edit Field.
3446     * An Edit Field is automatically an Combo Field.
3447     */
3448    Object.defineProperty(this, 'edit', {
3449        enumerable: true,
3450        set: function set(val) {
3451            if (val == true) {
3452                this._edit = true;
3453                // ComboBox has to be true
3454                this.combo = true;
3455            } else {
3456                this._edit = false;
3457            }
3458        },
3459        get: function get() {
3460            if (!this._edit) {
3461                return false;
3462            }
3463            return this._edit;
3464        },
3465        configurable: false
3466    });
3467    this.hasAppearanceStream = true;
3468    Object.defineProperty(this, 'V', {
3469        get: function get() {
3470            AcroForm.internal.toPdfString();
3471        }
3472    });
3473};
3474AcroForm.internal.inherit(AcroForm.ChoiceField, AcroForm.Field);
3475window["ChoiceField"] = AcroForm.ChoiceField;
3476
3477AcroForm.ListBox = function () {
3478    AcroForm.ChoiceField.call(this);
3479    //var combo = true;
3480};
3481AcroForm.internal.inherit(AcroForm.ListBox, AcroForm.ChoiceField);
3482window["ListBox"] = AcroForm.ListBox;
3483
3484AcroForm.ComboBox = function () {
3485    AcroForm.ListBox.call(this);
3486    this.combo = true;
3487};
3488AcroForm.internal.inherit(AcroForm.ComboBox, AcroForm.ListBox);
3489window["ComboBox"] = AcroForm.ComboBox;
3490
3491AcroForm.EditBox = function () {
3492    AcroForm.ComboBox.call(this);
3493    this.edit = true;
3494};
3495AcroForm.internal.inherit(AcroForm.EditBox, AcroForm.ComboBox);
3496window["EditBox"] = AcroForm.EditBox;
3497
3498AcroForm.Button = function () {
3499    AcroForm.Field.call(this);
3500    this.FT = "/Btn";
3501    //this.hasAnnotation = true;
3502};
3503AcroForm.internal.inherit(AcroForm.Button, AcroForm.Field);
3504window["Button"] = AcroForm.Button;
3505
3506AcroForm.PushButton = function () {
3507    AcroForm.Button.call(this);
3508    this.pushbutton = true;
3509};
3510AcroForm.internal.inherit(AcroForm.PushButton, AcroForm.Button);
3511window["PushButton"] = AcroForm.PushButton;
3512
3513AcroForm.RadioButton = function () {
3514    AcroForm.Button.call(this);
3515    this.radio = true;
3516    var _Kids = [];
3517    Object.defineProperty(this, 'Kids', {
3518        enumerable: true,
3519        get: function get() {
3520            if (_Kids.length > 0) {
3521                return _Kids;
3522            }
3523        }
3524    });
3525
3526    Object.defineProperty(this, '__Kids', {
3527        get: function get() {
3528            return _Kids;
3529        }
3530    });
3531
3532    var _noToggleToOff;
3533
3534    Object.defineProperty(this, 'noToggleToOff', {
3535        enumerable: false,
3536        get: function get() {
3537            return _noToggleToOff;
3538        },
3539        set: function set(val) {
3540            _noToggleToOff = val;
3541        }
3542    });
3543
3544    //this.hasAnnotation = false;
3545};
3546AcroForm.internal.inherit(AcroForm.RadioButton, AcroForm.Button);
3547window["RadioButton"] = AcroForm.RadioButton;
3548
3549/*
3550 * The Child classs of a RadioButton (the radioGroup)
3551 * -> The single Buttons
3552 */
3553AcroForm.ChildClass = function (parent, name) {
3554    AcroForm.Field.call(this);
3555    this.Parent = parent;
3556
3557    // todo: set AppearanceType as variable that can be set from the outside...
3558    this._AppearanceType = AcroForm.Appearance.RadioButton.Circle; // The Default appearanceType is the Circle
3559    this.appearanceStreamContent = this._AppearanceType.createAppearanceStream(name);
3560
3561    // Set Print in the Annot Flag
3562    this.F = AcroForm.internal.setBitPosition(this.F, 3, 1);
3563
3564    // Set AppearanceCharacteristicsDictionary with default appearance if field is not interacting with user
3565    this.MK = this._AppearanceType.createMK(); // (8) -> Cross, (1)-> Circle, ()-> nothing
3566
3567    // Default Appearance is Off
3568    this.AS = "/Off"; // + name;
3569
3570    this._Name = name;
3571};
3572AcroForm.internal.inherit(AcroForm.ChildClass, AcroForm.Field);
3573
3574AcroForm.RadioButton.prototype.setAppearance = function (appearance) {
3575    if (!('createAppearanceStream' in appearance && 'createMK' in appearance)) {
3576        console.log("Couldn't assign Appearance to RadioButton. Appearance was Invalid!");
3577        return;
3578    }
3579    for (var i in this.__Kids) {
3580        var child = this.__Kids[i];
3581
3582        child.appearanceStreamContent = appearance.createAppearanceStream(child._Name);
3583        child.MK = appearance.createMK();
3584    }
3585};
3586
3587AcroForm.RadioButton.prototype.createOption = function (name) {
3588    var parent = this;
3589    var kidCount = this.__Kids.length;
3590
3591    // Create new Child for RadioGroup
3592    var child = new AcroForm.ChildClass(parent, name);
3593    // Add to Parent
3594    this.__Kids.push(child);
3595
3596    jsPDF.API.addField(child);
3597
3598    return child;
3599};
3600
3601AcroForm.CheckBox = function () {
3602    Button.call(this);
3603    this.appearanceStreamContent = AcroForm.Appearance.CheckBox.createAppearanceStream();
3604    this.MK = AcroForm.Appearance.CheckBox.createMK();
3605    this.AS = "/On";
3606    this.V = "/On";
3607};
3608AcroForm.internal.inherit(AcroForm.CheckBox, AcroForm.Button);
3609window["CheckBox"] = AcroForm.CheckBox;
3610
3611AcroForm.TextField = function () {
3612    AcroForm.Field.call(this);
3613    this.DA = AcroForm.Appearance.createDefaultAppearanceStream();
3614    this.F = 4;
3615    var _V;
3616    Object.defineProperty(this, 'V', {
3617        get: function get() {
3618            if (_V) {
3619                return "(" + _V + ")";
3620            } else {
3621                return _V;
3622            }
3623        },
3624        enumerable: true,
3625        set: function set(val) {
3626            _V = val;
3627        }
3628    });
3629
3630    var _DV;
3631    Object.defineProperty(this, 'DV', {
3632        get: function get() {
3633            if (_DV) {
3634                return "(" + _DV + ")";
3635            } else {
3636                return _DV;
3637            }
3638        },
3639        enumerable: true,
3640        set: function set(val) {
3641            _DV = val;
3642        }
3643    });
3644
3645    var _multiline = false;
3646    Object.defineProperty(this, 'multiline', {
3647        enumerable: false,
3648        get: function get() {
3649            return _multiline;
3650        },
3651        set: function set(val) {
3652            _multiline = val;
3653        }
3654    });
3655
3656    //this.multiline = false;
3657    //this.password = false;
3658    /**
3659     * For PDF 1.4
3660     * @type {boolean}
3661     */
3662    //this.fileSelect = false;
3663    /**
3664     * For PDF 1.4
3665     * @type {boolean}
3666     */
3667    //this.doNotSpellCheck = false;
3668    /**
3669     * For PDF 1.4
3670     * @type {boolean}
3671     */
3672    //this.doNotScroll = false;
3673
3674    var _MaxLen = false;
3675    Object.defineProperty(this, 'MaxLen', {
3676        enumerable: true,
3677        get: function get() {
3678            return _MaxLen;
3679        },
3680        set: function set(val) {
3681            _MaxLen = val;
3682        }
3683    });
3684
3685    Object.defineProperty(this, 'hasAppearanceStream', {
3686        enumerable: false,
3687        get: function get() {
3688            return this.V || this.DV;
3689        }
3690    });
3691};
3692AcroForm.internal.inherit(AcroForm.TextField, AcroForm.Field);
3693window["TextField"] = AcroForm.TextField;
3694
3695AcroForm.PasswordField = function () {
3696    TextField.call(this);
3697    Object.defineProperty(this, 'password', {
3698        value: true,
3699        enumerable: false,
3700        configurable: false,
3701        writable: false
3702    });
3703};
3704AcroForm.internal.inherit(AcroForm.PasswordField, AcroForm.TextField);
3705window["PasswordField"] = AcroForm.PasswordField;
3706
3707// ############ internal functions
3708
3709/*
3710 * small workaround for calculating the TextMetric approximately
3711 * @param text
3712 * @param fontsize
3713 * @returns {TextMetrics} (Has Height and Width)
3714 */
3715AcroForm.internal.calculateFontSpace = function (text, fontsize, fonttype) {
3716    var fonttype = fonttype || "helvetica";
3717    //re-use canvas object for speed improvements
3718    var canvas = AcroForm.internal.calculateFontSpace.canvas || (AcroForm.internal.calculateFontSpace.canvas = document.createElement('canvas'));
3719
3720    var context = canvas.getContext('2d');
3721    context.save();
3722    var newFont = fontsize + " " + fonttype;
3723    context.font = newFont;
3724    var res = context.measureText(text);
3725    context.fontcolor = 'black';
3726    // Calculate height:
3727    var context = canvas.getContext('2d');
3728    res.height = context.measureText("3").width * 1.5; // 3 because in ZapfDingbats its a Hook and a 3 in normal fonts
3729    context.restore();
3730
3731    var width = res.width;
3732
3733    return res;
3734};
3735
3736AcroForm.internal.calculateX = function (formObject, text, font, maxFontSize) {
3737    var maxFontSize = maxFontSize || 12;
3738    var font = font || "helvetica";
3739    var returnValue = {
3740        text: "",
3741        fontSize: ""
3742    };
3743    // Remove Brackets
3744    text = text.substr(0, 1) == '(' ? text.substr(1) : text;
3745    text = text.substr(text.length - 1) == ')' ? text.substr(0, text.length - 1) : text;
3746    // split into array of words
3747    var textSplit = text.split(' ');
3748
3749    /**
3750     * the color could be ((alpha)||(r,g,b)||(c,m,y,k))
3751     * @type {string}
3752     */
3753    var color = "0 g\n";
3754    var fontSize = maxFontSize; // The Starting fontSize (The Maximum)
3755    var lineSpacing = 2;
3756    var borderPadding = 2;
3757
3758    var height = AcroForm.Appearance.internal.getHeight(formObject) || 0;
3759    height = height < 0 ? -height : height;
3760    var width = AcroForm.Appearance.internal.getWidth(formObject) || 0;
3761    width = width < 0 ? -width : width;
3762
3763    var isSmallerThanWidth = function isSmallerThanWidth(i, lastLine, fontSize) {
3764        if (i + 1 < textSplit.length) {
3765            var tmp = lastLine + " " + textSplit[i + 1];
3766            var TextWidth = AcroForm.internal.calculateFontSpace(tmp, fontSize + "px", font).width;
3767            var FieldWidth = width - 2 * borderPadding;
3768            return TextWidth <= FieldWidth;
3769        } else {
3770            return false;
3771        }
3772    };
3773
3774    fontSize++;
3775    FontSize: while (true) {
3776        var text = "";
3777        fontSize--;
3778        var textHeight = AcroForm.internal.calculateFontSpace("3", fontSize + "px", font).height;
3779        var startY = formObject.multiline ? height - fontSize : (height - textHeight) / 2;
3780        startY += lineSpacing;
3781        var startX = -borderPadding;
3782
3783        var lastX = startX,
3784            lastY = startY;
3785        var firstWordInLine = 0,
3786            lastWordInLine = 0;
3787        var lastLength = 0;
3788
3789        var y = 0;
3790        if (fontSize == 0) {
3791            // In case, the Text doesn't fit at all
3792            fontSize = 12;
3793            text = "(...) Tj\n";
3794            text += "% Width of Text: " + AcroForm.internal.calculateFontSpace(text, "1px").width + ", FieldWidth:" + width + "\n";
3795            break;
3796        }
3797
3798        lastLength = AcroForm.internal.calculateFontSpace(textSplit[0] + " ", fontSize + "px", font).width;
3799
3800        var lastLine = "";
3801        var lineCount = 0;
3802        Line: for (var i in textSplit) {
3803            lastLine += textSplit[i] + " ";
3804            // Remove last blank
3805            lastLine = lastLine.substr(lastLine.length - 1) == " " ? lastLine.substr(0, lastLine.length - 1) : lastLine;
3806            var key = parseInt(i);
3807            lastLength = AcroForm.internal.calculateFontSpace(lastLine + " ", fontSize + "px", font).width;
3808            var nextLineIsSmaller = isSmallerThanWidth(key, lastLine, fontSize);
3809            var isLastWord = i >= textSplit.length - 1;
3810            if (nextLineIsSmaller && !isLastWord) {
3811                lastLine += " ";
3812                continue; // Line
3813            } else if (!nextLineIsSmaller && !isLastWord) {
3814                if (!formObject.multiline) {
3815                    continue FontSize;
3816                } else {
3817                    if ((textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) {
3818                        // If the Text is higher than the FieldObject
3819                        continue FontSize;
3820                    }
3821                    lastWordInLine = key;
3822                    // go on
3823                }
3824            } else if (isLastWord) {
3825                lastWordInLine = key;
3826            } else {
3827                if (formObject.multiline && (textHeight + lineSpacing) * (lineCount + 2) + lineSpacing > height) {
3828                    // If the Text is higher than the FieldObject
3829                    continue FontSize;
3830                }
3831            }
3832
3833            var line = '';
3834
3835            for (var x = firstWordInLine; x <= lastWordInLine; x++) {
3836                line += textSplit[x] + ' ';
3837            }
3838
3839            // Remove last blank
3840            line = line.substr(line.length - 1) == " " ? line.substr(0, line.length - 1) : line;
3841            //lastLength -= blankSpace.width;
3842            lastLength = AcroForm.internal.calculateFontSpace(line, fontSize + "px", font).width;
3843
3844            // Calculate startX
3845            switch (formObject.Q) {
3846                case 2:
3847                    // Right justified
3848                    startX = width - lastLength - borderPadding;
3849                    break;
3850                case 1:
3851                    // Q = 1 := Text-Alignment: Center
3852                    startX = (width - lastLength) / 2;
3853                    break;
3854                case 0:
3855                default:
3856                    startX = borderPadding;
3857                    break;
3858            }
3859            text += startX + ' ' + lastY + ' Td\n';
3860            text += '(' + line + ') Tj\n';
3861            // reset X in PDF
3862            text += -startX + ' 0 Td\n';
3863
3864            // After a Line, adjust y position
3865            lastY = -(fontSize + lineSpacing);
3866            lastX = startX;
3867
3868            // Reset for next iteration step
3869            lastLength = 0;
3870            firstWordInLine = lastWordInLine + 1;
3871            lineCount++;
3872
3873            lastLine = "";
3874            continue Line;
3875        }
3876        break;
3877    }
3878
3879    returnValue.text = text;
3880    returnValue.fontSize = fontSize;
3881
3882    return returnValue;
3883};
3884
3885AcroForm.internal.calculateAppearanceStream = function (formObject) {
3886    if (formObject.appearanceStreamContent) {
3887        // If appearanceStream is already set, use it
3888        return formObject.appearanceStreamContent;
3889    }
3890
3891    if (!formObject.V && !formObject.DV) {
3892        return;
3893    }
3894
3895    // else calculate it
3896
3897    var stream = '';
3898
3899    var text = formObject.V || formObject.DV;
3900
3901    var calcRes = AcroForm.internal.calculateX(formObject, text);
3902
3903    stream += '/Tx BMC\n' + 'q\n' +
3904    //color + '\n' +
3905    '/F1 ' + calcRes.fontSize + ' Tf\n' +
3906    // Text Matrix
3907    '1 0 0 1 0 0 Tm\n';
3908    // Begin Text
3909    stream += 'BT\n';
3910    stream += calcRes.text;
3911    // End Text
3912    stream += 'ET\n';
3913    stream += 'Q\n' + 'EMC\n';
3914
3915    var appearanceStreamContent = new AcroForm.createFormXObject(formObject);
3916
3917    appearanceStreamContent.stream = stream;
3918
3919    var appearance = {
3920        N: {
3921            'Normal': appearanceStreamContent
3922        }
3923    };
3924
3925    return appearanceStreamContent;
3926};
3927
3928/*
3929 * Converts the Parameters from x,y,w,h to lowerLeftX, lowerLeftY, upperRightX, upperRightY
3930 * @param x
3931 * @param y
3932 * @param w
3933 * @param h
3934 * @returns {*[]}
3935 */
3936AcroForm.internal.calculateCoordinates = function (x, y, w, h) {
3937    var coordinates = {};
3938
3939    if (this.internal) {
3940        var mmtopx = function mmtopx(x) {
3941            return x * this.internal.scaleFactor;
3942        };
3943
3944        if (Array.isArray(x)) {
3945            x[0] = AcroForm.scale(x[0]);
3946            x[1] = AcroForm.scale(x[1]);
3947            x[2] = AcroForm.scale(x[2]);
3948            x[3] = AcroForm.scale(x[3]);
3949
3950            coordinates.lowerLeft_X = x[0] || 0;
3951            coordinates.lowerLeft_Y = mmtopx.call(this, this.internal.pageSize.height) - x[3] - x[1] || 0;
3952            coordinates.upperRight_X = x[0] + x[2] || 0;
3953            coordinates.upperRight_Y = mmtopx.call(this, this.internal.pageSize.height) - x[1] || 0;
3954        } else {
3955            x = AcroForm.scale(x);
3956            y = AcroForm.scale(y);
3957            w = AcroForm.scale(w);
3958            h = AcroForm.scale(h);
3959            coordinates.lowerLeft_X = x || 0;
3960            coordinates.lowerLeft_Y = this.internal.pageSize.height - y || 0;
3961            coordinates.upperRight_X = x + w || 0;
3962            coordinates.upperRight_Y = this.internal.pageSize.height - y + h || 0;
3963        }
3964    } else {
3965        // old method, that is fallback, if we can't get the pageheight, the coordinate-system starts from lower left
3966        if (Array.isArray(x)) {
3967            coordinates.lowerLeft_X = x[0] || 0;
3968            coordinates.lowerLeft_Y = x[1] || 0;
3969            coordinates.upperRight_X = x[0] + x[2] || 0;
3970            coordinates.upperRight_Y = x[1] + x[3] || 0;
3971        } else {
3972            coordinates.lowerLeft_X = x || 0;
3973            coordinates.lowerLeft_Y = y || 0;
3974            coordinates.upperRight_X = x + w || 0;
3975            coordinates.upperRight_Y = y + h || 0;
3976        }
3977    }
3978
3979    return [coordinates.lowerLeft_X, coordinates.lowerLeft_Y, coordinates.upperRight_X, coordinates.upperRight_Y];
3980};
3981
3982AcroForm.internal.calculateColor = function (r, g, b) {
3983    var color = new Array(3);
3984    color.r = r | 0;
3985    color.g = g | 0;
3986    color.b = b | 0;
3987    return color;
3988};
3989
3990AcroForm.internal.getBitPosition = function (variable, position) {
3991    variable = variable || 0;
3992    var bitMask = 1;
3993    bitMask = bitMask << position - 1;
3994    return variable | bitMask;
3995};
3996
3997AcroForm.internal.setBitPosition = function (variable, position, value) {
3998    variable = variable || 0;
3999    value = value || 1;
4000
4001    var bitMask = 1;
4002    bitMask = bitMask << position - 1;
4003
4004    if (value == 1) {
4005        // Set the Bit to 1
4006        var variable = variable | bitMask;
4007    } else {
4008        // Set the Bit to 0
4009        var variable = variable & ~bitMask;
4010    }
4011
4012    return variable;
4013};
4014
4015/**
4016 * jsPDF addHTML PlugIn
4017 * Copyright (c) 2014 Diego Casorran
4018 *
4019 * Licensed under the MIT License.
4020 * http://opensource.org/licenses/mit-license
4021 */
4022
4023(function (jsPDFAPI) {
4024	'use strict';
4025
4026	/**
4027  * Renders an HTML element to canvas object which added to the PDF
4028  *
4029  * This feature requires [html2canvas](https://github.com/niklasvh/html2canvas)
4030  * or [rasterizeHTML](https://github.com/cburgmer/rasterizeHTML.js)
4031  *
4032  * @returns {jsPDF}
4033  * @name addHTML
4034  * @param element {Mixed} HTML Element, or anything supported by html2canvas.
4035  * @param x {Number} starting X coordinate in jsPDF instance's declared units.
4036  * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
4037  * @param options {Object} Additional options, check the code below.
4038  * @param callback {Function} to call when the rendering has finished.
4039  * NOTE: Every parameter is optional except 'element' and 'callback', in such
4040  *       case the image is positioned at 0x0 covering the whole PDF document
4041  *       size. Ie, to easily take screenshots of webpages saving them to PDF.
4042  * @deprecated This is being replace with a vector-supporting API. See
4043  * [this link](https://cdn.rawgit.com/MrRio/jsPDF/master/examples/html2pdf/showcase_supported_html.html)
4044  */
4045
4046	jsPDFAPI.addHTML = function (element, x, y, options, callback) {
4047		'use strict';
4048
4049		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');
4050
4051		if (typeof x !== 'number') {
4052			options = x;
4053			callback = y;
4054		}
4055
4056		if (typeof options === 'function') {
4057			callback = options;
4058			options = null;
4059		}
4060
4061		var I = this.internal,
4062		    K = I.scaleFactor,
4063		    W = I.pageSize.width,
4064		    H = I.pageSize.height;
4065
4066		options = options || {};
4067		options.onrendered = function (obj) {
4068			x = parseInt(x) || 0;
4069			y = parseInt(y) || 0;
4070			var dim = options.dim || {};
4071			var h = dim.h || 0;
4072			var w = dim.w || Math.min(W, obj.width / K) - x;
4073
4074			var format = 'JPEG';
4075			if (options.format) format = options.format;
4076
4077			if (obj.height > H && options.pagesplit) {
4078				var crop = function () {
4079					var cy = 0;
4080					while (1) {
4081						var canvas = document.createElement('canvas');
4082						canvas.width = Math.min(W * K, obj.width);
4083						canvas.height = Math.min(H * K, obj.height - cy);
4084						var ctx = canvas.getContext('2d');
4085						ctx.drawImage(obj, 0, cy, obj.width, canvas.height, 0, 0, canvas.width, canvas.height);
4086						var args = [canvas, x, cy ? 0 : y, canvas.width / K, canvas.height / K, format, null, 'SLOW'];
4087						this.addImage.apply(this, args);
4088						cy += canvas.height;
4089						if (cy >= obj.height) break;
4090						this.addPage();
4091					}
4092					callback(w, cy, null, args);
4093				}.bind(this);
4094				if (obj.nodeName === 'CANVAS') {
4095					var img = new Image();
4096					img.onload = crop;
4097					img.src = obj.toDataURL("image/png");
4098					obj = img;
4099				} else {
4100					crop();
4101				}
4102			} else {
4103				var alias = Math.random().toString(35);
4104				var args = [obj, x, y, w, h, format, alias, 'SLOW'];
4105
4106				this.addImage.apply(this, args);
4107
4108				callback(w, h, alias, args);
4109			}
4110		}.bind(this);
4111
4112		if (typeof html2canvas !== 'undefined' && !options.rstz) {
4113			return html2canvas(element, options);
4114		}
4115
4116		if (typeof rasterizeHTML !== 'undefined') {
4117			var meth = 'drawDocument';
4118			if (typeof element === 'string') {
4119				meth = /^http/.test(element) ? 'drawURL' : 'drawHTML';
4120			}
4121			options.width = options.width || W * K;
4122			return rasterizeHTML[meth](element, void 0, options).then(function (r) {
4123				options.onrendered(r.image);
4124			}, function (e) {
4125				callback(null, e);
4126			});
4127		}
4128
4129		return null;
4130	};
4131})(jsPDF.API);
4132
4133/** @preserve
4134 * jsPDF addImage plugin
4135 * Copyright (c) 2012 Jason Siefken, https://github.com/siefkenj/
4136 *               2013 Chris Dowling, https://github.com/gingerchris
4137 *               2013 Trinh Ho, https://github.com/ineedfat
4138 *               2013 Edwin Alejandro Perez, https://github.com/eaparango
4139 *               2013 Norah Smith, https://github.com/burnburnrocket
4140 *               2014 Diego Casorran, https://github.com/diegocr
4141 *               2014 James Robb, https://github.com/jamesbrobb
4142 *
4143 * 
4144 */
4145
4146(function (jsPDFAPI) {
4147	'use strict';
4148
4149	var namespace = 'addImage_',
4150	    supported_image_types = ['jpeg', 'jpg', 'png'];
4151
4152	// Image functionality ported from pdf.js
4153	var putImage = function putImage(img) {
4154
4155		var objectNumber = this.internal.newObject(),
4156		    out = this.internal.write,
4157		    putStream = this.internal.putStream;
4158
4159		img['n'] = objectNumber;
4160
4161		out('<</Type /XObject');
4162		out('/Subtype /Image');
4163		out('/Width ' + img['w']);
4164		out('/Height ' + img['h']);
4165		if (img['cs'] === this.color_spaces.INDEXED) {
4166			out('/ColorSpace [/Indexed /DeviceRGB '
4167			// if an indexed png defines more than one colour with transparency, we've created a smask
4168			+ (img['pal'].length / 3 - 1) + ' ' + ('smask' in img ? objectNumber + 2 : objectNumber + 1) + ' 0 R]');
4169		} else {
4170			out('/ColorSpace /' + img['cs']);
4171			if (img['cs'] === this.color_spaces.DEVICE_CMYK) {
4172				out('/Decode [1 0 1 0 1 0 1 0]');
4173			}
4174		}
4175		out('/BitsPerComponent ' + img['bpc']);
4176		if ('f' in img) {
4177			out('/Filter /' + img['f']);
4178		}
4179		if ('dp' in img) {
4180			out('/DecodeParms <<' + img['dp'] + '>>');
4181		}
4182		if ('trns' in img && img['trns'].constructor == Array) {
4183			var trns = '',
4184			    i = 0,
4185			    len = img['trns'].length;
4186			for (; i < len; i++) {
4187				trns += img['trns'][i] + ' ' + img['trns'][i] + ' ';
4188			}out('/Mask [' + trns + ']');
4189		}
4190		if ('smask' in img) {
4191			out('/SMask ' + (objectNumber + 1) + ' 0 R');
4192		}
4193		out('/Length ' + img['data'].length + '>>');
4194
4195		putStream(img['data']);
4196
4197		out('endobj');
4198
4199		// Soft mask
4200		if ('smask' in img) {
4201			var dp = '/Predictor ' + img['p'] + ' /Colors 1 /BitsPerComponent ' + img['bpc'] + ' /Columns ' + img['w'];
4202			var smask = { 'w': img['w'], 'h': img['h'], 'cs': 'DeviceGray', 'bpc': img['bpc'], 'dp': dp, 'data': img['smask'] };
4203			if ('f' in img) smask.f = img['f'];
4204			putImage.call(this, smask);
4205		}
4206
4207		//Palette
4208		if (img['cs'] === this.color_spaces.INDEXED) {
4209
4210			this.internal.newObject();
4211			//out('<< /Filter / ' + img['f'] +' /Length ' + img['pal'].length + '>>');
4212			//putStream(zlib.compress(img['pal']));
4213			out('<< /Length ' + img['pal'].length + '>>');
4214			putStream(this.arrayBufferToBinaryString(new Uint8Array(img['pal'])));
4215			out('endobj');
4216		}
4217	},
4218	    putResourcesCallback = function putResourcesCallback() {
4219		var images = this.internal.collections[namespace + 'images'];
4220		for (var i in images) {
4221			putImage.call(this, images[i]);
4222		}
4223	},
4224	    putXObjectsDictCallback = function putXObjectsDictCallback() {
4225		var images = this.internal.collections[namespace + 'images'],
4226		    out = this.internal.write,
4227		    image;
4228		for (var i in images) {
4229			image = images[i];
4230			out('/I' + image['i'], image['n'], '0', 'R');
4231		}
4232	},
4233	    checkCompressValue = function checkCompressValue(value) {
4234		if (value && typeof value === 'string') value = value.toUpperCase();
4235		return value in jsPDFAPI.image_compression ? value : jsPDFAPI.image_compression.NONE;
4236	},
4237	    getImages = function getImages() {
4238		var images = this.internal.collections[namespace + 'images'];
4239		//first run, so initialise stuff
4240		if (!images) {
4241			this.internal.collections[namespace + 'images'] = images = {};
4242			this.internal.events.subscribe('putResources', putResourcesCallback);
4243			this.internal.events.subscribe('putXobjectDict', putXObjectsDictCallback);
4244		}
4245
4246		return images;
4247	},
4248	    getImageIndex = function getImageIndex(images) {
4249		var imageIndex = 0;
4250
4251		if (images) {
4252			// this is NOT the first time this method is ran on this instance of jsPDF object.
4253			imageIndex = Object.keys ? Object.keys(images).length : function (o) {
4254				var i = 0;
4255				for (var e in o) {
4256					if (o.hasOwnProperty(e)) {
4257						i++;
4258					}
4259				}
4260				return i;
4261			}(images);
4262		}
4263
4264		return imageIndex;
4265	},
4266	    notDefined = function notDefined(value) {
4267		return typeof value === 'undefined' || value === null;
4268	},
4269	    generateAliasFromData = function generateAliasFromData(data) {
4270		return typeof data === 'string' && jsPDFAPI.sHashCode(data);
4271	},
4272	    doesNotSupportImageType = function doesNotSupportImageType(type) {
4273		return supported_image_types.indexOf(type) === -1;
4274	},
4275	    processMethodNotEnabled = function processMethodNotEnabled(type) {
4276		return typeof jsPDFAPI['process' + type.toUpperCase()] !== 'function';
4277	},
4278	    isDOMElement = function isDOMElement(object) {
4279		return (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && object.nodeType === 1;
4280	},
4281	    createDataURIFromElement = function createDataURIFromElement(element, format, angle) {
4282
4283		//if element is an image which uses data url definition, just return the dataurl
4284		if (element.nodeName === 'IMG' && element.hasAttribute('src')) {
4285			var src = '' + element.getAttribute('src');
4286			if (!angle && src.indexOf('data:image/') === 0) return src;
4287
4288			// only if the user doesn't care about a format
4289			if (!format && /\.png(?:[?#].*)?$/i.test(src)) format = 'png';
4290		}
4291
4292		if (element.nodeName === 'CANVAS') {
4293			var canvas = element;
4294		} else {
4295			var canvas = document.createElement('canvas');
4296			canvas.width = element.clientWidth || element.width;
4297			canvas.height = element.clientHeight || element.height;
4298
4299			var ctx = canvas.getContext('2d');
4300			if (!ctx) {
4301				throw 'addImage requires canvas to be supported by browser.';
4302			}
4303			if (angle) {
4304				var x,
4305				    y,
4306				    b,
4307				    c,
4308				    s,
4309				    w,
4310				    h,
4311				    to_radians = Math.PI / 180,
4312				    angleInRadians;
4313
4314				if ((typeof angle === 'undefined' ? 'undefined' : _typeof(angle)) === 'object') {
4315					x = angle.x;
4316					y = angle.y;
4317					b = angle.bg;
4318					angle = angle.angle;
4319				}
4320				angleInRadians = angle * to_radians;
4321				c = Math.abs(Math.cos(angleInRadians));
4322				s = Math.abs(Math.sin(angleInRadians));
4323				w = canvas.width;
4324				h = canvas.height;
4325				canvas.width = h * s + w * c;
4326				canvas.height = h * c + w * s;
4327
4328				if (isNaN(x)) x = canvas.width / 2;
4329				if (isNaN(y)) y = canvas.height / 2;
4330
4331				ctx.clearRect(0, 0, canvas.width, canvas.height);
4332				ctx.fillStyle = b || 'white';
4333				ctx.fillRect(0, 0, canvas.width, canvas.height);
4334				ctx.save();
4335				ctx.translate(x, y);
4336				ctx.rotate(angleInRadians);
4337				ctx.drawImage(element, -(w / 2), -(h / 2));
4338				ctx.rotate(-angleInRadians);
4339				ctx.translate(-x, -y);
4340				ctx.restore();
4341			} else {
4342				ctx.drawImage(element, 0, 0, canvas.width, canvas.height);
4343			}
4344		}
4345		return canvas.toDataURL(('' + format).toLowerCase() == 'png' ? 'image/png' : 'image/jpeg');
4346	},
4347	    checkImagesForAlias = function checkImagesForAlias(alias, images) {
4348		var cached_info;
4349		if (images) {
4350			for (var e in images) {
4351				if (alias === images[e].alias) {
4352					cached_info = images[e];
4353					break;
4354				}
4355			}
4356		}
4357		return cached_info;
4358	},
4359	    determineWidthAndHeight = function determineWidthAndHeight(w, h, info) {
4360		if (!w && !h) {
4361			w = -96;
4362			h = -96;
4363		}
4364		if (w < 0) {
4365			w = -1 * info['w'] * 72 / w / this.internal.scaleFactor;
4366		}
4367		if (h < 0) {
4368			h = -1 * info['h'] * 72 / h / this.internal.scaleFactor;
4369		}
4370		if (w === 0) {
4371			w = h * info['w'] / info['h'];
4372		}
4373		if (h === 0) {
4374			h = w * info['h'] / info['w'];
4375		}
4376
4377		return [w, h];
4378	},
4379	    writeImageToPDF = function writeImageToPDF(x, y, w, h, info, index, images) {
4380		var dims = determineWidthAndHeight.call(this, w, h, info),
4381		    coord = this.internal.getCoordinateString,
4382		    vcoord = this.internal.getVerticalCoordinateString;
4383
4384		w = dims[0];
4385		h = dims[1];
4386
4387		images[index] = info;
4388
4389		this.internal.write('q', coord(w), '0 0', coord(h) // TODO: check if this should be shifted by vcoord
4390		, coord(x), vcoord(y + h), 'cm /I' + info['i'], 'Do Q');
4391	};
4392
4393	/**
4394  * COLOR SPACES
4395  */
4396	jsPDFAPI.color_spaces = {
4397		DEVICE_RGB: 'DeviceRGB',
4398		DEVICE_GRAY: 'DeviceGray',
4399		DEVICE_CMYK: 'DeviceCMYK',
4400		CAL_GREY: 'CalGray',
4401		CAL_RGB: 'CalRGB',
4402		LAB: 'Lab',
4403		ICC_BASED: 'ICCBased',
4404		INDEXED: 'Indexed',
4405		PATTERN: 'Pattern',
4406		SEPARATION: 'Separation',
4407		DEVICE_N: 'DeviceN'
4408	};
4409
4410	/**
4411  * DECODE METHODS
4412  */
4413	jsPDFAPI.decode = {
4414		DCT_DECODE: 'DCTDecode',
4415		FLATE_DECODE: 'FlateDecode',
4416		LZW_DECODE: 'LZWDecode',
4417		JPX_DECODE: 'JPXDecode',
4418		JBIG2_DECODE: 'JBIG2Decode',
4419		ASCII85_DECODE: 'ASCII85Decode',
4420		ASCII_HEX_DECODE: 'ASCIIHexDecode',
4421		RUN_LENGTH_DECODE: 'RunLengthDecode',
4422		CCITT_FAX_DECODE: 'CCITTFaxDecode'
4423	};
4424
4425	/**
4426  * IMAGE COMPRESSION TYPES
4427  */
4428	jsPDFAPI.image_compression = {
4429		NONE: 'NONE',
4430		FAST: 'FAST',
4431		MEDIUM: 'MEDIUM',
4432		SLOW: 'SLOW'
4433	};
4434
4435	jsPDFAPI.sHashCode = function (str) {
4436		return Array.prototype.reduce && str.split("").reduce(function (a, b) {
4437			a = (a << 5) - a + b.charCodeAt(0);return a & a;
4438		}, 0);
4439	};
4440
4441	jsPDFAPI.isString = function (object) {
4442		return typeof object === 'string';
4443	};
4444
4445	/**
4446  * Strips out and returns info from a valid base64 data URI
4447  * @param {String[dataURI]} a valid data URI of format 'data:[<MIME-type>][;base64],<data>'
4448  * @returns an Array containing the following
4449  * [0] the complete data URI
4450  * [1] <MIME-type>
4451  * [2] format - the second part of the mime-type i.e 'png' in 'image/png'
4452  * [4] <data>
4453  */
4454	jsPDFAPI.extractInfoFromBase64DataURI = function (dataURI) {
4455		return (/^data:([\w]+?\/([\w]+?));base64,(.+?)$/g.exec(dataURI)
4456		);
4457	};
4458
4459	/**
4460  * Check to see if ArrayBuffer is supported
4461  */
4462	jsPDFAPI.supportsArrayBuffer = function () {
4463		return typeof ArrayBuffer !== 'undefined' && typeof Uint8Array !== 'undefined';
4464	};
4465
4466	/**
4467  * Tests supplied object to determine if ArrayBuffer
4468  * @param {Object[object]}
4469  */
4470	jsPDFAPI.isArrayBuffer = function (object) {
4471		if (!this.supportsArrayBuffer()) return false;
4472		return object instanceof ArrayBuffer;
4473	};
4474
4475	/**
4476  * Tests supplied object to determine if it implements the ArrayBufferView (TypedArray) interface
4477  * @param {Object[object]}
4478  */
4479	jsPDFAPI.isArrayBufferView = function (object) {
4480		if (!this.supportsArrayBuffer()) return false;
4481		if (typeof Uint32Array === 'undefined') return false;
4482		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;
4483	};
4484
4485	/**
4486  * Exactly what it says on the tin
4487  */
4488	jsPDFAPI.binaryStringToUint8Array = function (binary_string) {
4489		/*
4490   * not sure how efficient this will be will bigger files. Is there a native method?
4491   */
4492		var len = binary_string.length;
4493		var bytes = new Uint8Array(len);
4494		for (var i = 0; i < len; i++) {
4495			bytes[i] = binary_string.charCodeAt(i);
4496		}
4497		return bytes;
4498	};
4499
4500	/**
4501  * @see this discussion
4502  * http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers
4503  *
4504  * As stated, i imagine the method below is highly inefficent for large files.
4505  *
4506  * Also of note from Mozilla,
4507  *
4508  * "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)."
4509  *
4510  * https://developer.mozilla.org/en-US/Add-ons/Code_snippets/StringView
4511  *
4512  * Although i'm strugglig to see how StringView solves this issue? Doesn't appear to be a direct method for conversion?
4513  *
4514  * Async method using Blob and FileReader could be best, but i'm not sure how to fit it into the flow?
4515  */
4516	jsPDFAPI.arrayBufferToBinaryString = function (buffer) {
4517		/*if('TextDecoder' in window){
4518  	var decoder = new TextDecoder('ascii');
4519  	return decoder.decode(buffer);
4520  }*/
4521
4522		if (this.isArrayBuffer(buffer)) buffer = new Uint8Array(buffer);
4523
4524		var binary_string = '';
4525		var len = buffer.byteLength;
4526		for (var i = 0; i < len; i++) {
4527			binary_string += String.fromCharCode(buffer[i]);
4528		}
4529		return binary_string;
4530		/*
4531   * Another solution is the method below - convert array buffer straight to base64 and then use atob
4532   */
4533		//return atob(this.arrayBufferToBase64(buffer));
4534	};
4535
4536	/**
4537  * Converts an ArrayBuffer directly to base64
4538  *
4539  * Taken from here
4540  *
4541  * http://jsperf.com/encoding-xhr-image-data/31
4542  *
4543  * Need to test if this is a better solution for larger files
4544  *
4545  */
4546	jsPDFAPI.arrayBufferToBase64 = function (arrayBuffer) {
4547		var base64 = '';
4548		var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
4549
4550		var bytes = new Uint8Array(arrayBuffer);
4551		var byteLength = bytes.byteLength;
4552		var byteRemainder = byteLength % 3;
4553		var mainLength = byteLength - byteRemainder;
4554
4555		var a, b, c, d;
4556		var chunk;
4557
4558		// Main loop deals with bytes in chunks of 3
4559		for (var i = 0; i < mainLength; i = i + 3) {
4560			// Combine the three bytes into a single integer
4561			chunk = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2];
4562
4563			// Use bitmasks to extract 6-bit segments from the triplet
4564			a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
4565			b = (chunk & 258048) >> 12; // 258048   = (2^6 - 1) << 12
4566			c = (chunk & 4032) >> 6; // 4032     = (2^6 - 1) << 6
4567			d = chunk & 63; // 63       = 2^6 - 1
4568
4569			// Convert the raw binary segments to the appropriate ASCII encoding
4570			base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
4571		}
4572
4573		// Deal with the remaining bytes and padding
4574		if (byteRemainder == 1) {
4575			chunk = bytes[mainLength];
4576
4577			a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
4578
4579			// Set the 4 least significant bits to zero
4580			b = (chunk & 3) << 4; // 3   = 2^2 - 1
4581
4582			base64 += encodings[a] + encodings[b] + '==';
4583		} else if (byteRemainder == 2) {
4584			chunk = bytes[mainLength] << 8 | bytes[mainLength + 1];
4585
4586			a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
4587			b = (chunk & 1008) >> 4; // 1008  = (2^6 - 1) << 4
4588
4589			// Set the 2 least significant bits to zero
4590			c = (chunk & 15) << 2; // 15    = 2^4 - 1
4591
4592			base64 += encodings[a] + encodings[b] + encodings[c] + '=';
4593		}
4594
4595		return base64;
4596	};
4597
4598	jsPDFAPI.createImageInfo = function (data, wd, ht, cs, bpc, f, imageIndex, alias, dp, trns, pal, smask, p) {
4599		var info = {
4600			alias: alias,
4601			w: wd,
4602			h: ht,
4603			cs: cs,
4604			bpc: bpc,
4605			i: imageIndex,
4606			data: data
4607			// n: objectNumber will be added by putImage code
4608		};
4609
4610		if (f) info.f = f;
4611		if (dp) info.dp = dp;
4612		if (trns) info.trns = trns;
4613		if (pal) info.pal = pal;
4614		if (smask) info.smask = smask;
4615		if (p) info.p = p; // predictor parameter for PNG compression
4616
4617		return info;
4618	};
4619
4620	jsPDFAPI.addImage = function (imageData, format, x, y, w, h, alias, compression, rotation) {
4621		'use strict';
4622
4623		if (typeof format !== 'string') {
4624			var tmp = h;
4625			h = w;
4626			w = y;
4627			y = x;
4628			x = format;
4629			format = tmp;
4630		}
4631
4632		if ((typeof imageData === 'undefined' ? 'undefined' : _typeof(imageData)) === 'object' && !isDOMElement(imageData) && "imageData" in imageData) {
4633			var options = imageData;
4634
4635			imageData = options.imageData;
4636			format = options.format || format;
4637			x = options.x || x || 0;
4638			y = options.y || y || 0;
4639			w = options.w || w;
4640			h = options.h || h;
4641			alias = options.alias || alias;
4642			compression = options.compression || compression;
4643			rotation = options.rotation || options.angle || rotation;
4644		}
4645
4646		if (isNaN(x) || isNaN(y)) {
4647			console.error('jsPDF.addImage: Invalid coordinates', arguments);
4648			throw new Error('Invalid coordinates passed to jsPDF.addImage');
4649		}
4650
4651		var images = getImages.call(this),
4652		    info;
4653
4654		if (!(info = checkImagesForAlias(imageData, images))) {
4655			var dataAsBinaryString;
4656
4657			if (isDOMElement(imageData)) imageData = createDataURIFromElement(imageData, format, rotation);
4658
4659			if (notDefined(alias)) alias = generateAliasFromData(imageData);
4660
4661			if (!(info = checkImagesForAlias(alias, images))) {
4662
4663				if (this.isString(imageData)) {
4664
4665					var base64Info = this.extractInfoFromBase64DataURI(imageData);
4666
4667					if (base64Info) {
4668
4669						format = base64Info[2];
4670						imageData = atob(base64Info[3]); //convert to binary string
4671					} else {
4672
4673						if (imageData.charCodeAt(0) === 0x89 && imageData.charCodeAt(1) === 0x50 && imageData.charCodeAt(2) === 0x4e && imageData.charCodeAt(3) === 0x47) format = 'png';
4674					}
4675				}
4676				format = (format || 'JPEG').toLowerCase();
4677
4678				if (doesNotSupportImageType(format)) throw new Error('addImage currently only supports formats ' + supported_image_types + ', not \'' + format + '\'');
4679
4680				if (processMethodNotEnabled(format)) throw new Error('please ensure that the plugin for \'' + format + '\' support is added');
4681
4682				/**
4683     * need to test if it's more efficient to convert all binary strings
4684     * to TypedArray - or should we just leave and process as string?
4685     */
4686				if (this.supportsArrayBuffer()) {
4687					// no need to convert if imageData is already uint8array
4688					if (!(imageData instanceof Uint8Array)) {
4689						dataAsBinaryString = imageData;
4690						imageData = this.binaryStringToUint8Array(imageData);
4691					}
4692				}
4693
4694				info = this['process' + format.toUpperCase()](imageData, getImageIndex(images), alias, checkCompressValue(compression), dataAsBinaryString);
4695
4696				if (!info) throw new Error('An unkwown error occurred whilst processing the image');
4697			}
4698		}
4699
4700		writeImageToPDF.call(this, x, y, w, h, info, info.i, images);
4701
4702		return this;
4703	};
4704
4705	/**
4706  * JPEG SUPPORT
4707  **/
4708
4709	//takes a string imgData containing the raw bytes of
4710	//a jpeg image and returns [width, height]
4711	//Algorithm from: http://www.64lines.com/jpeg-width-height
4712	var getJpegSize = function getJpegSize(imgData) {
4713		'use strict';
4714
4715		var width, height, numcomponents;
4716		// Verify we have a valid jpeg header 0xff,0xd8,0xff,0xe0,?,?,'J','F','I','F',0x00
4717		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) {
4718			throw new Error('getJpegSize requires a binary string jpeg file');
4719		}
4720		var blockLength = imgData.charCodeAt(4) * 256 + imgData.charCodeAt(5);
4721		var i = 4,
4722		    len = imgData.length;
4723		while (i < len) {
4724			i += blockLength;
4725			if (imgData.charCodeAt(i) !== 0xff) {
4726				throw new Error('getJpegSize could not find the size of the image');
4727			}
4728			if (imgData.charCodeAt(i + 1) === 0xc0 || //(SOF) Huffman  - Baseline DCT
4729			imgData.charCodeAt(i + 1) === 0xc1 || //(SOF) Huffman  - Extended sequential DCT
4730			imgData.charCodeAt(i + 1) === 0xc2 || // Progressive DCT (SOF2)
4731			imgData.charCodeAt(i + 1) === 0xc3 || // Spatial (sequential) lossless (SOF3)
4732			imgData.charCodeAt(i + 1) === 0xc4 || // Differential sequential DCT (SOF5)
4733			imgData.charCodeAt(i + 1) === 0xc5 || // Differential progressive DCT (SOF6)
4734			imgData.charCodeAt(i + 1) === 0xc6 || // Differential spatial (SOF7)
4735			imgData.charCodeAt(i + 1) === 0xc7) {
4736				height = imgData.charCodeAt(i + 5) * 256 + imgData.charCodeAt(i + 6);
4737				width = imgData.charCodeAt(i + 7) * 256 + imgData.charCodeAt(i + 8);
4738				numcomponents = imgData.charCodeAt(i + 9);
4739				return [width, height, numcomponents];
4740			} else {
4741				i += 2;
4742				blockLength = imgData.charCodeAt(i) * 256 + imgData.charCodeAt(i + 1);
4743			}
4744		}
4745	},
4746	    getJpegSizeFromBytes = function getJpegSizeFromBytes(data) {
4747
4748		var hdr = data[0] << 8 | data[1];
4749
4750		if (hdr !== 0xFFD8) throw new Error('Supplied data is not a JPEG');
4751
4752		var len = data.length,
4753		    block = (data[4] << 8) + data[5],
4754		    pos = 4,
4755		    bytes,
4756		    width,
4757		    height,
4758		    numcomponents;
4759
4760		while (pos < len) {
4761			pos += block;
4762			bytes = readBytes(data, pos);
4763			block = (bytes[2] << 8) + bytes[3];
4764			if ((bytes[1] === 0xC0 || bytes[1] === 0xC2) && bytes[0] === 0xFF && block > 7) {
4765				bytes = readBytes(data, pos + 5);
4766				width = (bytes[2] << 8) + bytes[3];
4767				height = (bytes[0] << 8) + bytes[1];
4768				numcomponents = bytes[4];
4769				return { width: width, height: height, numcomponents: numcomponents };
4770			}
4771
4772			pos += 2;
4773		}
4774
4775		throw new Error('getJpegSizeFromBytes could not find the size of the image');
4776	},
4777	    readBytes = function readBytes(data, offset) {
4778		return data.subarray(offset, offset + 5);
4779	};
4780
4781	jsPDFAPI.processJPEG = function (data, index, alias, compression, dataAsBinaryString) {
4782		'use strict';
4783
4784		var colorSpace = this.color_spaces.DEVICE_RGB,
4785		    filter = this.decode.DCT_DECODE,
4786		    bpc = 8,
4787		    dims;
4788
4789		if (this.isString(data)) {
4790			dims = getJpegSize(data);
4791			return this.createImageInfo(data, dims[0], dims[1], dims[3] == 1 ? this.color_spaces.DEVICE_GRAY : colorSpace, bpc, filter, index, alias);
4792		}
4793
4794		if (this.isArrayBuffer(data)) data = new Uint8Array(data);
4795
4796		if (this.isArrayBufferView(data)) {
4797
4798			dims = getJpegSizeFromBytes(data);
4799
4800			// if we already have a stored binary string rep use that
4801			data = dataAsBinaryString || this.arrayBufferToBinaryString(data);
4802
4803			return this.createImageInfo(data, dims.width, dims.height, dims.numcomponents == 1 ? this.color_spaces.DEVICE_GRAY : colorSpace, bpc, filter, index, alias);
4804		}
4805
4806		return null;
4807	};
4808
4809	jsPDFAPI.processJPG = function () /*data, index, alias, compression, dataAsBinaryString*/{
4810		return this.processJPEG.apply(this, arguments);
4811	};
4812})(jsPDF.API);
4813
4814/**
4815 * jsPDF Annotations PlugIn
4816 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC)  [email protected]
4817 *
4818 * Licensed under the MIT License.
4819 * http://opensource.org/licenses/mit-license
4820 */
4821
4822/**
4823 * There are many types of annotations in a PDF document. Annotations are placed
4824 * on a page at a particular location. They are not 'attached' to an object.
4825 * <br />
4826 * This plugin current supports <br />
4827 * <li> Goto Page (set pageNumber and top in options)
4828 * <li> Goto Name (set name and top in options)
4829 * <li> Goto URL (set url in options)
4830 * <p>
4831 * 	The destination magnification factor can also be specified when goto is a page number or a named destination. (see documentation below)
4832 *  (set magFactor in options).  XYZ is the default.
4833 * </p>
4834 * <p>
4835 *  Links, Text, Popup, and FreeText are supported.
4836 * </p>
4837 * <p>
4838 * Options In PDF spec Not Implemented Yet
4839 * <li> link border
4840 * <li> named target
4841 * <li> page coordinates
4842 * <li> destination page scaling and layout
4843 * <li> actions other than URL and GotoPage
4844 * <li> background / hover actions
4845 * </p>
4846 */
4847
4848/*
4849    Destination Magnification Factors
4850    See PDF 1.3 Page 386 for meanings and options
4851
4852    [supported]
4853	XYZ (options; left top zoom)
4854	Fit (no options)
4855	FitH (options: top)
4856	FitV (options: left)
4857
4858	[not supported]
4859	FitR
4860	FitB
4861	FitBH
4862	FitBV
4863 */
4864
4865(function (jsPDFAPI) {
4866	'use strict';
4867
4868	var annotationPlugin = {
4869
4870		/**
4871   * An array of arrays, indexed by <em>pageNumber</em>.
4872   */
4873		annotations: [],
4874
4875		f2: function f2(number) {
4876			return number.toFixed(2);
4877		},
4878
4879		notEmpty: function notEmpty(obj) {
4880			if (typeof obj != 'undefined') {
4881				if (obj != '') {
4882					return true;
4883				}
4884			}
4885		}
4886	};
4887
4888	jsPDF.API.annotationPlugin = annotationPlugin;
4889
4890	jsPDF.API.events.push(['addPage', function (info) {
4891		this.annotationPlugin.annotations[info.pageNumber] = [];
4892	}]);
4893
4894	jsPDFAPI.events.push(['putPage', function (info) {
4895		//TODO store annotations in pageContext so reorder/remove will not affect them.
4896		var pageAnnos = this.annotationPlugin.annotations[info.pageNumber];
4897
4898		var found = false;
4899		for (var a = 0; a < pageAnnos.length && !found; a++) {
4900			var anno = pageAnnos[a];
4901			switch (anno.type) {
4902				case 'link':
4903					if (annotationPlugin.notEmpty(anno.options.url) || annotationPlugin.notEmpty(anno.options.pageNumber)) {
4904						found = true;
4905						break;
4906					}
4907				case 'reference':
4908				case 'text':
4909				case 'freetext':
4910					found = true;
4911					break;
4912			}
4913		}
4914		if (found == false) {
4915			return;
4916		}
4917
4918		this.internal.write("/Annots [");
4919		var f2 = this.annotationPlugin.f2;
4920		var k = this.internal.scaleFactor;
4921		var pageHeight = this.internal.pageSize.height;
4922		var pageInfo = this.internal.getPageInfo(info.pageNumber);
4923		for (var a = 0; a < pageAnnos.length; a++) {
4924			var anno = pageAnnos[a];
4925
4926			switch (anno.type) {
4927				case 'reference':
4928					// References to Widget Anotations (for AcroForm Fields)
4929					this.internal.write(' ' + anno.object.objId + ' 0 R ');
4930					break;
4931				case 'text':
4932					// Create a an object for both the text and the popup
4933					var objText = this.internal.newAdditionalObject();
4934					var objPopup = this.internal.newAdditionalObject();
4935
4936					var title = anno.title || 'Note';
4937					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) + "] ";
4938					line = '<</Type /Annot /Subtype /' + 'Text' + ' ' + rect + '/Contents (' + anno.contents + ')';
4939					line += ' /Popup ' + objPopup.objId + " 0 R";
4940					line += ' /P ' + pageInfo.objId + " 0 R";
4941					line += ' /T (' + title + ') >>';
4942					objText.content = line;
4943
4944					var parent = objText.objId + ' 0 R';
4945					var popoff = 30;
4946					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) + "] ";
4947					//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) + "] ";
4948					line = '<</Type /Annot /Subtype /' + 'Popup' + ' ' + rect + ' /Parent ' + parent;
4949					if (anno.open) {
4950						line += ' /Open true';
4951					}
4952					line += ' >>';
4953					objPopup.content = line;
4954
4955					this.internal.write(objText.objId, '0 R', objPopup.objId, '0 R');
4956
4957					break;
4958				case 'freetext':
4959					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) + "] ";
4960					var color = anno.color || '#000000';
4961					line = '<</Type /Annot /Subtype /' + 'FreeText' + ' ' + rect + '/Contents (' + anno.contents + ')';
4962					line += ' /DS(font: Helvetica,sans-serif 12.0pt; text-align:left; color:#' + color + ')';
4963					line += ' /Border [0 0 0]';
4964					line += ' >>';
4965					this.internal.write(line);
4966					break;
4967				case 'link':
4968					if (anno.options.name) {
4969						var loc = this.annotations._nameMap[anno.options.name];
4970						anno.options.pageNumber = loc.page;
4971						anno.options.top = loc.y;
4972					} else {
4973						if (!anno.options.top) {
4974							anno.options.top = 0;
4975						}
4976					}
4977
4978					//var pageHeight = this.internal.pageSize.height * this.internal.scaleFactor;
4979					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) + "] ";
4980
4981					var line = '';
4982					if (anno.options.url) {
4983						line = '<</Type /Annot /Subtype /Link ' + rect + '/Border [0 0 0] /A <</S /URI /URI (' + anno.options.url + ') >>';
4984					} else if (anno.options.pageNumber) {
4985						// first page is 0
4986						var info = this.internal.getPageInfo(anno.options.pageNumber);
4987						line = '<</Type /Annot /Subtype /Link ' + rect + '/Border [0 0 0] /Dest [' + info.objId + " 0 R";
4988						anno.options.magFactor = anno.options.magFactor || "XYZ";
4989						switch (anno.options.magFactor) {
4990							case 'Fit':
4991								line += ' /Fit]';
4992								break;
4993							case 'FitH':
4994								//anno.options.top = anno.options.top || f2(pageHeight * k);
4995								line += ' /FitH ' + anno.options.top + ']';
4996								break;
4997							case 'FitV':
4998								anno.options.left = anno.options.left || 0;
4999								line += ' /FitV ' + anno.options.left + ']';
5000								break;
5001							case 'XYZ':
5002							default:
5003								var top = f2((pageHeight - anno.options.top) * k); // || f2(pageHeight * k);
5004								anno.options.left = anno.options.left || 0;
5005								// 0 or null zoom will not change zoom factor
5006								if (typeof anno.options.zoom === 'undefined') {
5007									anno.options.zoom = 0;
5008								}
5009								line += ' /XYZ ' + anno.options.left + ' ' + top + ' ' + anno.options.zoom + ']';
5010								break;
5011						}
5012					} else {
5013						// TODO error - should not be here
5014					}
5015					if (line != '') {
5016						line += " >>";
5017						this.internal.write(line);
5018					}
5019					break;
5020			}
5021		}
5022		this.internal.write("]");
5023	}]);
5024
5025	jsPDFAPI.createAnnotation = function (options) {
5026		switch (options.type) {
5027			case 'link':
5028				this.link(options.bounds.x, options.bounds.y, options.bounds.w, options.bounds.h, options);
5029				break;
5030			case 'text':
5031			case 'freetext':
5032				this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push(options);
5033				break;
5034		}
5035	};
5036
5037	/**
5038  * valid options
5039  * <li> pageNumber or url [required]
5040  * <p>If pageNumber is specified, top and zoom may also be specified</p>
5041  */
5042	jsPDFAPI.link = function (x, y, w, h, options) {
5043		'use strict';
5044
5045		this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push({
5046			x: x,
5047			y: y,
5048			w: w,
5049			h: h,
5050			options: options,
5051			type: 'link'
5052		});
5053	};
5054
5055	/**
5056  * valid options
5057  * <li> pageNumber or url [required]
5058  * <p>If pageNumber is specified, top and zoom may also be specified</p>
5059  */
5060	jsPDFAPI.link = function (x, y, w, h, options) {
5061		'use strict';
5062
5063		this.annotationPlugin.annotations[this.internal.getCurrentPageInfo().pageNumber].push({
5064			x: x,
5065			y: y,
5066			w: w,
5067			h: h,
5068			options: options,
5069			type: 'link'
5070		});
5071	};
5072
5073	/**
5074  * Currently only supports single line text.
5075  * Returns the width of the text/link
5076  */
5077	jsPDFAPI.textWithLink = function (text, x, y, options) {
5078		'use strict';
5079
5080		var width = this.getTextWidth(text);
5081		var height = this.internal.getLineHeight();
5082		this.text(text, x, y);
5083		//TODO We really need the text baseline height to do this correctly.
5084		// Or ability to draw text on top, bottom, center, or baseline.
5085		y += height * .2;
5086		this.link(x, y - height, width, height, options);
5087		return width;
5088	};
5089
5090	//TODO move into external library
5091	jsPDFAPI.getTextWidth = function (text) {
5092		'use strict';
5093
5094		var fontSize = this.internal.getFontSize();
5095		var txtWidth = this.getStringUnitWidth(text) * fontSize / this.internal.scaleFactor;
5096		return txtWidth;
5097	};
5098
5099	//TODO move into external library
5100	jsPDFAPI.getLineHeight = function () {
5101		return this.internal.getLineHeight();
5102	};
5103
5104	return this;
5105})(jsPDF.API);
5106
5107/**
5108 * jsPDF Autoprint Plugin
5109 *
5110 * Licensed under the MIT License.
5111 * http://opensource.org/licenses/mit-license
5112 */
5113
5114/**
5115* Makes the PDF automatically print. This works in Chrome, Firefox, Acrobat
5116* Reader.
5117*
5118* @returns {jsPDF}
5119* @name autoPrint
5120* @example
5121* var doc = new jsPDF()
5122* doc.text(10, 10, 'This is a test')
5123* doc.autoPrint()
5124* doc.save('autoprint.pdf')
5125*/
5126
5127(function (jsPDFAPI) {
5128  'use strict';
5129
5130  jsPDFAPI.autoPrint = function () {
5131    'use strict';
5132
5133    var refAutoPrintTag;
5134
5135    this.internal.events.subscribe('postPutResources', function () {
5136      refAutoPrintTag = this.internal.newObject();
5137      this.internal.write("<< /S/Named /Type/Action /N/Print >>", "endobj");
5138    });
5139
5140    this.internal.events.subscribe("putCatalog", function () {
5141      this.internal.write("/OpenAction " + refAutoPrintTag + " 0" + " R");
5142    });
5143    return this;
5144  };
5145})(jsPDF.API);
5146
5147/**
5148 * jsPDF Canvas PlugIn
5149 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC)  [email protected]
5150 *
5151 * Licensed under the MIT License.
5152 * http://opensource.org/licenses/mit-license
5153 */
5154
5155/**
5156 * This plugin mimics the HTML5 Canvas
5157 * 
5158 * The goal is to provide a way for current canvas users to print directly to a PDF.
5159 */
5160
5161(function (jsPDFAPI) {
5162	'use strict';
5163
5164	jsPDFAPI.events.push(['initialized', function () {
5165		this.canvas.pdf = this;
5166	}]);
5167
5168	jsPDFAPI.canvas = {
5169		getContext: function getContext(name) {
5170			this.pdf.context2d._canvas = this;
5171			return this.pdf.context2d;
5172		},
5173		style: {}
5174	};
5175
5176	Object.defineProperty(jsPDFAPI.canvas, 'width', {
5177		get: function get() {
5178			return this._width;
5179		},
5180		set: function set(value) {
5181			this._width = value;
5182			this.getContext('2d').pageWrapX = value + 1;
5183		}
5184	});
5185
5186	Object.defineProperty(jsPDFAPI.canvas, 'height', {
5187		get: function get() {
5188			return this._height;
5189		},
5190		set: function set(value) {
5191			this._height = value;
5192			this.getContext('2d').pageWrapY = value + 1;
5193		}
5194	});
5195
5196	return this;
5197})(jsPDF.API);
5198
5199/** ====================================================================
5200 * jsPDF Cell plugin
5201 * Copyright (c) 2013 Youssef Beddad, [email protected]
5202 *               2013 Eduardo Menezes de Morais, [email protected]
5203 *               2013 Lee Driscoll, https://github.com/lsdriscoll
5204 *               2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
5205 *               2014 James Hall, [email protected]
5206 *               2014 Diego Casorran, https://github.com/diegocr
5207 *
5208 * 
5209 * ====================================================================
5210 */
5211
5212(function (jsPDFAPI) {
5213    'use strict';
5214    /*jslint browser:true */
5215    /*global document: false, jsPDF */
5216
5217    var fontName,
5218        fontSize,
5219        fontStyle,
5220        padding = 3,
5221        margin = 13,
5222        headerFunction,
5223        lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined },
5224        pages = 1,
5225        setLastCellPosition = function setLastCellPosition(x, y, w, h, ln) {
5226        lastCellPos = { 'x': x, 'y': y, 'w': w, 'h': h, 'ln': ln };
5227    },
5228        getLastCellPosition = function getLastCellPosition() {
5229        return lastCellPos;
5230    },
5231        NO_MARGINS = { left: 0, top: 0, bottom: 0 };
5232
5233    jsPDFAPI.setHeaderFunction = function (func) {
5234        headerFunction = func;
5235    };
5236
5237    jsPDFAPI.getTextDimensions = function (txt) {
5238        fontName = this.internal.getFont().fontName;
5239        fontSize = this.table_font_size || this.internal.getFontSize();
5240        fontStyle = this.internal.getFont().fontStyle;
5241        // 1 pixel = 0.264583 mm and 1 mm = 72/25.4 point
5242        var px2pt = 0.264583 * 72 / 25.4,
5243            dimensions,
5244            text;
5245
5246        text = document.createElement('font');
5247        text.id = "jsPDFCell";
5248
5249        try {
5250            text.style.fontStyle = fontStyle;
5251        } catch (e) {
5252            text.style.fontWeight = fontStyle;
5253        }
5254
5255        text.style.fontName = fontName;
5256        text.style.fontSize = fontSize + 'pt';
5257        try {
5258            text.textContent = txt;
5259        } catch (e) {
5260            text.innerText = txt;
5261        }
5262
5263        document.body.appendChild(text);
5264
5265        dimensions = { w: (text.offsetWidth + 1) * px2pt, h: (text.offsetHeight + 1) * px2pt };
5266
5267        document.body.removeChild(text);
5268
5269        return dimensions;
5270    };
5271
5272    jsPDFAPI.cellAddPage = function () {
5273        var margins = this.margins || NO_MARGINS;
5274
5275        this.addPage();
5276
5277        setLastCellPosition(margins.left, margins.top, undefined, undefined);
5278        //setLastCellPosition(undefined, undefined, undefined, undefined, undefined);
5279        pages += 1;
5280    };
5281
5282    jsPDFAPI.cellInitialize = function () {
5283        lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined };
5284        pages = 1;
5285    };
5286
5287    jsPDFAPI.cell = function (x, y, w, h, txt, ln, align) {
5288        var curCell = getLastCellPosition();
5289        var pgAdded = false;
5290
5291        // If this is not the first cell, we must change its position
5292        if (curCell.ln !== undefined) {
5293            if (curCell.ln === ln) {
5294                //Same line
5295                x = curCell.x + curCell.w;
5296                y = curCell.y;
5297            } else {
5298                //New line
5299                var margins = this.margins || NO_MARGINS;
5300                if (curCell.y + curCell.h + h + margin >= this.internal.pageSize.height - margins.bottom) {
5301                    this.cellAddPage();
5302                    pgAdded = true;
5303                    if (this.printHeaders && this.tableHeaderRow) {
5304                        this.printHeaderRow(ln, true);
5305                    }
5306                }
5307                //We ignore the passed y: the lines may have different heights
5308                y = getLastCellPosition().y + getLastCellPosition().h;
5309                if (pgAdded) y = margin + 10;
5310            }
5311        }
5312
5313        if (txt[0] !== undefined) {
5314            if (this.printingHeaderRow) {
5315                this.rect(x, y, w, h, 'FD');
5316            } else {
5317                this.rect(x, y, w, h);
5318            }
5319            if (align === 'right') {
5320                if (!(txt instanceof Array)) {
5321                    txt = [txt];
5322                }
5323                for (var i = 0; i < txt.length; i++) {
5324                    var currentLine = txt[i];
5325                    var textSize = this.getStringUnitWidth(currentLine) * this.internal.getFontSize();
5326                    this.text(currentLine, x + w - textSize - padding, y + this.internal.getLineHeight() * (i + 1));
5327                }
5328            } else {
5329                this.text(txt, x + padding, y + this.internal.getLineHeight());
5330            }
5331        }
5332        setLastCellPosition(x, y, w, h, ln);
5333        return this;
5334    };
5335
5336    /**
5337     * Return the maximum value from an array
5338     * @param array
5339     * @param comparisonFn
5340     * @returns {*}
5341     */
5342    jsPDFAPI.arrayMax = function (array, comparisonFn) {
5343        var max = array[0],
5344            i,
5345            ln,
5346            item;
5347
5348        for (i = 0, ln = array.length; i < ln; i += 1) {
5349            item = array[i];
5350
5351            if (comparisonFn) {
5352                if (comparisonFn(max, item) === -1) {
5353                    max = item;
5354                }
5355            } else {
5356                if (item > max) {
5357                    max = item;
5358                }
5359            }
5360        }
5361
5362        return max;
5363    };
5364
5365    /**
5366     * Create a table from a set of data.
5367     * @param {Integer} [x] : left-position for top-left corner of table
5368     * @param {Integer} [y] top-position for top-left corner of table
5369     * @param {Object[]} [data] As array of objects containing key-value pairs corresponding to a row of data.
5370     * @param {String[]} [headers] Omit or null to auto-generate headers at a performance cost
5371      * @param {Object} [config.printHeaders] True to print column headers at the top of every page
5372     * @param {Object} [config.autoSize] True to dynamically set the column widths to match the widest cell value
5373     * @param {Object} [config.margins] margin values for left, top, bottom, and width
5374     * @param {Object} [config.fontSize] Integer fontSize to use (optional)
5375     */
5376
5377    jsPDFAPI.table = function (x, y, data, headers, config) {
5378        if (!data) {
5379            throw 'No data for PDF table';
5380        }
5381
5382        var headerNames = [],
5383            headerPrompts = [],
5384            header,
5385            i,
5386            ln,
5387            cln,
5388            columnMatrix = {},
5389            columnWidths = {},
5390            columnData,
5391            column,
5392            columnMinWidths = [],
5393            j,
5394            tableHeaderConfigs = [],
5395            model,
5396            jln,
5397            func,
5398
5399
5400        //set up defaults. If a value is provided in config, defaults will be overwritten:
5401        autoSize = false,
5402            printHeaders = true,
5403            fontSize = 12,
5404            margins = NO_MARGINS;
5405
5406        margins.width = this.internal.pageSize.width;
5407
5408        if (config) {
5409            //override config defaults if the user has specified non-default behavior:
5410            if (config.autoSize === true) {
5411                autoSize = true;
5412            }
5413            if (config.printHeaders === false) {
5414                printHeaders = false;
5415            }
5416            if (config.fontSize) {
5417                fontSize = config.fontSize;
5418            }
5419            if (config.css && typeof config.css['font-size'] !== "undefined") {
5420                fontSize = config.css['font-size'] * 16;
5421            }
5422            if (config.margins) {
5423                margins = config.margins;
5424            }
5425        }
5426
5427        /**
5428         * @property {Number} lnMod
5429         * Keep track of the current line number modifier used when creating cells
5430         */
5431        this.lnMod = 0;
5432        lastCellPos = { x: undefined, y: undefined, w: undefined, h: undefined, ln: undefined }, pages = 1;
5433
5434        this.printHeaders = printHeaders;
5435        this.margins = margins;
5436        this.setFontSize(fontSize);
5437        this.table_font_size = fontSize;
5438
5439        // Set header values
5440        if (headers === undefined || headers === null) {
5441            // No headers defined so we derive from data
5442            headerNames = Object.keys(data[0]);
5443        } else if (headers[0] && typeof headers[0] !== 'string') {
5444            var px2pt = 0.264583 * 72 / 25.4;
5445
5446            // Split header configs into names and prompts
5447            for (i = 0, ln = headers.length; i < ln; i += 1) {
5448                header = headers[i];
5449                headerNames.push(header.name);
5450                headerPrompts.push(header.prompt);
5451                columnWidths[header.name] = header.width * px2pt;
5452            }
5453        } else {
5454            headerNames = headers;
5455        }
5456
5457        if (autoSize) {
5458            // Create a matrix of columns e.g., {column_title: [row1_Record, row2_Record]}
5459            func = function func(rec) {
5460                return rec[header];
5461            };
5462
5463            for (i = 0, ln = headerNames.length; i < ln; i += 1) {
5464                header = headerNames[i];
5465
5466                columnMatrix[header] = data.map(func);
5467
5468                // get header width
5469                columnMinWidths.push(this.getTextDimensions(headerPrompts[i] || header).w);
5470                column = columnMatrix[header];
5471
5472                // get cell widths
5473                for (j = 0, cln = column.length; j < cln; j += 1) {
5474                    columnData = column[j];
5475                    columnMinWidths.push(this.getTextDimensions(columnData).w);
5476                }
5477
5478                // get final column width
5479                columnWidths[header] = jsPDFAPI.arrayMax(columnMinWidths);
5480
5481                //have to reset
5482                columnMinWidths = [];
5483            }
5484        }
5485
5486        // -- Construct the table
5487
5488        if (printHeaders) {
5489            var lineHeight = this.calculateLineHeight(headerNames, columnWidths, headerPrompts.length ? headerPrompts : headerNames);
5490
5491            // Construct the header row
5492            for (i = 0, ln = headerNames.length; i < ln; i += 1) {
5493                header = headerNames[i];
5494                tableHeaderConfigs.push([x, y, columnWidths[header], lineHeight, String(headerPrompts.length ? headerPrompts[i] : header)]);
5495            }
5496
5497            // Store the table header config
5498            this.setTableHeaderRow(tableHeaderConfigs);
5499
5500            // Print the header for the start of the table
5501            this.printHeaderRow(1, false);
5502        }
5503
5504        // Construct the data rows
5505        for (i = 0, ln = data.length; i < ln; i += 1) {
5506            var lineHeight;
5507            model = data[i];
5508            lineHeight = this.calculateLineHeight(headerNames, columnWidths, model);
5509
5510            for (j = 0, jln = headerNames.length; j < jln; j += 1) {
5511                header = headerNames[j];
5512                this.cell(x, y, columnWidths[header], lineHeight, model[header], i + 2, header.align);
5513            }
5514        }
5515        this.lastCellPos = lastCellPos;
5516        this.table_x = x;
5517        this.table_y = y;
5518        return this;
5519    };
5520    /**
5521     * Calculate the height for containing the highest column
5522     * @param {String[]} headerNames is the header, used as keys to the data
5523     * @param {Integer[]} columnWidths is size of each column
5524     * @param {Object[]} model is the line of data we want to calculate the height of
5525     */
5526    jsPDFAPI.calculateLineHeight = function (headerNames, columnWidths, model) {
5527        var header,
5528            lineHeight = 0;
5529        for (var j = 0; j < headerNames.length; j++) {
5530            header = headerNames[j];
5531            model[header] = this.splitTextToSize(String(model[header]), columnWidths[header] - padding);
5532            var h = this.internal.getLineHeight() * model[header].length + padding;
5533            if (h > lineHeight) lineHeight = h;
5534        }
5535        return lineHeight;
5536    };
5537
5538    /**
5539     * Store the config for outputting a table header
5540     * @param {Object[]} config
5541     * An array of cell configs that would define a header row: Each config matches the config used by jsPDFAPI.cell
5542     * except the ln parameter is excluded
5543     */
5544    jsPDFAPI.setTableHeaderRow = function (config) {
5545        this.tableHeaderRow = config;
5546    };
5547
5548    /**
5549     * Output the store header row
5550     * @param lineNumber The line number to output the header at
5551     */
5552    jsPDFAPI.printHeaderRow = function (lineNumber, new_page) {
5553        if (!this.tableHeaderRow) {
5554            throw 'Property tableHeaderRow does not exist.';
5555        }
5556
5557        var tableHeaderCell, tmpArray, i, ln;
5558
5559        this.printingHeaderRow = true;
5560        if (headerFunction !== undefined) {
5561            var position = headerFunction(this, pages);
5562            setLastCellPosition(position[0], position[1], position[2], position[3], -1);
5563        }
5564        this.setFontStyle('bold');
5565        var tempHeaderConf = [];
5566        for (i = 0, ln = this.tableHeaderRow.length; i < ln; i += 1) {
5567            this.setFillColor(200, 200, 200);
5568
5569            tableHeaderCell = this.tableHeaderRow[i];
5570            if (new_page) {
5571                this.margins.top = margin;
5572                tableHeaderCell[1] = this.margins && this.margins.top || 0;
5573                tempHeaderConf.push(tableHeaderCell);
5574            }
5575            tmpArray = [].concat(tableHeaderCell);
5576            this.cell.apply(this, tmpArray.concat(lineNumber));
5577        }
5578        if (tempHeaderConf.length > 0) {
5579            this.setTableHeaderRow(tempHeaderConf);
5580        }
5581        this.setFontStyle('normal');
5582        this.printingHeaderRow = false;
5583    };
5584})(jsPDF.API);
5585
5586/**
5587 * jsPDF Context2D PlugIn Copyright (c) 2014 Steven Spungin (TwelveTone LLC) [email protected]
5588 *
5589 * Licensed under the MIT License. http://opensource.org/licenses/mit-license
5590 */
5591
5592/**
5593 * This plugin mimics the HTML5 Canvas's context2d.
5594 *
5595 * The goal is to provide a way for current canvas implementations to print directly to a PDF.
5596 */
5597
5598/**
5599 * TODO implement stroke opacity (refactor from fill() method )
5600 * TODO transform angle and radii parameters
5601 */
5602
5603/**
5604 * require('jspdf.js'); require('lib/css_colors.js');
5605 */
5606
5607(function (jsPDFAPI) {
5608    'use strict';
5609
5610    jsPDFAPI.events.push(['initialized', function () {
5611        this.context2d.pdf = this;
5612        this.context2d.internal.pdf = this;
5613        this.context2d.ctx = new context();
5614        this.context2d.ctxStack = [];
5615        this.context2d.path = [];
5616    }]);
5617
5618    jsPDFAPI.context2d = {
5619        pageWrapXEnabled: false,
5620        pageWrapYEnabled: false,
5621        pageWrapX: 9999999,
5622        pageWrapY: 9999999,
5623        ctx: new context(),
5624        f2: function f2(number) {
5625            return number.toFixed(2);
5626        },
5627
5628        fillRect: function fillRect(x, y, w, h) {
5629            if (this._isFillTransparent()) {
5630                return;
5631            }
5632            x = this._wrapX(x);
5633            y = this._wrapY(y);
5634
5635            var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h });
5636            this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "f");
5637        },
5638
5639        strokeRect: function strokeRect(x, y, w, h) {
5640            if (this._isStrokeTransparent()) {
5641                return;
5642            }
5643            x = this._wrapX(x);
5644            y = this._wrapY(y);
5645
5646            var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h });
5647            this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "s");
5648        },
5649
5650        /**
5651         * We cannot clear PDF commands that were already written to PDF, so we use white instead. <br />
5652         * As a special case, read a special flag (ignoreClearRect) and do nothing if it is set.
5653         * This results in all calls to clearRect() to do nothing, and keep the canvas transparent.
5654         * This flag is stored in the save/restore context and is managed the same way as other drawing states.
5655         * @param x
5656         * @param y
5657         * @param w
5658         * @param h
5659         */
5660        clearRect: function clearRect(x, y, w, h) {
5661            if (this.ctx.ignoreClearRect) {
5662                return;
5663            }
5664
5665            x = this._wrapX(x);
5666            y = this._wrapY(y);
5667
5668            var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h });
5669            this.save();
5670            this.setFillStyle('#ffffff');
5671            //TODO This is hack to fill with white.
5672            this.pdf.rect(xRect.x, xRect.y, xRect.w, xRect.h, "f");
5673            this.restore();
5674        },
5675
5676        save: function save() {
5677            this.ctx._fontSize = this.pdf.internal.getFontSize();
5678            var ctx = new context();
5679            ctx.copy(this.ctx);
5680            this.ctxStack.push(this.ctx);
5681            this.ctx = ctx;
5682        },
5683
5684        restore: function restore() {
5685            this.ctx = this.ctxStack.pop();
5686            this.setFillStyle(this.ctx.fillStyle);
5687            this.setStrokeStyle(this.ctx.strokeStyle);
5688            this.setFont(this.ctx.font);
5689            this.pdf.setFontSize(this.ctx._fontSize);
5690            this.setLineCap(this.ctx.lineCap);
5691            this.setLineWidth(this.ctx.lineWidth);
5692            this.setLineJoin(this.ctx.lineJoin);
5693        },
5694
5695        rect: function rect(x, y, w, h) {
5696            this.moveTo(x, y);
5697            this.lineTo(x + w, y);
5698            this.lineTo(x + w, y + h);
5699            this.lineTo(x, y + h);
5700            this.lineTo(x, y); //TODO not needed
5701            this.closePath();
5702        },
5703
5704        beginPath: function beginPath() {
5705            this.path = [];
5706        },
5707
5708        closePath: function closePath() {
5709            this.path.push({
5710                type: 'close'
5711            });
5712        },
5713
5714        _getRgba: function _getRgba(style) {
5715            // get the decimal values of r, g, and b;
5716            var rgba = {};
5717
5718            if (this.internal.rxTransparent.test(style)) {
5719                rgba.r = 0;
5720                rgba.g = 0;
5721                rgba.b = 0;
5722                rgba.a = 0;
5723            } else {
5724                var m = this.internal.rxRgb.exec(style);
5725                if (m != null) {
5726                    rgba.r = parseInt(m[1]);
5727                    rgba.g = parseInt(m[2]);
5728                    rgba.b = parseInt(m[3]);
5729                    rgba.a = 1;
5730                } else {
5731                    m = this.internal.rxRgba.exec(style);
5732                    if (m != null) {
5733                        rgba.r = parseInt(m[1]);
5734                        rgba.g = parseInt(m[2]);
5735                        rgba.b = parseInt(m[3]);
5736                        rgba.a = parseFloat(m[4]);
5737                    } else {
5738                        rgba.a = 1;
5739                        if (style.charAt(0) != '#') {
5740                            style = CssColors.colorNameToHex(style);
5741                            if (!style) {
5742                                style = '#000000';
5743                            }
5744                        } else {}
5745
5746                        if (style.length === 4) {
5747                            rgba.r = style.substring(1, 2);
5748                            rgba.r += r;
5749                            rgba.g = style.substring(2, 3);
5750                            rgba.g += g;
5751                            rgba.b = style.substring(3, 4);
5752                            rgba.b += b;
5753                        } else {
5754                            rgba.r = style.substring(1, 3);
5755                            rgba.g = style.substring(3, 5);
5756                            rgba.b = style.substring(5, 7);
5757                        }
5758                        rgba.r = parseInt(rgba.r, 16);
5759                        rgba.g = parseInt(rgba.g, 16);
5760                        rgba.b = parseInt(rgba.b, 16);
5761                    }
5762                }
5763            }
5764            rgba.style = style;
5765            return rgba;
5766        },
5767
5768        setFillStyle: function setFillStyle(style) {
5769            // get the decimal values of r, g, and b;
5770            var r, g, b, a;
5771
5772            if (this.internal.rxTransparent.test(style)) {
5773                r = 0;
5774                g = 0;
5775                b = 0;
5776                a = 0;
5777            } else {
5778                var m = this.internal.rxRgb.exec(style);
5779                if (m != null) {
5780                    r = parseInt(m[1]);
5781                    g = parseInt(m[2]);
5782                    b = parseInt(m[3]);
5783                    a = 1;
5784                } else {
5785                    m = this.internal.rxRgba.exec(style);
5786                    if (m != null) {
5787                        r = parseInt(m[1]);
5788                        g = parseInt(m[2]);
5789                        b = parseInt(m[3]);
5790                        a = parseFloat(m[4]);
5791                    } else {
5792                        a = 1;
5793                        if (style.charAt(0) != '#') {
5794                            style = CssColors.colorNameToHex(style);
5795                            if (!style) {
5796                                style = '#000000';
5797                            }
5798                        } else {}
5799
5800                        if (style.length === 4) {
5801                            r = style.substring(1, 2);
5802                            r += r;
5803                            g = style.substring(2, 3);
5804                            g += g;
5805                            b = style.substring(3, 4);
5806                            b += b;
5807                        } else {
5808                            r = style.substring(1, 3);
5809                            g = style.substring(3, 5);
5810                            b = style.substring(5, 7);
5811                        }
5812                        r = parseInt(r, 16);
5813                        g = parseInt(g, 16);
5814                        b = parseInt(b, 16);
5815                    }
5816                }
5817            }
5818
5819            this.ctx.fillStyle = style;
5820            this.ctx._isFillTransparent = a == 0;
5821            this.ctx._fillOpacity = a;
5822
5823            this.pdf.setFillColor(r, g, b, {
5824                a: a
5825            });
5826            this.pdf.setTextColor(r, g, b, {
5827                a: a
5828            });
5829        },
5830
5831        setStrokeStyle: function setStrokeStyle(style) {
5832            var rgba = this._getRgba(style);
5833
5834            this.ctx.strokeStyle = rgba.style;
5835            this.ctx._isStrokeTransparent = rgba.a == 0;
5836            this.ctx._strokeOpacity = rgba.a;
5837
5838            //TODO jsPDF to handle rgba
5839            if (rgba.a === 0) {
5840                this.pdf.setDrawColor(255, 255, 255);
5841            } else if (rgba.a === 1) {
5842                this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b);
5843            } else {
5844                //this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b, {a: rgba.a});
5845                this.pdf.setDrawColor(rgba.r, rgba.g, rgba.b);
5846            }
5847        },
5848
5849        fillText: function fillText(text, x, y, maxWidth) {
5850            if (this._isFillTransparent()) {
5851                return;
5852            }
5853            x = this._wrapX(x);
5854            y = this._wrapY(y);
5855
5856            var xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
5857            x = xpt[0];
5858            y = xpt[1];
5859            var rads = this._matrix_rotation(this.ctx._transform);
5860            var degs = rads * 57.2958;
5861
5862            //TODO only push the clip if it has not been applied to the current PDF context
5863            if (this.ctx._clip_path.length > 0) {
5864                var lines;
5865                if (window.outIntercept) {
5866                    lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept;
5867                } else {
5868                    lines = this.internal.getCurrentPage();
5869                }
5870                lines.push("q");
5871                var origPath = this.path;
5872                this.path = this.ctx._clip_path;
5873                this.ctx._clip_path = [];
5874                this._fill(null, true);
5875                this.ctx._clip_path = this.path;
5876                this.path = origPath;
5877            }
5878
5879            var scale;
5880            if (this.pdf.hotfix && this.pdf.hotfix.scale_text) {
5881                scale = this._getTransform()[0];
5882            } else {
5883                scale = 1;
5884            }
5885            // In some cases the transform was very small (5.715760606202283e-17).  Most likely a canvg rounding error.
5886            if (scale < .01) {
5887                this.pdf.text(text, x, this._getBaseline(y), null, degs);
5888            } else {
5889                var oldSize = this.pdf.internal.getFontSize();
5890                this.pdf.setFontSize(oldSize * scale);
5891                this.pdf.text(text, x, this._getBaseline(y), null, degs);
5892                this.pdf.setFontSize(oldSize);
5893            }
5894
5895            if (this.ctx._clip_path.length > 0) {
5896                lines.push('Q');
5897            }
5898        },
5899
5900        strokeText: function strokeText(text, x, y, maxWidth) {
5901            if (this._isStrokeTransparent()) {
5902                return;
5903            }
5904            x = this._wrapX(x);
5905            y = this._wrapY(y);
5906
5907            var xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
5908            x = xpt[0];
5909            y = xpt[1];
5910            var rads = this._matrix_rotation(this.ctx._transform);
5911            var degs = rads * 57.2958;
5912
5913            //TODO only push the clip if it has not been applied to the current PDF context
5914            if (this.ctx._clip_path.length > 0) {
5915                var lines;
5916                if (window.outIntercept) {
5917                    lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept;
5918                } else {
5919                    lines = this.internal.getCurrentPage();
5920                }
5921                lines.push("q");
5922                var origPath = this.path;
5923                this.path = this.ctx._clip_path;
5924                this.ctx._clip_path = [];
5925                this._fill(null, true);
5926                this.ctx._clip_path = this.path;
5927                this.path = origPath;
5928            }
5929
5930            var scale;
5931            if (this.pdf.hotfix && this.pdf.hotfix.scale_text) {
5932                scale = this._getTransform()[0];
5933            } else {
5934                scale = 1;
5935            }
5936            if (scale === 1) {
5937                this.pdf.text(text, x, this._getBaseline(y), {
5938                    stroke: true
5939                }, degs);
5940            } else {
5941                var oldSize = this.pdf.internal.getFontSize();
5942                this.pdf.setFontSize(oldSize * scale);
5943                this.pdf.text(text, x, this._getBaseline(y), {
5944                    stroke: true
5945                }, degs);
5946                this.pdf.setFontSize(oldSize);
5947            }
5948
5949            if (this.ctx._clip_path.length > 0) {
5950                lines.push('Q');
5951            }
5952        },
5953
5954        setFont: function setFont(font) {
5955            this.ctx.font = font;
5956
5957            //var rx = /\s*(\w+)\s+(\w+)\s+(\w+)\s+([\d\.]+)(px|pt|em)\s+["']?(\w+)['"]?/;
5958            var rx = /\s*(\w+)\s+(\w+)\s+(\w+)\s+([\d\.]+)(px|pt|em)\s+(.*)?/;
5959            m = rx.exec(font);
5960            if (m != null) {
5961                var fontStyle = m[1];
5962                var fontVariant = m[2];
5963                var fontWeight = m[3];
5964                var fontSize = m[4];
5965                var fontSizeUnit = m[5];
5966                var fontFamily = m[6];
5967
5968                if ('px' === fontSizeUnit) {
5969                    fontSize = Math.floor(parseFloat(fontSize));
5970                    // fontSize = fontSize * 1.25;
5971                } else if ('em' === fontSizeUnit) {
5972                    fontSize = Math.floor(parseFloat(fontSize) * this.pdf.getFontSize());
5973                } else {
5974                    fontSize = Math.floor(parseFloat(fontSize));
5975                }
5976
5977                this.pdf.setFontSize(fontSize);
5978
5979                if (fontWeight === 'bold' || fontWeight === '700') {
5980                    this.pdf.setFontStyle('bold');
5981                } else {
5982                    if (fontStyle === 'italic') {
5983                        this.pdf.setFontStyle('italic');
5984                    } else {
5985                        this.pdf.setFontStyle('normal');
5986                    }
5987                }
5988
5989                var name = fontFamily;
5990                var parts = name.toLowerCase().split(/\s*,\s*/);
5991                var jsPdfFontName;
5992
5993                if (parts.indexOf('arial') != -1) {
5994                    jsPdfFontName = 'Arial';
5995                } else if (parts.indexOf('verdana') != -1) {
5996                    jsPdfFontName = 'Verdana';
5997                } else if (parts.indexOf('helvetica') != -1) {
5998                    jsPdfFontName = 'Helvetica';
5999                } else if (parts.indexOf('sans-serif') != -1) {
6000                    jsPdfFontName = 'sans-serif';
6001                } else if (parts.indexOf('fixed') != -1) {
6002                    jsPdfFontName = 'Fixed';
6003                } else if (parts.indexOf('monospace') != -1) {
6004                    jsPdfFontName = 'Monospace';
6005                } else if (parts.indexOf('terminal') != -1) {
6006                    jsPdfFontName = 'Terminal';
6007                } else if (parts.indexOf('courier') != -1) {
6008                    jsPdfFontName = 'Courier';
6009                } else if (parts.indexOf('times') != -1) {
6010                    jsPdfFontName = 'Times';
6011                } else if (parts.indexOf('cursive') != -1) {
6012                    jsPdfFontName = 'Cursive';
6013                } else if (parts.indexOf('fantasy') != -1) {
6014                    jsPdfFontName = 'Fantasy';
6015                } else if (parts.indexOf('serif') != -1) {
6016                    jsPdfFontName = 'Serif';
6017                } else {
6018                    jsPdfFontName = 'Serif';
6019                }
6020
6021                //TODO check more cases
6022                var style;
6023                if ('bold' === fontWeight) {
6024                    style = 'bold';
6025                } else {
6026                    style = 'normal';
6027                }
6028
6029                this.pdf.setFont(jsPdfFontName, style);
6030            } else {
6031                var rx = /(\d+)(pt|px|em)\s+(\w+)\s*(\w+)?/;
6032                var m = rx.exec(font);
6033                if (m != null) {
6034                    var size = m[1];
6035                    var unit = m[2];
6036                    var name = m[3];
6037                    var style = m[4];
6038                    if (!style) {
6039                        style = 'normal';
6040                    }
6041                    if ('em' === fontSizeUnit) {
6042                        size = Math.floor(parseFloat(fontSize) * this.pdf.getFontSize());
6043                    } else {
6044                        size = Math.floor(parseFloat(size));
6045                    }
6046                    this.pdf.setFontSize(size);
6047                    this.pdf.setFont(name, style);
6048                }
6049            }
6050        },
6051
6052        setTextBaseline: function setTextBaseline(baseline) {
6053            this.ctx.textBaseline = baseline;
6054        },
6055
6056        getTextBaseline: function getTextBaseline() {
6057            return this.ctx.textBaseline;
6058        },
6059
6060        //TODO implement textAlign
6061        setTextAlign: function setTextAlign(align) {
6062            this.ctx.textAlign = align;
6063        },
6064
6065        getTextAlign: function getTextAlign() {
6066            return this.ctx.textAlign;
6067        },
6068
6069        setLineWidth: function setLineWidth(width) {
6070            this.ctx.lineWidth = width;
6071            this.pdf.setLineWidth(width);
6072        },
6073
6074        setLineCap: function setLineCap(style) {
6075            this.ctx.lineCap = style;
6076            this.pdf.setLineCap(style);
6077        },
6078
6079        setLineJoin: function setLineJoin(style) {
6080            this.ctx.lineJoin = style;
6081            this.pdf.setLineJoin(style);
6082        },
6083
6084        moveTo: function moveTo(x, y) {
6085            x = this._wrapX(x);
6086            y = this._wrapY(y);
6087
6088            var xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
6089            x = xpt[0];
6090            y = xpt[1];
6091
6092            var obj = {
6093                type: 'mt',
6094                x: x,
6095                y: y
6096            };
6097            this.path.push(obj);
6098        },
6099
6100        _wrapX: function _wrapX(x) {
6101            if (this.pageWrapXEnabled) {
6102                return x % this.pageWrapX;
6103            } else {
6104                return x;
6105            }
6106        },
6107
6108        _wrapY: function _wrapY(y) {
6109            if (this.pageWrapYEnabled) {
6110                this._gotoPage(this._page(y));
6111                return (y - this.lastBreak) % this.pageWrapY;
6112            } else {
6113                return y;
6114            }
6115        },
6116
6117        transform: function transform(a, b, c, d, e, f) {
6118            //TODO apply to current transformation instead of replacing
6119            this.ctx._transform = [a, b, c, d, e, f];
6120        },
6121
6122        setTransform: function setTransform(a, b, c, d, e, f) {
6123            this.ctx._transform = [a, b, c, d, e, f];
6124        },
6125
6126        _getTransform: function _getTransform() {
6127            return this.ctx._transform;
6128        },
6129
6130        lastBreak: 0,
6131        // Y Position of page breaks.
6132        pageBreaks: [],
6133        // returns: One-based Page Number
6134        // Should only be used if pageWrapYEnabled is true
6135        _page: function _page(y) {
6136            if (this.pageWrapYEnabled) {
6137                this.lastBreak = 0;
6138                var manualBreaks = 0;
6139                var autoBreaks = 0;
6140                for (var i = 0; i < this.pageBreaks.length; i++) {
6141                    if (y >= this.pageBreaks[i]) {
6142                        manualBreaks++;
6143                        if (this.lastBreak === 0) {
6144                            autoBreaks++;
6145                        }
6146                        var spaceBetweenLastBreak = this.pageBreaks[i] - this.lastBreak;
6147                        this.lastBreak = this.pageBreaks[i];
6148                        var pagesSinceLastBreak = Math.floor(spaceBetweenLastBreak / this.pageWrapY);
6149                        autoBreaks += pagesSinceLastBreak;
6150                    }
6151                }
6152                if (this.lastBreak === 0) {
6153                    var pagesSinceLastBreak = Math.floor(y / this.pageWrapY) + 1;
6154                    autoBreaks += pagesSinceLastBreak;
6155                }
6156                return autoBreaks + manualBreaks;
6157            } else {
6158                return this.pdf.internal.getCurrentPageInfo().pageNumber;
6159            }
6160        },
6161
6162        _gotoPage: function _gotoPage(pageOneBased) {
6163            // This is a stub to be overriden if needed
6164        },
6165
6166        lineTo: function lineTo(x, y) {
6167            x = this._wrapX(x);
6168            y = this._wrapY(y);
6169
6170            var xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
6171            x = xpt[0];
6172            y = xpt[1];
6173
6174            var obj = {
6175                type: 'lt',
6176                x: x,
6177                y: y
6178            };
6179            this.path.push(obj);
6180        },
6181
6182        bezierCurveTo: function bezierCurveTo(x1, y1, x2, y2, x, y) {
6183            x1 = this._wrapX(x1);
6184            y1 = this._wrapY(y1);
6185            x2 = this._wrapX(x2);
6186            y2 = this._wrapY(y2);
6187            x = this._wrapX(x);
6188            y = this._wrapY(y);
6189
6190            var xpt;
6191            xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
6192            x = xpt[0];
6193            y = xpt[1];
6194            xpt = this._matrix_map_point(this.ctx._transform, [x1, y1]);
6195            x1 = xpt[0];
6196            y1 = xpt[1];
6197            xpt = this._matrix_map_point(this.ctx._transform, [x2, y2]);
6198            x2 = xpt[0];
6199            y2 = xpt[1];
6200
6201            var obj = {
6202                type: 'bct',
6203                x1: x1,
6204                y1: y1,
6205                x2: x2,
6206                y2: y2,
6207                x: x,
6208                y: y
6209            };
6210            this.path.push(obj);
6211        },
6212
6213        quadraticCurveTo: function quadraticCurveTo(x1, y1, x, y) {
6214            x1 = this._wrapX(x1);
6215            y1 = this._wrapY(y1);
6216            x = this._wrapX(x);
6217            y = this._wrapY(y);
6218
6219            var xpt;
6220            xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
6221            x = xpt[0];
6222            y = xpt[1];
6223            xpt = this._matrix_map_point(this.ctx._transform, [x1, y1]);
6224            x1 = xpt[0];
6225            y1 = xpt[1];
6226
6227            var obj = {
6228                type: 'qct',
6229                x1: x1,
6230                y1: y1,
6231                x: x,
6232                y: y
6233            };
6234            this.path.push(obj);
6235        },
6236
6237        arc: function arc(x, y, radius, startAngle, endAngle, anticlockwise) {
6238            x = this._wrapX(x);
6239            y = this._wrapY(y);
6240
6241            if (!this._matrix_is_identity(this.ctx._transform)) {
6242                var xpt = this._matrix_map_point(this.ctx._transform, [x, y]);
6243                x = xpt[0];
6244                y = xpt[1];
6245
6246                var x_radPt0 = this._matrix_map_point(this.ctx._transform, [0, 0]);
6247                var x_radPt = this._matrix_map_point(this.ctx._transform, [0, radius]);
6248                radius = Math.sqrt(Math.pow(x_radPt[0] - x_radPt0[0], 2) + Math.pow(x_radPt[1] - x_radPt0[1], 2));
6249
6250                //TODO angles need to be transformed
6251            }
6252
6253            var obj = {
6254                type: 'arc',
6255                x: x,
6256                y: y,
6257                radius: radius,
6258                startAngle: startAngle,
6259                endAngle: endAngle,
6260                anticlockwise: anticlockwise
6261            };
6262            this.path.push(obj);
6263        },
6264
6265        drawImage: function drawImage(img, x, y, w, h, x2, y2, w2, h2) {
6266            if (x2 !== undefined) {
6267                x = x2;
6268                y = y2;
6269                w = w2;
6270                h = h2;
6271            }
6272            x = this._wrapX(x);
6273            y = this._wrapY(y);
6274
6275            var xRect = this._matrix_map_rect(this.ctx._transform, { x: x, y: y, w: w, h: h });
6276            var xRect2 = this._matrix_map_rect(this.ctx._transform, { x: x2, y: y2, w: w2, h: h2 });
6277
6278            // TODO implement source clipping and image scaling
6279            var format;
6280            var rx = /data:image\/(\w+).*/i;
6281            var m = rx.exec(img);
6282            if (m != null) {
6283                format = m[1];
6284            } else {
6285                // format = "jpeg";
6286                format = "png";
6287            }
6288
6289            this.pdf.addImage(img, format, xRect.x, xRect.y, xRect.w, xRect.h);
6290        },
6291
6292        /**
6293         * Multiply the first matrix by the second
6294         * @param m1
6295         * @param m2
6296         * @returns {*[]}
6297         * @private
6298         */
6299        _matrix_multiply: function _matrix_multiply(m2, m1) {
6300            var sx = m1[0];
6301            var shy = m1[1];
6302            var shx = m1[2];
6303            var sy = m1[3];
6304            var tx = m1[4];
6305            var ty = m1[5];
6306
6307            var t0 = sx * m2[0] + shy * m2[2];
6308            var t2 = shx * m2[0] + sy * m2[2];
6309            var t4 = tx * m2[0] + ty * m2[2] + m2[4];
6310            shy = sx * m2[1] + shy * m2[3];
6311            sy = shx * m2[1] + sy * m2[3];
6312            ty = tx * m2[1] + ty * m2[3] + m2[5];
6313            sx = t0;
6314            shx = t2;
6315            tx = t4;
6316
6317            return [sx, shy, shx, sy, tx, ty];
6318        },
6319
6320        _matrix_rotation: function _matrix_rotation(m) {
6321            return Math.atan2(m[2], m[0]);
6322        },
6323
6324        _matrix_decompose: function _matrix_decompose(matrix) {
6325
6326            var a = matrix[0];
6327            var b = matrix[1];
6328            var c = matrix[2];
6329            var d = matrix[3];
6330
6331            var scaleX = Math.sqrt(a * a + b * b);
6332            a /= scaleX;
6333            b /= scaleX;
6334
6335            var shear = a * c + b * d;
6336            c -= a * shear;
6337            d -= b * shear;
6338
6339            var scaleY = Math.sqrt(c * c + d * d);
6340            c /= scaleY;
6341            d /= scaleY;
6342            shear /= scaleY;
6343
6344            if (a * d < b * c) {
6345                a = -a;
6346                b = -b;
6347                shear = -shear;
6348                scaleX = -scaleX;
6349            }
6350
6351            return {
6352                scale: [scaleX, 0, 0, scaleY, 0, 0],
6353                translate: [1, 0, 0, 1, matrix[4], matrix[5]],
6354                rotate: [a, b, -b, a, 0, 0],
6355                skew: [1, 0, shear, 1, 0, 0]
6356            };
6357        },
6358
6359        _matrix_map_point: function _matrix_map_point(m1, pt) {
6360            var sx = m1[0];
6361            var shy = m1[1];
6362            var shx = m1[2];
6363            var sy = m1[3];
6364            var tx = m1[4];
6365            var ty = m1[5];
6366
6367            var px = pt[0];
6368            var py = pt[1];
6369
6370            var x = px * sx + py * shx + tx;
6371            var y = px * shy + py * sy + ty;
6372            return [x, y];
6373        },
6374
6375        _matrix_map_point_obj: function _matrix_map_point_obj(m1, pt) {
6376            var xpt = this._matrix_map_point(m1, [pt.x, pt.y]);
6377            return { x: xpt[0], y: xpt[1] };
6378        },
6379
6380        _matrix_map_rect: function _matrix_map_rect(m1, rect) {
6381            var p1 = this._matrix_map_point(m1, [rect.x, rect.y]);
6382            var p2 = this._matrix_map_point(m1, [rect.x + rect.w, rect.y + rect.h]);
6383            return { x: p1[0], y: p1[1], w: p2[0] - p1[0], h: p2[1] - p1[1] };
6384        },
6385
6386        _matrix_is_identity: function _matrix_is_identity(m1) {
6387            if (m1[0] != 1) {
6388                return false;
6389            }
6390            if (m1[1] != 0) {
6391                return false;
6392            }
6393            if (m1[2] != 0) {
6394                return false;
6395            }
6396            if (m1[3] != 1) {
6397                return false;
6398            }
6399            if (m1[4] != 0) {
6400                return false;
6401            }
6402            if (m1[5] != 0) {
6403                return false;
6404            }
6405            return true;
6406        },
6407
6408        rotate: function rotate(angle) {
6409            var matrix = [Math.cos(angle), Math.sin(angle), -Math.sin(angle), Math.cos(angle), 0.0, 0.0];
6410            this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix);
6411        },
6412
6413        scale: function scale(sx, sy) {
6414            var matrix = [sx, 0.0, 0.0, sy, 0.0, 0.0];
6415            this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix);
6416        },
6417
6418        translate: function translate(x, y) {
6419            var matrix = [1.0, 0.0, 0.0, 1.0, x, y];
6420            this.ctx._transform = this._matrix_multiply(this.ctx._transform, matrix);
6421        },
6422
6423        stroke: function stroke() {
6424            if (this.ctx._clip_path.length > 0) {
6425
6426                var lines;
6427                if (window.outIntercept) {
6428                    lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept;
6429                } else {
6430                    lines = this.internal.getCurrentPage();
6431                }
6432                lines.push("q");
6433
6434                var origPath = this.path;
6435                this.path = this.ctx._clip_path;
6436                this.ctx._clip_path = [];
6437                this._stroke(true);
6438
6439                this.ctx._clip_path = this.path;
6440                this.path = origPath;
6441                this._stroke(false);
6442
6443                lines.push("Q");
6444            } else {
6445                this._stroke(false);
6446            }
6447        },
6448
6449        _stroke: function _stroke(isClip) {
6450            if (!isClip && this._isStrokeTransparent()) {
6451                return;
6452            }
6453
6454            //TODO opacity
6455
6456            var moves = [];
6457            var closed = false;
6458
6459            var xPath = this.path;
6460
6461            for (var i = 0; i < xPath.length; i++) {
6462                var pt = xPath[i];
6463                switch (pt.type) {
6464                    case 'mt':
6465                        moves.push({ start: pt, deltas: [], abs: [] });
6466                        break;
6467                    case 'lt':
6468                        var delta = [pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y];
6469                        moves[moves.length - 1].deltas.push(delta);
6470                        moves[moves.length - 1].abs.push(pt);
6471                        break;
6472                    case 'bct':
6473                        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];
6474                        moves[moves.length - 1].deltas.push(delta);
6475                        break;
6476                    case 'qct':
6477                        // convert to bezier
6478                        var x1 = xPath[i - 1].x + 2.0 / 3.0 * (pt.x1 - xPath[i - 1].x);
6479                        var y1 = xPath[i - 1].y + 2.0 / 3.0 * (pt.y1 - xPath[i - 1].y);
6480                        var x2 = pt.x + 2.0 / 3.0 * (pt.x1 - pt.x);
6481                        var y2 = pt.y + 2.0 / 3.0 * (pt.y1 - pt.y);
6482                        var x3 = pt.x;
6483                        var y3 = pt.y;
6484                        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];
6485                        moves[moves.length - 1].deltas.push(delta);
6486                        break;
6487                    case 'arc':
6488                        //TODO this was hack to avoid out-of-bounds issue
6489                        // No move-to before drawing the arc
6490                        if (moves.length == 0) {
6491                            moves.push({ start: { x: 0, y: 0 }, deltas: [], abs: [] });
6492                        }
6493                        moves[moves.length - 1].arc = true;
6494                        moves[moves.length - 1].abs.push(pt);
6495                        break;
6496                    case 'close':
6497                        closed = true;
6498                        break;
6499                }
6500            }
6501
6502            for (var i = 0; i < moves.length; i++) {
6503                var style;
6504                if (i == moves.length - 1) {
6505                    style = 's';
6506                } else {
6507                    style = null;
6508                }
6509                if (moves[i].arc) {
6510                    var arcs = moves[i].abs;
6511                    for (var ii = 0; ii < arcs.length; ii++) {
6512                        var arc = arcs[ii];
6513                        var start = arc.startAngle * 360 / (2 * Math.PI);
6514                        var end = arc.endAngle * 360 / (2 * Math.PI);
6515                        var x = arc.x;
6516                        var y = arc.y;
6517                        this.internal.arc2(this, x, y, arc.radius, start, end, arc.anticlockwise, style, isClip);
6518                    }
6519                } else {
6520                    var x = moves[i].start.x;
6521                    var y = moves[i].start.y;
6522                    if (!isClip) {
6523                        this.pdf.lines(moves[i].deltas, x, y, null, style);
6524                    } else {
6525                        this.pdf.lines(moves[i].deltas, x, y, null, null);
6526                        this.pdf.clip_fixed();
6527                    }
6528                }
6529            }
6530        },
6531
6532        _isFillTransparent: function _isFillTransparent() {
6533            return this.ctx._isFillTransparent || this.globalAlpha == 0;
6534        },
6535
6536        _isStrokeTransparent: function _isStrokeTransparent() {
6537            return this.ctx._isStrokeTransparent || this.globalAlpha == 0;
6538        },
6539
6540        fill: function fill(fillRule) {
6541            //evenodd or nonzero (default)
6542            if (this.ctx._clip_path.length > 0) {
6543
6544                var lines;
6545                if (window.outIntercept) {
6546                    lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept;
6547                } else {
6548                    lines = this.internal.getCurrentPage();
6549                }
6550                lines.push("q");
6551
6552                var origPath = this.path;
6553                this.path = this.ctx._clip_path;
6554                this.ctx._clip_path = [];
6555                this._fill(fillRule, true);
6556
6557                this.ctx._clip_path = this.path;
6558                this.path = origPath;
6559                this._fill(fillRule, false);
6560
6561                lines.push('Q');
6562            } else {
6563                this._fill(fillRule, false);
6564            }
6565        },
6566
6567        _fill: function _fill(fillRule, isClip) {
6568            if (this._isFillTransparent()) {
6569                return;
6570            }
6571            var v2Support = typeof this.pdf.internal.newObject2 === 'function';
6572
6573            var lines;
6574            if (window.outIntercept) {
6575                lines = window.outIntercept.type === 'group' ? window.outIntercept.stream : window.outIntercept;
6576            } else {
6577                lines = this.internal.getCurrentPage();
6578            }
6579
6580            // if (this.ctx._clip_path.length > 0) {
6581            //     lines.push('q');
6582            //     var oldPath = this.path;
6583            //     this.path = this.ctx._clip_path;
6584            //     this.ctx._clip_path = [];
6585            //     this._fill(fillRule, true);
6586            //     this.ctx._clip_path = this.path;
6587            //     this.path = oldPath;
6588            // }
6589
6590            var moves = [];
6591            var outInterceptOld = window.outIntercept;
6592
6593            if (v2Support) {
6594                // Blend and Mask
6595                switch (this.ctx.globalCompositeOperation) {
6596                    case 'normal':
6597                    case 'source-over':
6598                        break;
6599                    case 'destination-in':
6600                    case 'destination-out':
6601                        //TODO this need to be added to the current group or page
6602                        // define a mask stream
6603                        var obj = this.pdf.internal.newStreamObject();
6604
6605                        // define a mask state
6606                        var obj2 = this.pdf.internal.newObject2();
6607                        obj2.push('<</Type /ExtGState');
6608                        obj2.push('/SMask <</S /Alpha /G ' + obj.objId + ' 0 R>>'); // /S /Luminosity will need to define color space
6609                        obj2.push('>>');
6610
6611                        // add mask to page resources
6612                        var gsName = 'MASK' + obj2.objId;
6613                        this.pdf.internal.addGraphicsState(gsName, obj2.objId);
6614
6615                        var instruction = '/' + gsName + ' gs';
6616                        // add mask to page, group, or stream
6617                        lines.splice(0, 0, 'q');
6618                        lines.splice(1, 0, instruction);
6619                        lines.push('Q');
6620
6621                        window.outIntercept = obj;
6622                        break;
6623                    default:
6624                        var dictionaryEntry = '/' + this.pdf.internal.blendModeMap[this.ctx.globalCompositeOperation.toUpperCase()];
6625                        if (dictionaryEntry) {
6626                            this.pdf.internal.out(dictionaryEntry + ' gs');
6627                        }
6628                        break;
6629                }
6630            }
6631
6632            var alpha = this.ctx.globalAlpha;
6633            if (this.ctx._fillOpacity < 1) {
6634                // TODO combine this with global opacity
6635                alpha = this.ctx._fillOpacity;
6636            }
6637
6638            //TODO check for an opacity graphics state that was already created
6639            //TODO do not set opacity if current value is already active
6640            if (v2Support) {
6641                var objOpac = this.pdf.internal.newObject2();
6642                objOpac.push('<</Type /ExtGState');
6643                //objOpac.push(this.ctx.globalAlpha + " CA"); // Stroke
6644                //objOpac.push(this.ctx.globalAlpha + " ca"); // Not Stroke
6645                objOpac.push('/CA ' + alpha); // Stroke
6646                objOpac.push('/ca ' + alpha); // Not Stroke
6647                objOpac.push('>>');
6648                var gsName = 'GS_O_' + objOpac.objId;
6649                this.pdf.internal.addGraphicsState(gsName, objOpac.objId);
6650                this.pdf.internal.out('/' + gsName + ' gs');
6651            }
6652
6653            var xPath = this.path;
6654
6655            for (var i = 0; i < xPath.length; i++) {
6656                var pt = xPath[i];
6657                switch (pt.type) {
6658                    case 'mt':
6659                        moves.push({ start: pt, deltas: [], abs: [] });
6660                        break;
6661                    case 'lt':
6662                        var delta = [pt.x - xPath[i - 1].x, pt.y - xPath[i - 1].y];
6663                        moves[moves.length - 1].deltas.push(delta);
6664                        moves[moves.length - 1].abs.push(pt);
6665                        break;
6666                    case 'bct':
6667                        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];
6668                        moves[moves.length - 1].deltas.push(delta);
6669                        break;
6670                    case 'qct':
6671                        // convert to bezier
6672                        var x1 = xPath[i - 1].x + 2.0 / 3.0 * (pt.x1 - xPath[i - 1].x);
6673                        var y1 = xPath[i - 1].y + 2.0 / 3.0 * (pt.y1 - xPath[i - 1].y);
6674                        var x2 = pt.x + 2.0 / 3.0 * (pt.x1 - pt.x);
6675                        var y2 = pt.y + 2.0 / 3.0 * (pt.y1 - pt.y);
6676                        var x3 = pt.x;
6677                        var y3 = pt.y;
6678                        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];
6679                        moves[moves.length - 1].deltas.push(delta);
6680                        break;
6681                    case 'arc':
6682                        //TODO this was hack to avoid out-of-bounds issue when drawing circle
6683                        // No move-to before drawing the arc
6684                        if (moves.length === 0) {
6685                            moves.push({ deltas: [], abs: [] });
6686                        }
6687                        moves[moves.length - 1].arc = true;
6688                        moves[moves.length - 1].abs.push(pt);
6689                        break;
6690                    case 'close':
6691                        moves.push({ close: true });
6692                        break;
6693                }
6694            }
6695
6696            for (var i = 0; i < moves.length; i++) {
6697                var style;
6698                if (i == moves.length - 1) {
6699                    style = 'f';
6700                    if (fillRule === 'evenodd') {
6701                        style += '*';
6702                    }
6703                } else {
6704                    style = null;
6705                }
6706
6707                if (moves[i].close) {
6708                    this.pdf.internal.out('h');
6709                    this.pdf.internal.out('f');
6710                } else if (moves[i].arc) {
6711                    if (moves[i].start) {
6712                        this.internal.move2(this, moves[i].start.x, moves[i].start.y);
6713                    }
6714                    var arcs = moves[i].abs;
6715                    for (var ii = 0; ii < arcs.length; ii++) {
6716                        var arc = arcs[ii];
6717                        //TODO lines deltas were getting in here
6718                        if (typeof arc.startAngle !== 'undefined') {
6719                            var start = arc.startAngle * 360 / (2 * Math.PI);
6720                            var end = arc.endAngle * 360 / (2 * Math.PI);
6721                            var x = arc.x;
6722                            var y = arc.y;
6723                            if (ii === 0) {
6724                                this.internal.move2(this, x, y);
6725                            }
6726                            this.internal.arc2(this, x, y, arc.radius, start, end, arc.anticlockwise, null, isClip);
6727                            if (ii === arcs.length - 1) {
6728                                // The original arc move did not occur because of the algorithm
6729                                if (moves[i].start) {
6730                                    var x = moves[i].start.x;
6731                                    var y = moves[i].start.y;
6732                                    this.internal.line2(c2d, x, y);
6733                                }
6734                            }
6735                        } else {
6736                            this.internal.line2(c2d, arc.x, arc.y);
6737                        }
6738                    }
6739                } else {
6740                    var x = moves[i].start.x;
6741                    var y = moves[i].start.y;
6742                    if (!isClip) {
6743                        this.pdf.lines(moves[i].deltas, x, y, null, style);
6744                    } else {
6745                        this.pdf.lines(moves[i].deltas, x, y, null, null);
6746                        this.pdf.clip_fixed();
6747                    }
6748                }
6749            }
6750
6751            window.outIntercept = outInterceptOld;
6752
6753            // if (this.ctx._clip_path.length > 0) {
6754            //     lines.push('Q');
6755            // }
6756        },
6757
6758        pushMask: function pushMask() {
6759            var v2Support = typeof this.pdf.internal.newObject2 === 'function';
6760
6761            if (!v2Support) {
6762                console.log('jsPDF v2 not enabled');
6763                return;
6764            }
6765
6766            // define a mask stream
6767            var obj = this.pdf.internal.newStreamObject();
6768
6769            // define a mask state
6770            var obj2 = this.pdf.internal.newObject2();
6771            obj2.push('<</Type /ExtGState');
6772            obj2.push('/SMask <</S /Alpha /G ' + obj.objId + ' 0 R>>'); // /S /Luminosity will need to define color space
6773            obj2.push('>>');
6774
6775            // add mask to page resources
6776            var gsName = 'MASK' + obj2.objId;
6777            this.pdf.internal.addGraphicsState(gsName, obj2.objId);
6778
6779            var instruction = '/' + gsName + ' gs';
6780            this.pdf.internal.out(instruction);
6781        },
6782
6783        clip: function clip() {
6784            //TODO do we reset the path, or just copy it?
6785            if (this.ctx._clip_path.length > 0) {
6786                for (var i = 0; i < this.path.length; i++) {
6787                    this.ctx._clip_path.push(this.path[i]);
6788                }
6789            } else {
6790                this.ctx._clip_path = this.path;
6791            }
6792            this.path = [];
6793        },
6794
6795        measureText: function measureText(text) {
6796            var pdf = this.pdf;
6797            return {
6798                getWidth: function getWidth() {
6799                    var fontSize = pdf.internal.getFontSize();
6800                    var txtWidth = pdf.getStringUnitWidth(text) * fontSize / pdf.internal.scaleFactor;
6801                    // Convert points to pixels
6802                    txtWidth *= 1.3333;
6803                    return txtWidth;
6804                },
6805
6806                get width() {
6807                    return this.getWidth(text);
6808                }
6809            };
6810        },
6811        _getBaseline: function _getBaseline(y) {
6812            var height = parseInt(this.pdf.internal.getFontSize());
6813            // TODO Get descent from font descriptor
6814            var descent = height * .25;
6815            switch (this.ctx.textBaseline) {
6816                case 'bottom':
6817                    return y - descent;
6818                case 'top':
6819                    return y + height;
6820                case 'hanging':
6821                    return y + height - descent;
6822                case 'middle':
6823                    return y + height / 2 - descent;
6824                case 'ideographic':
6825                    // TODO not implemented
6826                    return y;
6827                case 'alphabetic':
6828                default:
6829                    return y;
6830            }
6831        }
6832    };
6833
6834    var c2d = jsPDFAPI.context2d;
6835
6836    // accessor methods
6837    Object.defineProperty(c2d, 'fillStyle', {
6838        set: function set(value) {
6839            this.setFillStyle(value);
6840        },
6841        get: function get() {
6842            return this.ctx.fillStyle;
6843        }
6844    });
6845    Object.defineProperty(c2d, 'strokeStyle', {
6846        set: function set(value) {
6847            this.setStrokeStyle(value);
6848        },
6849        get: function get() {
6850            return this.ctx.strokeStyle;
6851        }
6852    });
6853    Object.defineProperty(c2d, 'lineWidth', {
6854        set: function set(value) {
6855            this.setLineWidth(value);
6856        },
6857        get: function get() {
6858            return this.ctx.lineWidth;
6859        }
6860    });
6861    Object.defineProperty(c2d, 'lineCap', {
6862        set: function set(val) {
6863            this.setLineCap(val);
6864        },
6865        get: function get() {
6866            return this.ctx.lineCap;
6867        }
6868    });
6869    Object.defineProperty(c2d, 'lineJoin', {
6870        set: function set(val) {
6871            this.setLineJoin(val);
6872        },
6873        get: function get() {
6874            return this.ctx.lineJoin;
6875        }
6876    });
6877    Object.defineProperty(c2d, 'miterLimit', {
6878        set: function set(val) {
6879            this.ctx.miterLimit = val;
6880        },
6881        get: function get() {
6882            return this.ctx.miterLimit;
6883        }
6884    });
6885    Object.defineProperty(c2d, 'textBaseline', {
6886        set: function set(value) {
6887            this.setTextBaseline(value);
6888        },
6889        get: function get() {
6890            return this.getTextBaseline();
6891        }
6892    });
6893    Object.defineProperty(c2d, 'textAlign', {
6894        set: function set(value) {
6895            this.setTextAlign(value);
6896        },
6897        get: function get() {
6898            return this.getTextAlign();
6899        }
6900    });
6901    Object.defineProperty(c2d, 'font', {
6902        set: function set(value) {
6903            this.setFont(value);
6904        },
6905        get: function get() {
6906            return this.ctx.font;
6907        }
6908    });
6909    Object.defineProperty(c2d, 'globalCompositeOperation', {
6910        set: function set(value) {
6911            this.ctx.globalCompositeOperation = value;
6912        },
6913        get: function get() {
6914            return this.ctx.globalCompositeOperation;
6915        }
6916    });
6917    Object.defineProperty(c2d, 'globalAlpha', {
6918        set: function set(value) {
6919            this.ctx.globalAlpha = value;
6920        },
6921        get: function get() {
6922            return this.ctx.globalAlpha;
6923        }
6924    });
6925    // Not HTML API
6926    Object.defineProperty(c2d, 'ignoreClearRect', {
6927        set: function set(value) {
6928            this.ctx.ignoreClearRect = value;
6929        },
6930        get: function get() {
6931            return this.ctx.ignoreClearRect;
6932        }
6933    });
6934    // End Not HTML API
6935
6936    c2d.internal = {};
6937
6938    c2d.internal.rxRgb = /rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/;
6939    c2d.internal.rxRgba = /rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/;
6940    c2d.internal.rxTransparent = /transparent|rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*0+\s*\)/;
6941
6942    // http://hansmuller-flex.blogspot.com/2011/10/more-about-approximating-circular-arcs.html
6943    c2d.internal.arc = function (c2d, xc, yc, r, a1, a2, anticlockwise, style) {
6944        var includeMove = true;
6945
6946        var k = this.pdf.internal.scaleFactor;
6947        var pageHeight = this.pdf.internal.pageSize.height;
6948        var f2 = this.pdf.internal.f2;
6949
6950        var a1r = a1 * (Math.PI / 180);
6951        var a2r = a2 * (Math.PI / 180);
6952        var curves = this.createArc(r, a1r, a2r, anticlockwise);
6953        var pathData = null;
6954
6955        for (var i = 0; i < curves.length; i++) {
6956            var curve = curves[i];
6957            if (includeMove && i === 0) {
6958                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(' '));
6959            } else {
6960                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(' '));
6961            }
6962
6963            //c2d._lastPoint = {x: curve.x1 + xc, y: curve.y1 + yc};
6964            c2d._lastPoint = { x: xc, y: yc };
6965            // 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'
6966        }
6967
6968        if (style !== null) {
6969            this.pdf.internal.out(this.pdf.internal.getStyle(style));
6970        }
6971    };
6972
6973    /**
6974     *
6975     * @param x Edge point X
6976     * @param y Edge point Y
6977     * @param r Radius
6978     * @param a1 start angle
6979     * @param a2 end angle
6980     * @param anticlockwise
6981     * @param style
6982     * @param isClip
6983     */
6984    c2d.internal.arc2 = function (c2d, x, y, r, a1, a2, anticlockwise, style, isClip) {
6985        // we need to convert from cartesian to polar here methinks.
6986        var centerX = x; // + r;
6987        var centerY = y;
6988
6989        if (!isClip) {
6990            this.arc(c2d, centerX, centerY, r, a1, a2, anticlockwise, style);
6991        } else {
6992            this.arc(c2d, centerX, centerY, r, a1, a2, anticlockwise, null);
6993            this.pdf.clip_fixed();
6994        }
6995    };
6996
6997    c2d.internal.move2 = function (c2d, x, y) {
6998        var k = this.pdf.internal.scaleFactor;
6999        var pageHeight = this.pdf.internal.pageSize.height;
7000        var f2 = this.pdf.internal.f2;
7001
7002        this.pdf.internal.out([f2(x * k), f2((pageHeight - y) * k), 'm'].join(' '));
7003        c2d._lastPoint = { x: x, y: y };
7004    };
7005
7006    c2d.internal.line2 = function (c2d, dx, dy) {
7007        var k = this.pdf.internal.scaleFactor;
7008        var pageHeight = this.pdf.internal.pageSize.height;
7009        var f2 = this.pdf.internal.f2;
7010
7011        //var pt = {x: c2d._lastPoint.x + dx, y: c2d._lastPoint.y + dy};
7012        var pt = { x: dx, y: dy };
7013
7014        this.pdf.internal.out([f2(pt.x * k), f2((pageHeight - pt.y) * k), 'l'].join(' '));
7015        //this.pdf.internal.out('f');
7016        c2d._lastPoint = pt;
7017    };
7018
7019    /**
7020     * 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.
7021     *
7022     * 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.
7023     */
7024
7025    c2d.internal.createArc = function (radius, startAngle, endAngle, anticlockwise) {
7026        var EPSILON = 0.00001; // Roughly 1/1000th of a degree, see below
7027        var twoPI = Math.PI * 2;
7028        var piOverTwo = Math.PI / 2.0;
7029
7030        // normalize startAngle, endAngle to [0, 2PI]
7031        var startAngleN = startAngle;
7032        if (startAngleN < twoPI || startAngleN > twoPI) {
7033            startAngleN = startAngleN % twoPI;
7034        }
7035        if (startAngleN < 0) {
7036            startAngleN = twoPI + startAngleN;
7037        }
7038
7039        while (startAngle > endAngle) {
7040            startAngle = startAngle - twoPI;
7041        }
7042        var totalAngle = Math.abs(endAngle - startAngle);
7043        if (totalAngle < twoPI) {
7044            if (anticlockwise) {
7045                totalAngle = twoPI - totalAngle;
7046            }
7047        }
7048
7049        // Compute the sequence of arc curves, up to PI/2 at a time.
7050        var curves = [];
7051        var sgn = anticlockwise ? -1 : +1;
7052
7053        var a1 = startAngleN;
7054        for (; totalAngle > EPSILON;) {
7055            var remain = sgn * Math.min(totalAngle, piOverTwo);
7056            var a2 = a1 + remain;
7057            curves.push(this.createSmallArc(radius, a1, a2));
7058            totalAngle -= Math.abs(a2 - a1);
7059            a1 = a2;
7060        }
7061
7062        return curves;
7063    };
7064
7065    c2d.internal.getCurrentPage = function () {
7066        return this.pdf.internal.pages[this.pdf.internal.getCurrentPageInfo().pageNumber];
7067    };
7068
7069    /**
7070     * 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.
7071     *
7072     * 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 cubic bezier's control points.
7073     *
7074     * 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.
7075     */
7076
7077    c2d.internal.createSmallArc = function (r, a1, a2) {
7078        // Compute all four points for an arc that subtends the same total angle
7079        // but is centered on the X-axis
7080
7081        var a = (a2 - a1) / 2.0;
7082
7083        var x4 = r * Math.cos(a);
7084        var y4 = r * Math.sin(a);
7085        var x1 = x4;
7086        var y1 = -y4;
7087
7088        var q1 = x1 * x1 + y1 * y1;
7089        var q2 = q1 + x1 * x4 + y1 * y4;
7090        var k2 = 4 / 3 * (Math.sqrt(2 * q1 * q2) - q2) / (x1 * y4 - y1 * x4);
7091
7092        var x2 = x1 - k2 * y1;
7093        var y2 = y1 + k2 * x1;
7094        var x3 = x2;
7095        var y3 = -y2;
7096
7097        // Find the arc points' actual locations by computing x1,y1 and x4,y4
7098        // and rotating the control points by a + a1
7099
7100        var ar = a + a1;
7101        var cos_ar = Math.cos(ar);
7102        var sin_ar = Math.sin(ar);
7103
7104        return {
7105            x1: r * Math.cos(a1),
7106            y1: r * Math.sin(a1),
7107            x2: x2 * cos_ar - y2 * sin_ar,
7108            y2: x2 * sin_ar + y2 * cos_ar,
7109            x3: x3 * cos_ar - y3 * sin_ar,
7110            y3: x3 * sin_ar + y3 * cos_ar,
7111            x4: r * Math.cos(a2),
7112            y4: r * Math.sin(a2)
7113        };
7114    };
7115
7116    function context() {
7117        this._isStrokeTransparent = false;
7118        this._strokeOpacity = 1;
7119        this.strokeStyle = '#000000';
7120        this.fillStyle = '#000000';
7121        this._isFillTransparent = false;
7122        this._fillOpacity = 1;
7123        this.font = "12pt times";
7124        this.textBaseline = 'alphabetic'; // top,bottom,middle,ideographic,alphabetic,hanging
7125        this.textAlign = 'start';
7126        this.lineWidth = 1;
7127        this.lineJoin = 'miter'; // round, bevel, miter
7128        this.lineCap = 'butt'; // butt, round, square
7129        this._transform = [1, 0, 0, 1, 0, 0]; // sx, shy, shx, sy, tx, ty
7130        this.globalCompositeOperation = 'normal';
7131        this.globalAlpha = 1.0;
7132        this._clip_path = [];
7133        // TODO miter limit //default 10
7134
7135        // Not HTML API
7136        this.ignoreClearRect = false;
7137
7138        this.copy = function (ctx) {
7139            this._isStrokeTransparent = ctx._isStrokeTransparent;
7140            this._strokeOpacity = ctx._strokeOpacity;
7141            this.strokeStyle = ctx.strokeStyle;
7142            this._isFillTransparent = ctx._isFillTransparent;
7143            this._fillOpacity = ctx._fillOpacity;
7144            this.fillStyle = ctx.fillStyle;
7145            this.font = ctx.font;
7146            this.lineWidth = ctx.lineWidth;
7147            this.lineJoin = ctx.lineJoin;
7148            this.lineCap = ctx.lineCap;
7149            this.textBaseline = ctx.textBaseline;
7150            this.textAlign = ctx.textAlign;
7151            this._fontSize = ctx._fontSize;
7152            this._transform = ctx._transform.slice(0);
7153            this.globalCompositeOperation = ctx.globalCompositeOperation;
7154            this.globalAlpha = ctx.globalAlpha;
7155            this._clip_path = ctx._clip_path.slice(0); //TODO deep copy?
7156
7157            // Not HTML API
7158            this.ignoreClearRect = ctx.ignoreClearRect;
7159        };
7160    }
7161
7162    return this;
7163})(jsPDF.API);
7164
7165/** @preserve
7166 * jsPDF fromHTML plugin. BETA stage. API subject to change. Needs browser
7167 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
7168 *               2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
7169 *               2014 Diego Casorran, https://github.com/diegocr
7170 *               2014 Daniel Husar, https://github.com/danielhusar
7171 *               2014 Wolfgang Gassler, https://github.com/woolfg
7172 *               2014 Steven Spungin, https://github.com/flamenco
7173 *
7174 * 
7175 * ====================================================================
7176 */
7177
7178(function (jsPDFAPI) {
7179	var clone, _DrillForContent, FontNameDB, FontStyleMap, TextAlignMap, FontWeightMap, FloatMap, ClearMap, GetCSS, PurgeWhiteSpace, Renderer, ResolveFont, ResolveUnitedNumber, UnitedNumberMap, elementHandledElsewhere, images, loadImgs, checkForFooter, process, tableToJson;
7180	clone = function () {
7181		return function (obj) {
7182			Clone.prototype = obj;
7183			return new Clone();
7184		};
7185		function Clone() {}
7186	}();
7187	PurgeWhiteSpace = function PurgeWhiteSpace(array) {
7188		var fragment, i, l, lTrimmed, r, rTrimmed, trailingSpace;
7189		i = 0;
7190		l = array.length;
7191		fragment = void 0;
7192		lTrimmed = false;
7193		rTrimmed = false;
7194		while (!lTrimmed && i !== l) {
7195			fragment = array[i] = array[i].trimLeft();
7196			if (fragment) {
7197				lTrimmed = true;
7198			}
7199			i++;
7200		}
7201		i = l - 1;
7202		while (l && !rTrimmed && i !== -1) {
7203			fragment = array[i] = array[i].trimRight();
7204			if (fragment) {
7205				rTrimmed = true;
7206			}
7207			i--;
7208		}
7209		r = /\s+$/g;
7210		trailingSpace = true;
7211		i = 0;
7212		while (i !== l) {
7213			// Leave the line breaks intact
7214			if (array[i] != "\u2028") {
7215				fragment = array[i].replace(/\s+/g, " ");
7216				if (trailingSpace) {
7217					fragment = fragment.trimLeft();
7218				}
7219				if (fragment) {
7220					trailingSpace = r.test(fragment);
7221				}
7222				array[i] = fragment;
7223			}
7224			i++;
7225		}
7226		return array;
7227	};
7228	Renderer = function Renderer(pdf, x, y, settings) {
7229		this.pdf = pdf;
7230		this.x = x;
7231		this.y = y;
7232		this.settings = settings;
7233		//list of functions which are called after each element-rendering process
7234		this.watchFunctions = [];
7235		this.init();
7236		return this;
7237	};
7238	ResolveFont = function ResolveFont(css_font_family_string) {
7239		var name, part, parts;
7240		name = void 0;
7241		parts = css_font_family_string.split(",");
7242		part = parts.shift();
7243		while (!name && part) {
7244			name = FontNameDB[part.trim().toLowerCase()];
7245			part = parts.shift();
7246		}
7247		return name;
7248	};
7249	ResolveUnitedNumber = function ResolveUnitedNumber(css_line_height_string) {
7250
7251		//IE8 issues
7252		css_line_height_string = css_line_height_string === "auto" ? "0px" : css_line_height_string;
7253		if (css_line_height_string.indexOf("em") > -1 && !isNaN(Number(css_line_height_string.replace("em", "")))) {
7254			css_line_height_string = Number(css_line_height_string.replace("em", "")) * 18.719 + "px";
7255		}
7256		if (css_line_height_string.indexOf("pt") > -1 && !isNaN(Number(css_line_height_string.replace("pt", "")))) {
7257			css_line_height_string = Number(css_line_height_string.replace("pt", "")) * 1.333 + "px";
7258		}
7259
7260		var normal, undef, value;
7261		undef = void 0;
7262		normal = 16.00;
7263		value = UnitedNumberMap[css_line_height_string];
7264		if (value) {
7265			return value;
7266		}
7267		value = {
7268			"xx-small": 9,
7269			"x-small": 11,
7270			small: 13,
7271			medium: 16,
7272			large: 19,
7273			"x-large": 23,
7274			"xx-large": 28,
7275			auto: 0
7276		}[{ css_line_height_string: css_line_height_string }];
7277
7278		if (value !== undef) {
7279			return UnitedNumberMap[css_line_height_string] = value / normal;
7280		}
7281		if (value = parseFloat(css_line_height_string)) {
7282			return UnitedNumberMap[css_line_height_string] = value / normal;
7283		}
7284		value = css_line_height_string.match(/([\d\.]+)(px)/);
7285		if (value.length === 3) {
7286			return UnitedNumberMap[css_line_height_string] = parseFloat(value[1]) / normal;
7287		}
7288		return UnitedNumberMap[css_line_height_string] = 1;
7289	};
7290	GetCSS = function GetCSS(element) {
7291		var css, tmp, computedCSSElement;
7292		computedCSSElement = function (el) {
7293			var compCSS;
7294			compCSS = function (el) {
7295				if (document.defaultView && document.defaultView.getComputedStyle) {
7296					return document.defaultView.getComputedStyle(el, null);
7297				} else if (el.currentStyle) {
7298					return el.currentStyle;
7299				} else {
7300					return el.style;
7301				}
7302			}(el);
7303			return function (prop) {
7304				prop = prop.replace(/-\D/g, function (match) {
7305					return match.charAt(1).toUpperCase();
7306				});
7307				return compCSS[prop];
7308			};
7309		}(element);
7310		css = {};
7311		tmp = void 0;
7312		css["font-family"] = ResolveFont(computedCSSElement("font-family")) || "times";
7313		css["font-style"] = FontStyleMap[computedCSSElement("font-style")] || "normal";
7314		css["text-align"] = TextAlignMap[computedCSSElement("text-align")] || "left";
7315		tmp = FontWeightMap[computedCSSElement("font-weight")] || "normal";
7316		if (tmp === "bold") {
7317			if (css["font-style"] === "normal") {
7318				css["font-style"] = tmp;
7319			} else {
7320				css["font-style"] = tmp + css["font-style"];
7321			}
7322		}
7323		css["font-size"] = ResolveUnitedNumber(computedCSSElement("font-size")) || 1;
7324		css["line-height"] = ResolveUnitedNumber(computedCSSElement("line-height")) || 1;
7325		css["display"] = computedCSSElement("display") === "inline" ? "inline" : "block";
7326
7327		tmp = css["display"] === "block";
7328		css["margin-top"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-top")) || 0;
7329		css["margin-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-bottom")) || 0;
7330		css["padding-top"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-top")) || 0;
7331		css["padding-bottom"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-bottom")) || 0;
7332		css["margin-left"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-left")) || 0;
7333		css["margin-right"] = tmp && ResolveUnitedNumber(computedCSSElement("margin-right")) || 0;
7334		css["padding-left"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-left")) || 0;
7335		css["padding-right"] = tmp && ResolveUnitedNumber(computedCSSElement("padding-right")) || 0;
7336
7337		css["page-break-before"] = computedCSSElement("page-break-before") || "auto";
7338
7339		//float and clearing of floats
7340		css["float"] = FloatMap[computedCSSElement("cssFloat")] || "none";
7341		css["clear"] = ClearMap[computedCSSElement("clear")] || "none";
7342
7343		css["color"] = computedCSSElement("color");
7344
7345		return css;
7346	};
7347	elementHandledElsewhere = function elementHandledElsewhere(element, renderer, elementHandlers) {
7348		var handlers, i, isHandledElsewhere, l, t;
7349		isHandledElsewhere = false;
7350		i = void 0;
7351		l = void 0;
7352		t = void 0;
7353		handlers = elementHandlers["#" + element.id];
7354		if (handlers) {
7355			if (typeof handlers === "function") {
7356				isHandledElsewhere = handlers(element, renderer);
7357			} else {
7358				i = 0;
7359				l = handlers.length;
7360				while (!isHandledElsewhere && i !== l) {
7361					isHandledElsewhere = handlers[i](element, renderer);
7362					i++;
7363				}
7364			}
7365		}
7366		handlers = elementHandlers[element.nodeName];
7367		if (!isHandledElsewhere && handlers) {
7368			if (typeof handlers === "function") {
7369				isHandledElsewhere = handlers(element, renderer);
7370			} else {
7371				i = 0;
7372				l = handlers.length;
7373				while (!isHandledElsewhere && i !== l) {
7374					isHandledElsewhere = handlers[i](element, renderer);
7375					i++;
7376				}
7377			}
7378		}
7379		return isHandledElsewhere;
7380	};
7381	tableToJson = function tableToJson(table, renderer) {
7382		var data, headers, i, j, rowData, tableRow, table_obj, table_with, cell, l;
7383		data = [];
7384		headers = [];
7385		i = 0;
7386		l = table.rows[0].cells.length;
7387		table_with = table.clientWidth;
7388		while (i < l) {
7389			cell = table.rows[0].cells[i];
7390			headers[i] = {
7391				name: cell.textContent.toLowerCase().replace(/\s+/g, ''),
7392				prompt: cell.textContent.replace(/\r?\n/g, ''),
7393				width: cell.clientWidth / table_with * renderer.pdf.internal.pageSize.width
7394			};
7395			i++;
7396		}
7397		i = 1;
7398		while (i < table.rows.length) {
7399			tableRow = table.rows[i];
7400			rowData = {};
7401			j = 0;
7402			while (j < tableRow.cells.length) {
7403				rowData[headers[j].name] = tableRow.cells[j].textContent.replace(/\r?\n/g, '');
7404				j++;
7405			}
7406			data.push(rowData);
7407			i++;
7408		}
7409		return table_obj = {
7410			rows: data,
7411			headers: headers
7412		};
7413	};
7414	var SkipNode = {
7415		SCRIPT: 1,
7416		STYLE: 1,
7417		NOSCRIPT: 1,
7418		OBJECT: 1,
7419		EMBED: 1,
7420		SELECT: 1
7421	};
7422	var listCount = 1;
7423	_DrillForContent = function DrillForContent(element, renderer, elementHandlers) {
7424		var cn, cns, fragmentCSS, i, isBlock, l, px2pt, table2json, cb;
7425		cns = element.childNodes;
7426		cn = void 0;
7427		fragmentCSS = GetCSS(element);
7428		isBlock = fragmentCSS.display === "block";
7429		if (isBlock) {
7430			renderer.setBlockBoundary();
7431			renderer.setBlockStyle(fragmentCSS);
7432		}
7433		px2pt = 0.264583 * 72 / 25.4;
7434		i = 0;
7435		l = cns.length;
7436		while (i < l) {
7437			cn = cns[i];
7438			if ((typeof cn === "undefined" ? "undefined" : _typeof(cn)) === "object") {
7439
7440				//execute all watcher functions to e.g. reset floating
7441				renderer.executeWatchFunctions(cn);
7442
7443				/*** HEADER rendering **/
7444				if (cn.nodeType === 1 && cn.nodeName === 'HEADER') {
7445					var header = cn;
7446					//store old top margin
7447					var oldMarginTop = renderer.pdf.margins_doc.top;
7448					//subscribe for new page event and render header first on every page
7449					renderer.pdf.internal.events.subscribe('addPage', function (pageInfo) {
7450						//set current y position to old margin
7451						renderer.y = oldMarginTop;
7452						//render all child nodes of the header element
7453						_DrillForContent(header, renderer, elementHandlers);
7454						//set margin to old margin + rendered header + 10 space to prevent overlapping
7455						//important for other plugins (e.g. table) to start rendering at correct position after header
7456						renderer.pdf.margins_doc.top = renderer.y + 10;
7457						renderer.y += 10;
7458					}, false);
7459				}
7460
7461				if (cn.nodeType === 8 && cn.nodeName === "#comment") {
7462					if (~cn.textContent.indexOf("ADD_PAGE")) {
7463						renderer.pdf.addPage();
7464						renderer.y = renderer.pdf.margins_doc.top;
7465					}
7466				} else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) {
7467					/*** IMAGE RENDERING ***/
7468					var cached_image;
7469					if (cn.nodeName === "IMG") {
7470						var url = cn.getAttribute("src");
7471						cached_image = images[renderer.pdf.sHashCode(url) || url];
7472					}
7473					if (cached_image) {
7474						if (renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom < renderer.y + cn.height && renderer.y > renderer.pdf.margins_doc.top) {
7475							renderer.pdf.addPage();
7476							renderer.y = renderer.pdf.margins_doc.top;
7477							//check if we have to set back some values due to e.g. header rendering for new page
7478							renderer.executeWatchFunctions(cn);
7479						}
7480
7481						var imagesCSS = GetCSS(cn);
7482						var imageX = renderer.x;
7483						var fontToUnitRatio = 12 / renderer.pdf.internal.scaleFactor;
7484
7485						//define additional paddings, margins which have to be taken into account for margin calculations
7486						var additionalSpaceLeft = (imagesCSS["margin-left"] + imagesCSS["padding-left"]) * fontToUnitRatio;
7487						var additionalSpaceRight = (imagesCSS["margin-right"] + imagesCSS["padding-right"]) * fontToUnitRatio;
7488						var additionalSpaceTop = (imagesCSS["margin-top"] + imagesCSS["padding-top"]) * fontToUnitRatio;
7489						var additionalSpaceBottom = (imagesCSS["margin-bottom"] + imagesCSS["padding-bottom"]) * fontToUnitRatio;
7490
7491						//if float is set to right, move the image to the right border
7492						//add space if margin is set
7493						if (imagesCSS['float'] !== undefined && imagesCSS['float'] === 'right') {
7494							imageX += renderer.settings.width - cn.width - additionalSpaceRight;
7495						} else {
7496							imageX += additionalSpaceLeft;
7497						}
7498
7499						renderer.pdf.addImage(cached_image, imageX, renderer.y + additionalSpaceTop, cn.width, cn.height);
7500						cached_image = undefined;
7501						//if the float prop is specified we have to float the text around the image
7502						if (imagesCSS['float'] === 'right' || imagesCSS['float'] === 'left') {
7503							//add functiont to set back coordinates after image rendering
7504							renderer.watchFunctions.push(function (diffX, thresholdY, diffWidth, el) {
7505								//undo drawing box adaptions which were set by floating
7506								if (renderer.y >= thresholdY) {
7507									renderer.x += diffX;
7508									renderer.settings.width += diffWidth;
7509									return true;
7510								} else if (el && el.nodeType === 1 && !SkipNode[el.nodeName] && renderer.x + el.width > renderer.pdf.margins_doc.left + renderer.pdf.margins_doc.width) {
7511									renderer.x += diffX;
7512									renderer.y = thresholdY;
7513									renderer.settings.width += diffWidth;
7514									return true;
7515								} else {
7516									return false;
7517								}
7518							}.bind(this, imagesCSS['float'] === 'left' ? -cn.width - additionalSpaceLeft - additionalSpaceRight : 0, renderer.y + cn.height + additionalSpaceTop + additionalSpaceBottom, cn.width));
7519							//reset floating by clear:both divs
7520							//just set cursorY after the floating element
7521							renderer.watchFunctions.push(function (yPositionAfterFloating, pages, el) {
7522								if (renderer.y < yPositionAfterFloating && pages === renderer.pdf.internal.getNumberOfPages()) {
7523									if (el.nodeType === 1 && GetCSS(el).clear === 'both') {
7524										renderer.y = yPositionAfterFloating;
7525										return true;
7526									} else {
7527										return false;
7528									}
7529								} else {
7530									return true;
7531								}
7532							}.bind(this, renderer.y + cn.height, renderer.pdf.internal.getNumberOfPages()));
7533
7534							//if floating is set we decrease the available width by the image width
7535							renderer.settings.width -= cn.width + additionalSpaceLeft + additionalSpaceRight;
7536							//if left just add the image width to the X coordinate
7537							if (imagesCSS['float'] === 'left') {
7538								renderer.x += cn.width + additionalSpaceLeft + additionalSpaceRight;
7539							}
7540						} else {
7541							//if no floating is set, move the rendering cursor after the image height
7542							renderer.y += cn.height + additionalSpaceTop + additionalSpaceBottom;
7543						}
7544
7545						/*** TABLE RENDERING ***/
7546					} else if (cn.nodeName === "TABLE") {
7547						table2json = tableToJson(cn, renderer);
7548						renderer.y += 10;
7549						renderer.pdf.table(renderer.x, renderer.y, table2json.rows, table2json.headers, {
7550							autoSize: false,
7551							printHeaders: elementHandlers.printHeaders,
7552							margins: renderer.pdf.margins_doc,
7553							css: GetCSS(cn)
7554						});
7555						renderer.y = renderer.pdf.lastCellPos.y + renderer.pdf.lastCellPos.h + 20;
7556					} else if (cn.nodeName === "OL" || cn.nodeName === "UL") {
7557						listCount = 1;
7558						if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
7559							_DrillForContent(cn, renderer, elementHandlers);
7560						}
7561						renderer.y += 10;
7562					} else if (cn.nodeName === "LI") {
7563						var temp = renderer.x;
7564						renderer.x += 20 / renderer.pdf.internal.scaleFactor;
7565						renderer.y += 3;
7566						if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
7567							_DrillForContent(cn, renderer, elementHandlers);
7568						}
7569						renderer.x = temp;
7570					} else if (cn.nodeName === "BR") {
7571						renderer.y += fragmentCSS["font-size"] * renderer.pdf.internal.scaleFactor;
7572						renderer.addText("\u2028", clone(fragmentCSS));
7573					} else {
7574						if (!elementHandledElsewhere(cn, renderer, elementHandlers)) {
7575							_DrillForContent(cn, renderer, elementHandlers);
7576						}
7577					}
7578				} else if (cn.nodeType === 3) {
7579					var value = cn.nodeValue;
7580					if (cn.nodeValue && cn.parentNode.nodeName === "LI") {
7581						if (cn.parentNode.parentNode.nodeName === "OL") {
7582							value = listCount++ + '. ' + value;
7583						} else {
7584							var fontSize = fragmentCSS["font-size"];
7585							var offsetX = (3 - fontSize * 0.75) * renderer.pdf.internal.scaleFactor;
7586							var offsetY = fontSize * 0.75 * renderer.pdf.internal.scaleFactor;
7587							var radius = fontSize * 1.74 / renderer.pdf.internal.scaleFactor;
7588							cb = function cb(x, y) {
7589								this.pdf.circle(x + offsetX, y + offsetY, radius, 'FD');
7590							};
7591						}
7592					}
7593					// Only add the text if the text node is in the body element
7594					// Add compatibility with IE11
7595					if (!!(cn.ownerDocument.body.compareDocumentPosition(cn) & 16)) {
7596						renderer.addText(value, fragmentCSS);
7597					}
7598				} else if (typeof cn === "string") {
7599					renderer.addText(cn, fragmentCSS);
7600				}
7601			}
7602			i++;
7603		}
7604		elementHandlers.outY = renderer.y;
7605
7606		if (isBlock) {
7607			return renderer.setBlockBoundary(cb);
7608		}
7609	};
7610	images = {};
7611	loadImgs = function loadImgs(element, renderer, elementHandlers, cb) {
7612		var imgs = element.getElementsByTagName('img'),
7613		    l = imgs.length,
7614		    found_images,
7615		    x = 0;
7616		function done() {
7617			renderer.pdf.internal.events.publish('imagesLoaded');
7618			cb(found_images);
7619		}
7620		function loadImage(url, width, height) {
7621			if (!url) return;
7622			var img = new Image();
7623			found_images = ++x;
7624			img.crossOrigin = '';
7625			img.onerror = img.onload = function () {
7626				if (img.complete) {
7627					//to support data urls in images, set width and height
7628					//as those values are not recognized automatically
7629					if (img.src.indexOf('data:image/') === 0) {
7630						img.width = width || img.width || 0;
7631						img.height = height || img.height || 0;
7632					}
7633					//if valid image add to known images array
7634					if (img.width + img.height) {
7635						var hash = renderer.pdf.sHashCode(url) || url;
7636						images[hash] = images[hash] || img;
7637					}
7638				}
7639				if (! --x) {
7640					done();
7641				}
7642			};
7643			img.src = url;
7644		}
7645		while (l--) {
7646			loadImage(imgs[l].getAttribute("src"), imgs[l].width, imgs[l].height);
7647		}return x || done();
7648	};
7649	checkForFooter = function checkForFooter(elem, renderer, elementHandlers) {
7650		//check if we can found a <footer> element
7651		var footer = elem.getElementsByTagName("footer");
7652		if (footer.length > 0) {
7653
7654			footer = footer[0];
7655
7656			//bad hack to get height of footer
7657			//creat dummy out and check new y after fake rendering
7658			var oldOut = renderer.pdf.internal.write;
7659			var oldY = renderer.y;
7660			renderer.pdf.internal.write = function () {};
7661			_DrillForContent(footer, renderer, elementHandlers);
7662			var footerHeight = Math.ceil(renderer.y - oldY) + 5;
7663			renderer.y = oldY;
7664			renderer.pdf.internal.write = oldOut;
7665
7666			//add 20% to prevent overlapping
7667			renderer.pdf.margins_doc.bottom += footerHeight;
7668
7669			//Create function render header on every page
7670			var renderFooter = function renderFooter(pageInfo) {
7671				var pageNumber = pageInfo !== undefined ? pageInfo.pageNumber : 1;
7672				//set current y position to old margin
7673				var oldPosition = renderer.y;
7674				//render all child nodes of the header element
7675				renderer.y = renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom;
7676				renderer.pdf.margins_doc.bottom -= footerHeight;
7677
7678				//check if we have to add page numbers
7679				var spans = footer.getElementsByTagName('span');
7680				for (var i = 0; i < spans.length; ++i) {
7681					//if we find some span element with class pageCounter, set the page
7682					if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" pageCounter ") > -1) {
7683						spans[i].innerHTML = pageNumber;
7684					}
7685					//if we find some span element with class totalPages, set a variable which is replaced after rendering of all pages
7686					if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) {
7687						spans[i].innerHTML = '###jsPDFVarTotalPages###';
7688					}
7689				}
7690
7691				//render footer content
7692				_DrillForContent(footer, renderer, elementHandlers);
7693				//set bottom margin to previous height including the footer height
7694				renderer.pdf.margins_doc.bottom += footerHeight;
7695				//important for other plugins (e.g. table) to start rendering at correct position after header
7696				renderer.y = oldPosition;
7697			};
7698
7699			//check if footer contains totalPages which should be replace at the disoposal of the document
7700			var spans = footer.getElementsByTagName('span');
7701			for (var i = 0; i < spans.length; ++i) {
7702				if ((" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1) {
7703					renderer.pdf.internal.events.subscribe('htmlRenderingFinished', renderer.pdf.putTotalPages.bind(renderer.pdf, '###jsPDFVarTotalPages###'), true);
7704				}
7705			}
7706
7707			//register event to render footer on every new page
7708			renderer.pdf.internal.events.subscribe('addPage', renderFooter, false);
7709			//render footer on first page
7710			renderFooter();
7711
7712			//prevent footer rendering
7713			SkipNode['FOOTER'] = 1;
7714		}
7715	};
7716	process = function process(pdf, element, x, y, settings, callback) {
7717		if (!element) return false;
7718		if (typeof element !== "string" && !element.parentNode) element = '' + element.innerHTML;
7719		if (typeof element === "string") {
7720			element = function (element) {
7721				var $frame, $hiddendiv, framename, visuallyhidden;
7722				framename = "jsPDFhtmlText" + Date.now().toString() + (Math.random() * 1000).toFixed(0);
7723				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;";
7724				$hiddendiv = document.createElement('div');
7725				$hiddendiv.style.cssText = visuallyhidden;
7726				$hiddendiv.innerHTML = "<iframe style=\"height:1px;width:1px\" name=\"" + framename + "\" />";
7727				document.body.appendChild($hiddendiv);
7728				$frame = window.frames[framename];
7729				$frame.document.open();
7730				$frame.document.writeln(element);
7731				$frame.document.close();
7732				return $frame.document.body;
7733			}(element.replace(/<\/?script[^>]*?>/gi, ''));
7734		}
7735		var r = new Renderer(pdf, x, y, settings),
7736		    out;
7737
7738		// 1. load images
7739		// 2. prepare optional footer elements
7740		// 3. render content
7741		loadImgs.call(this, element, r, settings.elementHandlers, function (found_images) {
7742			checkForFooter(element, r, settings.elementHandlers);
7743			_DrillForContent(element, r, settings.elementHandlers);
7744			//send event dispose for final taks (e.g. footer totalpage replacement)
7745			r.pdf.internal.events.publish('htmlRenderingFinished');
7746			out = r.dispose();
7747			if (typeof callback === 'function') callback(out);else if (found_images) console.error('jsPDF Warning: rendering issues? provide a callback to fromHTML!');
7748		});
7749		return out || { x: r.x, y: r.y };
7750	};
7751	Renderer.prototype.init = function () {
7752		this.paragraph = {
7753			text: [],
7754			style: []
7755		};
7756		return this.pdf.internal.write("q");
7757	};
7758	Renderer.prototype.dispose = function () {
7759		this.pdf.internal.write("Q");
7760		return {
7761			x: this.x,
7762			y: this.y,
7763			ready: true
7764		};
7765	};
7766
7767	//Checks if we have to execute some watcher functions
7768	//e.g. to end text floating around an image
7769	Renderer.prototype.executeWatchFunctions = function (el) {
7770		var ret = false;
7771		var narray = [];
7772		if (this.watchFunctions.length > 0) {
7773			for (var i = 0; i < this.watchFunctions.length; ++i) {
7774				if (this.watchFunctions[i](el) === true) {
7775					ret = true;
7776				} else {
7777					narray.push(this.watchFunctions[i]);
7778				}
7779			}
7780			this.watchFunctions = narray;
7781		}
7782		return ret;
7783	};
7784
7785	Renderer.prototype.splitFragmentsIntoLines = function (fragments, styles) {
7786		var currentLineLength, defaultFontSize, ff, fontMetrics, fontMetricsCache, fragment, fragmentChopped, fragmentLength, fragmentSpecificMetrics, fs, k, line, lines, maxLineLength, style;
7787		defaultFontSize = 12;
7788		k = this.pdf.internal.scaleFactor;
7789		fontMetricsCache = {};
7790		ff = void 0;
7791		fs = void 0;
7792		fontMetrics = void 0;
7793		fragment = void 0;
7794		style = void 0;
7795		fragmentSpecificMetrics = void 0;
7796		fragmentLength = void 0;
7797		fragmentChopped = void 0;
7798		line = [];
7799		lines = [line];
7800		currentLineLength = 0;
7801		maxLineLength = this.settings.width;
7802		while (fragments.length) {
7803			fragment = fragments.shift();
7804			style = styles.shift();
7805			if (fragment) {
7806				ff = style["font-family"];
7807				fs = style["font-style"];
7808				fontMetrics = fontMetricsCache[ff + fs];
7809				if (!fontMetrics) {
7810					fontMetrics = this.pdf.internal.getFont(ff, fs).metadata.Unicode;
7811					fontMetricsCache[ff + fs] = fontMetrics;
7812				}
7813				fragmentSpecificMetrics = {
7814					widths: fontMetrics.widths,
7815					kerning: fontMetrics.kerning,
7816					fontSize: style["font-size"] * defaultFontSize,
7817					textIndent: currentLineLength
7818				};
7819				fragmentLength = this.pdf.getStringUnitWidth(fragment, fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
7820				if (fragment == "\u2028") {
7821					line = [];
7822					lines.push(line);
7823				} else if (currentLineLength + fragmentLength > maxLineLength) {
7824					fragmentChopped = this.pdf.splitTextToSize(fragment, maxLineLength, fragmentSpecificMetrics);
7825					line.push([fragmentChopped.shift(), style]);
7826					while (fragmentChopped.length) {
7827						line = [[fragmentChopped.shift(), style]];
7828						lines.push(line);
7829					}
7830					currentLineLength = this.pdf.getStringUnitWidth(line[0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
7831				} else {
7832					line.push([fragment, style]);
7833					currentLineLength += fragmentLength;
7834				}
7835			}
7836		}
7837
7838		//if text alignment was set, set margin/indent of each line
7839		if (style['text-align'] !== undefined && (style['text-align'] === 'center' || style['text-align'] === 'right' || style['text-align'] === 'justify')) {
7840			for (var i = 0; i < lines.length; ++i) {
7841				var length = this.pdf.getStringUnitWidth(lines[i][0][0], fragmentSpecificMetrics) * fragmentSpecificMetrics.fontSize / k;
7842				//if there is more than on line we have to clone the style object as all lines hold a reference on this object
7843				if (i > 0) {
7844					lines[i][0][1] = clone(lines[i][0][1]);
7845				}
7846				var space = maxLineLength - length;
7847
7848				if (style['text-align'] === 'right') {
7849					lines[i][0][1]['margin-left'] = space;
7850					//if alignment is not right, it has to be center so split the space to the left and the right
7851				} else if (style['text-align'] === 'center') {
7852					lines[i][0][1]['margin-left'] = space / 2;
7853					//if justify was set, calculate the word spacing and define in by using the css property
7854				} else if (style['text-align'] === 'justify') {
7855					var countSpaces = lines[i][0][0].split(' ').length - 1;
7856					lines[i][0][1]['word-spacing'] = space / countSpaces;
7857					//ignore the last line in justify mode
7858					if (i === lines.length - 1) {
7859						lines[i][0][1]['word-spacing'] = 0;
7860					}
7861				}
7862			}
7863		}
7864
7865		return lines;
7866	};
7867	Renderer.prototype.RenderTextFragment = function (text, style) {
7868		var defaultFontSize, font, maxLineHeight;
7869
7870		maxLineHeight = 0;
7871		defaultFontSize = 12;
7872
7873		if (this.pdf.internal.pageSize.height - this.pdf.margins_doc.bottom < this.y + this.pdf.internal.getFontSize()) {
7874			this.pdf.internal.write("ET", "Q");
7875			this.pdf.addPage();
7876			this.y = this.pdf.margins_doc.top;
7877			this.pdf.internal.write("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), style.color, "Td");
7878			//move cursor by one line on new page
7879			maxLineHeight = Math.max(maxLineHeight, style["line-height"], style["font-size"]);
7880			this.pdf.internal.write(0, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td");
7881		}
7882
7883		font = this.pdf.internal.getFont(style["font-family"], style["font-style"]);
7884
7885		// text color
7886		var pdfTextColor = this.getPdfColor(style["color"]);
7887		if (pdfTextColor !== this.lastTextColor) {
7888			this.pdf.internal.write(pdfTextColor);
7889			this.lastTextColor = pdfTextColor;
7890		}
7891
7892		//set the word spacing for e.g. justify style
7893		if (style['word-spacing'] !== undefined && style['word-spacing'] > 0) {
7894			this.pdf.internal.write(style['word-spacing'].toFixed(2), "Tw");
7895		}
7896
7897		this.pdf.internal.write("/" + font.id, (defaultFontSize * style["font-size"]).toFixed(2), "Tf", "(" + this.pdf.internal.pdfEscape(text) + ") Tj");
7898
7899		//set the word spacing back to neutral => 0
7900		if (style['word-spacing'] !== undefined) {
7901			this.pdf.internal.write(0, "Tw");
7902		}
7903	};
7904
7905	// Accepts #FFFFFF, rgb(int,int,int), or CSS Color Name
7906	Renderer.prototype.getPdfColor = function (style) {
7907		var textColor;
7908		var r, g, b;
7909
7910		var rx = /rgb\s*\(\s*(\d+),\s*(\d+),\s*(\d+\s*)\)/;
7911		var m = rx.exec(style);
7912		if (m != null) {
7913			r = parseInt(m[1]);
7914			g = parseInt(m[2]);
7915			b = parseInt(m[3]);
7916		} else {
7917			if (style.charAt(0) != '#') {
7918				style = CssColors.colorNameToHex(style);
7919				if (!style) {
7920					style = '#000000';
7921				}
7922			}
7923			r = style.substring(1, 3);
7924			r = parseInt(r, 16);
7925			g = style.substring(3, 5);
7926			g = parseInt(g, 16);
7927			b = style.substring(5, 7);
7928			b = parseInt(b, 16);
7929		}
7930
7931		if (typeof r === 'string' && /^#[0-9A-Fa-f]{6}$/.test(r)) {
7932			var hex = parseInt(r.substr(1), 16);
7933			r = hex >> 16 & 255;
7934			g = hex >> 8 & 255;
7935			b = hex & 255;
7936		}
7937
7938		var f3 = this.f3;
7939		if (r === 0 && g === 0 && b === 0 || typeof g === 'undefined') {
7940			textColor = f3(r / 255) + ' g';
7941		} else {
7942			textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' ');
7943		}
7944		return textColor;
7945	};
7946
7947	Renderer.prototype.f3 = function (number) {
7948		return number.toFixed(3); // Ie, %.3f
7949	}, Renderer.prototype.renderParagraph = function (cb) {
7950		var blockstyle, defaultFontSize, fontToUnitRatio, fragments, i, l, line, lines, maxLineHeight, out, paragraphspacing_after, paragraphspacing_before, priorblockstyle, styles, fontSize;
7951		fragments = PurgeWhiteSpace(this.paragraph.text);
7952		styles = this.paragraph.style;
7953		blockstyle = this.paragraph.blockstyle;
7954		priorblockstyle = this.paragraph.priorblockstyle || {};
7955		this.paragraph = {
7956			text: [],
7957			style: [],
7958			blockstyle: {},
7959			priorblockstyle: blockstyle
7960		};
7961		if (!fragments.join("").trim()) {
7962			return;
7963		}
7964		lines = this.splitFragmentsIntoLines(fragments, styles);
7965		line = void 0;
7966		maxLineHeight = void 0;
7967		defaultFontSize = 12;
7968		fontToUnitRatio = defaultFontSize / this.pdf.internal.scaleFactor;
7969		this.priorMarginBottom = this.priorMarginBottom || 0;
7970		paragraphspacing_before = (Math.max((blockstyle["margin-top"] || 0) - this.priorMarginBottom, 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio;
7971		paragraphspacing_after = ((blockstyle["margin-bottom"] || 0) + (blockstyle["padding-bottom"] || 0)) * fontToUnitRatio;
7972		this.priorMarginBottom = blockstyle["margin-bottom"] || 0;
7973
7974		if (blockstyle['page-break-before'] === 'always') {
7975			this.pdf.addPage();
7976			this.y = 0;
7977			paragraphspacing_before = ((blockstyle["margin-top"] || 0) + (blockstyle["padding-top"] || 0)) * fontToUnitRatio;
7978		}
7979
7980		out = this.pdf.internal.write;
7981		i = void 0;
7982		l = void 0;
7983		this.y += paragraphspacing_before;
7984		out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
7985
7986		//stores the current indent of cursor position
7987		var currentIndent = 0;
7988
7989		while (lines.length) {
7990			line = lines.shift();
7991			maxLineHeight = 0;
7992			i = 0;
7993			l = line.length;
7994			while (i !== l) {
7995				if (line[i][0].trim()) {
7996					maxLineHeight = Math.max(maxLineHeight, line[i][1]["line-height"], line[i][1]["font-size"]);
7997					fontSize = line[i][1]["font-size"] * 7;
7998				}
7999				i++;
8000			}
8001			//if we have to move the cursor to adapt the indent
8002			var indentMove = 0;
8003			var wantedIndent = 0;
8004			//if a margin was added (by e.g. a text-alignment), move the cursor
8005			if (line[0][1]["margin-left"] !== undefined && line[0][1]["margin-left"] > 0) {
8006				wantedIndent = this.pdf.internal.getCoordinateString(line[0][1]["margin-left"]);
8007				indentMove = wantedIndent - currentIndent;
8008				currentIndent = wantedIndent;
8009			}
8010			var indentMore = Math.max(blockstyle["margin-left"] || 0, 0) * fontToUnitRatio;
8011			//move the cursor
8012			out(indentMove + indentMore, (-1 * defaultFontSize * maxLineHeight).toFixed(2), "Td");
8013			i = 0;
8014			l = line.length;
8015			while (i !== l) {
8016				if (line[i][0]) {
8017					this.RenderTextFragment(line[i][0], line[i][1]);
8018				}
8019				i++;
8020			}
8021			this.y += maxLineHeight * fontToUnitRatio;
8022
8023			//if some watcher function was executed successful, so e.g. margin and widths were changed,
8024			//reset line drawing and calculate position and lines again
8025			//e.g. to stop text floating around an image
8026			if (this.executeWatchFunctions(line[0][1]) && lines.length > 0) {
8027				var localFragments = [];
8028				var localStyles = [];
8029				//create fragment array of
8030				lines.forEach(function (localLine) {
8031					var i = 0;
8032					var l = localLine.length;
8033					while (i !== l) {
8034						if (localLine[i][0]) {
8035							localFragments.push(localLine[i][0] + ' ');
8036							localStyles.push(localLine[i][1]);
8037						}
8038						++i;
8039					}
8040				});
8041				//split lines again due to possible coordinate changes
8042				lines = this.splitFragmentsIntoLines(PurgeWhiteSpace(localFragments), localStyles);
8043				//reposition the current cursor
8044				out("ET", "Q");
8045				out("q", "BT 0 g", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
8046			}
8047		}
8048		if (cb && typeof cb === "function") {
8049			cb.call(this, this.x - 9, this.y - fontSize / 2);
8050		}
8051		out("ET", "Q");
8052		return this.y += paragraphspacing_after;
8053	};
8054	Renderer.prototype.setBlockBoundary = function (cb) {
8055		return this.renderParagraph(cb);
8056	};
8057	Renderer.prototype.setBlockStyle = function (css) {
8058		return this.paragraph.blockstyle = css;
8059	};
8060	Renderer.prototype.addText = function (text, css) {
8061		this.paragraph.text.push(text);
8062		return this.paragraph.style.push(css);
8063	};
8064	FontNameDB = {
8065		helvetica: "helvetica",
8066		"sans-serif": "helvetica",
8067		"times new roman": "times",
8068		serif: "times",
8069		times: "times",
8070		monospace: "courier",
8071		courier: "courier"
8072	};
8073	FontWeightMap = {
8074		100: "normal",
8075		200: "normal",
8076		300: "normal",
8077		400: "normal",
8078		500: "bold",
8079		600: "bold",
8080		700: "bold",
8081		800: "bold",
8082		900: "bold",
8083		normal: "normal",
8084		bold: "bold",
8085		bolder: "bold",
8086		lighter: "normal"
8087	};
8088	FontStyleMap = {
8089		normal: "normal",
8090		italic: "italic",
8091		oblique: "italic"
8092	};
8093	TextAlignMap = {
8094		left: "left",
8095		right: "right",
8096		center: "center",
8097		justify: "justify"
8098	};
8099	FloatMap = {
8100		none: 'none',
8101		right: 'right',
8102		left: 'left'
8103	};
8104	ClearMap = {
8105		none: 'none',
8106		both: 'both'
8107	};
8108	UnitedNumberMap = {
8109		normal: 1
8110	};
8111	/**
8112  * Converts HTML-formatted text into formatted PDF text.
8113  *
8114  * Notes:
8115  * 2012-07-18
8116  * Plugin relies on having browser, DOM around. The HTML is pushed into dom and traversed.
8117  * Plugin relies on jQuery for CSS extraction.
8118  * Targeting HTML output from Markdown templating, which is a very simple
8119  * markup - div, span, em, strong, p. No br-based paragraph separation supported explicitly (but still may work.)
8120  * Images, tables are NOT supported.
8121  *
8122  * @public
8123  * @function
8124  * @param HTML {String or DOM Element} HTML-formatted text, or pointer to DOM element that is to be rendered into PDF.
8125  * @param x {Number} starting X coordinate in jsPDF instance's declared units.
8126  * @param y {Number} starting Y coordinate in jsPDF instance's declared units.
8127  * @param settings {Object} Additional / optional variables controlling parsing, rendering.
8128  * @returns {Object} jsPDF instance
8129  */
8130	jsPDFAPI.fromHTML = function (HTML, x, y, settings, callback, margins) {
8131		"use strict";
8132
8133		this.margins_doc = margins || {
8134			top: 0,
8135			bottom: 0
8136		};
8137		if (!settings) settings = {};
8138		if (!settings.elementHandlers) settings.elementHandlers = {};
8139
8140		return process(this, HTML, isNaN(x) ? 4 : x, isNaN(y) ? 4 : y, settings, callback);
8141	};
8142})(jsPDF.API);
8143
8144/** ==================================================================== 
8145 * jsPDF JavaScript plugin
8146 * Copyright (c) 2013 Youssef Beddad, [email protected]
8147 * 
8148 * 
8149 * ====================================================================
8150 */
8151
8152/*global jsPDF */
8153
8154(function (jsPDFAPI) {
8155    'use strict';
8156
8157    var jsNamesObj, jsJsObj, text;
8158    jsPDFAPI.addJS = function (txt) {
8159        text = txt;
8160        this.internal.events.subscribe('postPutResources', function (txt) {
8161            jsNamesObj = this.internal.newObject();
8162            this.internal.write('<< /Names [(EmbeddedJS) ' + (jsNamesObj + 1) + ' 0 R] >>', 'endobj');
8163            jsJsObj = this.internal.newObject();
8164            this.internal.write('<< /S /JavaScript /JS (', text, ') >>', 'endobj');
8165        });
8166        this.internal.events.subscribe('putCatalog', function () {
8167            if (jsNamesObj !== undefined && jsJsObj !== undefined) {
8168                this.internal.write('/Names <</JavaScript ' + jsNamesObj + ' 0 R>>');
8169            }
8170        });
8171        return this;
8172    };
8173})(jsPDF.API);
8174
8175/**
8176 * jsPDF Outline PlugIn
8177 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC)  [email protected]
8178 *
8179 * Licensed under the MIT License.
8180 * http://opensource.org/licenses/mit-license
8181 */
8182
8183/**
8184 * Generates a PDF Outline
8185 */
8186
8187(function (jsPDFAPI) {
8188	'use strict';
8189
8190	jsPDFAPI.events.push(['postPutResources', function () {
8191		var pdf = this;
8192		var rx = /^(\d+) 0 obj$/;
8193
8194		// Write action goto objects for each page
8195		// this.outline.destsGoto = [];
8196		// for (var i = 0; i < totalPages; i++) {
8197		// var id = pdf.internal.newObject();
8198		// this.outline.destsGoto.push(id);
8199		// pdf.internal.write("<</D[" + (i * 2 + 3) + " 0 R /XYZ null
8200		// null null]/S/GoTo>> endobj");
8201		// }
8202		//
8203		// for (var i = 0; i < dests.length; i++) {
8204		// pdf.internal.write("(page_" + (i + 1) + ")" + dests[i] + " 0
8205		// R");
8206		// }
8207		//				
8208		if (this.outline.root.children.length > 0) {
8209			var lines = pdf.outline.render().split(/\r\n/);
8210			for (var i = 0; i < lines.length; i++) {
8211				var line = lines[i];
8212				var m = rx.exec(line);
8213				if (m != null) {
8214					var oid = m[1];
8215					pdf.internal.newObjectDeferredBegin(oid);
8216				}
8217				pdf.internal.write(line);
8218			}
8219		}
8220
8221		// This code will write named destination for each page reference
8222		// (page_1, etc)
8223		if (this.outline.createNamedDestinations) {
8224			var totalPages = this.internal.pages.length;
8225			// WARNING: this assumes jsPDF starts on page 3 and pageIDs
8226			// follow 5, 7, 9, etc
8227			// Write destination objects for each page
8228			var dests = [];
8229			for (var i = 0; i < totalPages; i++) {
8230				var id = pdf.internal.newObject();
8231				dests.push(id);
8232				var info = pdf.internal.getPageInfo(i + 1);
8233				pdf.internal.write("<< /D[" + info.objId + " 0 R /XYZ null null null]>> endobj");
8234			}
8235
8236			// assign a name for each destination
8237			var names2Oid = pdf.internal.newObject();
vendor: 5,061 bytes, lines 8238-8427
8238			pdf.internal.write('<< /Names [ ');
8239			for (var i = 0; i < dests.length; i++) {
8240				pdf.internal.write("(page_" + (i + 1) + ")" + dests[i] + " 0 R");
8241			}
8242			pdf.internal.write(' ] >>', 'endobj');
8243
8244			// var kids = pdf.internal.newObject();
8245			// pdf.internal.write('<< /Kids [ ' + names2Oid + ' 0 R');
8246			// pdf.internal.write(' ] >>', 'endobj');
8247
8248			var namesOid = pdf.internal.newObject();
8249			pdf.internal.write('<< /Dests ' + names2Oid + " 0 R");
8250			pdf.internal.write('>>', 'endobj');
8251		}
8252	}]);
8253
8254	jsPDFAPI.events.push(['putCatalog', function () {
8255		var pdf = this;
8256		if (pdf.outline.root.children.length > 0) {
8257			pdf.internal.write("/Outlines", this.outline.makeRef(this.outline.root));
8258			if (this.outline.createNamedDestinations) {
8259				pdf.internal.write("/Names " + namesOid + " 0 R");
8260			}
8261			// Open with Bookmarks showing
8262			// pdf.internal.write("/PageMode /UseOutlines");
8263		}
8264	}]);
8265
8266	jsPDFAPI.events.push(['initialized', function () {
8267		var pdf = this;
8268
8269		pdf.outline = {
8270			createNamedDestinations: false,
8271			root: {
8272				children: []
8273			}
8274		};
8275
8276		var namesOid;
8277		var destsGoto = [];
8278
8279		/**
8280   * Options: pageNumber
8281   */
8282		pdf.outline.add = function (parent, title, options) {
8283			var item = {
8284				title: title,
8285				options: options,
8286				children: []
8287			};
8288			if (parent == null) {
8289				parent = this.root;
8290			}
8291			parent.children.push(item);
8292			return item;
8293		};
8294
8295		pdf.outline.render = function () {
8296			this.ctx = {};
8297			this.ctx.val = '';
8298			this.ctx.pdf = pdf;
8299
8300			this.genIds_r(this.root);
8301			this.renderRoot(this.root);
8302			this.renderItems(this.root);
8303
8304			return this.ctx.val;
8305		};
8306
8307		pdf.outline.genIds_r = function (node) {
8308			node.id = pdf.internal.newObjectDeferred();
8309			for (var i = 0; i < node.children.length; i++) {
8310				this.genIds_r(node.children[i]);
8311			}
8312		};
8313
8314		pdf.outline.renderRoot = function (node) {
8315			this.objStart(node);
8316			this.line('/Type /Outlines');
8317			if (node.children.length > 0) {
8318				this.line('/First ' + this.makeRef(node.children[0]));
8319				this.line('/Last ' + this.makeRef(node.children[node.children.length - 1]));
8320			}
8321			this.line('/Count ' + this.count_r({
8322				count: 0
8323			}, node));
8324			this.objEnd();
8325		};
8326
8327		pdf.outline.renderItems = function (node) {
8328			for (var i = 0; i < node.children.length; i++) {
8329				var item = node.children[i];
8330				this.objStart(item);
8331
8332				this.line('/Title ' + this.makeString(item.title));
8333
8334				this.line('/Parent ' + this.makeRef(node));
8335				if (i > 0) {
8336					this.line('/Prev ' + this.makeRef(node.children[i - 1]));
8337				}
8338				if (i < node.children.length - 1) {
8339					this.line('/Next ' + this.makeRef(node.children[i + 1]));
8340				}
8341				if (item.children.length > 0) {
8342					this.line('/First ' + this.makeRef(item.children[0]));
8343					this.line('/Last ' + this.makeRef(item.children[item.children.length - 1]));
8344				}
8345
8346				var count = this.count = this.count_r({
8347					count: 0
8348				}, item);
8349				if (count > 0) {
8350					this.line('/Count ' + count);
8351				}
8352
8353				if (item.options) {
8354					if (item.options.pageNumber) {
8355						// Explicit Destination
8356						//WARNING this assumes page ids are 3,5,7, etc.
8357						var info = pdf.internal.getPageInfo(item.options.pageNumber);
8358						this.line('/Dest ' + '[' + info.objId + ' 0 R /XYZ 0 ' + this.ctx.pdf.internal.pageSize.height + ' 0]');
8359						// this line does not work on all clients (pageNumber instead of page ref)
8360						//this.line('/Dest ' + '[' + (item.options.pageNumber - 1) + ' /XYZ 0 ' + this.ctx.pdf.internal.pageSize.height + ' 0]');
8361
8362						// Named Destination
8363						// this.line('/Dest (page_' + (item.options.pageNumber) + ')');
8364
8365						// Action Destination
8366						// var id = pdf.internal.newObject();
8367						// pdf.internal.write('<</D[' + (item.options.pageNumber - 1) + ' /XYZ null null null]/S/GoTo>> endobj');
8368						// this.line('/A ' + id + ' 0 R' );
8369					}
8370				}
8371				this.objEnd();
8372			}
8373			for (var i = 0; i < node.children.length; i++) {
8374				var item = node.children[i];
8375				this.renderItems(item);
8376			}
8377		};
8378
8379		pdf.outline.line = function (text) {
8380			this.ctx.val += text + '\r\n';
8381		};
8382
8383		pdf.outline.makeRef = function (node) {
8384			return node.id + ' 0 R';
8385		};
8386
8387		pdf.outline.makeString = function (val) {
8388			return '(' + pdf.internal.pdfEscape(val) + ')';
8389		};
8390
8391		pdf.outline.objStart = function (node) {
8392			this.ctx.val += '\r\n' + node.id + ' 0 obj' + '\r\n<<\r\n';
8393		};
8394
8395		pdf.outline.objEnd = function (node) {
8396			this.ctx.val += '>> \r\n' + 'endobj' + '\r\n';
8397		};
8398
8399		pdf.outline.count_r = function (ctx, node) {
8400			for (var i = 0; i < node.children.length; i++) {
8401				ctx.count++;
8402				this.count_r(ctx, node.children[i]);
8403			}
8404			return ctx.count;
8405		};
8406	}]);
8407
8408	return this;
8409})(jsPDF.API);
8410
8411/**@preserve
8412 *  ====================================================================
8413 * jsPDF PNG PlugIn
8414 * Copyright (c) 2014 James Robb, https://github.com/jamesbrobb
8415 *
8416 * 
8417 * ====================================================================
8418 */
8419
8420(function (jsPDFAPI) {
8421	'use strict';
8422
8423	/*
8424  * @see http://www.w3.org/TR/PNG-Chunks.html
8425  *
8426  Color    Allowed      Interpretation
8427  Type     Bit Depths
8428 	   0       1,2,4,8,16  Each pixel is a grayscale sample.
8429 	   2       8,16        Each pixel is an R,G,B triple.
8430 	   3       1,2,4,8     Each pixel is a palette index;
8431                        a PLTE chunk must appear.
8432 	   4       8,16        Each pixel is a grayscale sample,
8433                        followed by an alpha sample.
8434 	   6       8,16        Each pixel is an R,G,B triple,
8435                        followed by an alpha sample.
8436 */
8437
8438	/*
8439  * PNG filter method types
8440  *
8441  * @see http://www.w3.org/TR/PNG-Filters.html
8442  * @see http://www.libpng.org/pub/png/book/chapter09.html
8443  *
8444  * This is what the value 'Predictor' in decode params relates to
8445  *
8446  * 15 is "optimal prediction", which means the prediction algorithm can change from line to line.
8447  * 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.
8448  *
8449    0       None
8450    1       Sub
8451    2       Up
8452    3       Average
8453    4       Paeth
8454  */
8455
8456	var doesNotHavePngJS = function doesNotHavePngJS() {
8457		return typeof PNG !== 'function' || typeof FlateStream !== 'function';
8458	},
8459	    canCompress = function canCompress(value) {
8460		return value !== jsPDFAPI.image_compression.NONE && hasCompressionJS();
8461	},
8462	    hasCompressionJS = function hasCompressionJS() {
8463		var inst = typeof Deflater === 'function';
8464		if (!inst) throw new Error("requires deflate.js for compression");
8465		return inst;
8466	},
8467	    compressBytes = function compressBytes(bytes, lineLength, colorsPerPixel, compression) {
8468
8469		var level = 5,
8470		    filter_method = filterUp;
8471
8472		switch (compression) {
8473
8474			case jsPDFAPI.image_compression.FAST:
8475
8476				level = 3;
8477				filter_method = filterSub;
8478				break;
8479
8480			case jsPDFAPI.image_compression.MEDIUM:
8481
8482				level = 6;
8483				filter_method = filterAverage;
8484				break;
8485
8486			case jsPDFAPI.image_compression.SLOW:
8487
8488				level = 9;
8489				filter_method = filterPaeth; //uses to sum to choose best filter for each line
8490				break;
8491		}
8492
8493		bytes = applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method);
8494
8495		var header = new Uint8Array(createZlibHeader(level));
8496		var checksum = adler32(bytes);
8497
8498		var deflate = new Deflater(level);
8499		var a = deflate.append(bytes);
8500		var cBytes = deflate.flush();
8501
8502		var len = header.length + a.length + cBytes.length;
8503
8504		var cmpd = new Uint8Array(len + 4);
8505		cmpd.set(header);
8506		cmpd.set(a, header.length);
8507		cmpd.set(cBytes, header.length + a.length);
8508
8509		cmpd[len++] = checksum >>> 24 & 0xff;
8510		cmpd[len++] = checksum >>> 16 & 0xff;
8511		cmpd[len++] = checksum >>> 8 & 0xff;
8512		cmpd[len++] = checksum & 0xff;
8513
8514		return jsPDFAPI.arrayBufferToBinaryString(cmpd);
8515	},
8516	    createZlibHeader = function createZlibHeader(bytes, level) {
8517		/*
8518   * @see http://www.ietf.org/rfc/rfc1950.txt for zlib header
8519   */
8520		var cm = 8;
8521		var cinfo = Math.LOG2E * Math.log(0x8000) - 8;
8522		var cmf = cinfo << 4 | cm;
8523
8524		var hdr = cmf << 8;
8525		var flevel = Math.min(3, (level - 1 & 0xff) >> 1);
8526
8527		hdr |= flevel << 6;
8528		hdr |= 0; //FDICT
8529		hdr += 31 - hdr % 31;
8530
8531		return [cmf, hdr & 0xff & 0xff];
8532	},
8533	    adler32 = function adler32(array, param) {
8534		var adler = 1;
8535		var s1 = adler & 0xffff,
8536		    s2 = adler >>> 16 & 0xffff;
8537		var len = array.length;
8538		var tlen;
8539		var i = 0;
8540
8541		while (len > 0) {
8542			tlen = len > param ? param : len;
8543			len -= tlen;
8544			do {
8545				s1 += array[i++];
8546				s2 += s1;
8547			} while (--tlen);
8548
8549			s1 %= 65521;
8550			s2 %= 65521;
8551		}
8552
8553		return (s2 << 16 | s1) >>> 0;
8554	},
8555	    applyPngFilterMethod = function applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method) {
8556		var lines = bytes.length / lineLength,
8557		    result = new Uint8Array(bytes.length + lines),
8558		    filter_methods = getFilterMethods(),
8559		    i = 0,
8560		    line,
8561		    prevLine,
8562		    offset;
8563
8564		for (; i < lines; i++) {
8565			offset = i * lineLength;
8566			line = bytes.subarray(offset, offset + lineLength);
8567
8568			if (filter_method) {
8569				result.set(filter_method(line, colorsPerPixel, prevLine), offset + i);
8570			} else {
8571
8572				var j = 0,
8573				    len = filter_methods.length,
8574				    results = [];
8575
8576				for (; j < len; j++) {
8577					results[j] = filter_methods[j](line, colorsPerPixel, prevLine);
8578				}var ind = getIndexOfSmallestSum(results.concat());
8579
8580				result.set(results[ind], offset + i);
8581			}
8582
8583			prevLine = line;
8584		}
8585
8586		return result;
8587	},
8588	    filterNone = function filterNone(line, colorsPerPixel, prevLine) {
8589		/*var result = new Uint8Array(line.length + 1);
8590  result[0] = 0;
8591  result.set(line, 1);*/
8592
8593		var result = Array.apply([], line);
8594		result.unshift(0);
8595
8596		return result;
8597	},
8598	    filterSub = function filterSub(line, colorsPerPixel, prevLine) {
8599		var result = [],
8600		    i = 0,
8601		    len = line.length,
8602		    left;
8603
8604		result[0] = 1;
8605
8606		for (; i < len; i++) {
8607			left = line[i - colorsPerPixel] || 0;
8608			result[i + 1] = line[i] - left + 0x0100 & 0xff;
8609		}
8610
8611		return result;
8612	},
8613	    filterUp = function filterUp(line, colorsPerPixel, prevLine) {
8614		var result = [],
8615		    i = 0,
8616		    len = line.length,
8617		    up;
8618
8619		result[0] = 2;
8620
8621		for (; i < len; i++) {
8622			up = prevLine && prevLine[i] || 0;
8623			result[i + 1] = line[i] - up + 0x0100 & 0xff;
8624		}
8625
8626		return result;
8627	},
8628	    filterAverage = function filterAverage(line, colorsPerPixel, prevLine) {
8629		var result = [],
8630		    i = 0,
8631		    len = line.length,
8632		    left,
8633		    up;
8634
8635		result[0] = 3;
8636
8637		for (; i < len; i++) {
8638			left = line[i - colorsPerPixel] || 0;
8639			up = prevLine && prevLine[i] || 0;
8640			result[i + 1] = line[i] + 0x0100 - (left + up >>> 1) & 0xff;
8641		}
8642
8643		return result;
8644	},
8645	    filterPaeth = function filterPaeth(line, colorsPerPixel, prevLine) {
8646		var result = [],
8647		    i = 0,
8648		    len = line.length,
8649		    left,
8650		    up,
8651		    upLeft,
8652		    paeth;
8653
8654		result[0] = 4;
8655
8656		for (; i < len; i++) {
8657			left = line[i - colorsPerPixel] || 0;
8658			up = prevLine && prevLine[i] || 0;
8659			upLeft = prevLine && prevLine[i - colorsPerPixel] || 0;
8660			paeth = paethPredictor(left, up, upLeft);
8661			result[i + 1] = line[i] - paeth + 0x0100 & 0xff;
8662		}
8663
8664		return result;
8665	},
8666	    paethPredictor = function paethPredictor(left, up, upLeft) {
8667
8668		var p = left + up - upLeft,
8669		    pLeft = Math.abs(p - left),
8670		    pUp = Math.abs(p - up),
8671		    pUpLeft = Math.abs(p - upLeft);
8672
8673		return pLeft <= pUp && pLeft <= pUpLeft ? left : pUp <= pUpLeft ? up : upLeft;
8674	},
8675	    getFilterMethods = function getFilterMethods() {
8676		return [filterNone, filterSub, filterUp, filterAverage, filterPaeth];
8677	},
8678	    getIndexOfSmallestSum = function getIndexOfSmallestSum(arrays) {
8679		var i = 0,
8680		    len = arrays.length,
8681		    sum,
8682		    min,
8683		    ind;
8684
8685		while (i < len) {
8686			sum = absSum(arrays[i].slice(1));
8687
8688			if (sum < min || !min) {
8689				min = sum;
8690				ind = i;
8691			}
8692
8693			i++;
8694		}
8695
8696		return ind;
8697	},
8698	    absSum = function absSum(array) {
8699		var i = 0,
8700		    len = array.length,
8701		    sum = 0;
8702
8703		while (i < len) {
8704			sum += Math.abs(array[i++]);
8705		}return sum;
8706	},
8707	    getPredictorFromCompression = function getPredictorFromCompression(compression) {
8708		var predictor;
8709		switch (compression) {
8710			case jsPDFAPI.image_compression.FAST:
8711				predictor = 11;
8712				break;
8713
8714			case jsPDFAPI.image_compression.MEDIUM:
8715				predictor = 13;
8716				break;
8717
8718			case jsPDFAPI.image_compression.SLOW:
8719				predictor = 14;
8720				break;
8721
8722			default:
8723				predictor = 12;
8724				break;
8725		}
8726		return predictor;
8727	},
8728	    logImg = function logImg(img) {
8729		console.log("width: " + img.width);
8730		console.log("height: " + img.height);
8731		console.log("bits: " + img.bits);
8732		console.log("colorType: " + img.colorType);
8733		console.log("transparency:");
8734		console.log(img.transparency);
8735		console.log("text:");
8736		console.log(img.text);
8737		console.log("compressionMethod: " + img.compressionMethod);
8738		console.log("filterMethod: " + img.filterMethod);
8739		console.log("interlaceMethod: " + img.interlaceMethod);
8740		console.log("imgData:");
8741		console.log(img.imgData);
8742		console.log("palette:");
8743		console.log(img.palette);
8744		console.log("colors: " + img.colors);
8745		console.log("colorSpace: " + img.colorSpace);
8746		console.log("pixelBitlength: " + img.pixelBitlength);
8747		console.log("hasAlphaChannel: " + img.hasAlphaChannel);
8748	};
8749
8750	jsPDFAPI.processPNG = function (imageData, imageIndex, alias, compression, dataAsBinaryString) {
8751		'use strict';
8752
8753		var colorSpace = this.color_spaces.DEVICE_RGB,
8754		    decode = this.decode.FLATE_DECODE,
8755		    bpc = 8,
8756		    img,
8757		    dp,
8758		    trns,
8759		    colors,
8760		    pal,
8761		    smask;
8762
8763		/*	if(this.isString(imageData)) {
8764  		}*/
8765
8766		if (this.isArrayBuffer(imageData)) imageData = new Uint8Array(imageData);
8767
8768		if (this.isArrayBufferView(imageData)) {
8769
8770			if (doesNotHavePngJS()) throw new Error("PNG support requires png.js and zlib.js");
8771
8772			img = new PNG(imageData);
8773			imageData = img.imgData;
8774			bpc = img.bits;
8775			colorSpace = img.colorSpace;
8776			colors = img.colors;
8777
8778			//logImg(img);
8779
8780			/*
8781    * colorType 6 - Each pixel is an R,G,B triple, followed by an alpha sample.
8782    *
8783    * colorType 4 - Each pixel is a grayscale sample, followed by an alpha sample.
8784    *
8785    * Extract alpha to create two separate images, using the alpha as a sMask
8786    */
8787			if ([4, 6].indexOf(img.colorType) !== -1) {
8788
8789				/*
8790     * processes 8 bit RGBA and grayscale + alpha images
8791     */
8792				if (img.bits === 8) {
8793
8794					var pixels = img.pixelBitlength == 32 ? new Uint32Array(img.decodePixels().buffer) : img.pixelBitlength == 16 ? new Uint16Array(img.decodePixels().buffer) : new Uint8Array(img.decodePixels().buffer),
8795					    len = pixels.length,
8796					    imgData = new Uint8Array(len * img.colors),
8797					    alphaData = new Uint8Array(len),
8798					    pDiff = img.pixelBitlength - img.bits,
8799					    i = 0,
8800					    n = 0,
8801					    pixel,
8802					    pbl;
8803
8804					for (; i < len; i++) {
8805						pixel = pixels[i];
8806						pbl = 0;
8807
8808						while (pbl < pDiff) {
8809
8810							imgData[n++] = pixel >>> pbl & 0xff;
8811							pbl = pbl + img.bits;
8812						}
8813
8814						alphaData[i] = pixel >>> pbl & 0xff;
8815					}
8816				}
8817
8818				/*
8819     * processes 16 bit RGBA and grayscale + alpha images
8820     */
8821				if (img.bits === 16) {
8822
8823					var pixels = new Uint32Array(img.decodePixels().buffer),
8824					    len = pixels.length,
8825					    imgData = new Uint8Array(len * (32 / img.pixelBitlength) * img.colors),
8826					    alphaData = new Uint8Array(len * (32 / img.pixelBitlength)),
8827					    hasColors = img.colors > 1,
8828					    i = 0,
8829					    n = 0,
8830					    a = 0,
8831					    pixel;
8832
8833					while (i < len) {
8834						pixel = pixels[i++];
8835
8836						imgData[n++] = pixel >>> 0 & 0xFF;
8837
8838						if (hasColors) {
8839							imgData[n++] = pixel >>> 16 & 0xFF;
8840
8841							pixel = pixels[i++];
8842							imgData[n++] = pixel >>> 0 & 0xFF;
8843						}
8844
8845						alphaData[a++] = pixel >>> 16 & 0xFF;
8846					}
8847
8848					bpc = 8;
8849				}
8850
8851				if (canCompress(compression)) {
8852
8853					imageData = compressBytes(imgData, img.width * img.colors, img.colors, compression);
8854					smask = compressBytes(alphaData, img.width, 1, compression);
8855				} else {
8856
8857					imageData = imgData;
8858					smask = alphaData;
8859					decode = null;
8860				}
8861			}
8862
8863			/*
8864    * Indexed png. Each pixel is a palette index.
8865    */
8866			if (img.colorType === 3) {
8867
8868				colorSpace = this.color_spaces.INDEXED;
8869				pal = img.palette;
8870
8871				if (img.transparency.indexed) {
8872
8873					var trans = img.transparency.indexed;
8874
8875					var total = 0,
8876					    i = 0,
8877					    len = trans.length;
8878
8879					for (; i < len; ++i) {
8880						total += trans[i];
8881					}total = total / 255;
8882
8883					/*
8884      * a single color is specified as 100% transparent (0),
8885      * so we set trns to use a /Mask with that index
8886      */
8887					if (total === len - 1 && trans.indexOf(0) !== -1) {
8888						trns = [trans.indexOf(0)];
8889
8890						/*
8891       * there's more than one colour within the palette that specifies
8892       * a transparency value less than 255, so we unroll the pixels to create an image sMask
8893       */
8894					} else if (total !== len) {
8895
8896						var pixels = img.decodePixels(),
8897						    alphaData = new Uint8Array(pixels.length),
8898						    i = 0,
8899						    len = pixels.length;
8900
8901						for (; i < len; i++) {
8902							alphaData[i] = trans[pixels[i]];
8903						}smask = compressBytes(alphaData, img.width, 1);
8904					}
8905				}
8906			}
8907
8908			var predictor = getPredictorFromCompression(compression);
8909
8910			if (decode === this.decode.FLATE_DECODE) dp = '/Predictor ' + predictor + ' /Colors ' + colors + ' /BitsPerComponent ' + bpc + ' /Columns ' + img.width;else
8911				//remove 'Predictor' as it applies to the type of png filter applied to its IDAT - we only apply with compression
8912				dp = '/Colors ' + colors + ' /BitsPerComponent ' + bpc + ' /Columns ' + img.width;
8913
8914			if (this.isArrayBuffer(imageData) || this.isArrayBufferView(imageData)) imageData = this.arrayBufferToBinaryString(imageData);
8915
8916			if (smask && this.isArrayBuffer(smask) || this.isArrayBufferView(smask)) smask = this.arrayBufferToBinaryString(smask);
8917
8918			return this.createImageInfo(imageData, img.width, img.height, colorSpace, bpc, decode, imageIndex, alias, dp, trns, pal, smask, predictor);
8919		}
8920
8921		throw new Error("Unsupported PNG image data, try using JPEG instead.");
8922	};
8923})(jsPDF.API);
8924
8925/**
8926 * jsPDF Autoprint Plugin
8927 *
8928 * Licensed under the MIT License.
8929 * http://opensource.org/licenses/mit-license
8930 */
8931
8932(function (jsPDFAPI) {
8933  'use strict';
8934
8935  jsPDFAPI.autoPrint = function () {
8936    'use strict';
8937
8938    var refAutoPrintTag;
8939
8940    this.internal.events.subscribe('postPutResources', function () {
8941      refAutoPrintTag = this.internal.newObject();
8942      this.internal.write("<< /S/Named /Type/Action /N/Print >>", "endobj");
8943    });
8944
8945    this.internal.events.subscribe("putCatalog", function () {
8946      this.internal.write("/OpenAction " + refAutoPrintTag + " 0" + " R");
8947    });
8948    return this;
8949  };
8950})(jsPDF.API);
8951
8952/** @preserve
8953 * jsPDF split_text_to_size plugin - MIT license.
8954 * Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
8955 *               2014 Diego Casorran, https://github.com/diegocr
8956 */
8957/**
8958 * 
8959 * ====================================================================
8960 */
8961
8962(function (API) {
8963	'use strict';
8964
8965	/**
8966 Returns an array of length matching length of the 'word' string, with each
8967 cell ocupied by the width of the char in that position.
8968 
8969 @function
8970 @param word {String}
8971 @param widths {Object}
8972 @param kerning {Object}
8973 @returns {Array}
8974 */
8975
8976	var getCharWidthsArray = API.getCharWidthsArray = function (text, options) {
8977
8978		if (!options) {
8979			options = {};
8980		}
8981
8982		var widths = options.widths ? options.widths : this.internal.getFont().metadata.Unicode.widths,
8983		    widthsFractionOf = widths.fof ? widths.fof : 1,
8984		    kerning = options.kerning ? options.kerning : this.internal.getFont().metadata.Unicode.kerning,
8985		    kerningFractionOf = kerning.fof ? kerning.fof : 1;
8986
8987		// console.log("widths, kergnings", widths, kerning)
8988
8989		var i,
8990		    l,
8991		    char_code,
8992		    prior_char_code = 0 // for kerning
8993		,
8994		    default_char_width = widths[0] || widthsFractionOf,
8995		    output = [];
8996
8997		for (i = 0, l = text.length; i < l; i++) {
8998			char_code = text.charCodeAt(i);
8999			output.push((widths[char_code] || default_char_width) / widthsFractionOf + (kerning[char_code] && kerning[char_code][prior_char_code] || 0) / kerningFractionOf);
9000			prior_char_code = char_code;
9001		}
9002
9003		return output;
9004	};
9005	var getArraySum = function getArraySum(array) {
9006		var i = array.length,
9007		    output = 0;
9008		while (i) {
9009			i--;
9010			output += array[i];
9011		}
9012		return output;
9013	};
9014	/**
9015 Returns a widths of string in a given font, if the font size is set as 1 point.
9016 
9017 In other words, this is "proportional" value. For 1 unit of font size, the length
9018 of the string will be that much.
9019 
9020 Multiply by font size to get actual width in *points*
9021 Then divide by 72 to get inches or divide by (72/25.6) to get 'mm' etc.
9022 
9023 @public
9024 @function
9025 @param
9026 @returns {Type}
9027 */
9028	var getStringUnitWidth = API.getStringUnitWidth = function (text, options) {
9029		return getArraySum(getCharWidthsArray.call(this, text, options));
9030	};
9031
9032	/**
9033 returns array of lines
9034 */
9035	var splitLongWord = function splitLongWord(word, widths_array, firstLineMaxLen, maxLen) {
9036		var answer = [];
9037
9038		// 1st, chop off the piece that can fit on the hanging line.
9039		var i = 0,
9040		    l = word.length,
9041		    workingLen = 0;
9042		while (i !== l && workingLen + widths_array[i] < firstLineMaxLen) {
9043			workingLen += widths_array[i];i++;
9044		}
9045		// this is first line.
9046		answer.push(word.slice(0, i));
9047
9048		// 2nd. Split the rest into maxLen pieces.
9049		var startOfLine = i;
9050		workingLen = 0;
9051		while (i !== l) {
9052			if (workingLen + widths_array[i] > maxLen) {
9053				answer.push(word.slice(startOfLine, i));
9054				workingLen = 0;
9055				startOfLine = i;
9056			}
9057			workingLen += widths_array[i];i++;
9058		}
9059		if (startOfLine !== i) {
9060			answer.push(word.slice(startOfLine, i));
9061		}
9062
9063		return answer;
9064	};
9065
9066	// Note, all sizing inputs for this function must be in "font measurement units"
9067	// By default, for PDF, it's "point".
9068	var splitParagraphIntoLines = function splitParagraphIntoLines(text, maxlen, options) {
9069		// at this time works only on Western scripts, ones with space char
9070		// separating the words. Feel free to expand.
9071
9072		if (!options) {
9073			options = {};
9074		}
9075
9076		var line = [],
9077		    lines = [line],
9078		    line_length = options.textIndent || 0,
9079		    separator_length = 0,
9080		    current_word_length = 0,
9081		    word,
9082		    widths_array,
9083		    words = text.split(' '),
9084		    spaceCharWidth = getCharWidthsArray(' ', options)[0],
9085		    i,
9086		    l,
9087		    tmp,
9088		    lineIndent;
9089
9090		if (options.lineIndent === -1) {
9091			lineIndent = words[0].length + 2;
9092		} else {
9093			lineIndent = options.lineIndent || 0;
9094		}
9095		if (lineIndent) {
9096			var pad = Array(lineIndent).join(" "),
9097			    wrds = [];
9098			words.map(function (wrd) {
9099				wrd = wrd.split(/\s*\n/);
9100				if (wrd.length > 1) {
9101					wrds = wrds.concat(wrd.map(function (wrd, idx) {
9102						return (idx && wrd.length ? "\n" : "") + wrd;
9103					}));
9104				} else {
9105					wrds.push(wrd[0]);
9106				}
9107			});
9108			words = wrds;
9109			lineIndent = getStringUnitWidth(pad, options);
9110		}
9111
9112		for (i = 0, l = words.length; i < l; i++) {
9113			var force = 0;
9114
9115			word = words[i];
9116			if (lineIndent && word[0] == "\n") {
9117				word = word.substr(1);
9118				force = 1;
9119			}
9120			widths_array = getCharWidthsArray(word, options);
9121			current_word_length = getArraySum(widths_array);
9122
9123			if (line_length + separator_length + current_word_length > maxlen || force) {
9124				if (current_word_length > maxlen) {
9125					// this happens when you have space-less long URLs for example.
9126					// we just chop these to size. We do NOT insert hiphens
9127					tmp = splitLongWord(word, widths_array, maxlen - (line_length + separator_length), maxlen);
9128					// first line we add to existing line object
9129					line.push(tmp.shift()); // it's ok to have extra space indicator there
9130					// last line we make into new line object
9131					line = [tmp.pop()];
9132					// lines in the middle we apped to lines object as whole lines
9133					while (tmp.length) {
9134						lines.push([tmp.shift()]); // single fragment occupies whole line
9135					}
9136					current_word_length = getArraySum(widths_array.slice(word.length - line[0].length));
9137				} else {
9138					// just put it on a new line
9139					line = [word];
9140				}
9141
9142				// now we attach new line to lines
9143				lines.push(line);
9144				line_length = current_word_length + lineIndent;
9145				separator_length = spaceCharWidth;
9146			} else {
9147				line.push(word);
9148
9149				line_length += separator_length + current_word_length;
9150				separator_length = spaceCharWidth;
9151			}
9152		}
9153
9154		if (lineIndent) {
9155			var postProcess = function postProcess(ln, idx) {
9156				return (idx ? pad : '') + ln.join(" ");
9157			};
9158		} else {
9159			var postProcess = function postProcess(ln) {
9160				return ln.join(" ");
9161			};
9162		}
9163
9164		return lines.map(postProcess);
9165	};
9166
9167	/**
9168 Splits a given string into an array of strings. Uses 'size' value
9169 (in measurement units declared as default for the jsPDF instance)
9170 and the font's "widths" and "Kerning" tables, where available, to
9171 determine display length of a given string for a given font.
9172 
9173 We use character's 100% of unit size (height) as width when Width
9174 table or other default width is not available.
9175 
9176 @public
9177 @function
9178 @param text {String} Unencoded, regular JavaScript (Unicode, UTF-16 / UCS-2) string.
9179 @param size {Number} Nominal number, measured in units default to this instance of jsPDF.
9180 @param options {Object} Optional flags needed for chopper to do the right thing.
9181 @returns {Array} with strings chopped to size.
9182 */
9183	API.splitTextToSize = function (text, maxlen, options) {
9184		'use strict';
9185
9186		if (!options) {
9187			options = {};
9188		}
9189
9190		var fsize = options.fontSize || this.internal.getFontSize(),
9191		    newOptions = function (options) {
9192			var widths = { 0: 1 },
9193			    kerning = {};
9194
9195			if (!options.widths || !options.kerning) {
9196				var f = this.internal.getFont(options.fontName, options.fontStyle),
9197				    encoding = 'Unicode';
9198				// NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE
9199				// Actual JavaScript-native String's 16bit char codes used.
9200				// no multi-byte logic here
9201
9202				if (f.metadata[encoding]) {
9203					return {
9204						widths: f.metadata[encoding].widths || widths,
9205						kerning: f.metadata[encoding].kerning || kerning
9206					};
9207				}
9208			} else {
9209				return {
9210					widths: options.widths,
9211					kerning: options.kerning
9212				};
9213			}
9214
9215			// then use default values
9216			return {
9217				widths: widths,
9218				kerning: kerning
9219			};
9220		}.call(this, options);
9221
9222		// first we split on end-of-line chars
9223		var paragraphs;
9224		if (Array.isArray(text)) {
9225			paragraphs = text;
9226		} else {
9227			paragraphs = text.split(/\r?\n/);
9228		}
9229
9230		// now we convert size (max length of line) into "font size units"
9231		// at present time, the "font size unit" is always 'point'
9232		// 'proportional' means, "in proportion to font size"
9233		var fontUnit_maxLen = 1.0 * this.internal.scaleFactor * maxlen / fsize;
9234		// at this time, fsize is always in "points" regardless of the default measurement unit of the doc.
9235		// this may change in the future?
9236		// until then, proportional_maxlen is likely to be in 'points'
9237
9238		// If first line is to be indented (shorter or longer) than maxLen
9239		// we indicate that by using CSS-style "text-indent" option.
9240		// here it's in font units too (which is likely 'points')
9241		// it can be negative (which makes the first line longer than maxLen)
9242		newOptions.textIndent = options.textIndent ? options.textIndent * 1.0 * this.internal.scaleFactor / fsize : 0;
9243		newOptions.lineIndent = options.lineIndent;
9244
9245		var i,
9246		    l,
9247		    output = [];
9248		for (i = 0, l = paragraphs.length; i < l; i++) {
9249			output = output.concat(splitParagraphIntoLines(paragraphs[i], fontUnit_maxLen, newOptions));
9250		}
9251
9252		return output;
9253	};
9254})(jsPDF.API);
9255
9256/** @preserve 
9257jsPDF standard_fonts_metrics plugin
9258Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
9259MIT license.
9260*/
9261/**
9262 * 
9263 * ====================================================================
9264 */
9265
9266(function (API) {
9267	'use strict';
9268
9269	/*
9270 # reference (Python) versions of 'compress' and 'uncompress'
9271 # only 'uncompress' function is featured lower as JavaScript
9272 # if you want to unit test "roundtrip", just transcribe the reference
9273 # 'compress' function from Python into JavaScript
9274 
9275 def compress(data):
9276 
9277 	keys =   '0123456789abcdef'
9278 	values = 'klmnopqrstuvwxyz'
9279 	mapping = dict(zip(keys, values))
9280 	vals = []
9281 	for key in data.keys():
9282 		value = data[key]
9283 		try:
9284 			keystring = hex(key)[2:]
9285 			keystring = keystring[:-1] + mapping[keystring[-1:]]
9286 		except:
9287 			keystring = key.join(["'","'"])
9288 			#print('Keystring is %s' % keystring)
9289 
9290 		try:
9291 			if value < 0:
9292 				valuestring = hex(value)[3:]
9293 				numberprefix = '-'
9294 			else:
9295 				valuestring = hex(value)[2:]
9296 				numberprefix = ''
9297 			valuestring = numberprefix + valuestring[:-1] + mapping[valuestring[-1:]]
9298 		except:
9299 			if type(value) == dict:
9300 				valuestring = compress(value)
9301 			else:
9302 				raise Exception("Don't know what to do with value type %s" % type(value))
9303 
9304 		vals.append(keystring+valuestring)
9305 	
9306 	return '{' + ''.join(vals) + '}'
9307 
9308 def uncompress(data):
9309 
9310 	decoded = '0123456789abcdef'
9311 	encoded = 'klmnopqrstuvwxyz'
9312 	mapping = dict(zip(encoded, decoded))
9313 
9314 	sign = +1
9315 	stringmode = False
9316 	stringparts = []
9317 
9318 	output = {}
9319 
9320 	activeobject = output
9321 	parentchain = []
9322 
9323 	keyparts = ''
9324 	valueparts = ''
9325 
9326 	key = None
9327 
9328 	ending = set(encoded)
9329 
9330 	i = 1
9331 	l = len(data) - 1 # stripping starting, ending {}
9332 	while i != l: # stripping {}
9333 		# -, {, }, ' are special.
9334 
9335 		ch = data[i]
9336 		i += 1
9337 
9338 		if ch == "'":
9339 			if stringmode:
9340 				# end of string mode
9341 				stringmode = False
9342 				key = ''.join(stringparts)
9343 			else:
9344 				# start of string mode
9345 				stringmode = True
9346 				stringparts = []
9347 		elif stringmode == True:
9348 			#print("Adding %s to stringpart" % ch)
9349 			stringparts.append(ch)
9350 
9351 		elif ch == '{':
9352 			# start of object
9353 			parentchain.append( [activeobject, key] )
9354 			activeobject = {}
9355 			key = None
9356 			#DEBUG = True
9357 		elif ch == '}':
9358 			# end of object
9359 			parent, key = parentchain.pop()
9360 			parent[key] = activeobject
9361 			key = None
9362 			activeobject = parent
9363 			#DEBUG = False
9364 
9365 		elif ch == '-':
9366 			sign = -1
9367 		else:
9368 			# must be number
9369 			if key == None:
9370 				#debug("In Key. It is '%s', ch is '%s'" % (keyparts, ch))
9371 				if ch in ending:
9372 					#debug("End of key")
9373 					keyparts += mapping[ch]
9374 					key = int(keyparts, 16) * sign
9375 					sign = +1
9376 					keyparts = ''
9377 				else:
9378 					keyparts += ch
9379 			else:
9380 				#debug("In value. It is '%s', ch is '%s'" % (valueparts, ch))
9381 				if ch in ending:
9382 					#debug("End of value")
9383 					valueparts += mapping[ch]
9384 					activeobject[key] = int(valueparts, 16) * sign
9385 					sign = +1
9386 					key = None
9387 					valueparts = ''
9388 				else:
9389 					valueparts += ch
9390 
9391 			#debug(activeobject)
9392 
9393 	return output
9394 
9395 */
9396
9397	/**
9398 Uncompresses data compressed into custom, base16-like format. 
9399 @public
9400 @function
9401 @param
9402 @returns {Type}
9403 */
9404
9405	var uncompress = function uncompress(data) {
9406
9407		var decoded = '0123456789abcdef',
9408		    encoded = 'klmnopqrstuvwxyz',
9409		    mapping = {};
9410
9411		for (var i = 0; i < encoded.length; i++) {
9412			mapping[encoded[i]] = decoded[i];
9413		}
9414
9415		var undef,
9416		    output = {},
9417		    sign = 1,
9418		    stringparts // undef. will be [] in string mode
9419
9420		,
9421		    activeobject = output,
9422		    parentchain = [],
9423		    parent_key_pair,
9424		    keyparts = '',
9425		    valueparts = '',
9426		    key // undef. will be Truthy when Key is resolved.
9427		,
9428		    datalen = data.length - 1 // stripping ending }
9429		,
9430		    ch;
9431
9432		i = 1; // stripping starting {
9433
9434		while (i != datalen) {
9435			// - { } ' are special.
9436
9437			ch = data[i];
9438			i += 1;
9439
9440			if (ch == "'") {
9441				if (stringparts) {
9442					// end of string mode
9443					key = stringparts.join('');
9444					stringparts = undef;
9445				} else {
9446					// start of string mode
9447					stringparts = [];
9448				}
9449			} else if (stringparts) {
9450				stringparts.push(ch);
9451			} else if (ch == '{') {
9452				// start of object
9453				parentchain.push([activeobject, key]);
9454				activeobject = {};
9455				key = undef;
9456			} else if (ch == '}') {
9457				// end of object
9458				parent_key_pair = parentchain.pop();
9459				parent_key_pair[0][parent_key_pair[1]] = activeobject;
9460				key = undef;
9461				activeobject = parent_key_pair[0];
9462			} else if (ch == '-') {
9463				sign = -1;
9464			} else {
9465				// must be number
9466				if (key === undef) {
9467					if (mapping.hasOwnProperty(ch)) {
9468						keyparts += mapping[ch];
9469						key = parseInt(keyparts, 16) * sign;
9470						sign = +1;
9471						keyparts = '';
9472					} else {
9473						keyparts += ch;
9474					}
9475				} else {
9476					if (mapping.hasOwnProperty(ch)) {
9477						valueparts += mapping[ch];
9478						activeobject[key] = parseInt(valueparts, 16) * sign;
9479						sign = +1;
9480						key = undef;
9481						valueparts = '';
9482					} else {
9483						valueparts += ch;
9484					}
9485				}
9486			}
9487		} // end while
9488
9489		return output;
9490	};
9491
9492	// encoding = 'Unicode' 
9493	// NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE. NO clever BOM behavior
9494	// Actual 16bit char codes used.
9495	// no multi-byte logic here
9496
9497	// Unicode characters to WinAnsiEncoding:
9498	// {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}
9499	// as you can see, all Unicode chars are outside of 0-255 range. No char code conflicts.
9500	// this means that you can give Win cp1252 encoded strings to jsPDF for rendering directly
9501	// as well as give strings with some (supported by these fonts) Unicode characters and 
9502	// these will be mapped to win cp1252 
9503	// for example, you can send char code (cp1252) 0x80 or (unicode) 0x20AC, getting "Euro" glyph displayed in both cases.
9504
9505	var encodingBlock = {
9506		'codePages': ['WinAnsiEncoding'],
9507		'WinAnsiEncoding': uncompress("{19m8n201n9q201o9r201s9l201t9m201u8m201w9n201x9o201y8o202k8q202l8r202m9p202q8p20aw8k203k8t203t8v203u9v2cq8s212m9t15m8w15n9w2dw9s16k8u16l9u17s9z17x8y17y9y}")
9508	},
9509	    encodings = { 'Unicode': {
9510			'Courier': encodingBlock,
9511			'Courier-Bold': encodingBlock,
9512			'Courier-BoldOblique': encodingBlock,
9513			'Courier-Oblique': encodingBlock,
9514			'Helvetica': encodingBlock,
9515			'Helvetica-Bold': encodingBlock,
9516			'Helvetica-BoldOblique': encodingBlock,
9517			'Helvetica-Oblique': encodingBlock,
9518			'Times-Roman': encodingBlock,
9519			'Times-Bold': encodingBlock,
9520			'Times-BoldItalic': encodingBlock,
9521			'Times-Italic': encodingBlock
9522			//	, 'Symbol'
9523			//	, 'ZapfDingbats'
9524		} }
9525	/** 
9526 Resources:
9527 Font metrics data is reprocessed derivative of contents of
9528 "Font Metrics for PDF Core 14 Fonts" package, which exhibits the following copyright and license:
9529 
9530 Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
9531 
9532 This file and the 14 PostScript(R) AFM files it accompanies may be used,
9533 copied, and distributed for any purpose and without charge, with or without
9534 modification, provided that all copyright notices are retained; that the AFM
9535 files are not distributed without this file; that all modifications to this
9536 file or any of the AFM files are prominently noted in the modified file(s);
9537 and that this paragraph is not modified. Adobe Systems has no responsibility
9538 or obligation to support the use of the AFM files.
9539 
9540 */
9541	,
9542	    fontMetrics = { 'Unicode': {
9543			// all sizing numbers are n/fontMetricsFractionOf = one font size unit
9544			// this means that if fontMetricsFractionOf = 1000, and letter A's width is 476, it's
9545			// width is 476/1000 or 47.6% of its height (regardless of font size)
9546			// At this time this value applies to "widths" and "kerning" numbers.
9547
9548			// char code 0 represents "default" (average) width - use it for chars missing in this table.
9549			// key 'fof' represents the "fontMetricsFractionOf" value
9550
9551			'Courier-Oblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
9552			'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}}}"),
9553			'Helvetica-Bold': uncompress("{'widths'{k3s2q4scx1w201n3r201o6o201s1w201t1w201u1w201w3m201x3m201y3m2k1w2l2l202m2n2n3r2o3r2p5t202q6o2r1s2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v2l3w3u3x3u3y3u3z3x4k6l4l4s4m4s4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3r4v4s4w3x4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v2l5w1w5x2l5y3u5z3r6k2l6l3r6m3x6n3r6o3x6p3r6q2l6r3x6s3x6t1w6u1w6v3r6w1w6x5t6y3x6z3x7k3x7l3x7m2r7n3r7o2l7p3x7q3r7r4y7s3r7t3r7u3m7v2r7w1w7x2r7y3u202l3rcl4sal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3xbq3rbr1wbs2lbu2obv3rbz3xck4s202k3rcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw1w2m2zcy1wcz1wdl4sdm4y
9553dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3res3ret3reu3rev3rew1wex1wey1wez1wfl3xfm3xfn3xfo3xfp3xfq3xfr3ufs3xft3xfu3xfv3xfw3xfz3r203k6o212m6o2dw2l2cq2l3t3r3u2l17s4m19m3r}'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}}}"),
9554			'Courier': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
9555			'Courier-BoldOblique': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
9556			'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}}}")
9557			//, 'Symbol': uncompress("{'widths'{k3uaw4r19m3m2k1t2l2l202m2y2n3m2p5n202q6o3k3m2s2l2t2l2v3r2w1t3m3m2y1t2z1wbk2sbl3r'fof'6o3n3m3o3m3p3m3q3m3r3m3s3m3t3m3u1w3v1w3w3r3x3r3y3r3z2wbp3t3l3m5v2l5x2l5z3m2q4yfr3r7v3k7w1o7x3k}'kerning'{'fof'-6o}}")
9558			, 'Helvetica': uncompress("{'widths'{k3p2q4mcx1w201n3r201o6o201s1q201t1q201u1q201w2l201x2l201y2l2k1w2l1w202m2n2n3r2o3r2p5t202q6o2r1n2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v1w3w3u3x3u3y3u3z3r4k6p4l4m4m4m4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3m4v4m4w3r4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v1w5w1w5x1w5y2z5z3r6k2l6l3r6m3r6n3m6o3r6p3r6q1w6r3r6s3r6t1q6u1q6v3m6w1q6x5n6y3r6z3r7k3r7l3r7m2l7n3m7o1w7p3r7q3m7r4s7s3m7t3m7u3m7v2l7w1u7x2l7y3u202l3rcl4mal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3rbr1wbs2lbu2obv3rbz3xck4m202k3rcm4mcn4mco4mcp4mcq6ocr4scs4mct4mcu4mcv4mcw1w2m2ncy1wcz1wdl4sdm4y
9558dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3mes3ret3reu3rev3rew1wex1wey1wez1wfl3rfm3rfn3rfo3rfp3rfq3rfr3ufs3xft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3r3u1w17s4m19m3r}'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}}}"),
9559			'Helvetica-BoldOblique': uncompress("{'widths'{k3s2q4scx1w201n3r201o6o201s1w201t1w201u1w201w3m201x3m201y3m2k1w2l2l202m2n2n3r2o3r2p5t202q6o2r1s2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v2l3w3u3x3u3y3u3z3x4k6l4l4s4m4s4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3r4v4s4w3x4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v2l5w1w5x2l5y3u5z3r6k2l6l3r6m3x6n3r6o3x6p3r6q2l6r3x6s3x6t1w6u1w6v3r6w1w6x5t6y3x6z3x7k3x7l3x7m2r7n3r7o2l7p3x7q3r7r4y7s3r7t3r7u3m7v2r7w1w7x2r7y3u202l3rcl4sal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3xbq3rbr1wbs2lbu2obv3rbz3xck4s202k3rcm4scn4sco4scp4scq6ocr4scs4mct4mcu4mcv4mcw1w2m2zcy1wcz1wdl4sdm4y
9559dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3res3ret3reu3rev3rew1wex1wey1wez1wfl3xfm3xfn3xfo3xfp3xfq3xfr3ufs3xft3xfu3xfv3xfw3xfz3r203k6o212m6o2dw2l2cq2l3t3r3u2l17s4m19m3r}'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}}}")
9560			//, 'ZapfDingbats': uncompress("{'widths'{k4u2k1w'fof'6o}'kerning'{'fof'-6o}}")
9561			, 'Courier-Bold': uncompress("{'widths'{k3w'fof'6o}'kerning'{'fof'-6o}}"),
9562			'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}
9562fv{17su5tu5qs}fw{17su5tu5qs}}}"),
9563			'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}}}"),
9564			'Helvetica-Oblique': uncompress("{'widths'{k3p2q4mcx1w201n3r201o6o201s1q201t1q201u1q201w2l201x2l201y2l2k1w2l1w202m2n2n3r2o3r2p5t202q6o2r1n2s2l2t2l2u2r2v3u2w1w2x2l2y1w2z1w3k3r3l3r3m3r3n3r3o3r3p3r3q3r3r3r3s3r203t2l203u2l3v1w3w3u3x3u3y3u3z3r4k6p4l4m4m4m4n4s4o4s4p4m4q3x4r4y4s4s4t1w4u3m4v4m4w3r4x5n4y4s4z4y5k4m5l4y5m4s5n4m5o3x5p4s5q4m5r5y5s4m5t4m5u3x5v1w5w1w5x1w5y2z5z3r6k2l6l3r6m3r6n3m6o3r6p3r6q1w6r3r6s3r6t1q6u1q6v3m6w1q6x5n6y3r6z3r7k3r7l3r7m2l7n3m7o1w7p3r7q3m7r4s7s3m7t3m7u3m7v2l7w1u7x2l7y3u202l3rcl4mal2lam3ran3rao3rap3rar3ras2lat4tau2pav3raw3uay4taz2lbk2sbl3u'fof'6obo2lbp3rbr1wbs2lbu2obv3rbz3xck4m202k3rcm4mcn4mco4mcp4mcq6ocr4scs4mct4mcu4mcv4mcw1w2m2ncy1wcz1wdl4sdm4y
9564dn4ydo4ydp4ydq4yds4ydt4sdu4sdv4sdw4sdz3xek3rel3rem3ren3reo3rep3req5ter3mes3ret3reu3rev3rew1wex1wey1wez1wfl3rfm3rfn3rfo3rfp3rfq3rfr3ufs3xft3rfu3rfv3rfw3rfz3m203k6o212m6o2dw2l2cq2l3t3r3u1w17s4m19m3r}'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}}}")
9565		} };
9566
9567	/*
9568 This event handler is fired when a new jsPDF object is initialized
9569 This event handler appends metrics data to standard fonts within
9570 that jsPDF instance. The metrics are mapped over Unicode character
9571 codes, NOT CIDs or other codes matching the StandardEncoding table of the
9572 standard PDF fonts.
9573 Future:
9574 Also included is the encoding maping table, converting Unicode (UCS-2, UTF-16)
9575 char codes to StandardEncoding character codes. The encoding table is to be used
9576 somewhere around "pdfEscape" call.
9577 */
9578
9579	API.events.push(['addFont', function (font) {
9580		var metrics,
9581		    unicode_section,
9582		    encoding = 'Unicode',
9583		    encodingBlock;
9584
9585		metrics = fontMetrics[encoding][font.PostScriptName];
9586		if (metrics) {
9587			if (font.metadata[encoding]) {
9588				unicode_section = font.metadata[encoding];
9589			} else {
9590				unicode_section = font.metadata[encoding] = {};
9591			}
9592
9593			unicode_section.widths = metrics.widths;
9594			unicode_section.kerning = metrics.kerning;
9595		}
9596
9597		encodingBlock = encodings[encoding][font.PostScriptName];
9598		if (encodingBlock) {
9599			if (font.metadata[encoding]) {
9600				unicode_section = font.metadata[encoding];
9601			} else {
9602				unicode_section = font.metadata[encoding] = {};
9603			}
9604
9605			unicode_section.encoding = encodingBlock;
9606			if (encodingBlock.codePages && encodingBlock.codePages.length) {
9607				font.encoding = encodingBlock.codePages[0];
9608			}
9609		}
9610	}]); // end of adding event handler
9611})(jsPDF.API);
9612
9613/** @preserve
9614jsPDF SVG plugin
9615Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
9616*/
9617/**
9618 * 
9619 * ====================================================================
9620 */
9621
9622(function (jsPDFAPI) {
9623	'use strict';
9624
9625	/**
9626 Parses SVG XML and converts only some of the SVG elements into
9627 PDF elements.
9628 
9629 Supports:
9630  paths
9631 
9632 @public
9633 @function
9634 @param
9635 @returns {Type}
9636 */
9637
9638	jsPDFAPI.addSVG = function (svgtext, x, y, w, h) {
9639		// 'this' is _jsPDF object returned when jsPDF is inited (new jsPDF())
9640
9641		var undef;
9642
9643		if (x === undef || y === undef) {
9644			throw new Error("addSVG needs values for 'x' and 'y'");
9645		}
9646
9647		function InjectCSS(cssbody, document) {
9648			var styletag = document.createElement('style');
9649			styletag.type = 'text/css';
9650			if (styletag.styleSheet) {
9651				// ie
9652				styletag.styleSheet.cssText = cssbody;
9653			} else {
9654				// others
9655				styletag.appendChild(document.createTextNode(cssbody));
9656			}
9657			document.getElementsByTagName("head")[0].appendChild(styletag);
9658		}
9659
9660		function createWorkerNode(document) {
9661
9662			var frameID = 'childframe' // Date.now().toString() + '_' + (Math.random() * 100).toString()
9663			,
9664			    frame = document.createElement('iframe');
9665
9666			InjectCSS('.jsPDF_sillysvg_iframe {display:none;position:absolute;}', document);
9667
9668			frame.name = frameID;
9669			frame.setAttribute("width", 0);
9670			frame.setAttribute("height", 0);
9671			frame.setAttribute("frameborder", "0");
9672			frame.setAttribute("scrolling", "no");
9673			frame.setAttribute("seamless", "seamless");
9674			frame.setAttribute("class", "jsPDF_sillysvg_iframe");
9675
9676			document.body.appendChild(frame);
9677
9678			return frame;
9679		}
9680
9681		function attachSVGToWorkerNode(svgtext, frame) {
9682			var framedoc = (frame.contentWindow || frame.contentDocument).document;
9683			framedoc.write(svgtext);
9684			framedoc.close();
9685			return framedoc.getElementsByTagName('svg')[0];
9686		}
9687
9688		function convertPathToPDFLinesArgs(path) {
9689			'use strict';
9690			// we will use 'lines' method call. it needs:
9691			// - starting coordinate pair
9692			// - array of arrays of vector shifts (2-len for line, 6 len for bezier)
9693			// - scale array [horizontal, vertical] ratios
9694			// - style (stroke, fill, both)
9695
9696			var x = parseFloat(path[1]),
9697			    y = parseFloat(path[2]),
9698			    vectors = [],
9699			    position = 3,
9700			    len = path.length;
9701
9702			while (position < len) {
9703				if (path[position] === 'c') {
9704					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])]);
9705					position += 7;
9706				} else if (path[position] === 'l') {
9707					vectors.push([parseFloat(path[position + 1]), parseFloat(path[position + 2])]);
9708					position += 3;
9709				} else {
9710					position += 1;
9711				}
9712			}
9713			return [x, y, vectors];
9714		}
9715
9716		var workernode = createWorkerNode(document),
9717		    svgnode = attachSVGToWorkerNode(svgtext, workernode),
9718		    scale = [1, 1],
9719		    svgw = parseFloat(svgnode.getAttribute('width')),
9720		    svgh = parseFloat(svgnode.getAttribute('height'));
9721
9722		if (svgw && svgh) {
9723			// setting both w and h makes image stretch to size.
9724			// this may distort the image, but fits your demanded size
9725			if (w && h) {
9726				scale = [w / svgw, h / svgh];
9727			}
9728			// if only one is set, that value is set as max and SVG
9729			// is scaled proportionately.
9730			else if (w) {
9731					scale = [w / svgw, w / svgw];
9732				} else if (h) {
9733					scale = [h / svgh, h / svgh];
9734				}
9735		}
9736
9737		var i,
9738		    l,
9739		    tmp,
9740		    linesargs,
9741		    items = svgnode.childNodes;
9742		for (i = 0, l = items.length; i < l; i++) {
9743			tmp = items[i];
9744			if (tmp.tagName && tmp.tagName.toUpperCase() === 'PATH') {
9745				linesargs = convertPathToPDFLinesArgs(tmp.getAttribute("d").split(' '));
9746				// path start x coordinate
9747				linesargs[0] = linesargs[0] * scale[0] + x; // where x is upper left X of image
9748				// path start y coordinate
9749				linesargs[1] = linesargs[1] * scale[1] + y; // where y is upper left Y of image
9750				// the rest of lines are vectors. these will adjust with scale value auto.
9751				this.lines.call(this, linesargs[2] // lines
9752				, linesargs[0] // starting x
9753				, linesargs[1] // starting y
9754				, scale);
9755			}
9756		}
9757
9758		// clean up
9759		// workernode.parentNode.removeChild(workernode)
9760
9761		return this;
9762	};
9763})(jsPDF.API);
9764
9765/** ==================================================================== 
9766 * jsPDF total_pages plugin
9767 * Copyright (c) 2013 Eduardo Menezes de Morais, [email protected]
9768 * 
9769 * 
9770 * ====================================================================
9771 */
9772
9773(function (jsPDFAPI) {
9774  'use strict';
9775
9776  jsPDFAPI.putTotalPages = function (pageExpression) {
9777    'use strict';
9778
9779    var replaceExpression = new RegExp(pageExpression, 'g');
9780    for (var n = 1; n <= this.internal.getNumberOfPages(); n++) {
9781      for (var i = 0; i < this.internal.pages[n].length; i++) {
9782        this.internal.pages[n][i] = this.internal.pages[n][i].replace(replaceExpression, this.internal.getNumberOfPages());
9783      }
9784    }
9785    return this;
9786  };
9787})(jsPDF.API);
9788
9789/** ==================================================================== 
9790 * jsPDF XMP metadata plugin
9791 * Copyright (c) 2016 Jussi Utunen, [email protected]
9792 * 
9793 * 
9794 * ====================================================================
9795 */
9796
9797/*global jsPDF */
9798
9799/**
9800* Adds XMP formatted metadata to PDF
9801*
9802* @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.
9803* @param {String} namespaceuri Sets the namespace URI for the metadata. Last character should be slash or hash.
9804* @function
9805* @returns {jsPDF}
9806* @methodOf jsPDF#
9807* @name addMetadata
9808*/
9809
9810(function (jsPDFAPI) {
9811    'use strict';
9812
9813    var xmpmetadata = "";
9814    var xmpnamespaceuri = "";
9815    var metadata_object_number = "";
9816
9817    jsPDFAPI.addMetadata = function (metadata, namespaceuri) {
9818        xmpnamespaceuri = namespaceuri || "http://jspdf.default.namespaceuri/"; //The namespace URI for an XMP name shall not be empty
9819        xmpmetadata = metadata;
9820        this.internal.events.subscribe('postPutResources', function () {
9821            if (!xmpmetadata) {
9822                metadata_object_number = "";
9823            } else {
9824                var xmpmeta_beginning = '<x:xmpmeta xmlns:x="adobe:ns:meta/">';
9825                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>';
9826                var rdf_ending = '</jspdf:metadata></rdf:Description></rdf:RDF>';
9827                var xmpmeta_ending = '</x:xmpmeta>';
9828                var utf8_xmpmeta_beginning = unescape(encodeURIComponent(xmpmeta_beginning));
9829                var utf8_rdf_beginning = unescape(encodeURIComponent(rdf_beginning));
9830                var utf8_metadata = unescape(encodeURIComponent(xmpmetadata));
9831                var utf8_rdf_ending = unescape(encodeURIComponent(rdf_ending));
9832                var utf8_xmpmeta_ending = unescape(encodeURIComponent(xmpmeta_ending));
9833
9834                var total_len = utf8_rdf_beginning.length + utf8_metadata.length + utf8_rdf_ending.length + utf8_xmpmeta_beginning.length + utf8_xmpmeta_ending.length;
9835
9836                metadata_object_number = this.internal.newObject();
vendor: 7,132 bytes, lines 9837-10065
9837                this.internal.write('<< /Type /Metadata /Subtype /XML /Length ' + total_len + ' >>');
9838                this.internal.write('stream');
9839                this.internal.write(utf8_xmpmeta_beginning + utf8_rdf_beginning + utf8_metadata + utf8_rdf_ending + utf8_xmpmeta_ending);
9840                this.internal.write('endstream');
9841                this.internal.write('endobj');
9842            }
9843        });
9844        this.internal.events.subscribe('putCatalog', function () {
9845            if (metadata_object_number) {
9846                this.internal.write('/Metadata ' + metadata_object_number + ' 0 R');
9847            }
9848        });
9849        return this;
9850    };
9851})(jsPDF.API);
9852
9853/* Blob.js
9854 * A Blob implementation.
9855 * 2014-07-24
9856 *
9857 * By Eli Grey, http://eligrey.com
9858 * By Devin Samarin, https://github.com/dsamarin
9859 * License: X11/MIT
9860 *   See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
9861 */
9862
9863/*global self, unescape */
9864/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
9865  plusplus: true */
9866
9867/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */
9868
9869(function (view) {
9870	"use strict";
9871
9872	view.URL = view.URL || view.webkitURL;
9873
9874	if (view.Blob && view.URL) {
9875		try {
9876			new Blob;
9877			return;
9878		} catch (e) {}
9879	}
9880
9881	// Internally we use a BlobBuilder implementation to base Blob off of
9882	// in order to support older browsers that only have BlobBuilder
9883	var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) {
9884		var
9885			  get_class = function(object) {
9886				return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
9887			}
9888			, FakeBlobBuilder = function BlobBuilder() {
9889				this.data = [];
9890			}
9891			, FakeBlob = function Blob(data, type, encoding) {
9892				this.data = data;
9893				this.size = data.length;
9894				this.type = type;
9895				this.encoding = encoding;
9896			}
9897			, FBB_proto = FakeBlobBuilder.prototype
9898			, FB_proto = FakeBlob.prototype
9899			, FileReaderSync = view.FileReaderSync
9900			, FileException = function(type) {
9901				this.code = this[this.name = type];
9902			}
9903			, file_ex_codes = (
9904				  "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
9905				+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
9906			).split(" ")
9907			, file_ex_code = file_ex_codes.length
9908			, real_URL = view.URL || view.webkitURL || view
9909			, real_create_object_URL = real_URL.createObjectURL
9910			, real_revoke_object_URL = real_URL.revokeObjectURL
9911			, URL = real_URL
9912			, btoa = view.btoa
9913			, atob = view.atob
9914
9915			, ArrayBuffer = view.ArrayBuffer
9916			, Uint8Array = view.Uint8Array
9917
9918			, origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/;
9919		FakeBlob.fake = FB_proto.fake = true;
9920		while (file_ex_code--) {
9921			FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
9922		}
9923		// Polyfill URL
9924		if (!real_URL.createObjectURL) {
9925			URL = view.URL = function(uri) {
9926				var
9927					  uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
9928					, uri_origin;
9929				uri_info.href = uri;
9930				if (!("origin" in uri_info)) {
9931					if (uri_info.protocol.toLowerCase() === "data:") {
9932						uri_info.origin = null;
9933					} else {
9934						uri_origin = uri.match(origin);
9935						uri_info.origin = uri_origin && uri_origin[1];
9936					}
9937				}
9938				return uri_info;
9939			};
9940		}
9941		URL.createObjectURL = function(blob) {
9942			var
9943				  type = blob.type
9944				, data_URI_header;
9945			if (type === null) {
9946				type = "application/octet-stream";
9947			}
9948			if (blob instanceof FakeBlob) {
9949				data_URI_header = "data:" + type;
9950				if (blob.encoding === "base64") {
9951					return data_URI_header + ";base64," + blob.data;
9952				} else if (blob.encoding === "URI") {
9953					return data_URI_header + "," + decodeURIComponent(blob.data);
9954				} if (btoa) {
9955					return data_URI_header + ";base64," + btoa(blob.data);
9956				} else {
9957					return data_URI_header + "," + encodeURIComponent(blob.data);
9958				}
9959			} else if (real_create_object_URL) {
9960				return real_create_object_URL.call(real_URL, blob);
9961			}
9962		};
9963		URL.revokeObjectURL = function(object_URL) {
9964			if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
9965				real_revoke_object_URL.call(real_URL, object_URL);
9966			}
9967		};
9968		FBB_proto.append = function(data/*, endings*/) {
9969			var bb = this.data;
9970			// decode data to a binary string
9971			if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
9972				var
9973					  str = ""
9974					, buf = new Uint8Array(data)
9975					, i = 0
9976					, buf_len = buf.length;
9977				for (; i < buf_len; i++) {
9978					str += String.fromCharCode(buf[i]);
9979				}
9980				bb.push(str);
9981			} else if (get_class(data) === "Blob" || get_class(data) === "File") {
9982				if (FileReaderSync) {
9983					var fr = new FileReaderSync;
9984					bb.push(fr.readAsBinaryString(data));
9985				} else {
9986					// async FileReader won't work as BlobBuilder is sync
9987					throw new FileException("NOT_READABLE_ERR");
9988				}
9989			} else if (data instanceof FakeBlob) {
9990				if (data.encoding === "base64" && atob) {
9991					bb.push(atob(data.data));
9992				} else if (data.encoding === "URI") {
9993					bb.push(decodeURIComponent(data.data));
9994				} else if (data.encoding === "raw") {
9995					bb.push(data.data);
9996				}
9997			} else {
9998				if (typeof data !== "string") {
9999					data += ""; // convert unsupported types to strings
10000				}
10001				// decode UTF-16 to binary string
10002				bb.push(unescape(encodeURIComponent(data)));
10003			}
10004		};
10005		FBB_proto.getBlob = function(type) {
10006			if (!arguments.length) {
10007				type = null;
10008			}
10009			return new FakeBlob(this.data.join(""), type, "raw");
10010		};
10011		FBB_proto.toString = function() {
10012			return "[object BlobBuilder]";
10013		};
10014		FB_proto.slice = function(start, end, type) {
10015			var args = arguments.length;
10016			if (args < 3) {
10017				type = null;
10018			}
10019			return new FakeBlob(
10020				  this.data.slice(start, args > 1 ? end : this.data.length)
10021				, type
10022				, this.encoding
10023			);
10024		};
10025		FB_proto.toString = function() {
10026			return "[object Blob]";
10027		};
10028		FB_proto.close = function() {
10029			this.size = 0;
10030			delete this.data;
10031		};
10032		return FakeBlobBuilder;
10033	}(view));
10034
10035	view.Blob = function(blobParts, options) {
10036		var type = options ? (options.type || "") : "";
10037		var builder = new BlobBuilder();
10038		if (blobParts) {
10039			for (var i = 0, len = blobParts.length; i < len; i++) {
10040				if (Uint8Array && blobParts[i] instanceof Uint8Array) {
10041					builder.append(blobParts[i].buffer);
10042				}
10043				else {
10044					builder.append(blobParts[i]);
10045				}
10046			}
10047		}
10048		var blob = builder.getBlob(type);
10049		if (!blob.slice && blob.webkitSlice) {
10050			blob.slice = blob.webkitSlice;
10051		}
10052		return blob;
10053	};
10054
10055	var getPrototypeOf = Object.getPrototypeOf || function(object) {
10056		return object.__proto__;
10057	};
10058	view.Blob.prototype = getPrototypeOf(new view.Blob());
10059}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined.content || undefined));
10060
10061/* FileSaver.js
10062 * A saveAs() FileSaver implementation.
10063 * 1.1.20151003
10064 *
10065 * By Eli Grey, http://eligrey.com
10066 * License: MIT
10067 *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
10068 */
10069
10070/*global self */
10071/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
10072
10073/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
10074
10075var saveAs = saveAs || (function(view) {
10076	"use strict";
10077	// IE <10 is explicitly unsupported
10078	if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
10079		return;
10080	}
10081	var
10082		  doc = view.document
10083		  // only get URL when necessary in case Blob.js hasn't overridden it yet
10084		, get_URL = function() {
10085			return view.URL || view.webkitURL || view;
10086		}
10087		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
10088		, can_use_save_link = "download" in save_link
10089		, click = function(node) {
10090			var event = new MouseEvent("click");
10091			node.dispatchEvent(event);
10092		}
10093		, is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent)
10094		, webkit_req_fs = view.webkitRequestFileSystem
10095		, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
10096		, throw_outside = function(ex) {
10097			(view.setImmediate || view.setTimeout)(function() {
10098				throw ex;
10099			}, 0);
10100		}
10101		, force_saveable_type = "application/octet-stream"
10102		, fs_min_size = 0
10103		// See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and
10104		// https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047
10105		// for the reasoning behind the timeout and revocation flow
10106		, arbitrary_revoke_timeout = 500 // in ms
10107		, revoke = function(file) {
10108			var revoker = function() {
10109				if (typeof file === "string") { // file is an object URL
10110					get_URL().revokeObjectURL(file);
10111				} else { // file is a File
10112					file.remove();
10113				}
10114			};
10115			if (view.chrome) {
10116				revoker();
10117			} else {
10118				setTimeout(revoker, arbitrary_revoke_timeout);
10119			}
10120		}
10121		, dispatch = function(filesaver, event_types, event) {
10122			event_types = [].concat(event_types);
10123			var i = event_types.length;
10124			while (i--) {
10125				var listener = filesaver["on" + event_types[i]];
10126				if (typeof listener === "function") {
10127					try {
10128						listener.call(filesaver, event || filesaver);
10129					} catch (ex) {
10130						throw_outside(ex);
10131					}
10132				}
10133			}
10134		}
10135		, auto_bom = function(blob) {
10136			// prepend BOM for UTF-8 XML and text/* types (including HTML)
10137			if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
10138				return new Blob(["\ufeff", blob], {type: blob.type});
10139			}
10140			return blob;
10141		}
10142		, FileSaver = function(blob, name, no_auto_bom) {
10143			if (!no_auto_bom) {
10144				blob = auto_bom(blob);
10145			}
10146			// First try a.download, then web filesystem, then object URLs
10147			var
10148				  filesaver = this
10149				, type = blob.type
10150				, blob_changed = false
10151				, object_url
10152				, target_view
10153				, dispatch_all = function() {
10154					dispatch(filesaver, "writestart progress write writeend".split(" "));
10155				}
10156				// on any filesys errors revert to saving with object URLs
10157				, fs_error = function() {
10158					if (target_view && is_safari && typeof FileReader !== "undefined") {
10159						// Safari doesn't allow downloading of blob urls
10160						var reader = new FileReader();
10161						reader.onloadend = function() {
10162							var base64Data = reader.result;
10163							target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
10164							filesaver.readyState = filesaver.DONE;
10165							dispatch_all();
10166						};
10167						reader.readAsDataURL(blob);
10168						filesaver.readyState = filesaver.INIT;
10169						return;
10170					}
10171					// don't create more object URLs than needed
10172					if (blob_changed || !object_url) {
10173						object_url = get_URL().createObjectURL(blob);
10174					}
10175					if (target_view) {
10176						target_view.location.href = object_url;
10177					} else {
10178						var new_tab = view.open(object_url, "_blank");
10179						if (new_tab == undefined && is_safari) {
10180							//Apple do not allow window.open, see http://bit.ly/1kZffRI
10181							view.location.href = object_url;
10182						}
10183					}
10184					filesaver.readyState = filesaver.DONE;
10185					dispatch_all();
10186					revoke(object_url);
10187				}
10188				, abortable = function(func) {
10189					return function() {
10190						if (filesaver.readyState !== filesaver.DONE) {
10191							return func.apply(this, arguments);
10192						}
10193					};
10194				}
10195				, create_if_not_found = {create: true, exclusive: false}
10196				, slice;
10197			filesaver.readyState = filesaver.INIT;
10198			if (!name) {
10199				name = "download";
10200			}
10201			if (can_use_save_link) {
10202				object_url = get_URL().createObjectURL(blob);
10203				setTimeout(function() {
10204					save_link.href = object_url;
10205					save_link.download = name;
10206					click(save_link);
10207					dispatch_all();
10208					revoke(object_url);
10209					filesaver.readyState = filesaver.DONE;
10210				});
10211				return;
10212			}
10213			// Object and web filesystem URLs have a problem saving in Google Chrome when
10214			// viewed in a tab, so I force save with application/octet-stream
10215			// http://code.google.com/p/chromium/issues/detail?id=91158
10216			// Update: Google errantly closed 91158, I submitted it again:
10217			// https://code.google.com/p/chromium/issues/detail?id=389642
10218			if (view.chrome && type && type !== force_saveable_type) {
10219				slice = blob.slice || blob.webkitSlice;
10220				blob = slice.call(blob, 0, blob.size, force_saveable_type);
10221				blob_changed = true;
10222			}
10223			// Since I can't be sure that the guessed media type will trigger a download
10224			// in WebKit, I append .download to the filename.
10225			// https://bugs.webkit.org/show_bug.cgi?id=65440
10226			if (webkit_req_fs && name !== "download") {
10227				name += ".download";
10228			}
10229			if (type === force_saveable_type || webkit_req_fs) {
10230				target_view = view;
10231			}
10232			if (!req_fs) {
10233				fs_error();
10234				return;
10235			}
10236			fs_min_size += blob.size;
10237			req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
10238				fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
10239					var save = function() {
10240						dir.getFile(name, create_if_not_found, abortable(function(file) {
10241							file.createWriter(abortable(function(writer) {
10242								writer.onwriteend = function(event) {
10243									target_view.location.href = file.toURL();
10244									filesaver.readyState = filesaver.DONE;
10245									dispatch(filesaver, "writeend", event);
10246									revoke(file);
10247								};
10248								writer.onerror = function() {
10249									var error = writer.error;
10250									if (error.code !== error.ABORT_ERR) {
10251										fs_error();
10252									}
10253								};
10254								"writestart progress write abort".split(" ").forEach(function(event) {
10255									writer["on" + event] = filesaver["on" + event];
10256								});
10257								writer.write(blob);
10258								filesaver.abort = function() {
10259									writer.abort();
10260									filesaver.readyState = filesaver.DONE;
10261								};
10262								filesaver.readyState = filesaver.WRITING;
10263							}), fs_error);
10264						}), fs_error);
10265					};
10266					dir.getFile(name, {create: false}, abortable(function(file) {
10267						// delete file if it already exists
10268						file.remove();
10269						save();
10270					}), abortable(function(ex) {
10271						if (ex.code === ex.NOT_FOUND_ERR) {
10272							save();
10273						} else {
10274							fs_error();
10275						}
10276					}));
10277				}), fs_error);
10278			}), fs_error);
10279		}
10280		, FS_proto = FileSaver.prototype
10281		, saveAs = function(blob, name, no_auto_bom) {
10282			return new FileSaver(blob, name, no_auto_bom);
10283		};
10284	// IE 10+ (native saveAs)
10285	if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
10286		return function(blob, name, no_auto_bom) {
10287			if (!no_auto_bom) {
10288				blob = auto_bom(blob);
10289			}
10290			return navigator.msSaveOrOpenBlob(blob, name || "download");
10291		};
10292	}
10293
10294	FS_proto.abort = function() {
10295		var filesaver = this;
10296		filesaver.readyState = filesaver.DONE;
10297		dispatch(filesaver, "abort");
10298	};
10299	FS_proto.readyState = FS_proto.INIT = 0;
10300	FS_proto.WRITING = 1;
10301	FS_proto.DONE = 2;
10302
10303	FS_proto.error =
10304	FS_proto.onwritestart =
10305	FS_proto.onprogress =
10306	FS_proto.onwrite =
10307	FS_proto.onabort =
10308	FS_proto.onerror =
10309	FS_proto.onwriteend =
10310		null;
10311
10312	return saveAs;
10313}(
10314	   typeof self !== "undefined" && self
10315	|| typeof window !== "undefined" && window
10316	|| undefined.content
10317));
10318// `self` is undefined in Firefox for Android content script context
10319// while `this` is nsIContentFrameMessageManager
10320// with an attribute `content` that corresponds to the window
10321
10322if (typeof module !== "undefined" && module.exports) {
10323  module.exports.saveAs = saveAs;
10324} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
10325  define([], function() {
10326    return saveAs;
10327  });
10328}
10329
10330/*
10331 * Copyright (c) 2012 chick307 <[email protected]>
10332 *
10333 * Licensed under the MIT License.
10334 * http://opensource.org/licenses/mit-license
10335 */
10336
10337void function(global, callback) {
10338	if (typeof module === 'object') {
10339		module.exports = callback();
10340	} else if (typeof define === 'function') {
10341		define(callback);
10342	} else {
10343		global.adler32cs = callback();
10344	}
10345}(jsPDF, function() {
10346	var _hasArrayBuffer = typeof ArrayBuffer === 'function' &&
10347		typeof Uint8Array === 'function';
10348
10349	var _Buffer = null, _isBuffer = (function() {
10350		if (!_hasArrayBuffer)
10351			return function _isBuffer() { return false };
10352
10353		try {
10354			var buffer = {};
10355			if (typeof buffer.Buffer === 'function')
10356				_Buffer = buffer.Buffer;
10357		} catch (error) {}
10358
10359		return function _isBuffer(value) {
10360			return value instanceof ArrayBuffer ||
10361				_Buffer !== null && value instanceof _Buffer;
10362		};
10363	}());
10364
10365	var _utf8ToBinary = (function() {
10366		if (_Buffer !== null) {
10367			return function _utf8ToBinary(utf8String) {
10368				return new _Buffer(utf8String, 'utf8').toString('binary');
10369			};
10370		} else {
10371			return function _utf8ToBinary(utf8String) {
10372				return unescape(encodeURIComponent(utf8String));
10373			};
10374		}
10375	}());
10376
10377	var MOD = 65521;
10378
10379	var _update = function _update(checksum, binaryString) {
10380		var a = checksum & 0xFFFF, b = checksum >>> 16;
10381		for (var i = 0, length = binaryString.length; i < length; i++) {
10382			a = (a + (binaryString.charCodeAt(i) & 0xFF)) % MOD;
10383			b = (b + a) % MOD;
10384		}
10385		return (b << 16 | a) >>> 0;
10386	};
10387
10388	var _updateUint8Array = function _updateUint8Array(checksum, uint8Array) {
10389		var a = checksum & 0xFFFF, b = checksum >>> 16;
10390		for (var i = 0, length = uint8Array.length, x; i < length; i++) {
10391			a = (a + uint8Array[i]) % MOD;
10392			b = (b + a) % MOD;
10393		}
10394		return (b << 16 | a) >>> 0
10395	};
10396
10397	var exports = {};
10398
10399	var Adler32 = exports.Adler32 = (function() {
10400		var ctor = function Adler32(checksum) {
10401			if (!(this instanceof ctor)) {
10402				throw new TypeError(
10403					'Constructor cannot called be as a function.');
10404			}
10405			if (!isFinite(checksum = checksum == null ? 1 : +checksum)) {
10406				throw new Error(
10407					'First arguments needs to be a finite number.');
10408			}
10409			this.checksum = checksum >>> 0;
10410		};
10411
10412		var proto = ctor.prototype = {};
10413		proto.constructor = ctor;
10414
10415		ctor.from = function(from) {
10416			from.prototype = proto;
10417			return from;
10418		}(function from(binaryString) {
10419			if (!(this instanceof ctor)) {
10420				throw new TypeError(
10421					'Constructor cannot called be as a function.');
10422			}
10423			if (binaryString == null)
10424				throw new Error('First argument needs to be a string.');
10425			this.checksum = _update(1, binaryString.toString());
10426		});
10427
10428		ctor.fromUtf8 = function(fromUtf8) {
10429			fromUtf8.prototype = proto;
10430			return fromUtf8;
10431		}(function fromUtf8(utf8String) {
10432			if (!(this instanceof ctor)) {
10433				throw new TypeError(
10434					'Constructor cannot called be as a function.');
10435			}
10436			if (utf8String == null)
10437				throw new Error('First argument needs to be a string.');
10438			var binaryString = _utf8ToBinary(utf8String.toString());
10439			this.checksum = _update(1, binaryString);
10440		});
10441
10442		if (_hasArrayBuffer) {
10443			ctor.fromBuffer = function(fromBuffer) {
10444				fromBuffer.prototype = proto;
10445				return fromBuffer;
10446			}(function fromBuffer(buffer) {
10447				if (!(this instanceof ctor)) {
10448					throw new TypeError(
10449						'Constructor cannot called be as a function.');
10450				}
10451				if (!_isBuffer(buffer))
10452					throw new Error('First argument needs to be ArrayBuffer.');
10453				var array = new Uint8Array(buffer);
10454				return this.checksum = _updateUint8Array(1, array);
10455			});
10456		}
10457
10458		proto.update = function update(binaryString) {
10459			if (binaryString == null)
10460				throw new Error('First argument needs to be a string.');
10461			binaryString = binaryString.toString();
10462			return this.checksum = _update(this.checksum, binaryString);
10463		};
10464
10465		proto.updateUtf8 = function updateUtf8(utf8String) {
10466			if (utf8String == null)
10467				throw new Error('First argument needs to be a string.');
10468			var binaryString = _utf8ToBinary(utf8String.toString());
10469			return this.checksum = _update(this.checksum, binaryString);
10470		};
10471
10472		if (_hasArrayBuffer) {
10473			proto.updateBuffer = function updateBuffer(buffer) {
10474				if (!_isBuffer(buffer))
10475					throw new Error('First argument needs to be ArrayBuffer.');
10476				var array = new Uint8Array(buffer);
10477				return this.checksum = _updateUint8Array(this.checksum, array);
10478			};
10479		}
10480
10481		proto.clone = function clone() {
10482			return new Adler32(this.checksum);
10483		};
10484
10485		return ctor;
10486	}());
10487
10488	exports.from = function from(binaryString) {
10489		if (binaryString == null)
10490			throw new Error('First argument needs to be a string.');
10491		return _update(1, binaryString.toString());
10492	};
10493
10494	exports.fromUtf8 = function fromUtf8(utf8String) {
10495		if (utf8String == null)
10496			throw new Error('First argument needs to be a string.');
10497		var binaryString = _utf8ToBinary(utf8String.toString());
10498		return _update(1, binaryString);
10499	};
10500
10501	if (_hasArrayBuffer) {
10502		exports.fromBuffer = function fromBuffer(buffer) {
10503			if (!_isBuffer(buffer))
10504				throw new Error('First argument need to be ArrayBuffer.');
10505			var array = new Uint8Array(buffer);
10506			return _updateUint8Array(1, array);
10507		};
10508	}
10509
10510	return exports;
10511});
10512
10513/**
10514 * CssColors
10515 * Copyright (c) 2014 Steven Spungin (TwelveTone LLC)  [email protected]
10516 *
10517 * Licensed under the MIT License.
10518 * http://opensource.org/licenses/mit-license
10519 */
10520
10521/**
10522 * Usage CssColors('red');
10523 * Returns RGB hex color with '#' prefix
10524 */
10525
10526var CssColors = {};
10527CssColors._colorsTable = {
10528	"aliceblue" : "#f0f8ff",
10529	"antiquewhite" : "#faebd7",
10530	"aqua" : "#00ffff",
10531	"aquamarine" : "#7fffd4",
10532	"azure" : "#f0ffff",
10533	"beige" : "#f5f5dc",
10534	"bisque" : "#ffe4c4",
10535	"black" : "#000000",
10536	"blanchedalmond" : "#ffebcd",
10537	"blue" : "#0000ff",
10538	"blueviolet" : "#8a2be2",
10539	"brown" : "#a52a2a",
10540	"burlywood" : "#deb887",
10541	"cadetblue" : "#5f9ea0",
10542	"chartreuse" : "#7fff00",
10543	"chocolate" : "#d2691e",
10544	"coral" : "#ff7f50",
10545	"cornflowerblue" : "#6495ed",
10546	"cornsilk" : "#fff8dc",
10547	"crimson" : "#dc143c",
10548	"cyan" : "#00ffff",
10549	"darkblue" : "#00008b",
10550	"darkcyan" : "#008b8b",
10551	"darkgoldenrod" : "#b8860b",
10552	"darkgray" : "#a9a9a9",
10553	"darkgreen" : "#006400",
10554	"darkkhaki" : "#bdb76b",
10555	"darkmagenta" : "#8b008b",
10556	"darkolivegreen" : "#556b2f",
10557	"darkorange" : "#ff8c00",
10558	"darkorchid" : "#9932cc",
10559	"darkred" : "#8b0000",
10560	"darksalmon" : "#e9967a",
10561	"darkseagreen" : "#8fbc8f",
10562	"darkslateblue" : "#483d8b",
10563	"darkslategray" : "#2f4f4f",
10564	"darkturquoise" : "#00ced1",
10565	"darkviolet" : "#9400d3",
10566	"deeppink" : "#ff1493",
10567	"deepskyblue" : "#00bfff",
10568	"dimgray" : "#696969",
10569	"dodgerblue" : "#1e90ff",
10570	"firebrick" : "#b22222",
10571	"floralwhite" : "#fffaf0",
10572	"forestgreen" : "#228b22",
10573	"fuchsia" : "#ff00ff",
10574	"gainsboro" : "#dcdcdc",
10575	"ghostwhite" : "#f8f8ff",
10576	"gold" : "#ffd700",
10577	"goldenrod" : "#daa520",
10578	"gray" : "#808080",
10579	"green" : "#008000",
10580	"greenyellow" : "#adff2f",
10581	"honeydew" : "#f0fff0",
10582	"hotpink" : "#ff69b4",
10583	"indianred " : "#cd5c5c",
10584	"indigo" : "#4b0082",
10585	"ivory" : "#fffff0",
10586	"khaki" : "#f0e68c",
10587	"lavender" : "#e6e6fa",
10588	"lavenderblush" : "#fff0f5",
10589	"lawngreen" : "#7cfc00",
10590	"lemonchiffon" : "#fffacd",
10591	"lightblue" : "#add8e6",
10592	"lightcoral" : "#f08080",
10593	"lightcyan" : "#e0ffff",
10594	"lightgoldenrodyellow" : "#fafad2",
10595	"lightgrey" : "#d3d3d3",
10596	"lightgreen" : "#90ee90",
10597	"lightpink" : "#ffb6c1",
10598	"lightsalmon" : "#ffa07a",
10599	"lightseagreen" : "#20b2aa",
10600	"lightskyblue" : "#87cefa",
10601	"lightslategray" : "#778899",
10602	"lightsteelblue" : "#b0c4de",
10603	"lightyellow" : "#ffffe0",
10604	"lime" : "#00ff00",
10605	"limegreen" : "#32cd32",
10606	"linen" : "#faf0e6",
10607	"magenta" : "#ff00ff",
10608	"maroon" : "#800000",
10609	"mediumaquamarine" : "#66cdaa",
10610	"mediumblue" : "#0000cd",
10611	"mediumorchid" : "#ba55d3",
10612	"mediumpurple" : "#9370d8",
10613	"mediumseagreen" : "#3cb371",
10614	"mediumslateblue" : "#7b68ee",
10615	"mediumspringgreen" : "#00fa9a",
10616	"mediumturquoise" : "#48d1cc",
10617	"mediumvioletred" : "#c71585",
10618	"midnightblue" : "#191970",
10619	"mintcream" : "#f5fffa",
10620	"mistyrose" : "#ffe4e1",
10621	"moccasin" : "#ffe4b5",
10622	"navajowhite" : "#ffdead",
10623	"navy" : "#000080",
10624	"oldlace" : "#fdf5e6",
10625	"olive" : "#808000",
10626	"olivedrab" : "#6b8e23",
10627	"orange" : "#ffa500",
10628	"orangered" : "#ff4500",
10629	"orchid" : "#da70d6",
10630	"palegoldenrod" : "#eee8aa",
10631	"palegreen" : "#98fb98",
10632	"paleturquoise" : "#afeeee",
10633	"palevioletred" : "#d87093",
10634	"papayawhip" : "#ffefd5",
10635	"peachpuff" : "#ffdab9",
10636	"peru" : "#cd853f",
10637	"pink" : "#ffc0cb",
10638	"plum" : "#dda0dd",
10639	"powderblue" : "#b0e0e6",
10640	"purple" : "#800080",
10641	"red" : "#ff0000",
10642	"rosybrown" : "#bc8f8f",
10643	"royalblue" : "#4169e1",
10644	"saddlebrown" : "#8b4513",
10645	"salmon" : "#fa8072",
10646	"sandybrown" : "#f4a460",
10647	"seagreen" : "#2e8b57",
10648	"seashell" : "#fff5ee",
10649	"sienna" : "#a0522d",
10650	"silver" : "#c0c0c0",
10651	"skyblue" : "#87ceeb",
10652	"slateblue" : "#6a5acd",
10653	"slategray" : "#708090",
10654	"snow" : "#fffafa",
10655	"springgreen" : "#00ff7f",
10656	"steelblue" : "#4682b4",
10657	"tan" : "#d2b48c",
10658	"teal" : "#008080",
10659	"thistle" : "#d8bfd8",
10660	"tomato" : "#ff6347",
10661	"turquoise" : "#40e0d0",
10662	"violet" : "#ee82ee",
10663	"wheat" : "#f5deb3",
10664	"white" : "#ffffff",
10665	"whitesmoke" : "#f5f5f5",
10666	"yellow" : "#ffff00",
10667	"yellowgreen" : "#9acd32"
10668};
10669
10670CssColors.colorNameToHex = function(color) {
10671	color = color.toLowerCase();
10672	if (typeof this._colorsTable[color] != 'undefined')
10673		return this._colorsTable[color];
10674
10675	return false;
10676};
10677
10678/*
10679 Deflate.js - https://github.com/gildas-lormeau/zip.js
10680 Copyright (c) 2013 Gildas Lormeau. All rights reserved.
10681
10682 Redistribution and use in source and binary forms, with or without
10683 modification, are permitted provided that the following conditions are met:
10684
10685 1. Redistributions of source code must retain the above copyright notice,
10686 this list of conditions and the following disclaimer.
10687
10688 2. Redistributions in binary form must reproduce the above copyright 
10689 notice, this list of conditions and the following disclaimer in 
10690 the documentation and/or other materials provided with the distribution.
10691
10692 3. The names of the authors may not be used to endorse or promote products
10693 derived from this software without specific prior written permission.
10694
10695 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
10696 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
10697 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
10698 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
10699 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10700 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
10701 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
10702 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
10703 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
10704 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10705 */
10706
10707/*
10708 * This program is based on JZlib 1.0.2 ymnk, JCraft,Inc.
10709 * JZlib is based on zlib-1.1.3, so all credit should go authors
10710 * Jean-loup Gailly([email protected]) and Mark Adler([email protected])
10711 * and contributors of zlib.
10712 */
10713
10714var Deflater = (function(obj) {
10715
10716	// Global
10717
10718	var MAX_BITS = 15;
10719	var D_CODES = 30;
10720	var BL_CODES = 19;
10721
10722	var LENGTH_CODES = 29;
10723	var LITERALS = 256;
10724	var L_CODES = (LITERALS + 1 + LENGTH_CODES);
10725	var HEAP_SIZE = (2 * L_CODES + 1);
10726
10727	var END_BLOCK = 256;
10728
10729	// Bit length codes must not exceed MAX_BL_BITS bits
10730	var MAX_BL_BITS = 7;
10731
10732	// repeat previous bit length 3-6 times (2 bits of repeat count)
10733	var REP_3_6 = 16;
10734
10735	// repeat a zero length 3-10 times (3 bits of repeat count)
10736	var REPZ_3_10 = 17;
10737
10738	// repeat a zero length 11-138 times (7 bits of repeat count)
10739	var REPZ_11_138 = 18;
10740
10741	// The lengths of the bit length codes are sent in order of decreasing
10742	// probability, to avoid transmitting the lengths for unused bit
10743	// length codes.
10744
10745	var Buf_size = 8 * 2;
10746
10747	// JZlib version : "1.0.2"
10748	var Z_DEFAULT_COMPRESSION = -1;
10749
10750	// compression strategy
10751	var Z_FILTERED = 1;
10752	var Z_HUFFMAN_ONLY = 2;
10753	var Z_DEFAULT_STRATEGY = 0;
10754
10755	var Z_NO_FLUSH = 0;
10756	var Z_PARTIAL_FLUSH = 1;
10757	var Z_FULL_FLUSH = 3;
10758	var Z_FINISH = 4;
10759
10760	var Z_OK = 0;
10761	var Z_STREAM_END = 1;
10762	var Z_NEED_DICT = 2;
10763	var Z_STREAM_ERROR = -2;
10764	var Z_DATA_ERROR = -3;
10765	var Z_BUF_ERROR = -5;
10766
10767	// Tree
10768
10769	// see definition of array dist_code below
10770	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,
10771			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,
10772			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,
10773			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,
10774			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,
10775			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,
10776			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,
10777			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,
10778			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,
10779			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,
10780			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,
10781			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,
10782			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,
10783			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 ];
10784
10785	function Tree() {
10786		var that = this;
10787
10788		// dyn_tree; // the dynamic tree
10789		// max_code; // largest code with non zero frequency
10790		// stat_desc; // the corresponding static tree
10791
10792		// Compute the optimal bit lengths for a tree and update the total bit
10793		// length
10794		// for the current block.
10795		// IN assertion: the fields freq and dad are set, heap[heap_max] and
10796		// above are the tree nodes sorted by increasing frequency.
10797		// OUT assertions: the field len is set to the optimal bit length, the
10798		// array bl_count contains the frequencies for each bit length.
10799		// The length opt_len is updated; static_len is also updated if stree is
10800		// not null.
10801		function gen_bitlen(s) {
10802			var tree = that.dyn_tree;
10803			var stree = that.stat_desc.static_tree;
10804			var extra = that.stat_desc.extra_bits;
10805			var base = that.stat_desc.extra_base;
10806			var max_length = that.stat_desc.max_length;
10807			var h; // heap index
10808			var n, m; // iterate over the tree elements
10809			var bits; // bit length
10810			var xbits; // extra bits
10811			var f; // frequency
10812			var overflow = 0; // number of elements with bit length too large
10813
10814			for (bits = 0; bits <= MAX_BITS; bits++)
10815				s.bl_count[bits] = 0;
10816
10817			// In a first pass, compute the optimal bit lengths (which may
10818			// overflow in the case of the bit length tree).
10819			tree[s.heap[s.heap_max] * 2 + 1] = 0; // root of the heap
10820
10821			for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
10822				n = s.heap[h];
10823				bits = tree[tree[n * 2 + 1] * 2 + 1] + 1;
10824				if (bits > max_length) {
10825					bits = max_length;
10826					overflow++;
10827				}
10828				tree[n * 2 + 1] = bits;
10829				// We overwrite tree[n*2+1] which is no longer needed
10830
10831				if (n > that.max_code)
10832					continue; // not a leaf node
10833
10834				s.bl_count[bits]++;
10835				xbits = 0;
10836				if (n >= base)
10837					xbits = extra[n - base];
10838				f = tree[n * 2];
10839				s.opt_len += f * (bits + xbits);
10840				if (stree)
10841					s.static_len += f * (stree[n * 2 + 1] + xbits);
10842			}
10843			if (overflow === 0)
10844				return;
10845
10846			// This happens for example on obj2 and pic of the Calgary corpus
10847			// Find the first bit length which could increase:
10848			do {
10849				bits = max_length - 1;
10850				while (s.bl_count[bits] === 0)
10851					bits--;
10852				s.bl_count[bits]--; // move one leaf down the tree
10853				s.bl_count[bits + 1] += 2; // move one overflow item as its brother
10854				s.bl_count[max_length]--;
10855				// The brother of the overflow item also moves one step up,
10856				// but this does not affect bl_count[max_length]
10857				overflow -= 2;
10858			} while (overflow > 0);
10859
10860			for (bits = max_length; bits !== 0; bits--) {
10861				n = s.bl_count[bits];
10862				while (n !== 0) {
10863					m = s.heap[--h];
10864					if (m > that.max_code)
10865						continue;
10866					if (tree[m * 2 + 1] != bits) {
10867						s.opt_len += (bits - tree[m * 2 + 1]) * tree[m * 2];
10868						tree[m * 2 + 1] = bits;
10869					}
10870					n--;
10871				}
10872			}
10873		}
10874
10875		// Reverse the first len bits of a code, using straightforward code (a
10876		// faster
10877		// method would use a table)
10878		// IN assertion: 1 <= len <= 15
10879		function bi_reverse(code, // the value to invert
10880		len // its bit length
10881		) {
10882			var res = 0;
10883			do {
10884				res |= code & 1;
10885				code >>>= 1;
10886				res <<= 1;
10887			} while (--len > 0);
10888			return res >>> 1;
10889		}
10890
10891		// Generate the codes for a given tree and bit counts (which need not be
10892		// optimal).
10893		// IN assertion: the array bl_count contains the bit length statistics for
10894		// the given tree and the field len is set for all tree elements.
10895		// OUT assertion: the field code is set for all tree elements of non
10896		// zero code length.
10897		function gen_codes(tree, // the tree to decorate
10898		max_code, // largest code with non zero frequency
10899		bl_count // number of codes at each bit length
10900		) {
10901			var next_code = []; // next code value for each
10902			// bit length
10903			var code = 0; // running code value
10904			var bits; // bit index
10905			var n; // code index
10906			var len;
10907
10908			// The distribution counts are first used to generate the code values
10909			// without bit reversal.
10910			for (bits = 1; bits <= MAX_BITS; bits++) {
10911				next_code[bits] = code = ((code + bl_count[bits - 1]) << 1);
10912			}
10913
10914			// Check that the bit counts in bl_count are consistent. The last code
10915			// must be all ones.
10916			// Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
10917			// "inconsistent bit counts");
10918			// Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
10919
10920			for (n = 0; n <= max_code; n++) {
10921				len = tree[n * 2 + 1];
10922				if (len === 0)
10923					continue;
10924				// Now reverse the bits
10925				tree[n * 2] = bi_reverse(next_code[len]++, len);
10926			}
10927		}
10928
10929		// Construct one Huffman tree and assigns the code bit strings and lengths.
10930		// Update the total bit length for the current block.
10931		// IN assertion: the field freq is set for all tree elements.
10932		// OUT assertions: the fields len and code are set to the optimal bit length
10933		// and corresponding code. The length opt_len is updated; static_len is
10934		// also updated if stree is not null. The field max_code is set.
10935		that.build_tree = function(s) {
10936			var tree = that.dyn_tree;
10937			var stree = that.stat_desc.static_tree;
10938			var elems = that.stat_desc.elems;
10939			var n, m; // iterate over heap elements
10940			var max_code = -1; // largest code with non zero frequency
10941			var node; // new node being created
10942
10943			// Construct the initial heap, with least frequent element in
10944			// heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
10945			// heap[0] is not used.
10946			s.heap_len = 0;
10947			s.heap_max = HEAP_SIZE;
10948
10949			for (n = 0; n < elems; n++) {
10950				if (tree[n * 2] !== 0) {
10951					s.heap[++s.heap_len] = max_code = n;
10952					s.depth[n] = 0;
10953				} else {
10954					tree[n * 2 + 1] = 0;
10955				}
10956			}
10957
10958			// The pkzip format requires that at least one distance code exists,
10959			// and that at least one bit should be sent even if there is only one
10960			// possible code. So to avoid special checks later on we force at least
10961			// two codes of non zero frequency.
10962			while (s.heap_len < 2) {
10963				node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0;
10964				tree[node * 2] = 1;
10965				s.depth[node] = 0;
10966				s.opt_len--;
10967				if (stree)
10968					s.static_len -= stree[node * 2 + 1];
10969				// node is 0 or 1 so it does not have extra bits
10970			}
10971			that.max_code = max_code;
10972
10973			// The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
10974			// establish sub-heaps of increasing lengths:
10975
10976			for (n = Math.floor(s.heap_len / 2); n >= 1; n--)
10977				s.pqdownheap(tree, n);
10978
10979			// Construct the Huffman tree by repeatedly combining the least two
10980			// frequent nodes.
10981
10982			node = elems; // next internal node of the tree
10983			do {
10984				// n = node of least frequency
10985				n = s.heap[1];
10986				s.heap[1] = s.heap[s.heap_len--];
10987				s.pqdownheap(tree, 1);
10988				m = s.heap[1]; // m = node of next least frequency
10989
10990				s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
10991				s.heap[--s.heap_max] = m;
10992
10993				// Create a new node father of n and m
10994				tree[node * 2] = (tree[n * 2] + tree[m * 2]);
10995				s.depth[node] = Math.max(s.depth[n], s.depth[m]) + 1;
10996				tree[n * 2 + 1] = tree[m * 2 + 1] = node;
10997
10998				// and insert the new node in the heap
10999				s.heap[1] = node++;
11000				s.pqdownheap(tree, 1);
11001			} while (s.heap_len >= 2);
11002
11003			s.heap[--s.heap_max] = s.heap[1];
11004
11005			// At this point, the fields freq and dad are set. We can now
11006			// generate the bit lengths.
11007
11008			gen_bitlen(s);
11009
11010			// The field len is now set, we can generate the bit codes
11011			gen_codes(tree, that.max_code, s.bl_count);
11012		};
11013
11014	}
11015
11016	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,
11017			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,
11018			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,
11019			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,
11020			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,
11021			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,
11022			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 ];
11023
11024	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 ];
11025
11026	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,
11027			24576 ];
11028
11029	// Mapping from a distance to a distance code. dist is the distance - 1 and
11030	// must not have side effects. _dist_code[256] and _dist_code[257] are never
11031	// used.
11032	Tree.d_code = function(dist) {
11033		return ((dist) < 256 ? _dist_code[dist] : _dist_code[256 + ((dist) >>> 7)]);
11034	};
11035
11036	// extra bits for each length code
11037	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 ];
11038
11039	// extra bits for each distance code
11040	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 ];
11041
11042	// extra bits for each bit length code
11043	Tree.extra_blbits = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 ];
11044
11045	Tree.bl_order = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
11046
11047	// StaticTree
11048
11049	function StaticTree(static_tree, extra_bits, extra_base, elems, max_length) {
11050		var that = this;
11051		that.static_tree = static_tree;
11052		that.extra_bits = extra_bits;
11053		that.extra_base = extra_base;
11054		that.elems = elems;
11055		that.max_length = max_length;
11056	}
11057
11058	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,
11059			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,
11060			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,
11061			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,
11062			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,
11063			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,
11064			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,
11065			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
110655, 9, 147, 9, 403, 9, 83, 9, 339, 9, 211, 9, 467, 9,
11066			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,
11067			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,
11068			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,
11069			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,
11070			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,
11071			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,
11072			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,
11073			99, 8, 227, 8 ];
11074
11075	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,
11076			25, 5, 5, 5, 21, 5, 13, 5, 29, 5, 3, 5, 19, 5, 11, 5, 27, 5, 7, 5, 23, 5 ];
11077
11078	StaticTree.static_l_desc = new StaticTree(StaticTree.static_ltree, Tree.extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
11079
11080	StaticTree.static_d_desc = new StaticTree(StaticTree.static_dtree, Tree.extra_dbits, 0, D_CODES, MAX_BITS);
11081
11082	StaticTree.static_bl_desc = new StaticTree(null, Tree.extra_blbits, 0, BL_CODES, MAX_BL_BITS);
11083
11084	// Deflate
11085
11086	var MAX_MEM_LEVEL = 9;
11087	var DEF_MEM_LEVEL = 8;
11088
11089	function Config(good_length, max_lazy, nice_length, max_chain, func) {
11090		var that = this;
11091		that.good_length = good_length;
11092		that.max_lazy = max_lazy;
11093		that.nice_length = nice_length;
11094		that.max_chain = max_chain;
11095		that.func = func;
11096	}
11097
11098	var STORED = 0;
11099	var FAST = 1;
11100	var SLOW = 2;
11101	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),
11102			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),
11103			new Config(32, 128, 258, 1024, SLOW), new Config(32, 258, 258, 4096, SLOW) ];
11104
11105	var z_errmsg = [ "need dictionary", // Z_NEED_DICT
11106	// 2
11107	"stream end", // Z_STREAM_END 1
11108	"", // Z_OK 0
11109	"", // Z_ERRNO (-1)
11110	"stream error", // Z_STREAM_ERROR (-2)
11111	"data error", // Z_DATA_ERROR (-3)
11112	"", // Z_MEM_ERROR (-4)
11113	"buffer error", // Z_BUF_ERROR (-5)
11114	"",// Z_VERSION_ERROR (-6)
11115	"" ];
11116
11117	// block not completed, need more input or more output
11118	var NeedMore = 0;
11119
11120	// block flush performed
11121	var BlockDone = 1;
11122
11123	// finish started, need only more output at next deflate
11124	var FinishStarted = 2;
11125
11126	// finish done, accept no more input or output
11127	var FinishDone = 3;
11128
11129	// preset dictionary flag in zlib header
11130	var PRESET_DICT = 0x20;
11131
11132	var INIT_STATE = 42;
11133	var BUSY_STATE = 113;
11134	var FINISH_STATE = 666;
11135
11136	// The deflate compression method
11137	var Z_DEFLATED = 8;
11138
11139	var STORED_BLOCK = 0;
11140	var STATIC_TREES = 1;
11141	var DYN_TREES = 2;
11142
11143	var MIN_MATCH = 3;
11144	var MAX_MATCH = 258;
11145	var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
11146
11147	function smaller(tree, n, m, depth) {
11148		var tn2 = tree[n * 2];
11149		var tm2 = tree[m * 2];
11150		return (tn2 < tm2 || (tn2 == tm2 && depth[n] <= depth[m]));
11151	}
11152
11153	function Deflate() {
11154
11155		var that = this;
11156		var strm; // pointer back to this zlib stream
11157		var status; // as the name implies
11158		// pending_buf; // output still pending
11159		var pending_buf_size; // size of pending_buf
11160		// pending_out; // next pending byte to output to the stream
11161		// pending; // nb of bytes in the pending buffer
11162		var method; // STORED (for zip only) or DEFLATED
11163		var last_flush; // value of flush param for previous deflate call
11164
11165		var w_size; // LZ77 window size (32K by default)
11166		var w_bits; // log2(w_size) (8..16)
11167		var w_mask; // w_size - 1
11168
11169		var window;
11170		// Sliding window. Input bytes are read into the second half of the window,
11171		// and move to the first half later to keep a dictionary of at least wSize
11172		// bytes. With this organization, matches are limited to a distance of
11173		// wSize-MAX_MATCH bytes, but this ensures that IO is always
11174		// performed with a length multiple of the block size. Also, it limits
11175		// the window size to 64K, which is quite useful on MSDOS.
11176		// To do: use the user input buffer as sliding window.
11177
11178		var window_size;
11179		// Actual size of window: 2*wSize, except when the user input buffer
11180		// is directly used as sliding window.
11181
11182		var prev;
11183		// Link to older string with same hash index. To limit the size of this
11184		// array to 64K, this link is maintained only for the last 32K strings.
11185		// An index in this array is thus a window index modulo 32K.
11186
11187		var head; // Heads of the hash chains or NIL.
11188
11189		var ins_h;
11189 // hash index of string to be inserted
11190		var hash_size; // number of elements in hash table
11191		var hash_bits; // log2(hash_size)
11192		var hash_mask; // hash_size-1
11193
11194		// Number of bits by which ins_h must be shifted at each input
11195		// step. It must be such that after MIN_MATCH steps, the oldest
11196		// byte no longer takes part in the hash key, that is:
11197		// hash_shift * MIN_MATCH >= hash_bits
11198		var hash_shift;
11199
11200		// Window position at the beginning of the current output block. Gets
11201		// negative when the window is moved backwards.
11202
11203		var block_start;
11204
11205		var match_length; // length of best match
11206		var prev_match; // previous match
11207		var match_available; // set if previous match exists
11208		var strstart; // start of string to insert
11209		var match_start; // start of matching string
11210		var lookahead; // number of valid bytes ahead in window
11211
11212		// Length of the best match at previous step. Matches not greater than this
11213		// are discarded. This is used in the lazy match evaluation.
11214		var prev_length;
11215
11216		// To speed up deflation, hash chains are never searched beyond this
11217		// length. A higher limit improves compression ratio but degrades the speed.
11218		var max_chain_length;
11219
11220		// Attempt to find a better match only when the current match is strictly
11221		// smaller than this value. This mechanism is used only for compression
11222		// levels >= 4.
11223		var max_lazy_match;
11224
11225		// Insert new strings in the hash table only if the match length is not
11226		// greater than this length. This saves time but degrades compression.
11227		// max_insert_length is used only for compression levels <= 3.
11228
11229		var level; // compression level (1..9)
11230		var strategy; // favor or force Huffman coding
11231
11232		// Use a faster search when the previous match is longer than this
11233		var good_match;
11234
11235		// Stop searching when current match exceeds this
11236		var nice_match;
11237
11238		var dyn_ltree; // literal and length tree
11239		var dyn_dtree; // distance tree
11240		var bl_tree; // Huffman tree for bit lengths
11241
11242		var l_desc = new Tree(); // desc for literal tree
11243		var d_desc = new Tree(); // desc for distance tree
11244		var bl_desc = new Tree(); // desc for bit length tree
11245
11246		// that.heap_len; // number of elements in the heap
11247		// that.heap_max; // element of largest frequency
11248		// The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
11249		// The same heap array is used to build all trees.
11250
11251		// Depth of each subtree used as tie breaker for trees of equal frequency
11252		that.depth = [];
11253
11254		var l_buf; // index for literals or lengths */
11255
11256		// Size of match buffer for literals/lengths. There are 4 reasons for
11257		// limiting lit_bufsize to 64K:
11258		// - frequencies can be kept in 16 bit counters
11259		// - if compression is not successful for the first block, all input
11260		// data is still in the window so we can still emit a stored block even
11261		// when input comes from standard input. (This can also be done for
11262		// all blocks if lit_bufsize is not greater than 32K.)
11263		// - if compression is not successful for a file smaller than 64K, we can
11264		// even emit a stored file instead of a stored block (saving 5 bytes).
11265		// This is applicable only for zip (not gzip or zlib).
11266		// - creating new Huffman trees less frequently may not provide fast
11267		// adaptation to changes in the input data statistics. (Take for
11268		// example a binary file with poorly compressible code followed by
11269		// a highly compressible string table.) Smaller buffer sizes give
11270		// fast adaptation but have of course the overhead of transmitting
11271		// trees more frequently.
11272		// - I can't count above 4
11273		var lit_bufsize;
11274
11275		var last_lit; // running index in l_buf
11276
11277		// Buffer for distances. To simplify the code, d_buf and l_buf have
11278		// the same number of elements. To use different lengths, an extra flag
11279		// array would be necessary.
11280
11281		var d_buf; // index of pendig_buf
11282
11283		// that.opt_len; // bit length of current block with optimal trees
11284		// that.static_len; // bit length of current block with static trees
11285		var matches; // number of string matches in current block
11286		var last_eob_len; // bit length of EOB code for last block
11287
11288		// Output buffer. bits are inserted starting at the bottom (least
11289		// significant bits).
11290		var bi_buf;
11291
11292		// Number of valid bits in bi_buf. All bits above the last valid bit
11293		// are always zero.
11294		var bi_valid;
11295
11296		// number of codes at each bit length for an optimal tree
11297		that.bl_count = [];
11298
11299		// heap used to build the Huffman trees
11300		that.heap = [];
11301
11302		dyn_ltree = [];
11303		dyn_dtree = [];
11304		bl_tree = [];
11305
11306		function lm_init() {
11307			var i;
11308			window_size = 2 * w_size;
11309
11310			head[hash_size - 1] = 0;
11311			for (i = 0; i < hash_size - 1; i++) {
11312				head[i] = 0;
11313			}
11314
11315			// Set the default configuration parameters:
11316			max_lazy_match = config_table[level].max_lazy;
11317			good_match = config_table[level].good_length;
11318			nice_match = config_table[level].nice_length;
11319			max_chain_length = config_table[level].max_chain;
11320
11321			strstart = 0;
11322			block_start = 0;
11323			lookahead = 0;
11324			match_length = prev_length = MIN_MATCH - 1;
11325			match_available = 0;
11326			ins_h = 0;
11327		}
11328
11329		function init_block() {
11330			var i;
11331			// Initialize the trees.
11332			for (i = 0; i < L_CODES; i++)
11333				dyn_ltree[i * 2] = 0;
11334			for (i = 0; i < D_CODES; i++)
11335				dyn_dtree[i * 2] = 0;
11336			for (i = 0; i < BL_CODES; i++)
11337				bl_tree[i * 2] = 0;
11338
11339			dyn_ltree[END_BLOCK * 2] = 1;
11340			that.opt_len = that.static_len = 0;
11341			last_lit = matches = 0;
11342		}
11343
11344		// Initialize the tree data structures for a new zlib stream.
11345		function tr_init() {
11346
11347			l_desc.dyn_tree = dyn_ltree;
11348			l_desc.stat_desc = StaticTree.static_l_desc;
11349
11350			d_desc.dyn_tree = dyn_dtree;
11351			d_desc.stat_desc = StaticTree.static_d_desc;
11352
11353			bl_desc.dyn_tree = bl_tree;
11354			bl_desc.stat_desc = StaticTree.static_bl_desc;
11355
11356			bi_buf = 0;
11357			bi_valid = 0;
11358			last_eob_len = 8; // enough lookahead for inflate
11359
11360			// Initialize the first block of the first file:
11361			init_block();
11362		}
11363
11364		// Restore the heap property by moving down the tree starting at node k,
11365		// exchanging a node with the smallest of its two sons if necessary,
11366		// stopping
11367		// when the heap property is re-established (each father smaller than its
11368		// two sons).
11369		that.pqdownheap = function(tree, // the tree to restore
11370		k // node to move down
11371		) {
11372			var heap = that.heap;
11373			var v = heap[k];
11374			var j = k << 1; // left son of k
11375			while (j <= that.heap_len) {
11376				// Set j to the smallest of the two sons:
11377				if (j < that.heap_len && smaller(tree, heap[j + 1], heap[j], that.depth)) {
11378					j++;
11379				}
11380				// Exit if v is smaller than both sons
11381				if (smaller(tree, v, heap[j], that.depth))
11382					break;
11383
11384				// Exchange v with the smallest son
11385				heap[k] = heap[j];
11386				k = j;
11387				// And continue down the tree, setting j to the left son of k
11388				j <<= 1;
11389			}
11390			heap[k] = v;
11391		};
11392
11393		// Scan a literal or distance tree to determine the frequencies of the codes
11394		// in the bit length tree.
11395		function scan_tree(tree,// the tree to be scanned
11396		max_code // and its largest code of non zero frequency
11397		) {
11398			var n; // iterates over all tree elements
11399			var prevlen = -1; // last emitted length
11400			var curlen; // length of current code
11401			var nextlen = tree[0 * 2 + 1]; // length of next code
11402			var count = 0; // repeat count of the current code
11403			var max_count = 7; // max repeat count
11404			var min_count = 4; // min repeat count
11405
11406			if (nextlen === 0) {
11407				max_count = 138;
11408				min_count = 3;
11409			}
11410			tree[(max_code + 1) * 2 + 1] = 0xffff; // guard
11411
11412			for (n = 0; n <= max_code; n++) {
11413				curlen = nextlen;
11414				nextlen = tree[(n + 1) * 2 + 1];
11415				if (++count < max_count && curlen == nextlen) {
11416					continue;
11417				} else if (count < min_count) {
11418					bl_tree[curlen * 2] += count;
11419				} else if (curlen !== 0) {
11420					if (curlen != prevlen)
11421						bl_tree[curlen * 2]++;
11422					bl_tree[REP_3_6 * 2]++;
11423				} else if (count <= 10) {
11424					bl_tree[REPZ_3_10 * 2]++;
11425				} else {
11426					bl_tree[REPZ_11_138 * 2]++;
11427				}
11428				count = 0;
11429				prevlen = curlen;
11430				if (nextlen === 0) {
11431					max_count = 138;
11432					min_count = 3;
11433				} else if (curlen == nextlen) {
11434					max_count = 6;
11435					min_count = 3;
11436				} else {
11437					max_count = 7;
11438					min_count = 4;
11439				}
11440			}
11441		}
11442
11443		// Construct the Huffman tree for the bit lengths and return the index in
11444		// bl_order of the last bit length code to send.
11445		function build_bl_tree() {
11446			var max_blindex; // index of last bit length code of non zero freq
11447
11448			// Determine the bit length frequencies for literal and distance trees
11449			scan_tree(dyn_ltree, l_desc.max_code);
11450			scan_tree(dyn_dtree, d_desc.max_code);
11451
11452			// Build the bit length tree:
11453			bl_desc.build_tree(that);
11454			// opt_len now includes the length of the tree representations, except
11455			// the lengths of the bit lengths codes and the 5+5+4 bits for the
11456			// counts.
11457
11458			// Determine the number of bit length codes to send. The pkzip format
11459			// requires that at least 4 bit length codes be sent. (appnote.txt says
11460			// 3 but the actual value used is 4.)
11461			for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
11462				if (bl_tree[Tree.bl_order[max_blindex] * 2 + 1] !== 0)
11463					break;
11464			}
11465			// Update opt_len to include the bit length tree and counts
11466			that.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
11467
11468			return max_blindex;
11469		}
11470
11471		// Output a byte on the stream.
11472		// IN assertion: there is enough room in pending_buf.
11473		function put_byte(p) {
11474			that.pending_buf[that.pending++] = p;
11475		}
11476
11477		function put_short(w) {
11478			put_byte(w & 0xff);
11479			put_byte((w >>> 8) & 0xff);
11480		}
11481
11482		function putShortMSB(b) {
11483			put_byte((b >> 8) & 0xff);
11484			put_byte((b & 0xff) & 0xff);
11485		}
11486
11487		function send_bits(value, length) {
11488			var val, len = length;
11489			if (bi_valid > Buf_size - len) {
11490				val = value;
11491				// bi_buf |= (val << bi_valid);
11492				bi_buf |= ((val << bi_valid) & 0xffff);
11493				put_short(bi_buf);
11494				bi_buf = val >>> (Buf_size - bi_valid);
11495				bi_valid += len - Buf_size;
11496			} else {
11497				// bi_buf |= (value) << bi_valid;
11498				bi_buf |= (((value) << bi_valid) & 0xffff);
11499				bi_valid += len;
11500			}
11501		}
11502
11503		function send_code(c, tree) {
11504			var c2 = c * 2;
11505			send_bits(tree[c2] & 0xffff, tree[c2 + 1] & 0xffff);
11506		}
11507
11508		// Send a literal or distance tree in compressed form, using the codes in
11509		// bl_tree.
11510		function send_tree(tree,// the tree to be sent
11511		max_code // and its largest code of non zero frequency
11512		) {
11513			var n; // iterates over all tree elements
11514			var prevlen = -1; // last emitted length
11515			var curlen; // length of current code
11516			var nextlen = tree[0 * 2 + 1]; // length of next code
11517			var count = 0; // repeat count of the current code
11518			var max_count = 7; // max repeat count
11519			var min_count = 4; // min repeat count
11520
11521			if (nextlen === 0) {
11522				max_count = 138;
11523				min_count = 3;
11524			}
11525
11526			for (n = 0; n <= max_code; n++) {
11527				curlen = nextlen;
11528				nextlen = tree[(n + 1) * 2 + 1];
11529				if (++count < max_count && curlen == nextlen) {
11530					continue;
11531				} else if (count < min_count) {
11532					do {
11533						send_code(curlen, bl_tree);
11534					} while (--count !== 0);
11535				} else if (curlen !== 0) {
11536					if (curlen != prevlen) {
11537						send_code(curlen, bl_tree);
11538						count--;
11539					}
11540					send_code(REP_3_6, bl_tree);
11541					send_bits(count - 3, 2);
11542				} else if (count <= 10) {
11543					send_code(REPZ_3_10, bl_tree);
11544					send_bits(count - 3, 3);
11545				} else {
11546					send_code(REPZ_11_138, bl_tree);
11547					send_bits(count - 11, 7);
11548				}
11549				count = 0;
11550				prevlen = curlen;
11551				if (nextlen === 0) {
11552					max_count = 138;
11553					min_count = 3;
11554				} else if (curlen == nextlen) {
11555					max_count = 6;
11556					min_count = 3;
11557				} else {
11558					max_count = 7;
11559					min_count = 4;
11560				}
11561			}
11562		}
11563
11564		// Send the header for a block using dynamic Huffman trees: the counts, the
11565		// lengths of the bit length codes, the literal tree and the distance tree.
11566		// IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
11567		function send_all_trees(lcodes, dcodes, blcodes) {
11568			var rank; // index in bl_order
11569
11570			send_bits(lcodes - 257, 5); // not +255 as stated in appnote.txt
11571			send_bits(dcodes - 1, 5);
11572			send_bits(blcodes - 4, 4); // not -3 as stated in appnote.txt
11573			for (rank = 0; rank < blcodes; rank++) {
11574				send_bits(bl_tree[Tree.bl_order[rank] * 2 + 1], 3);
11575			}
11576			send_tree(dyn_ltree, lcodes - 1); // literal tree
11577			send_tree(dyn_dtree, dcodes - 1); // distance tree
11578		}
11579
11580		// Flush the bit buffer, keeping at most 7 bits in it.
11581		function bi_flush() {
11582			if (bi_valid == 16) {
11583				put_short(bi_buf);
11584				bi_buf = 0;
11585				bi_valid = 0;
11586			} else if (bi_valid >= 8) {
11587				put_byte(bi_buf & 0xff);
11588				bi_buf >>>= 8;
11589				bi_valid -= 8;
11590			}
11591		}
11592
11593		// Send one empty static block to give enough lookahead for inflate.
11594		// This takes 10 bits, of which 7 may remain in the bit buffer.
11595		// The current inflate code requires 9 bits of lookahead. If the
11596		// last two codes for the previous block (real code plus EOB) were coded
11597		// on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
11598		// the last real code. In this case we send two empty static blocks instead
11599		// of one. (There are no problems if the previous block is stored or fixed.)
11600		// To simplify the code, we assume the worst case of last real code encoded
11601		// on one bit only.
11602		function _tr_align() {
11603			send_bits(STATIC_TREES << 1, 3);
11604			send_code(END_BLOCK, StaticTree.static_ltree);
11605
11606			bi_flush();
11607
11608			// Of the 10 bits for the empty block, we have already sent
11609			// (10 - bi_valid) bits. The lookahead for the last real code (before
11610			// the EOB of the previous block) was thus at least one plus the length
11611			// of the EOB plus what we have just sent of the empty static block.
11612			if (1 + last_eob_len + 10 - bi_valid < 9) {
11613				send_bits(STATIC_TREES << 1, 3);
11614				send_code(END_BLOCK, StaticTree.static_ltree);
11615				bi_flush();
11616			}
11617			last_eob_len = 7;
11618		}
11619
11620		// Save the match info and tally the frequency counts. Return true if
11621		// the current block must be flushed.
11622		function _tr_tally(dist, // distance of matched string
11623		lc // match length-MIN_MATCH or unmatched char (if dist==0)
11624		) {
11625			var out_length, in_length, dcode;
11626			that.pending_buf[d_buf + last_lit * 2] = (dist >>> 8) & 0xff;
11627			that.pending_buf[d_buf + last_lit * 2 + 1] = dist & 0xff;
11628
11629			that.pending_buf[l_buf + last_lit] = lc & 0xff;
11630			last_lit++;
11631
11632			if (dist === 0) {
11633				// lc is the unmatched char
11634				dyn_ltree[lc * 2]++;
11635			} else {
11636				matches++;
11637				// Here, lc is the match length - MIN_MATCH
11638				dist--; // dist = match distance - 1
11639				dyn_ltree[(Tree._length_code[lc] + LITERALS + 1) * 2]++;
11640				dyn_dtree[Tree.d_code(dist) * 2]++;
11641			}
11642
11643			if ((last_lit & 0x1fff) === 0 && level > 2) {
11644				// Compute an upper bound for the compressed length
11645				out_length = last_lit * 8;
11646				in_length = strstart - block_start;
11647				for (dcode = 0; dcode < D_CODES; dcode++) {
11648					out_length += dyn_dtree[dcode * 2] * (5 + Tree.extra_dbits[dcode]);
11649				}
11650				out_length >>>= 3;
11651				if ((matches < Math.floor(last_lit / 2)) && out_length < Math.floor(in_length / 2))
11652					return true;
11653			}
11654
11655			return (last_lit == lit_bufsize - 1);
11656			// We avoid equality with lit_bufsize because of wraparound at 64K
11657			// on 16 bit machines and because stored blocks are restricted to
11658			// 64K-1 bytes.
11659		}
11660
11661		// Send the block data compressed using the given Huffman trees
11662		function compress_block(ltree, dtree) {
11663			var dist; // distance of matched string
11664			var lc; // match length or unmatched char (if dist === 0)
11665			var lx = 0; // running index in l_buf
11666			var code; // the code to send
11667			var extra; // number of extra bits to send
11668
11669			if (last_lit !== 0) {
11670				do {
11671					dist = ((that.pending_buf[d_buf + lx * 2] << 8) & 0xff00) | (that.pending_buf[d_buf + lx * 2 + 1] & 0xff);
11672					lc = (that.pending_buf[l_buf + lx]) & 0xff;
11673					lx++;
11674
11675					if (dist === 0) {
11676						send_code(lc, ltree); // send a literal byte
11677					} else {
11678						// Here, lc is the match length - MIN_MATCH
11679						code = Tree._length_code[lc];
11680
11681						send_code(code + LITERALS + 1, ltree); // send the length
11682						// code
11683						extra = Tree.extra_lbits[code];
11684						if (extra !== 0) {
11685							lc -= Tree.base_length[code];
11686							send_bits(lc, extra); // send the extra length bits
11687						}
11688						dist--; // dist is now the match distance - 1
11689						code = Tree.d_code(dist);
11690
11691						send_code(code, dtree); // send the distance code
11692						extra = Tree.extra_dbits[code];
11693						if (extra !== 0) {
11694							dist -= Tree.base_dist[code];
11695							send_bits(dist, extra); // send the extra distance bits
11696						}
11697					} // literal or match pair ?
11698
11699					// Check that the overlay between pending_buf and d_buf+l_buf is
11700					// ok:
11701				} while (lx < last_lit);
11702			}
11703
11704			send_code(END_BLOCK, ltree);
11705			last_eob_len = ltree[END_BLOCK * 2 + 1];
11706		}
11707
11708		// Flush the bit buffer and align the output on a byte boundary
11709		function bi_windup() {
11710			if (bi_valid > 8) {
11711				put_short(bi_buf);
11712			} else if (bi_valid > 0) {
11713				put_byte(bi_buf & 0xff);
11714			}
11715			bi_buf = 0;
11716			bi_valid = 0;
11717		}
11718
11719		// Copy a stored block, storing first the length and its
11720		// one's complement if requested.
11721		function copy_block(buf, // the input data
11722		len, // its length
11723		header // true if block header must be written
11724		) {
11725			bi_windup(); // align on byte boundary
11726			last_eob_len = 8; // enough lookahead for inflate
11727
11728			if (header) {
11729				put_short(len);
11730				put_short(~len);
11731			}
11732
11733			that.pending_buf.set(window.subarray(buf, buf + len), that.pending);
11734			that.pending += len;
11735		}
11736
11737		// Send a stored block
11738		function _tr_stored_block(buf, // input block
11739		stored_len, // length of input block
11740		eof // true if this is the last block for a file
11741		) {
11742			send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type
11743			copy_block(buf, stored_len, true); // with header
11744		}
11745
11746		// Determine the best encoding for the current block: dynamic trees, static
11747		// trees or store, and output the encoded block to the zip file.
11748		function _tr_flush_block(buf, // input block, or NULL if too old
11749		stored_len, // length of input block
11750		eof // true if this is the last block for a file
11751		) {
11752			var opt_lenb, static_lenb;// opt_len and static_len in bytes
11753			var max_blindex = 0; // index of last bit length code of non zero freq
11754
11755			// Build the Huffman trees unless a stored block is forced
11756			if (level > 0) {
11757				// Construct the literal and distance trees
11758				l_desc.build_tree(that);
11759
11760				d_desc.build_tree(that);
11761
11762				// At this point, opt_len and static_len are the total bit lengths
11763				// of
11764				// the compressed block data, excluding the tree representations.
11765
11766				// Build the bit length tree for the above two trees, and get the
11767				// index
11768				// in bl_order of the last bit length code to send.
11769				max_blindex = build_bl_tree();
11770
11771				// Determine the best encoding. Compute first the block length in
11772				// bytes
11773				opt_lenb = (that.opt_len + 3 + 7) >>> 3;
11774				static_lenb = (that.static_len + 3 + 7) >>> 3;
11775
11776				if (static_lenb <= opt_lenb)
11777					opt_lenb = static_lenb;
11778			} else {
11779				opt_lenb = static_lenb = stored_len + 5; // force a stored block
11780			}
11781
11782			if ((stored_len + 4 <= opt_lenb) && buf != -1) {
11783				// 4: two words for the lengths
11784				// The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
11785				// Otherwise we can't have processed more than WSIZE input bytes
11786				// since
11787				// the last block flush, because compression would have been
11788				// successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
11789				// transform a block into a stored block.
11790				_tr_stored_block(buf, stored_len, eof);
11791			} else if (static_lenb == opt_lenb) {
11792				send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3);
11793				compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
11794			} else {
11795				send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3);
11796				send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1);
11797				compress_block(dyn_ltree, dyn_dtree);
11798			}
11799
11800			// The above check is made mod 2^32, for files larger than 512 MB
11801			// and uLong implemented on 32 bits.
11802
11803			init_block();
11804
11805			if (eof) {
11806				bi_windup();
11807			}
11808		}
11809
11810		function flush_block_only(eof) {
11811			_tr_flush_block(block_start >= 0 ? block_start : -1, strstart - block_start, eof);
11812			block_start = strstart;
11813			strm.flush_pending();
11814		}
11815
11816		// Fill the window when the lookahead becomes insufficient.
11817		// Updates strstart and lookahead.
11818		//
11819		// IN assertion: lookahead < MIN_LOOKAHEAD
11820		// OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
11821		// At least one byte has been read, or avail_in === 0; reads are
11822		// performed for at least two bytes (required for the zip translate_eol
11823		// option -- not supported here).
11824		function fill_window() {
11825			var n, m;
11826			var p;
11827			var more; // Amount of free space at the end of the window.
11828
11829			do {
11830				more = (window_size - lookahead - strstart);
11831
11832				// Deal with !@#$% 64K limit:
11833				if (more === 0 && strstart === 0 && lookahead === 0) {
11834					more = w_size;
11835				} else if (more == -1) {
11836					// Very unlikely, but possible on 16 bit machine if strstart ==
11837					// 0
11838					// and lookahead == 1 (input done one byte at time)
11839					more--;
11840
11841					// If the window is almost full and there is insufficient
11842					// lookahead,
11843					// move the upper half to the lower one to make room in the
11844					// upper half.
11845				} else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) {
11846					window.set(window.subarray(w_size, w_size + w_size), 0);
11847
11848					match_start -= w_size;
11849					strstart -= w_size; // we now have strstart >= MAX_DIST
11850					block_start -= w_size;
11851
11852					// Slide the hash table (could be avoided with 32 bit values
11853					// at the expense of memory usage). We slide even when level ==
11854					// 0
11855					// to keep the hash table consistent if we switch back to level
11856					// > 0
11857					// later. (Using level 0 permanently is not an optimal usage of
11858					// zlib, so we don't care about this pathological case.)
11859
11860					n = hash_size;
11861					p = n;
11862					do {
11863						m = (head[--p] & 0xffff);
11864						head[p] = (m >= w_size ? m - w_size : 0);
11865					} while (--n !== 0);
11866
11867					n = w_size;
11868					p = n;
11869					do {
11870						m = (prev[--p] & 0xffff);
11871						prev[p] = (m >= w_size ? m - w_size : 0);
11872						// If n is not on any hash chain, prev[n] is garbage but
11873						// its value will never be used.
11874					} while (--n !== 0);
11875					more += w_size;
11876				}
11877
11878				if (strm.avail_in === 0)
11879					return;
11880
11881				// If there was no sliding:
11882				// strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
11883				// more == window_size - lookahead - strstart
11884				// => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
11885				// => more >= window_size - 2*WSIZE + 2
11886				// In the BIG_MEM or MMAP case (not yet supported),
11887				// window_size == input_size + MIN_LOOKAHEAD &&
11888				// strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
11889				// Otherwise, window_size == 2*WSIZE so more >= 2.
11890				// If there was sliding, more >= WSIZE. So in all cases, more >= 2.
11891
11892				n = strm.read_buf(window, strstart + lookahead, more);
11893				lookahead += n;
11894
11895				// Initialize the hash value now that we have some input:
11896				if (lookahead >= MIN_MATCH) {
11897					ins_h = window[strstart] & 0xff;
11898					ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
11899				}
11900				// If the whole input has less than MIN_MATCH bytes, ins_h is
11901				// garbage,
11902				// but this is not important since only literal bytes will be
11903				// emitted.
11904			} while (lookahead < MIN_LOOKAHEAD && strm.avail_in !== 0);
11905		}
11906
11907		// Copy without compression as much as possible from the input stream,
11908		// return
11909		// the current block state.
11910		// This function does not insert new strings in the dictionary since
11911		// uncompressible data is probably not useful. This function is used
11912		// only for the level=0 compression option.
11913		// NOTE: this function should be optimized to avoid extra copying from
11914		// window to pending_buf.
11915		function deflate_stored(flush) {
11916			// Stored blocks are limited to 0xffff bytes, pending_buf is limited
11917			// to pending_buf_size, and each stored block has a 5 byte header:
11918
11919			var max_block_size = 0xffff;
11920			var max_start;
11921
11922			if (max_block_size > pending_buf_size - 5) {
11923				max_block_size = pending_buf_size - 5;
11924			}
11925
11926			// Copy as much as possible from input to output:
11927			while (true) {
11928				// Fill the window as much as possible:
11929				if (lookahead <= 1) {
11930					fill_window();
11931					if (lookahead === 0 && flush == Z_NO_FLUSH)
11932						return NeedMore;
11933					if (lookahead === 0)
11934						break; // flush the current block
11935				}
11936
11937				strstart += lookahead;
11938				lookahead = 0;
11939
11940				// Emit a stored block if pending_buf will be full:
11941				max_start = block_start + max_block_size;
11942				if (strstart === 0 || strstart >= max_start) {
11943					// strstart === 0 is possible when wraparound on 16-bit machine
11944					lookahead = (strstart - max_start);
11945					strstart = max_start;
11946
11947					flush_block_only(false);
11948					if (strm.avail_out === 0)
11949						return NeedMore;
11950
11951				}
11952
11953				// Flush if we may have to slide, otherwise block_start may become
11954				// negative and the data will be gone:
11955				if (strstart - block_start >= w_size - MIN_LOOKAHEAD) {
11956					flush_block_only(false);
11957					if (strm.avail_out === 0)
11958						return NeedMore;
11959				}
11960			}
11961
11962			flush_block_only(flush == Z_FINISH);
11963			if (strm.avail_out === 0)
11964				return (flush == Z_FINISH) ? FinishStarted : NeedMore;
11965
11966			return flush == Z_FINISH ? FinishDone : BlockDone;
11967		}
11968
11969		function longest_match(cur_match) {
11970			var chain_length = max_chain_length; // max hash chain length
11971			var scan = strstart; // current string
11972			var match; // matched string
11973			var len; // length of current match
11974			var best_len = prev_length; // best match length so far
11975			var limit = strstart > (w_size - MIN_LOOKAHEAD) ? strstart - (w_size - MIN_LOOKAHEAD) : 0;
11976			var _nice_match = nice_match;
11977
11978			// Stop when cur_match becomes <= limit. To simplify the code,
11979			// we prevent matches with the string of window index 0.
11980
11981			var wmask = w_mask;
11982
11983			var strend = strstart + MAX_MATCH;
11984			var scan_end1 = window[scan + best_len - 1];
11985			var scan_end = window[scan + best_len];
11986
11987			// The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of
11988			// 16.
11989			// It is easy to get rid of this optimization if necessary.
11990
11991			// Do not waste too much time if we already have a good match:
11992			if (prev_length >= good_match) {
11993				chain_length >>= 2;
11994			}
11995
11996			// Do not look for matches beyond the end of the input. This is
11997			// necessary
11998			// to make deflate deterministic.
11999			if (_nice_match > lookahead)
12000				_nice_match = lookahead;
12001
12002			do {
12003				match = cur_match;
12004
12005				// Skip to next match if the match length cannot increase
12006				// or if the match length is less than 2:
12007				if (window[match + best_len] != scan_end || window[match + best_len - 1] != scan_end1 || window[match] != window[scan]
12008						|| window[++match] != window[scan + 1])
12009					continue;
12010
12011				// The check at best_len-1 can be removed because it will be made
12012				// again later. (This heuristic is not always a win.)
12013				// It is not necessary to compare scan[2] and match[2] since they
12014				// are always equal when the other bytes match, given that
12015				// the hash keys are equal and that HASH_BITS >= 8.
12016				scan += 2;
12017				match++;
12018
12019				// We check for insufficient lookahead only every 8th comparison;
12020				// the 256th check will be made at strstart+258.
12021				do {
12022				} while (window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match]
12023						&& window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match]
12024						&& window[++scan] == window[++match] && window[++scan] == window[++match] && scan < strend);
12025
12026				len = MAX_MATCH - (strend - scan);
12027				scan = strend - MAX_MATCH;
12028
12029				if (len > best_len) {
12030					match_start = cur_match;
12031					best_len = len;
12032					if (len >= _nice_match)
12033						break;
12034					scan_end1 = window[scan + best_len - 1];
12035					scan_end = window[scan + best_len];
12036				}
12037
12038			} while ((cur_match = (prev[cur_match & wmask] & 0xffff)) > limit && --chain_length !== 0);
12039
12040			if (best_len <= lookahead)
12041				return best_len;
12042			return lookahead;
12043		}
12044
12045		// Compress as much as possible from the input stream, return the current
12046		// block state.
12047		// This function does not perform lazy evaluation of matches and inserts
12048		// new strings in the dictionary only for unmatched strings or for short
12049		// matches. It is used only for the fast compression options.
12050		function deflate_fast(flush) {
12051			// short hash_head = 0; // head of the hash chain
12052			var hash_head = 0; // head of the hash chain
12053			var bflush; // set if current block must be flushed
12054
12055			while (true) {
12056				// Make sure that we always have enough lookahead, except
12057				// at the end of the input file. We need MAX_MATCH bytes
12058				// for the next match, plus MIN_MATCH bytes to insert the
12059				// string following the next match.
12060				if (lookahead < MIN_LOOKAHEAD) {
12061					fill_window();
12062					if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
12063						return NeedMore;
12064					}
12065					if (lookahead === 0)
12066						break; // flush the current block
12067				}
12068
12069				// Insert the string window[strstart .. strstart+2] in the
12070				// dictionary, and set hash_head to the head of the hash chain:
12071				if (lookahead >= MIN_MATCH) {
12072					ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
12073
12074					// prev[strstart&w_mask]=hash_head=head[ins_h];
12075					hash_head = (head[ins_h] & 0xffff);
12076					prev[strstart & w_mask] = head[ins_h];
12077					head[ins_h] = strstart;
12078				}
12079
12080				// Find the longest match, discarding those <= prev_length.
12081				// At this point we have always match_length < MIN_MATCH
12082
12083				if (hash_head !== 0 && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
12084					// To simplify the code, we prevent matches with the string
12085					// of window index 0 (in particular we have to avoid a match
12086					// of the string with itself at the start of the input file).
12087					if (strategy != Z_HUFFMAN_ONLY) {
12088						match_length = longest_match(hash_head);
12089					}
12090					// longest_match() sets match_start
12091				}
12092				if (match_length >= MIN_MATCH) {
12093					// check_match(strstart, match_start, match_length);
12094
12095					bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH);
12096
12097					lookahead -= match_length;
12098
12099					// Insert new strings in the hash table only if the match length
12100					// is not too large. This saves time but degrades compression.
12101					if (match_length <= max_lazy_match && lookahead >= MIN_MATCH) {
12102						match_length--; // string at strstart already in hash table
12103						do {
12104							strstart++;
12105
12106							ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
12107							// prev[strstart&w_mask]=hash_head=head[ins_h];
12108							hash_head = (head[ins_h] & 0xffff);
12109							prev[strstart & w_mask] = head[ins_h];
12110							head[ins_h] = strstart;
12111
12112							// strstart never exceeds WSIZE-MAX_MATCH, so there are
12113							// always MIN_MATCH bytes ahead.
12114						} while (--match_length !== 0);
12115						strstart++;
12116					} else {
12117						strstart += match_length;
12118						match_length = 0;
12119						ins_h = window[strstart] & 0xff;
12120
12121						ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask;
12122						// If lookahead < MIN_MATCH, ins_h is garbage, but it does
12123						// not
12124						// matter since it will be recomputed at next deflate call.
12125					}
12126				} else {
12127					// No match, output a literal byte
12128
12129					bflush = _tr_tally(0, window[strstart] & 0xff);
12130					lookahead--;
12131					strstart++;
12132				}
12133				if (bflush) {
12134
12135					flush_block_only(false);
12136					if (strm.avail_out === 0)
12137						return NeedMore;
12138				}
12139			}
12140
12141			flush_block_only(flush == Z_FINISH);
12142			if (strm.avail_out === 0) {
12143				if (flush == Z_FINISH)
12144					return FinishStarted;
12145				else
12146					return NeedMore;
12147			}
12148			return flush == Z_FINISH ? FinishDone : BlockDone;
12149		}
12150
12151		// Same as above, but achieves better compression. We use a lazy
12152		// evaluation for matches: a match is finally adopted only if there is
12153		// no better match at the next window position.
12154		function deflate_slow(flush) {
12155			// short hash_head = 0; // head of hash chain
12156			var hash_head = 0; // head of hash chain
12157			var bflush; // set if current block must be flushed
12158			var max_insert;
12159
12160			// Process the input block.
12161			while (true) {
12162				// Make sure that we always have enough lookahead, except
12163				// at the end of the input file. We need MAX_MATCH bytes
12164				// for the next match, plus MIN_MATCH bytes to insert the
12165				// string following the next match.
12166
12167				if (lookahead < MIN_LOOKAHEAD) {
12168					fill_window();
12169					if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
12170						return NeedMore;
12171					}
12172					if (lookahead === 0)
12173						break; // flush the current block
12174				}
12175
12176				// Insert the string window[strstart .. strstart+2] in the
12177				// dictionary, and set hash_head to the head of the hash chain:
12178
12179				if (lookahead >= MIN_MATCH) {
12180					ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
12181					// prev[strstart&w_mask]=hash_head=head[ins_h];
12182					hash_head = (head[ins_h] & 0xffff);
12183					prev[strstart & w_mask] = head[ins_h];
12184					head[ins_h] = strstart;
12185				}
12186
12187				// Find the longest match, discarding those <= prev_length.
12188				prev_length = match_length;
12189				prev_match = match_start;
12190				match_length = MIN_MATCH - 1;
12191
12192				if (hash_head !== 0 && prev_length < max_lazy_match && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) {
12193					// To simplify the code, we prevent matches with the string
12194					// of window index 0 (in particular we have to avoid a match
12195					// of the string with itself at the start of the input file).
12196
12197					if (strategy != Z_HUFFMAN_ONLY) {
12198						match_length = longest_match(hash_head);
12199					}
12200					// longest_match() sets match_start
12201
12202					if (match_length <= 5 && (strategy == Z_FILTERED || (match_length == MIN_MATCH && strstart - match_start > 4096))) {
12203
12204						// If prev_match is also MIN_MATCH, match_start is garbage
12205						// but we will ignore the current match anyway.
12206						match_length = MIN_MATCH - 1;
12207					}
12208				}
12209
12210				// If there was a match at the previous step and the current
12211				// match is not better, output the previous match:
12212				if (prev_length >= MIN_MATCH && match_length <= prev_length) {
12213					max_insert = strstart + lookahead - MIN_MATCH;
12214					// Do not insert strings in hash table beyond this.
12215
12216					// check_match(strstart-1, prev_match, prev_length);
12217
12218					bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH);
12219
12220					// Insert in hash table all strings up to the end of the match.
12221					// strstart-1 and strstart are already inserted. If there is not
12222					// enough lookahead, the last two strings are not inserted in
12223					// the hash table.
12224					lookahead -= prev_length - 1;
12225					prev_length -= 2;
12226					do {
12227						if (++strstart <= max_insert) {
12228							ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
12229							// prev[strstart&w_mask]=hash_head=head[ins_h];
12230							hash_head = (head[ins_h] & 0xffff);
12231							prev[strstart & w_mask] = head[ins_h];
12232							head[ins_h] = strstart;
12233						}
12234					} while (--prev_length !== 0);
12235					match_available = 0;
12236					match_length = MIN_MATCH - 1;
12237					strstart++;
12238
12239					if (bflush) {
12240						flush_block_only(false);
12241						if (strm.avail_out === 0)
12242							return NeedMore;
12243					}
12244				} else if (match_available !== 0) {
12245
12246					// If there was no match at the previous position, output a
12247					// single literal. If there was a match but the current match
12248					// is longer, truncate the previous match to a single literal.
12249
12250					bflush = _tr_tally(0, window[strstart - 1] & 0xff);
12251
12252					if (bflush) {
12253						flush_block_only(false);
12254					}
12255					strstart++;
12256					lookahead--;
12257					if (strm.avail_out === 0)
12258						return NeedMore;
12259				} else {
12260					// There is no previous match to compare with, wait for
12261					// the next step to decide.
12262
12263					match_available = 1;
12264					strstart++;
12265					lookahead--;
12266				}
12267			}
12268
12269			if (match_available !== 0) {
12270				bflush = _tr_tally(0, window[strstart - 1] & 0xff);
12271				match_available = 0;
12272			}
12273			flush_block_only(flush == Z_FINISH);
12274
12275			if (strm.avail_out === 0) {
12276				if (flush == Z_FINISH)
12277					return FinishStarted;
12278				else
12279					return NeedMore;
12280			}
12281
12282			return flush == Z_FINISH ? FinishDone : BlockDone;
12283		}
12284
12285		function deflateReset(strm) {
12286			strm.total_in = strm.total_out = 0;
12287			strm.msg = null; //
12288			
12289			that.pending = 0;
12290			that.pending_out = 0;
12291
12292			status = BUSY_STATE;
12293
12294			last_flush = Z_NO_FLUSH;
12295
12296			tr_init();
12297			lm_init();
12298			return Z_OK;
12299		}
12300
12301		that.deflateInit = function(strm, _level, bits, _method, memLevel, _strategy) {
12302			if (!_method)
12303				_method = Z_DEFLATED;
12304			if (!memLevel)
12305				memLevel = DEF_MEM_LEVEL;
12306			if (!_strategy)
12307				_strategy = Z_DEFAULT_STRATEGY;
12308
12309			// byte[] my_version=ZLIB_VERSION;
12310
12311			//
12312			// if (!version || version[0] != my_version[0]
12313			// || stream_size != sizeof(z_stream)) {
12314			// return Z_VERSION_ERROR;
12315			// }
12316
12317			strm.msg = null;
12318
12319			if (_level == Z_DEFAULT_COMPRESSION)
12320				_level = 6;
12321
12322			if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || _method != Z_DEFLATED || bits < 9 || bits > 15 || _level < 0 || _level > 9 || _strategy < 0
12323					|| _strategy > Z_HUFFMAN_ONLY) {
12324				return Z_STREAM_ERROR;
12325			}
12326
12327			strm.dstate = that;
12328
12329			w_bits = bits;
12330			w_size = 1 << w_bits;
12331			w_mask = w_size - 1;
12332
12333			hash_bits = memLevel + 7;
12334			hash_size = 1 << hash_bits;
12335			hash_mask = hash_size - 1;
12336			hash_shift = Math.floor((hash_bits + MIN_MATCH - 1) / MIN_MATCH);
12337
12338			window = new Uint8Array(w_size * 2);
12339			prev = [];
12340			head = [];
12341
12342			lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
12343
12344			// We overlay pending_buf and d_buf+l_buf. This works since the average
12345			// output size for (length,distance) codes is <= 24 bits.
12346			that.pending_buf = new Uint8Array(lit_bufsize * 4);
12347			pending_buf_size = lit_bufsize * 4;
12348
12349			d_buf = Math.floor(lit_bufsize / 2);
12350			l_buf = (1 + 2) * lit_bufsize;
12351
12352			level = _level;
12353
12354			strategy = _strategy;
12355			method = _method & 0xff;
12356
12357			return deflateReset(strm);
12358		};
12359
12360		that.deflateEnd = function() {
12361			if (status != INIT_STATE && status != BUSY_STATE && status != FINISH_STATE) {
12362				return Z_STREAM_ERROR;
12363			}
12364			// Deallocate in reverse order of allocations:
12365			that.pending_buf = null;
12366			head = null;
12367			prev = null;
12368			window = null;
12369			// free
12370			that.dstate = null;
12371			return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
12372		};
12373
12374		that.deflateParams = function(strm, _level, _strategy) {
12375			var err = Z_OK;
12376
12377			if (_level == Z_DEFAULT_COMPRESSION) {
12378				_level = 6;
12379			}
12380			if (_level < 0 || _level > 9 || _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
12381				return Z_STREAM_ERROR;
12382			}
12383
12384			if (config_table[level].func != config_table[_level].func && strm.total_in !== 0) {
12385				// Flush the last buffer:
12386				err = strm.deflate(Z_PARTIAL_FLUSH);
12387			}
12388
12389			if (level != _level) {
12390				level = _level;
12391				max_lazy_match = config_table[level].max_lazy;
12392				good_match = config_table[level].good_length;
12393				nice_match = config_table[level].nice_length;
12394				max_chain_length = config_table[level].max_chain;
12395			}
12396			strategy = _strategy;
12397			return err;
12398		};
12399
12400		that.deflateSetDictionary = function(strm, dictionary, dictLength) {
12401			var length = dictLength;
12402			var n, index = 0;
12403
12404			if (!dictionary || status != INIT_STATE)
12405				return Z_STREAM_ERROR;
12406
12407			if (length < MIN_MATCH)
12408				return Z_OK;
12409			if (length > w_size - MIN_LOOKAHEAD) {
12410				length = w_size - MIN_LOOKAHEAD;
12411				index = dictLength - length; // use the tail of the dictionary
12412			}
12413			window.set(dictionary.subarray(index, index + length), 0);
12414
12415			strstart = length;
12416			block_start = length;
12417
12418			// Insert all strings in the hash table (except for the last two bytes).
12419			// s->lookahead stays null, so s->ins_h will be recomputed at the next
12420			// call of fill_window.
12421
12422			ins_h = window[0] & 0xff;
12423			ins_h = (((ins_h) << hash_shift) ^ (window[1] & 0xff)) & hash_mask;
12424
12425			for (n = 0; n <= length - MIN_MATCH; n++) {
12426				ins_h = (((ins_h) << hash_shift) ^ (window[(n) + (MIN_MATCH - 1)] & 0xff)) & hash_mask;
12427				prev[n & w_mask] = head[ins_h];
12428				head[ins_h] = n;
12429			}
12430			return Z_OK;
12431		};
12432
12433		that.deflate = function(_strm, flush) {
12434			var i, header, level_flags, old_flush, bstate;
12435
12436			if (flush > Z_FINISH || flush < 0) {
12437				return Z_STREAM_ERROR;
12438			}
12439
12440			if (!_strm.next_out || (!_strm.next_in && _strm.avail_in !== 0) || (status == FINISH_STATE && flush != Z_FINISH)) {
12441				_strm.msg = z_errmsg[Z_NEED_DICT - (Z_STREAM_ERROR)];
12442				return Z_STREAM_ERROR;
12443			}
12444			if (_strm.avail_out === 0) {
12445				_strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
12446				return Z_BUF_ERROR;
12447			}
12448
12449			strm = _strm; // just in case
12450			old_flush = last_flush;
12451			last_flush = flush;
12452
12453			// Write the zlib header
12454			if (status == INIT_STATE) {
12455				header = (Z_DEFLATED + ((w_bits - 8) << 4)) << 8;
12456				level_flags = ((level - 1) & 0xff) >> 1;
12457
12458				if (level_flags > 3)
12459					level_flags = 3;
12460				header |= (level_flags << 6);
12461				if (strstart !== 0)
12462					header |= PRESET_DICT;
12463				header += 31 - (header % 31);
12464
12465				status = BUSY_STATE;
12466				putShortMSB(header);
12467			}
12468
12469			// Flush as much pending output as possible
12470			if (that.pending !== 0) {
12471				strm.flush_pending();
12472				if (strm.avail_out === 0) {
12473					// console.log(" avail_out==0");
12474					// Since avail_out is 0, deflate will be called again with
12475					// more output space, but possibly with both pending and
12476					// avail_in equal to zero. There won't be anything to do,
12477					// but this is not an error situation so make sure we
12478					// return OK instead of BUF_ERROR at next call of deflate:
12479					last_flush = -1;
12480					return Z_OK;
12481				}
12482
12483				// Make sure there is something to do and avoid duplicate
12484				// consecutive
12485				// flushes. For repeated and useless calls with Z_FINISH, we keep
12486				// returning Z_STREAM_END instead of Z_BUFF_ERROR.
12487			} else if (strm.avail_in === 0 && flush <= old_flush && flush != Z_FINISH) {
12488				strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
12489				return Z_BUF_ERROR;
12490			}
12491
12492			// User must not provide more input after the first FINISH:
12493			if (status == FINISH_STATE && strm.avail_in !== 0) {
12494				_strm.msg = z_errmsg[Z_NEED_DICT - (Z_BUF_ERROR)];
12495				return Z_BUF_ERROR;
12496			}
12497
12498			// Start a new block or continue the current one.
12499			if (strm.avail_in !== 0 || lookahead !== 0 || (flush != Z_NO_FLUSH && status != FINISH_STATE)) {
12500				bstate = -1;
12501				switch (config_table[level].func) {
12502				case STORED:
12503					bstate = deflate_stored(flush);
12504					break;
12505				case FAST:
12506					bstate = deflate_fast(flush);
12507					break;
12508				case SLOW:
12509					bstate = deflate_slow(flush);
12510					break;
12511				default:
12512				}
12513
12514				if (bstate == FinishStarted || bstate == FinishDone) {
12515					status = FINISH_STATE;
12516				}
12517				if (bstate == NeedMore || bstate == FinishStarted) {
12518					if (strm.avail_out === 0) {
12519						last_flush = -1; // avoid BUF_ERROR next call, see above
12520					}
12521					return Z_OK;
12522					// If flush != Z_NO_FLUSH && avail_out === 0, the next call
12523					// of deflate should use the same flush parameter to make sure
12524					// that the flush is complete. So we don't have to output an
12525					// empty block here, this will be done at next call. This also
12526					// ensures that for a very small output buffer, we emit at most
12527					// one empty block.
12528				}
12529
12530				if (bstate == BlockDone) {
12531					if (flush == Z_PARTIAL_FLUSH) {
12532						_tr_align();
12533					} else { // FULL_FLUSH or SYNC_FLUSH
12534						_tr_stored_block(0, 0, false);
12535						// For a full flush, this empty block will be recognized
12536						// as a special marker by inflate_sync().
12537						if (flush == Z_FULL_FLUSH) {
12538							// state.head[s.hash_size-1]=0;
12539							for (i = 0; i < hash_size/*-1*/; i++)
12540								// forget history
12541								head[i] = 0;
12542						}
12543					}
12544					strm.flush_pending();
12545					if (strm.avail_out === 0) {
12546						last_flush = -1; // avoid BUF_ERROR at next call, see above
12547						return Z_OK;
12548					}
12549				}
12550			}
12551
12552			if (flush != Z_FINISH)
12553				return Z_OK;
12554			return Z_STREAM_END;
12555		};
12556	}
12557
12558	// ZStream
12559
12560	function ZStream() {
12561		var that = this;
12562		that.next_in_index = 0;
12563		that.next_out_index = 0;
12564		// that.next_in; // next input byte
12565		that.avail_in = 0; // number of bytes available at next_in
12566		that.total_in = 0; // total nb of input bytes read so far
12567		// that.next_out; // next output byte should be put there
12568		that.avail_out = 0; // remaining free space at next_out
12569		that.total_out = 0; // total nb of bytes output so far
12570		// that.msg;
12571		// that.dstate;
12572	}
12573
12574	ZStream.prototype = {
12575		deflateInit : function(level, bits) {
12576			var that = this;
12577			that.dstate = new Deflate();
12578			if (!bits)
12579				bits = MAX_BITS;
12580			return that.dstate.deflateInit(that, level, bits);
12581		},
12582
12583		deflate : function(flush) {
12584			var that = this;
12585			if (!that.dstate) {
12586				return Z_STREAM_ERROR;
12587			}
12588			return that.dstate.deflate(that, flush);
12589		},
12590
12591		deflateEnd : function() {
12592			var that = this;
12593			if (!that.dstate)
12594				return Z_STREAM_ERROR;
12595			var ret = that.dstate.deflateEnd();
12596			that.dstate = null;
12597			return ret;
12598		},
12599
12600		deflateParams : function(level, strategy) {
12601			var that = this;
12602			if (!that.dstate)
12603				return Z_STREAM_ERROR;
12604			return that.dstate.deflateParams(that, level, strategy);
12605		},
12606
12607		deflateSetDictionary : function(dictionary, dictLength) {
12608			var that = this;
12609			if (!that.dstate)
12610				return Z_STREAM_ERROR;
12611			return that.dstate.deflateSetDictionary(that, dictionary, dictLength);
12612		},
12613
12614		// Read a new buffer from the current input stream, update the
12615		// total number of bytes read. All deflate() input goes through
12616		// this function so some applications may wish to modify it to avoid
12617		// allocating a large strm->next_in buffer and copying from it.
12618		// (See also flush_pending()).
12619		read_buf : function(buf, start, size) {
12620			var that = this;
12621			var len = that.avail_in;
12622			if (len > size)
12623				len = size;
12624			if (len === 0)
12625				return 0;
12626			that.avail_in -= len;
12627			buf.set(that.next_in.subarray(that.next_in_index, that.next_in_index + len), start);
12628			that.next_in_index += len;
12629			that.total_in += len;
12630			return len;
12631		},
12632
12633		// Flush as much pending output as possible. All deflate() output goes
12634		// through this function so some applications may wish to modify it
12635		// to avoid allocating a large strm->next_out buffer and copying into it.
12636		// (See also read_buf()).
12637		flush_pending : function() {
12638			var that = this;
12639			var len = that.dstate.pending;
12640
12641			if (len > that.avail_out)
12642				len = that.avail_out;
12643			if (len === 0)
12644				return;
12645
12646			// if (that.dstate.pending_buf.length <= that.dstate.pending_out || that.next_out.length <= that.next_out_index
12647			// || that.dstate.pending_buf.length < (that.dstate.pending_out + len) || that.next_out.length < (that.next_out_index +
12648			// len)) {
12649			// console.log(that.dstate.pending_buf.length + ", " + that.dstate.pending_out + ", " + that.next_out.length + ", " +
12650			// that.next_out_index + ", " + len);
12651			// console.log("avail_out=" + that.avail_out);
12652			// }
12653
12654			that.next_out.set(that.dstate.pending_buf.subarray(that.dstate.pending_out, that.dstate.pending_out + len), that.next_out_index);
12655
12656			that.next_out_index += len;
12657			that.dstate.pending_out += len;
12658			that.total_out += len;
12659			that.avail_out -= len;
12660			that.dstate.pending -= len;
12661			if (that.dstate.pending === 0) {
12662				that.dstate.pending_out = 0;
12663			}
12664		}
12665	};
12666
12667	// Deflater
12668
12669	return function Deflater(level) {
12670		var that = this;
12671		var z = new ZStream();
12672		var bufsize = 512;
12673		var flush = Z_NO_FLUSH;
12674		var buf = new Uint8Array(bufsize);
12675
12676		if (typeof level == "undefined")
12677			level = Z_DEFAULT_COMPRESSION;
12678		z.deflateInit(level);
12679		z.next_out = buf;
12680
12681		that.append = function(data, onprogress) {
12682			var err, buffers = [], lastIndex = 0, bufferIndex = 0, bufferSize = 0, array;
12683			if (!data.length)
12684				return;
12685			z.next_in_index = 0;
12686			z.next_in = data;
12687			z.avail_in = data.length;
12688			do {
12689				z.next_out_index = 0;
12690				z.avail_out = bufsize;
12691				err = z.deflate(flush);
12692				if (err != Z_OK)
12693					throw "deflating: " + z.msg;
12694				if (z.next_out_index)
12695					if (z.next_out_index == bufsize)
12696						buffers.push(new Uint8Array(buf));
12697					else
12698						buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
12699				bufferSize += z.next_out_index;
12700				if (onprogress && z.next_in_index > 0 && z.next_in_index != lastIndex) {
12701					onprogress(z.next_in_index);
12702					lastIndex = z.next_in_index;
12703				}
12704			} while (z.avail_in > 0 || z.avail_out === 0);
12705			array = new Uint8Array(bufferSize);
12706			buffers.forEach(function(chunk) {
12707				array.set(chunk, bufferIndex);
12708				bufferIndex += chunk.length;
12709			});
12710			return array;
12711		};
12712		that.flush = function() {
12713			var err, buffers = [], bufferIndex = 0, bufferSize = 0, array;
12714			do {
12715				z.next_out_index = 0;
12716				z.avail_out = bufsize;
12717				err = z.deflate(Z_FINISH);
12718				if (err != Z_STREAM_END && err != Z_OK)
12719					throw "deflating: " + z.msg;
12720				if (bufsize - z.avail_out > 0)
12721					buffers.push(new Uint8Array(buf.subarray(0, z.next_out_index)));
12722				bufferSize += z.next_out_index;
12723			} while (z.avail_in > 0 || z.avail_out === 0);
12724			z.deflateEnd();
12725			array = new Uint8Array(bufferSize);
12726			buffers.forEach(function(chunk) {
12727				array.set(chunk, bufferIndex);
12728				bufferIndex += chunk.length;
12729			});
12730			return array;
12731		};
12732	};
12733})(undefined);
12734
12735
12736/*
12737  html2canvas 0.5.0-beta3 <http://html2canvas.hertzen.com>
12738  Copyright (c) 2016 Niklas von Hertzen
12739
12740  Released under  License
12741*/
12742
12743!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){
12744(function (global){
12745/*! http://mths.be/punycode v1.2.4 by @mathias */
12746(function(root) {
12747
12748	/** Detect free variables */
12749	var freeExports = typeof exports == 'object' && exports;
12750	var freeModule = typeof module == 'object' && module &&
12751		module.exports == freeExports && module;
12752	var freeGlobal = typeof global == 'object' && global;
12753	if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
12754		root = freeGlobal;
12755	}
12756
12757	/**
12758	 * The `punycode` object.
12759	 * @name punycode
12760	 * @type Object
12761	 */
12762	var punycode,
12763
12764	/** Highest positive signed 32-bit float value */
12765	maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
12766
12767	/** Bootstring parameters */
12768	base = 36,
12769	tMin = 1,
12770	tMax = 26,
12771	skew = 38,
12772	damp = 700,
12773	initialBias = 72,
12774	initialN = 128, // 0x80
12775	delimiter = '-', // '\x2D'
12776
12777	/** Regular expressions */
12778	regexPunycode = /^xn--/,
12779	regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars
12780	regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators
12781
12782	/** Error messages */
12783	errors = {
12784		'overflow': 'Overflow: input needs wider integers to process',
12785		'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
12786		'invalid-input': 'Invalid input'
12787	},
12788
12789	/** Convenience shortcuts */
12790	baseMinusTMin = base - tMin,
12791	floor = Math.floor,
12792	stringFromCharCode = String.fromCharCode,
12793
12794	/** Temporary variable */
12795	key;
12796
12797	/*--------------------------------------------------------------------------*/
12798
12799	/**
12800	 * A generic error utility function.
12801	 * @private
12802	 * @param {String} type The error type.
12803	 * @returns {Error} Throws a `RangeError` with the applicable error message.
12804	 */
12805	function error(type) {
12806		throw RangeError(errors[type]);
12807	}
12808
12809	/**
12810	 * A generic `Array#map` utility function.
12811	 * @private
12812	 * @param {Array} array The array to iterate over.
12813	 * @param {Function} callback The function that gets called for every array
12814	 * item.
12815	 * @returns {Array} A new array of values returned by the callback function.
12816	 */
12817	function map(array, fn) {
12818		var length = array.length;
12819		while (length--) {
12820			array[length] = fn(array[length]);
12821		}
12822		return array;
12823	}
12824
12825	/**
12826	 * A simple `Array#map`-like wrapper to work with domain name strings.
12827	 * @private
12828	 * @param {String} domain The domain name.
12829	 * @param {Function} callback The function that gets called for every
12830	 * character.
12831	 * @returns {Array} A new string of characters returned by the callback
12832	 * function.
12833	 */
12834	function mapDomain(string, fn) {
12835		return map(string.split(regexSeparators), fn).join('.');
12836	}
12837
12838	/**
12839	 * Creates an array containing the numeric code points of each Unicode
12840	 * character in the string. While JavaScript uses UCS-2 internally,
12841	 * this function will convert a pair of surrogate halves (each of which
12842	 * UCS-2 exposes as separate characters) into a single code point,
12843	 * matching UTF-16.
12844	 * @see `punycode.ucs2.encode`
12845	 * @see <http://mathiasbynens.be/notes/javascript-encoding>
12846	 * @memberOf punycode.ucs2
12847	 * @name decode
12848	 * @param {String} string The Unicode input string (UCS-2).
12849	 * @returns {Array} The new array of code points.
12850	 */
12851	function ucs2decode(string) {
12852		var output = [],
12853		    counter = 0,
12854		    length = string.length,
12855		    value,
12856		    extra;
12857		while (counter < length) {
12858			value = string.charCodeAt(counter++);
12859			if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
12860				// high surrogate, and there is a next character
12861				extra = string.charCodeAt(counter++);
12862				if ((extra & 0xFC00) == 0xDC00) { // low surrogate
vendor: 9,396 bytes, lines 12863-13207
12863					output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
12864				} else {
12865					// unmatched surrogate; only append this code unit, in case the next
12866					// code unit is the high surrogate of a surrogate pair
12867					output.push(value);
12868					counter--;
12869				}
12870			} else {
12871				output.push(value);
12872			}
12873		}
12874		return output;
12875	}
12876
12877	/**
12878	 * Creates a string based on an array of numeric code points.
12879	 * @see `punycode.ucs2.decode`
12880	 * @memberOf punycode.ucs2
12881	 * @name encode
12882	 * @param {Array} codePoints The array of numeric code points.
12883	 * @returns {String} The new Unicode string (UCS-2).
12884	 */
12885	function ucs2encode(array) {
12886		return map(array, function(value) {
12887			var output = '';
12888			if (value > 0xFFFF) {
12889				value -= 0x10000;
12890				output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
12891				value = 0xDC00 | value & 0x3FF;
12892			}
12893			output += stringFromCharCode(value);
12894			return output;
12895		}).join('');
12896	}
12897
12898	/**
12899	 * Converts a basic code point into a digit/integer.
12900	 * @see `digitToBasic()`
12901	 * @private
12902	 * @param {Number} codePoint The basic numeric code point value.
12903	 * @returns {Number} The numeric value of a basic code point (for use in
12904	 * representing integers) in the range `0` to `base - 1`, or `base` if
12905	 * the code point does not represent a value.
12906	 */
12907	function basicToDigit(codePoint) {
12908		if (codePoint - 48 < 10) {
12909			return codePoint - 22;
12910		}
12911		if (codePoint - 65 < 26) {
12912			return codePoint - 65;
12913		}
12914		if (codePoint - 97 < 26) {
12915			return codePoint - 97;
12916		}
12917		return base;
12918	}
12919
12920	/**
12921	 * Converts a digit/integer into a basic code point.
12922	 * @see `basicToDigit()`
12923	 * @private
12924	 * @param {Number} digit The numeric value of a basic code point.
12925	 * @returns {Number} The basic code point whose value (when used for
12926	 * representing integers) is `digit`, which needs to be in the range
12927	 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
12928	 * used; else, the lowercase form is used. The behavior is undefined
12929	 * if `flag` is non-zero and `digit` has no uppercase form.
12930	 */
12931	function digitToBasic(digit, flag) {
12932		//  0..25 map to ASCII a..z or A..Z
12933		// 26..35 map to ASCII 0..9
12934		return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
12935	}
12936
12937	/**
12938	 * Bias adaptation function as per section 3.4 of RFC 3492.
12939	 * http://tools.ietf.org/html/rfc3492#section-3.4
12940	 * @private
12941	 */
12942	function adapt(delta, numPoints, firstTime) {
12943		var k = 0;
12944		delta = firstTime ? floor(delta / damp) : delta >> 1;
12945		delta += floor(delta / numPoints);
12946		for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
12947			delta = floor(delta / baseMinusTMin);
12948		}
12949		return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
12950	}
12951
12952	/**
12953	 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
12954	 * symbols.
12955	 * @memberOf punycode
12956	 * @param {String} input The Punycode string of ASCII-only symbols.
12957	 * @returns {String} The resulting string of Unicode symbols.
12958	 */
12959	function decode(input) {
12960		// Don't use UCS-2
12961		var output = [],
12962		    inputLength = input.length,
12963		    out,
12964		    i = 0,
12965		    n = initialN,
12966		    bias = initialBias,
12967		    basic,
12968		    j,
12969		    index,
12970		    oldi,
12971		    w,
12972		    k,
12973		    digit,
12974		    t,
12975		    /** Cached calculation results */
12976		    baseMinusT;
12977
12978		// Handle the basic code points: let `basic` be the number of input code
12979		// points before the last delimiter, or `0` if there is none, then copy
12980		// the first basic code points to the output.
12981
12982		basic = input.lastIndexOf(delimiter);
12983		if (basic < 0) {
12984			basic = 0;
12985		}
12986
12987		for (j = 0; j < basic; ++j) {
12988			// if it's not a basic code point
12989			if (input.charCodeAt(j) >= 0x80) {
12990				error('not-basic');
12991			}
12992			output.push(input.charCodeAt(j));
12993		}
12994
12995		// Main decoding loop: start just after the last delimiter if any basic code
12996		// points were copied; start at the beginning otherwise.
12997
12998		for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
12999
13000			// `index` is the index of the next character to be consumed.
13001			// Decode a generalized variable-length integer into `delta`,
13002			// which gets added to `i`. The overflow checking is easier
13003			// if we increase `i` as we go, then subtract off its starting
13004			// value at the end to obtain `delta`.
13005			for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
13006
13007				if (index >= inputLength) {
13008					error('invalid-input');
13009				}
13010
13011				digit = basicToDigit(input.charCodeAt(index++));
13012
13013				if (digit >= base || digit > floor((maxInt - i) / w)) {
13014					error('overflow');
13015				}
13016
13017				i += digit * w;
13018				t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
13019
13020				if (digit < t) {
13021					break;
13022				}
13023
13024				baseMinusT = base - t;
13025				if (w > floor(maxInt / baseMinusT)) {
13026					error('overflow');
13027				}
13028
13029				w *= baseMinusT;
13030
13031			}
13032
13033			out = output.length + 1;
13034			bias = adapt(i - oldi, out, oldi == 0);
13035
13036			// `i` was supposed to wrap around from `out` to `0`,
13037			// incrementing `n` each time, so we'll fix that now:
13038			if (floor(i / out) > maxInt - n) {
13039				error('overflow');
13040			}
13041
13042			n += floor(i / out);
13043			i %= out;
13044
13045			// Insert `n` at position `i` of the output
13046			output.splice(i++, 0, n);
13047
13048		}
13049
13050		return ucs2encode(output);
13051	}
13052
13053	/**
13054	 * Converts a string of Unicode symbols to a Punycode string of ASCII-only
13055	 * symbols.
13056	 * @memberOf punycode
13057	 * @param {String} input The string of Unicode symbols.
13058	 * @returns {String} The resulting Punycode string of ASCII-only symbols.
13059	 */
13060	function encode(input) {
13061		var n,
13062		    delta,
13063		    handledCPCount,
13064		    basicLength,
13065		    bias,
13066		    j,
13067		    m,
13068		    q,
13069		    k,
13070		    t,
13071		    currentValue,
13072		    output = [],
13073		    /** `inputLength` will hold the number of code points in `input`. */
13074		    inputLength,
13075		    /** Cached calculation results */
13076		    handledCPCountPlusOne,
13077		    baseMinusT,
13078		    qMinusT;
13079
13080		// Convert the input in UCS-2 to Unicode
13081		input = ucs2decode(input);
13082
13083		// Cache the length
13084		inputLength = input.length;
13085
13086		// Initialize the state
13087		n = initialN;
13088		delta = 0;
13089		bias = initialBias;
13090
13091		// Handle the basic code points
13092		for (j = 0; j < inputLength; ++j) {
13093			currentValue = input[j];
13094			if (currentValue < 0x80) {
13095				output.push(stringFromCharCode(currentValue));
13096			}
13097		}
13098
13099		handledCPCount = basicLength = output.length;
13100
13101		// `handledCPCount` is the number of code points that have been handled;
13102		// `basicLength` is the number of basic code points.
13103
13104		// Finish the basic string - if it is not empty - with a delimiter
13105		if (basicLength) {
13106			output.push(delimiter);
13107		}
13108
13109		// Main encoding loop:
13110		while (handledCPCount < inputLength) {
13111
13112			// All non-basic code points < n have been handled already. Find the next
13113			// larger one:
13114			for (m = maxInt, j = 0; j < inputLength; ++j) {
13115				currentValue = input[j];
13116				if (currentValue >= n && currentValue < m) {
13117					m = currentValue;
13118				}
13119			}
13120
13121			// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
13122			// but guard against overflow
13123			handledCPCountPlusOne = handledCPCount + 1;
13124			if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
13125				error('overflow');
13126			}
13127
13128			delta += (m - n) * handledCPCountPlusOne;
13129			n = m;
13130
13131			for (j = 0; j < inputLength; ++j) {
13132				currentValue = input[j];
13133
13134				if (currentValue < n && ++delta > maxInt) {
13135					error('overflow');
13136				}
13137
13138				if (currentValue == n) {
13139					// Represent delta as a generalized variable-length integer
13140					for (q = delta, k = base; /* no condition */; k += base) {
13141						t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
13142						if (q < t) {
13143							break;
13144						}
13145						qMinusT = q - t;
13146						baseMinusT = base - t;
13147						output.push(
13148							stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
13149						);
13150						q = floor(qMinusT / baseMinusT);
13151					}
13152
13153					output.push(stringFromCharCode(digitToBasic(q, 0)));
13154					bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
13155					delta = 0;
13156					++handledCPCount;
13157				}
13158			}
13159
13160			++delta;
13161			++n;
13162
13163		}
13164		return output.join('');
13165	}
13166
13167	/**
13168	 * Converts a Punycode string representing a domain name to Unicode. Only the
13169	 * Punycoded parts of the domain name will be converted, i.e. it doesn't
13170	 * matter if you call it on a string that has already been converted to
13171	 * Unicode.
13172	 * @memberOf punycode
13173	 * @param {String} domain The Punycode domain name to convert to Unicode.
13174	 * @returns {String} The Unicode representation of the given Punycode
13175	 * string.
13176	 */
13177	function toUnicode(domain) {
13178		return mapDomain(domain, function(string) {
13179			return regexPunycode.test(string)
13180				? decode(string.slice(4).toLowerCase())
13181				: string;
13182		});
13183	}
13184
13185	/**
13186	 * Converts a Unicode string representing a domain name to Punycode. Only the
13187	 * non-ASCII parts of the domain name will be converted, i.e. it doesn't
13188	 * matter if you call it with a domain that's already in ASCII.
13189	 * @memberOf punycode
13190	 * @param {String} domain The domain name to convert, as a Unicode string.
13191	 * @returns {String} The Punycode representation of the given domain name.
13192	 */
13193	function toASCII(domain) {
13194		return mapDomain(domain, function(string) {
13195			return regexNonASCII.test(string)
13196				? 'xn--' + encode(string)
13197				: string;
13198		});
13199	}
13200
13201	/*--------------------------------------------------------------------------*/
13202
13203	/** Define the public API */
13204	punycode = {
13205		/**
13206		 * A string representing the current Punycode.js version number.
13207		 * @memberOf punycode
13208		 * @type String
13209		 */
13210		'version': '1.2.4',
13211		/**
13212		 * An object of methods to convert from JavaScript's internal character
13213		 * representation (UCS-2) to Unicode code points, and back.
13214		 * @see <http://mathiasbynens.be/notes/javascript-encoding>
13215		 * @memberOf punycode
13216		 * @type Object
13217		 */
13218		'ucs2': {
13219			'decode': ucs2decode,
13220			'encode': ucs2encode
13221		},
13222		'decode': decode,
13223		'encode': encode,
13224		'toASCII': toASCII,
13225		'toUnicode': toUnicode
13226	};
13227
13228	/** Expose `punycode` */
13229	// Some AMD build optimizers, like r.js, check for specific condition patterns
13230	// like the following:
13231	if (
13232		typeof define == 'function' &&
13233		typeof define.amd == 'object' &&
13234		define.amd
13235	) {
13236		define('punycode', function() {
13237			return punycode;
13238		});
13239	} else if (freeExports && !freeExports.nodeType) {
13240		if (freeModule) { // in Node.js or RingoJS v0.8.0+
13241			freeModule.exports = punycode;
13242		} else { // in Narwhal or RingoJS v0.7.0-
13243			for (key in punycode) {
13244				punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
13245			}
13246		}
13247	} else { // in Rhino or a web browser
13248		root.punycode = punycode;
13249	}
13250
13251}(this));
13252
13253}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {});
13254},{}],2:[function(_dereq_,module,exports){
13255var log = _dereq_('./log');
13256
13257function restoreOwnerScroll(ownerDocument, x, y) {
13258    if (ownerDocument.defaultView && (x !== ownerDocument.defaultView.pageXOffset || y !== ownerDocument.defaultView.pageYOffset)) {
13259        ownerDocument.defaultView.scrollTo(x, y);
13260    }
13261}
13262
13263function cloneCanvasContents(canvas, clonedCanvas) {
13264    try {
13265        if (clonedCanvas) {
13266            clonedCanvas.width = canvas.width;
13267            clonedCanvas.height = canvas.height;
13268            clonedCanvas.getContext("2d").putImageData(canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height), 0, 0);
13269        }
13270    } catch(e) {
13271        log("Unable to copy canvas content from", canvas, e);
13272    }
13273}
13274
13275function cloneNode(node, javascriptEnabled) {
13276    var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);
13277
13278    var child = node.firstChild;
13279    while(child) {
13280        if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
13281            clone.appendChild(cloneNode(child, javascriptEnabled));
13282        }
13283        child = child.nextSibling;
13284    }
13285
13286    if (node.nodeType === 1) {
13287        clone._scrollTop = node.scrollTop;
13288        clone._scrollLeft = node.scrollLeft;
13289        if (node.nodeName === "CANVAS") {
13290            cloneCanvasContents(node, clone);
13291        } else if (node.nodeName === "TEXTAREA" || node.nodeName === "SELECT") {
13292            clone.value = node.value;
13293        }
13294    }
13295
13296    return clone;
13297}
13298
13299function initNode(node) {
13300    if (node.nodeType === 1) {
13301        node.scrollTop = node._scrollTop;
13302        node.scrollLeft = node._scrollLeft;
13303
13304        var child = node.firstChild;
13305        while(child) {
13306            initNode(child);
13307            child = child.nextSibling;
13308        }
13309    }
13310}
13311
13312module.exports = function(ownerDocument, containerDocument, width, height, options, x ,y) {
13313    var documentElement = cloneNode(ownerDocument.documentElement, options.javascriptEnabled);
13314    var container = containerDocument.createElement("iframe");
13315
13316    container.className = "html2canvas-container";
13317    container.style.visibility = "hidden";
13318    container.style.position = "fixed";
13319    container.style.left = "-10000px";
13320    container.style.top = "0px";
13321    container.style.border = "0";
13322    container.width = width;
13323    container.height = height;
13324    container.scrolling = "no"; // ios won't scroll without it
13325    containerDocument.body.appendChild(container);
13326
13327    return new Promise(function(resolve) {
13328        var documentClone = container.contentWindow.document;
13329
13330        /* Chrome doesn't detect relative background-images assigned in inline <style> sheets when fetched through getComputedStyle
13331         if window url is about:blank, we can assign the url to current by writing onto the document
13332         */
13333        container.contentWindow.onload = container.onload = function() {
13334            var interval = setInterval(function() {
13335                if (documentClone.body.childNodes.length > 0) {
13336                    initNode(documentClone.documentElement);
13337                    clearInterval(interval);
13338                    if (options.type === "view") {
13339                        container.contentWindow.scrollTo(x, y);
13340                        if ((/(iPad|iPhone|iPod)/g).test(navigator.userAgent) && (container.contentWindow.scrollY !== y || container.contentWindow.scrollX !== x)) {
13341                            documentClone.documentElement.style.top = (-y) + "px";
13342                            documentClone.documentElement.style.left = (-x) + "px";
13343                            documentClone.documentElement.style.position = 'absolute';
13344                        }
13345                    }
13346                    resolve(container);
13347                }
13348            }, 50);
13349        };
13350
13351        documentClone.open();
13352        documentClone.write("<!DOCTYPE html><html></html>");
13353        // Chrome scrolls the parent document for some reason after the write to the cloned window???
13354        restoreOwnerScroll(ownerDocument, x, y);
13355        documentClone.replaceChild(documentClone.adoptNode(documentElement), documentClone.documentElement);
13356        documentClone.close();
13357    });
13358};
13359
13360},{"./log":13}],3:[function(_dereq_,module,exports){
13361// http://dev.w3.org/csswg/css-color/
13362
13363function Color(value) {
13364    this.r = 0;
13365    this.g = 0;
13366    this.b = 0;
13367    this.a = null;
13368    var result = this.fromArray(value) ||
13369        this.namedColor(value) ||
13370        this.rgb(value) ||
13371        this.rgba(value) ||
13372        this.hex6(value) ||
13373        this.hex3(value);
13374}
13375
13376Color.prototype.darken = function(amount) {
13377    var a = 1 - amount;
13378    return  new Color([
13379        Math.round(this.r * a),
13380        Math.round(this.g * a),
13381        Math.round(this.b * a),
13382        this.a
13383    ]);
13384};
13385
13386Color.prototype.isTransparent = function() {
13387    return this.a === 0;
13388};
13389
13390Color.prototype.isBlack = function() {
13391    return this.r === 0 && this.g === 0 && this.b === 0;
13392};
13393
13394Color.prototype.fromArray = function(array) {
13395    if (Array.isArray(array)) {
13396        this.r = Math.min(array[0], 255);
13397        this.g = Math.min(array[1], 255);
13398        this.b = Math.min(array[2], 255);
13399        if (array.length > 3) {
13400            this.a = array[3];
13401        }
13402    }
13403
13404    return (Array.isArray(array));
13405};
13406
13407var _hex3 = /^#([a-f0-9]{3})$/i;
13408
13409Color.prototype.hex3 = function(value) {
13410    var match = null;
13411    if ((match = value.match(_hex3)) !== null) {
13412        this.r = parseInt(match[1][0] + match[1][0], 16);
13413        this.g = parseInt(match[1][1] + match[1][1], 16);
13414        this.b = parseInt(match[1][2] + match[1][2], 16);
13415    }
13416    return match !== null;
13417};
13418
13419var _hex6 = /^#([a-f0-9]{6})$/i;
13420
13421Color.prototype.hex6 = function(value) {
13422    var match = null;
13423    if ((match = value.match(_hex6)) !== null) {
13424        this.r = parseInt(match[1].substring(0, 2), 16);
13425        this.g = parseInt(match[1].substring(2, 4), 16);
13426        this.b = parseInt(match[1].substring(4, 6), 16);
13427    }
13428    return match !== null;
13429};
13430
13431
13432var _rgb = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/;
13433
13434Color.prototype.rgb = function(value) {
13435    var match = null;
13436    if ((match = value.match(_rgb)) !== null) {
13437        this.r = Number(match[1]);
13438        this.g = Number(match[2]);
13439        this.b = Number(match[3]);
13440    }
13441    return match !== null;
13442};
13443
13444var _rgba = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d?\.?\d+)\s*\)$/;
13445
13446Color.prototype.rgba = function(value) {
13447    var match = null;
13448    if ((match = value.match(_rgba)) !== null) {
13449        this.r = Number(match[1]);
13450        this.g = Number(match[2]);
13451        this.b = Number(match[3]);
13452        this.a = Number(match[4]);
13453    }
13454    return match !== null;
13455};
13456
13457Color.prototype.toString = function() {
13458    return this.a !== null && this.a !== 1 ?
13459    "rgba(" + [this.r, this.g, this.b, this.a].join(",") + ")" :
13460    "rgb(" + [this.r, this.g, this.b].join(",") + ")";
13461};
13462
13463Color.prototype.namedColor = function(value) {
13464    value = value.toLowerCase();
13465    var color = colors[value];
13466    if (color) {
13467        this.r = color[0];
13468        this.g = color[1];
13469        this.b = color[2];
13470    } else if (value === "transparent") {
13471        this.r = this.g = this.b = this.a = 0;
13472        return true;
13473    }
13474
13475    return !!color;
13476};
13477
13478Color.prototype.isColor = true;
13479
13480// 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}, {}))
13481var colors = {
13482    "aliceblue": [240, 248, 255],
13483    "antiquewhite": [250, 235, 215],
13484    "aqua": [0, 255, 255],
13485    "aquamarine": [127, 255, 212],
13486    "azure": [240, 255, 255],
13487    "beige": [245, 245, 220],
13488    "bisque": [255, 228, 196],
13489    "black": [0, 0, 0],
13490    "blanchedalmond": [255, 235, 205],
13491    "blue": [0, 0, 255],
13492    "blueviolet": [138, 43, 226],
13493    "brown": [165, 42, 42],
13494    "burlywood": [222, 184, 135],
13495    "cadetblue": [95, 158, 160],
13496    "chartreuse": [127, 255, 0],
13497    "chocolate": [210, 105, 30],
13498    "coral": [255, 127, 80],
13499    "cornflowerblue": [100, 149, 237],
13500    "cornsilk": [255, 248, 220],
13501    "crimson": [220, 20, 60],
13502    "cyan": [0, 255, 255],
13503    "darkblue": [0, 0, 139],
13504    "darkcyan": [0, 139, 139],
13505    "darkgoldenrod": [184, 134, 11],
13506    "darkgray": [169, 169, 169],
13507    "darkgreen": [0, 100, 0],
13508    "darkgrey": [169, 169, 169],
13509    "darkkhaki": [189, 183, 107],
13510    "darkmagenta": [139, 0, 139],
13511    "darkolivegreen": [85, 107, 47],
13512    "darkorange": [255, 140, 0],
13513    "darkorchid": [153, 50, 204],
13514    "darkred": [139, 0, 0],
13515    "darksalmon": [233, 150, 122],
13516    "darkseagreen": [143, 188, 143],
13517    "darkslateblue": [72, 61, 139],
13518    "darkslategray": [47, 79, 79],
13519    "darkslategrey": [47, 79, 79],
13520    "darkturquoise": [0, 206, 209],
13521    "darkviolet": [148, 0, 211],
13522    "deeppink": [255, 20, 147],
13523    "deepskyblue": [0, 191, 255],
13524    "dimgray": [105, 105, 105],
13525    "dimgrey": [105, 105, 105],
13526    "dodgerblue": [30, 144, 255],
13527    "firebrick": [178, 34, 34],
13528    "floralwhite": [255, 250, 240],
13529    "forestgreen": [34, 139, 34],
13530    "fuchsia": [255, 0, 255],
13531    "gainsboro": [220, 220, 220],
13532    "ghostwhite": [248, 248, 255],
13533    "gold": [255, 215, 0],
13534    "goldenrod": [218, 165, 32],
13535    "gray": [128, 128, 128],
13536    "green": [0, 128, 0],
13537    "greenyellow": [173, 255, 47],
13538    "grey": [128, 128, 128],
13539    "honeydew": [240, 255, 240],
13540    "hotpink": [255, 105, 180],
13541    "indianred": [205, 92, 92],
13542    "indigo": [75, 0, 130],
13543    "ivory": [255, 255, 240],
13544    "khaki": [240, 230, 140],
13545    "lavender": [230, 230, 250],
13546    "lavenderblush": [255, 240, 245],
13547    "lawngreen": [124, 252, 0],
13548    "lemonchiffon": [255, 250, 205],
13549    "lightblue": [173, 216, 230],
13550    "lightcoral": [240, 128, 128],
13551    "lightcyan": [224, 255, 255],
13552    "lightgoldenrodyellow": [250, 250, 210],
13553    "lightgray": [211, 211, 211],
13554    "lightgreen": [144, 238, 144],
13555    "lightgrey": [211, 211, 211],
13556    "lightpink": [255, 182, 193],
13557    "lightsalmon": [255, 160, 122],
13558    "lightseagreen": [32, 178, 170],
13559    "lightskyblue": [135, 206, 250],
13560    "lightslategray": [119, 136, 153],
13561    "lightslategrey": [119, 136, 153],
13562    "lightsteelblue": [176, 196, 222],
13563    "lightyellow": [255, 255, 224],
13564    "lime": [0, 255, 0],
13565    "limegreen": [50, 205, 50],
13566    "linen": [250, 240, 230],
13567    "magenta": [255, 0, 255],
13568    "maroon": [128, 0, 0],
13569    "mediumaquamarine": [102, 205, 170],
13570    "mediumblue": [0, 0, 205],
13571    "mediumorchid": [186, 85, 211],
13572    "mediumpurple": [147, 112, 219],
13573    "mediumseagreen": [60, 179, 113],
13574    "mediumslateblue": [123, 104, 238],
13575    "mediumspringgreen": [0, 250, 154],
13576    "mediumturquoise": [72, 209, 204],
13577    "mediumvioletred": [199, 21, 133],
13578    "midnightblue": [25, 25, 112],
13579    "mintcream": [245, 255, 250],
13580    "mistyrose": [255, 228, 225],
13581    "moccasin": [255, 228, 181],
13582    "navajowhite": [255, 222, 173],
13583    "navy": [0, 0, 128],
13584    "oldlace": [253, 245, 230],
13585    "olive": [128, 128, 0],
13586    "olivedrab": [107, 142, 35],
13587    "orange": [255, 165, 0],
13588    "orangered": [255, 69, 0],
13589    "orchid": [218, 112, 214],
13590    "palegoldenrod": [238, 232, 170],
13591    "palegreen": [152, 251, 152],
13592    "paleturquoise": [175, 238, 238],
13593    "palevioletred": [219, 112, 147],
13594    "papayawhip": [255, 239, 213],
13595    "peachpuff": [255, 218, 185],
13596    "peru": [205, 133, 63],
13597    "pink": [255, 192, 203],
13598    "plum": [221, 160, 221],
13599    "powderblue": [176, 224, 230],
13600    "purple": [128, 0, 128],
13601    "rebeccapurple": [102, 51, 153],
13602    "red": [255, 0, 0],
13603    "rosybrown": [188, 143, 143],
13604    "royalblue": [65, 105, 225],
13605    "saddlebrown": [139, 69, 19],
13606    "salmon": [250, 128, 114],
13607    "sandybrown": [244, 164, 96],
13608    "seagreen": [46, 139, 87],
13609    "seashell": [255, 245, 238],
13610    "sienna": [160, 82, 45],
13611    "silver": [192, 192, 192],
13612    "skyblue": [135, 206, 235],
13613    "slateblue": [106, 90, 205],
13614    "slategray": [112, 128, 144],
13615    "slategrey": [112, 128, 144],
13616    "snow": [255, 250, 250],
13617    "springgreen": [0, 255, 127],
13618    "steelblue": [70, 130, 180],
13619    "tan": [210, 180, 140],
13620    "teal": [0, 128, 128],
13621    "thistle": [216, 191, 216],
13622    "tomato": [255, 99, 71],
13623    "turquoise": [64, 224, 208],
13624    "violet": [238, 130, 238],
13625    "wheat": [245, 222, 179],
13626    "white": [255, 255, 255],
13627    "whitesmoke": [245, 245, 245],
13628    "yellow": [255, 255, 0],
13629    "yellowgreen": [154, 205, 50]
13630};
13631
13632module.exports = Color;
13633
13634},{}],4:[function(_dereq_,module,exports){
13635var Support = _dereq_('./support');
13636var CanvasRenderer = _dereq_('./renderers/canvas');
13637var ImageLoader = _dereq_('./imageloader');
13638var NodeParser = _dereq_('./nodeparser');
13639var NodeContainer = _dereq_('./nodecontainer');
13640var log = _dereq_('./log');
13641var utils = _dereq_('./utils');
13642var createWindowClone = _dereq_('./clone');
13643var loadUrlDocument = _dereq_('./proxy').loadUrlDocument;
13644var getBounds = utils.getBounds;
13645
13646var html2canvasNodeAttribute = "data-html2canvas-node";
13647var html2canvasCloneIndex = 0;
13648
13649function html2canvas(nodeList, options) {
13650    var index = html2canvasCloneIndex++;
13651    options = options || {};
13652    if (options.logging) {
13653        log.options.logging = true;
13654        log.options.start = Date.now();
13655    }
13656
13657    options.async = typeof(options.async) === "undefined" ? true : options.async;
13658    options.allowTaint = typeof(options.allowTaint) === "undefined" ? false : options.allowTaint;
13659    options.removeContainer = typeof(options.removeContainer) === "undefined" ? true : options.removeContainer;
13660    options.javascriptEnabled = typeof(options.javascriptEnabled) === "undefined" ? false : options.javascriptEnabled;
13661    options.imageTimeout = typeof(options.imageTimeout) === "undefined" ? 10000 : options.imageTimeout;
13662    options.renderer = typeof(options.renderer) === "function" ? options.renderer : CanvasRenderer;
13663    options.strict = !!options.strict;
13664
13665    if (typeof(nodeList) === "string") {
13666        if (typeof(options.proxy) !== "string") {
13667            return Promise.reject("Proxy must be used when rendering url");
13668        }
13669        var width = options.width != null ? options.width : window.innerWidth;
13670        var height = options.height != null ? options.height : window.innerHeight;
13671        return loadUrlDocument(absoluteUrl(nodeList), options.proxy, document, width, height, options).then(function(container) {
13672            return renderWindow(container.contentWindow.document.documentElement, container, options, width, height);
13673        });
13674    }
13675
13676    var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0];
13677    node.setAttribute(html2canvasNodeAttribute + index, index);
13678    return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {
13679        if (typeof(options.onrendered) === "function") {
13680            log("options.onrendered is deprecated, html2canvas returns a Promise containing the canvas");
13681            options.onrendered(canvas);
13682        }
13683        return canvas;
13684    });
13685}
13686
13687html2canvas.CanvasRenderer = CanvasRenderer;
13688html2canvas.NodeContainer = NodeContainer;
13689html2canvas.log = log;
13690html2canvas.utils = utils;
13691
13692var html2canvasExport = (typeof(document) === "undefined" || typeof(Object.create) !== "function" || typeof(document.createElement("canvas").getContext) !== "function") ? function() {
13693    return Promise.reject("No canvas support");
13694} : html2canvas;
13695
13696module.exports = html2canvasExport;
13697
13698if (typeof(define) === 'function' && define.amd) {
13699    define('html2canvas', [], function() {
13700        return html2canvasExport;
13701    });
13702}
13703
13704function renderDocument(document, options, windowWidth, windowHeight, html2canvasIndex) {
13705    return createWindowClone(document, document, windowWidth, windowHeight, options, document.defaultView.pageXOffset, document.defaultView.pageYOffset).then(function(container) {
13706        log("Document cloned");
13707        var attributeName = html2canvasNodeAttribute + html2canvasIndex;
13708        var selector = "[" + attributeName + "='" + html2canvasIndex + "']";
13709        document.querySelector(selector).removeAttribute(attributeName);
13710        var clonedWindow = container.contentWindow;
13711        var node = clonedWindow.document.querySelector(selector);
13712        var oncloneHandler = (typeof(options.onclone) === "function") ? Promise.resolve(options.onclone(clonedWindow.document)) : Promise.resolve(true);
13713        return oncloneHandler.then(function() {
13714            return renderWindow(node, container, options, windowWidth, windowHeight);
13715        });
13716    });
13717}
13718
13719function renderWindow(node, container, options, windowWidth, windowHeight) {
13720    var clonedWindow = container.contentWindow;
13721    var support = new Support(clonedWindow.document);
13722    var imageLoader = new ImageLoader(options, support);
13723    var bounds = getBounds(node);
13724    var width = options.type === "view" ? windowWidth : documentWidth(clonedWindow.document);
13725    var height = options.type === "view" ? windowHeight : documentHeight(clonedWindow.document);
13726    var renderer = new options.renderer(width, height, imageLoader, options, document);
13727    var parser = new NodeParser(node, renderer, support, imageLoader, options);
13728    return parser.ready.then(function() {
13729        log("Finished rendering");
13730        var canvas;
13731
13732        if (options.type === "view") {
13733            canvas = crop(renderer.canvas, {width: renderer.canvas.width, height: renderer.canvas.height, top: 0, left: 0, x: 0, y: 0});
13734        } else if (node === clonedWindow.document.body || node === clonedWindow.document.documentElement || options.canvas != null) {
13735            canvas = renderer.canvas;
13736        } else {
13737            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});
13738        }
13739
13740        cleanupContainer(container, options);
13741        return canvas;
13742    });
13743}
13744
13745function cleanupContainer(container, options) {
13746    if (options.removeContainer) {
13747        container.parentNode.removeChild(container);
13748        log("Cleaned up container");
13749    }
13750}
13751
13752function crop(canvas, bounds) {
13753    var croppedCanvas = document.createElement("canvas");
13754    var x1 = Math.min(canvas.width - 1, Math.max(0, bounds.left));
13755    var x2 = Math.min(canvas.width, Math.max(1, bounds.left + bounds.width));
13756    var y1 = Math.min(canvas.height - 1, Math.max(0, bounds.top));
13757    var y2 = Math.min(canvas.height, Math.max(1, bounds.top + bounds.height));
13758    croppedCanvas.width = bounds.width;
13759    croppedCanvas.height =  bounds.height;
13760    var width = x2-x1;
13761    var height = y2-y1;
13762    log("Cropping canvas at:", "left:", bounds.left, "top:", bounds.top, "width:", width, "height:", height);
13763    log("Resulting crop with width", bounds.width, "and height", bounds.height, "with x", x1, "and y", y1);
13764    croppedCanvas.getContext("2d").drawImage(canvas, x1, y1, width, height, bounds.x, bounds.y, width, height);
13765    return croppedCanvas;
13766}
13767
13768function documentWidth (doc) {
13769    return Math.max(
13770        Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),
13771        Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),
13772        Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)
13773    );
13774}
13775
13776function documentHeight (doc) {
13777    return Math.max(
13778        Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),
13779        Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),
13780        Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)
13781    );
13782}
13783
13784function absoluteUrl(url) {
13785    var link = document.createElement("a");
13786    link.href = url;
13787    link.href = link.href;
13788    return link;
13789}
13790
13791},{"./clone":2,"./imageloader":11,"./log":13,"./nodecontainer":14,"./nodeparser":15,"./proxy":16,"./renderers/canvas":20,"./support":22,"./utils":26}],5:[function(_dereq_,module,exports){
13792var log = _dereq_('./log');
13793var smallImage = _dereq_('./utils').smallImage;
13794
13795function DummyImageContainer(src) {
13796    this.src = src;
13797    log("DummyImageContainer for", src);
13798    if (!this.promise || !this.image) {
13799        log("Initiating DummyImageContainer");
13800        DummyImageContainer.prototype.image = new Image();
13801        var image = this.image;
13802        DummyImageContainer.prototype.promise = new Promise(function(resolve, reject) {
13803            image.onload = resolve;
13804            image.onerror = reject;
13805            image.src = smallImage();
13806            if (image.complete === true) {
13807                resolve(image);
13808            }
13809        });
13810    }
13811}
13812
13813module.exports = DummyImageContainer;
13814
13815}
13815,{"./log":13,"./utils":26}],6:[function(_dereq_,module,exports){
13816var smallImage = _dereq_('./utils').smallImage;
13817
13818function Font(family, size) {
13819    var container = document.createElement('div'),
13820        img = document.createElement('img'),
13821        span = document.createElement('span'),
13822        sampleText = 'Hidden Text',
13823        baseline,
13824        middle;
13825
13826    container.style.visibility = "hidden";
13827    container.style.fontFamily = family;
13828    container.style.fontSize = size;
13829    container.style.margin = 0;
13830    container.style.padding = 0;
13831
13832    document.body.appendChild(container);
13833
13834    img.src = smallImage();
13835    img.width = 1;
13836    img.height = 1;
13837
13838    img.style.margin = 0;
13839    img.style.padding = 0;
13840    img.style.verticalAlign = "baseline";
13841
13842    span.style.fontFamily = family;
13843    span.style.fontSize = size;
13844    span.style.margin = 0;
13845    span.style.padding = 0;
13846
13847    span.appendChild(document.createTextNode(sampleText));
13848    container.appendChild(span);
13849    container.appendChild(img);
13850    baseline = (img.offsetTop - span.offsetTop) + 1;
13851
13852    container.removeChild(span);
13853    container.appendChild(document.createTextNode(sampleText));
13854
13855    container.style.lineHeight = "normal";
13856    img.style.verticalAlign = "super";
13857
13858    middle = (img.offsetTop-container.offsetTop) + 1;
13859
13860    document.body.removeChild(container);
13861
13862    this.baseline = baseline;
13863    this.lineWidth = 1;
13864    this.middle = middle;
13865}
13866
13867module.exports = Font;
13868
13869},{"./utils":26}],7:[function(_dereq_,module,exports){
13870var Font = _dereq_('./font');
13871
13872function FontMetrics() {
13873    this.data = {};
13874}
13875
13876FontMetrics.prototype.getMetrics = function(family, size) {
13877    if (this.data[family + "-" + size] === undefined) {
13878        this.data[family + "-" + size] = new Font(family, size);
13879    }
13880    return this.data[family + "-" + size];
13881};
13882
13883module.exports = FontMetrics;
13884
13885},{"./font":6}],8:[function(_dereq_,module,exports){
13886var utils = _dereq_('./utils');
13887var getBounds = utils.getBounds;
13888var loadUrlDocument = _dereq_('./proxy').loadUrlDocument;
13889
13890function FrameContainer(container, sameOrigin, options) {
13891    this.image = null;
13892    this.src = container;
13893    var self = this;
13894    var bounds = getBounds(container);
13895    this.promise = (!sameOrigin ? this.proxyLoad(options.proxy, bounds, options) : new Promise(function(resolve) {
13896        if (container.contentWindow.document.URL === "about:blank" || container.contentWindow.document.documentElement == null) {
13897            container.contentWindow.onload = container.onload = function() {
13898                resolve(container);
13899            };
13900        } else {
13901            resolve(container);
13902        }
13903    })).then(function(container) {
13904        var html2canvas = _dereq_('./core');
13905        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});
13906    }).then(function(canvas) {
13907        return self.image = canvas;
13908    });
13909}
13910
13911FrameContainer.prototype.proxyLoad = function(proxy, bounds, options) {
13912    var container = this.src;
13913    return loadUrlDocument(container.src, proxy, container.ownerDocument, bounds.width, bounds.height, options);
13914};
13915
13916module.exports = FrameContainer;
13917
13918},{"./core":4,"./proxy":16,"./utils":26}],9:[function(_dereq_,module,exports){
13919function GradientContainer(imageData) {
13920    this.src = imageData.value;
13921    this.colorStops = [];
13922    this.type = null;
13923    this.x0 = 0.5;
13924    this.y0 = 0.5;
13925    this.x1 = 0.5;
13926    this.y1 = 0.5;
13927    this.promise = Promise.resolve(true);
13928}
13929
13930GradientContainer.TYPES = {
13931    LINEAR: 1,
13932    RADIAL: 2
13933};
13934
13935// TODO: support hsl[a], negative %/length values
13936// TODO: support <angle> (e.g. -?\d{1,3}(?:\.\d+)deg, etc. : https://developer.mozilla.org/docs/Web/CSS/angle )
13937GradientContainer.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;
13938
13939module.exports = GradientContainer;
13940
13941},{}],10:[function(_dereq_,module,exports){
13942function ImageContainer(src, cors) {
13943    this.src = src;
13944    this.image = new Image();
13945    var self = this;
13946    this.tainted = null;
13947    this.promise = new Promise(function(resolve, reject) {
13948        self.image.onload = resolve;
13949        self.image.onerror = reject;
13950        if (cors) {
13951            self.image.crossOrigin = "anonymous";
13952        }
13953        self.image.src = src;
13954        if (self.image.complete === true) {
13955            resolve(self.image);
13956        }
13957    });
13958}
13959
13960module.exports = ImageContainer;
13961
13962},{}],11:[function(_dereq_,module,exports){
13963var log = _dereq_('./log');
13964var ImageContainer = _dereq_('./imagecontainer');
13965var DummyImageContainer = _dereq_('./dummyimagecontainer');
13966var ProxyImageContainer = _dereq_('./proxyimagecontainer');
13967var FrameContainer = _dereq_('./framecontainer');
13968var SVGContainer = _dereq_('./svgcontainer');
13969var SVGNodeContainer = _dereq_('./svgnodecontainer');
13970var LinearGradientContainer = _dereq_('./lineargradientcontainer');
13971var WebkitGradientContainer = _dereq_('./webkitgradientcontainer');
13972var bind = _dereq_('./utils').bind;
13973
13974function ImageLoader(options, support) {
13975    this.link = null;
13976    this.options = options;
13977    this.support = support;
13978    this.origin = this.getOrigin(window.location.href);
13979}
13980
13981ImageLoader.prototype.findImages = function(nodes) {
13982    var images = [];
13983    nodes.reduce(function(imageNodes, container) {
13984        switch(container.node.nodeName) {
13985        case "IMG":
13986            return imageNodes.concat([{
13987                args: [container.node.src],
13988                method: "url"
13989            }]);
13990        case "svg":
13991        case "IFRAME":
13992            return imageNodes.concat([{
13993                args: [container.node],
13994                method: container.node.nodeName
13995            }]);
13996        }
13997        return imageNodes;
13998    }
13998, []).forEach(this.addImage(images, this.loadImage), this);
13999    return images;
14000};
14001
14002ImageLoader.prototype.findBackgroundImage = function(images, container) {
14003    container.parseBackgroundImages().filter(this.hasImageBackground).forEach(this.addImage(images, this.loadImage), this);
14004    return images;
14005};
14006
14007ImageLoader.prototype.addImage = function(images, callback) {
14008    return function(newImage) {
14009        newImage.args.forEach(function(image) {
14010            if (!this.imageExists(images, image)) {
14011                images.splice(0, 0, callback.call(this, newImage));
14012                log('Added image #' + (images.length), typeof(image) === "string" ? image.substring(0, 100) : image);
14013            }
14014        }, this);
14015    };
14016};
14017
14018ImageLoader.prototype.hasImageBackground = function(imageData) {
14019    return imageData.method !== "none";
14020};
14021
14022ImageLoader.prototype.loadImage = function(imageData) {
14023    if (imageData.method === "url") {
14024        var src = imageData.args[0];
14025        if (this.isSVG(src) && !this.support.svg && !this.options.allowTaint) {
14026            return new SVGContainer(src);
14027        } else if (src.match(/data:image\/.*;base64,/i)) {
14028            return new ImageContainer(src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''), false);
14029        } else if (this.isSameOrigin(src) || this.options.allowTaint === true || this.isSVG(src)) {
14030            return new ImageContainer(src, false);
14031        } else if (this.support.cors && !this.options.allowTaint && this.options.useCORS) {
14032            return new ImageContainer(src, true);
14033        } else if (this.options.proxy) {
14034            return new ProxyImageContainer(src, this.options.proxy);
14035        } else {
14036            return new DummyImageContainer(src);
14037        }
14038    } else if (imageData.method === "linear-gradient") {
14039        return new LinearGradientContainer(imageData);
14040    } else if (imageData.method === "gradient") {
14041        return new WebkitGradientContainer(imageData);
14042    } else if (imageData.method === "svg") {
14043        return new SVGNodeContainer(imageData.args[0], this.support.svg);
14044    } else if (imageData.method === "IFRAME") {
14045        return new FrameContainer(imageData.args[0], this.isSameOrigin(imageData.args[0].src), this.options);
14046    } else {
14047        return new DummyImageContainer(imageData);
14048    }
14049};
14050
14051ImageLoader.prototype.isSVG = function(src) {
14052    return src.substring(src.length - 3).toLowerCase() === "svg" || SVGContainer.prototype.isInline(src);
14053};
14054
14055ImageLoader.prototype.imageExists = function(images, src) {
14056    return images.some(function(image) {
14057        return image.src === src;
14058    });
14059};
14060
14061ImageLoader.prototype.isSameOrigin = function(url) {
14062    return (this.getOrigin(url) === this.origin);
14063};
14064
14065ImageLoader.prototype.getOrigin = function(url) {
14066    var link = this.link || (this.link = document.createElement("a"));
14067    link.href = url;
14068    link.href = link.href; // IE9, LOL! - http://jsfiddle.net/niklasvh/2e48b/
14069    return link.protocol + link.hostname + link.port;
14070};
14071
14072ImageLoader.prototype.getPromise = function(container) {
14073    return this.timeout(container, this.options.imageTimeout)['catch'](function() {
14074        var dummy = new DummyImageContainer(container.src);
14075        return dummy.promise.then(function(image) {
14076            container.image = image;
14077        });
14078    });
14079};
14080
14081ImageLoader.prototype.get = function(src) {
14082    var found = null;
14083    return this.images.some(function(img) {
14084        return (found = img).src === src;
14085    }) ? found : null;
14086};
14087
14088ImageLoader.prototype.fetch = function(nodes) {
14089    this.images = nodes.reduce(bind(this.findBackgroundImage, this), this.findImages(nodes));
14090    this.images.forEach(function(image, index) {
14091        image.promise.then(function() {
14092            log("Succesfully loaded image #"+ (index+1), image);
14093        }, function(e) {
14094            log("Failed loading image #"+ (index+1), image, e);
14095        });
14096    });
14097    this.ready = Promise.all(this.images.map(this.getPromise, this));
14098    log("Finished searching images");
14099    return this;
14100};
14101
14102ImageLoader.prototype.timeout = function(container, timeout) {
14103    var timer;
14104    var promise = Promise.race([container.promise, new Promise(function(res, reject) {
14105        timer = setTimeout(function() {
14106            log("Timed out loading image", container);
14107            reject(container);
14108        }, timeout);
14109    })]).then(function(container) {
14110        clearTimeout(timer);
14111        return container;
14112    });
14113    promise['catch'](function() {
14114        clearTimeout(timer);
14115    });
14116    return promise;
14117};
14118
14119module.exports = ImageLoader;
14120
14121},{"./dummyimagecontainer":5,"./framecontainer":8,"./imagecontainer":10,"./lineargradientcontainer":12,"./log":13,"./proxyimagecontainer":17,"./svgcontainer":23,"./svgnodecontainer":24,"./ut
14121ils":26,"./webkitgradientcontainer":27}],12:[function(_dereq_,module,exports){
14122var GradientContainer = _dereq_('./gradientcontainer');
14123var Color = _dereq_('./color');
14124
14125function LinearGradientContainer(imageData) {
14126    GradientContainer.apply(this, arguments);
14127    this.type = GradientContainer.TYPES.LINEAR;
14128
14129    var hasDirection = LinearGradientContainer.REGEXP_DIRECTION.test( imageData.args[0] ) ||
14130        !GradientContainer.REGEXP_COLORSTOP.test( imageData.args[0] );
14131
14132    if (hasDirection) {
14133        imageData.args[0].split(/\s+/).reverse().forEach(function(position, index) {
14134            switch(position) {
14135            case "left":
14136                this.x0 = 0;
14137                this.x1 = 1;
14138                break;
14139            case "top":
14140                this.y0 = 0;
14141                this.y1 = 1;
14142                break;
14143            case "right":
14144                this.x0 = 1;
14145                this.x1 = 0;
14146                break;
14147            case "bottom":
14148                this.y0 = 1;
14149                this.y1 = 0;
14150                break;
14151            case "to":
14152                var y0 = this.y0;
14153                var x0 = this.x0;
14154                this.y0 = this.y1;
14155                this.x0 = this.x1;
14156                this.x1 = x0;
14157                this.y1 = y0;
14158                break;
14159            case "center":
14160                break; // centered by default
14161            // Firefox internally converts position keywords to percentages:
14162            // http://www.w3.org/TR/2010/WD-CSS2-20101207/colors.html#propdef-background-position
14163            default: // percentage or absolute length
14164                // TODO: support absolute start point positions (e.g., use bounds to convert px to a ratio)
14165                var ratio = parseFloat(position, 10) * 1e-2;
14166                if (isNaN(ratio)) { // invalid or unhandled value
14167                    break;
14168                }
14169                if (index === 0) {
14170                    this.y0 = ratio;
14171                    this.y1 = 1 - this.y0;
14172                } else {
14173                    this.x0 = ratio;
14174                    this.x1 = 1 - this.x0;
14175                }
14176                break;
14177            }
14178        }, this);
14179    } else {
14180        this.y0 = 0;
14181        this.y1 = 1;
14182    }
14183
14184    this.colorStops = imageData.args.slice(hasDirection ? 1 : 0).map(function(colorStop) {
14185        var colorStopMatch = colorStop.match(GradientContainer.REGEXP_COLORSTOP);
14186        var value = +colorStopMatch[2];
14187        var unit = value === 0 ? "%" : colorStopMatch[3]; // treat "0" as "0%"
14188        return {
14189            color: new Color(colorStopMatch[1]),
14190            // TODO: support absolute stop positions (e.g., compute gradient line length & convert px to ratio)
14191            stop: unit === "%" ? value / 100 : null
14192        };
14193    });
14194
14195    if (this.colorStops[0].stop === null) {
14196        this.colorStops[0].stop = 0;
14197    }
14198
14199    if (this.colorStops[this.colorStops.length - 1].stop === null) {
14200        this.colorStops[this.colorStops.length - 1].stop = 1;
14201    }
14202
14203    // calculates and fills-in explicit stop positions when omitted from rule
14204    this.colorStops.forEach(function(colorStop, index) {
14205        if (colorStop.stop === null) {
14206            this.colorStops.slice(index).some(function(find, count) {
14207                if (find.stop !== null) {
14208                    colorStop.stop = ((find.stop - this.colorStops[index - 1].stop) / (count + 1)) + this.colorStops[index - 1].stop;
14209                    return true;
14210                } else {
14211                    return false;
14212                }
14213            }, this);
14214        }
14215    }, this);
14216}
14217
14218LinearGradientContainer.prototype = Object.create(GradientContainer.prototype);
14219
14220// TODO: support <angle> (e.g. -?\d{1,3}(?:\.\d+)deg, etc. : https://developer.mozilla.org/docs/Web/CSS/angle )
14221LinearGradientContainer.REGEXP_DIRECTION = /^\s*(?:to|left|right|top|bottom|center|\d{1,3}(?:\.\d+)?%?)(?:\s|$)/i;
14222
14223module.exports = LinearGradientContainer;
14224
14225},{"./color":3,"./gradientcontainer":9}],13:[function(_dereq_,module,exports){
14226var logger = function() {
14227    if (logger.options.logging && window.console && window.console.log) {
14228        Function.prototype.bind.call(window.console.log, (window.console)).apply(window.console, [(Date.now() - logger.options.start) + "ms", "html2canvas:"].concat([].slice.call(arguments, 0)));
14229    }
14230};
14231
14232logger.options = {logging: false};
14233module.exports = logger;
14234
14235},{}],14:[function(_dereq_,module,exports){
14236var Color = _dereq_('./color');
14237var utils = _dereq_('./utils');
14238var getBounds = utils.getBounds;
14239var parseBackgrounds = utils.parseBackgrounds;
14240var offsetBounds = utils.offsetBounds;
14241
14242function NodeContainer(node, parent) {
14243    this.node = node;
14244    this.parent = parent;
14245    this.stack = null;
14246    this.bounds = null;
14247    this.borders = null;
14248    this.clip = [];
14249    this.backgroundClip = [];
14250    this.offsetBounds = null;
14251    this.visible = null;
14252    this.computedStyles = null;
14253    this.colors = {};
14254    this.styles = {};
14255    this.backgroundImages = null;
14256    this.transformData = null;
14257    this.transformMatrix = null;
14258    this.isPseudoElement = false;
14259    this.opacity = null;
14260}
14261
14262NodeContainer.prototype.cloneTo = function(stack) {
14263    stack.visible = this.visible;
14264    stack.borders = this.borders;
14265    stack.bounds = this.bounds;
14266    stack.clip = this.clip;
14267    stack.backgroundClip = this.backgroundClip;
14268    stack.computedStyles = this.computedStyles;
14269    stack.styles = this.styles;
14270    stack.backgroundImages = this.backgroundImages;
14271    stack.opacity = this.opacity;
14272};
14273
14274NodeContainer.prototype.getOpacity = function() {
14275    return this.opacity === null ? (this.opacity = this.cssFloat('opacity')) : this.opacity;
14276};
14277
14278NodeContainer.prototype.assignStack = function(stack) {
14279    this.stack = stack;
14280    stack.children.push(this);
14281};
14282
14283NodeContainer.prototype.isElementVisible = function() {
14284    return this.node.nodeType === Node.TEXT_NODE ? this.parent.visible : (
14285        this.css('display') !== "none" &&
14286        this.css('visibility') !== "hidden" &&
14287        !this.node.hasAttribute("data-html2canvas-ignore") &&
14288        (this.node.nodeName !== "INPUT" || this.node.getAttribute("type") !== "hidden")
14289    );
14290};
14291
14292NodeContainer.prototype.css = function(attribute) {
14293    if (!this.computedStyles) {
14294        this.computedStyles = this.isPseudoElement ? this.parent.computedStyle(this.before ? ":before" : ":after") : this.computedStyle(null);
14295    }
14296
14297    return this.styles[attribute] || (this.styles[attribute] = this.computedStyles[attribute]);
14298};
14299
14300NodeContainer.prototype.prefixedCss = function(attribute) {
14301    var prefixes = ["webkit", "moz", "ms", "o"];
14302    var value = this.css(attribute);
14303    if (value === undefined) {
14304        prefixes.some(function(prefix) {
14305            value = this.css(prefix + attribute.substr(0, 1).toUpperCase() + attribute.substr(1));
14306            return value !== undefined;
14307        }, this);
14308    }
14309    return value === undefined ? null : value;
14310};
14311
14312NodeContainer.prototype.computedStyle = function(type) {
14313    return this.node.ownerDocument.defaultView.getComputedStyle(this.node, type);
14314};
14315
14316NodeContainer.prototype.cssInt = function(attribute) {
14317    var value = parseInt(this.css(attribute), 10);
14318    return (isNaN(value)) ? 0 : value; // borders in old IE are throwing 'medium' for demo.html
14319};
14320
14321NodeContainer.prototype.color = function(attribute) {
14322    return this.colors[attribute] || (this.colors[attribute] = new Color(this.css(attribute)));
14323};
14324
14325NodeContainer.prototype.cssFloat = function(attribute) {
14326    var value = parseFloat(this.css(attribute));
14327    return (isNaN(value)) ? 0 : value;
14328};
14329
14330NodeContainer.prototype.fontWeight = function() {
14331    var weight = this.css("fontWeight");
14332    switch(parseInt(weight, 10)){
14333    case 401:
14334        weight = "bold";
14335        break;
14336    case 400:
14337        weight = "normal";
14338        break;
14339    }
14340    return weight;
14341};
14342
14343NodeContainer.prototype.parseClip = function() {
14344    var matches = this.css('clip').match(this.CLIP);
14345    if (matches) {
14346        return {
14347            top: parseInt(matches[1], 10),
14348            right: parseInt(matches[2], 10),
14349            bottom: parseInt(matches[3], 10),
14350            left: parseInt(matches[4], 10)
14351        };
14352    }
14353    return null;
14354};
14355
14356NodeContainer.prototype.parseBackgroundImages = function() {
14357    return this.backgroundImages || (this.backgroundImages = parseBackgrounds(this.css("backgroundImage")));
14358};
14359
14360NodeContainer.prototype.cssList = function(property, index) {
14361    var value = (this.css(property) || '').split(',');
14362    value = value[index || 0] || value[0] || 'auto';
14363    value = value.trim().split(' ');
14364    if (value.length === 1) {
14365        value = [value[0], isPercentage(value[0]) ? 'auto' : value[0]];
14366    }
14367    return value;
14368};
14369
14370NodeContainer.prototype.parseBackgroundSize = function(bounds, image, index) {
14371    var size = this.cssList("backgroundSize", index);
14372    var width, height;
14373
14374    if (isPercentage(size[0])) {
14375        width = bounds.width * parseFloat(size[0]) / 100;
14376    } else if (/contain|cover/.test(size[0])) {
14377        var targetRatio = bounds.width / bounds.height, currentRatio = image.width / image.height;
14378        return (targetRatio < currentRatio ^ size[0] === 'contain') ?  {width: bounds.height * currentRatio, height: bounds.height} : {width: bounds.width, height: bounds.width / currentRatio};
14379    } else {
14380        width = parseInt(size[0], 10);
14381    }
14382
14383    if (size[0] === 'auto' && size[1] === 'auto') {
14384        height = image.height;
14385    } else if (size[1] === 'auto') {
14386        height = width / image.width * image.height;
14387    } else if (isPercentage(size[1])) {
14388        height =  bounds.height * parseFloat(size[1]) / 100;
14389    } else {
14390        height = parseInt(size[1], 10);
14391    }
14392
14393    if (size[0] === 'auto') {
14394        width = height / image.height * image.width;
14395    }
14396
14397    return {width: width, height: height};
14398};
14399
14400NodeContainer.prototype.parseBackgroundPosition = function(bounds, image, index, backgroundSize) {
14401    var position = this.cssList('backgroundPosition', index);
14402    var left, top;
14403
14404    if (isPercentage(position[0])){
14405        left = (bounds.width - (backgroundSize || image).width) * (parseFloat(position[0]) / 100);
14406    } else {
14407        left = parseInt(position[0], 10);
14408    }
14409
14410    if (position[1] === 'auto') {
14411        top = left / image.width * image.height;
14412    } else if (isPercentage(position[1])){
14413        top =  (bounds.height - (backgroundSize || image).height) * parseFloat(position[1]) / 100;
14414    } else {
14415        top = parseInt(position[1], 10);
14416    }
14417
14418    if (position[0] === 'auto') {
14419        left = top / image.height * image.width;
14420    }
14421
14422    return {left: left, top: top};
14423};
14424
14425NodeContainer.prototype.parseBackgroundRepeat = function(index) {
14426    return this.cssList("backgroundRepeat", index)[0];
14427};
14428
14429NodeContainer.prototype.parseTextShadows = function() {
14430    var textShadow = this.css("textShadow");
14431    var results = [];
14432
14433    if (textShadow && textShadow !== 'none') {
14434        var shadows = textShadow.match(this.TEXT_SHADOW_PROPERTY);
14435        for (var i = 0; shadows && (i < shadows.length); i++) {
14436            var s = shadows[i].match(this.TEXT_SHADOW_VALUES);
14437            results.push({
14438                color: new Color(s[0]),
14439                offsetX: s[1] ? parseFloat(s[1].replace('px', '')) : 0,
14440                offsetY: s[2] ? parseFloat(s[2].replace('px', '')) : 0,
14441                blur: s[3] ? s[3].replace('px', '') : 0
14442            });
14443        }
14444    }
14445    return results;
14446};
14447
14448NodeContainer.prototype.parseTransform = function() {
14449    if (!this.transformData) {
14450        if (this.hasTransform()) {
14451            var offset = this.parseBounds();
14452            var origin = this.prefixedCss("transformOrigin").split(" ").map(removePx).map(asFloat);
14453            origin[0] += offset.left;
14454            origin[1] += offset.top;
14455            this.transformData = {
14456                origin: origin,
14457                matrix: this.parseTransformMatrix()
14458            };
14459        } else {
14460            this.transformData = {
14461                origin: [0, 0],
14462                matrix: [1, 0, 0, 1, 0, 0]
14463            };
14464        }
14465    }
14466    return this.transformData;
14467};
14468
14469NodeContainer.prototype.parseTransformMatrix = function() {
14470    if (!this.transformMatrix) {
14471        var transform = this.prefixedCss("transform");
14472        var matrix = transform ? parseMatrix(transform.match(this.MATRIX_PROPERTY)) : null;
14473        this.transformMatrix = matrix ? matrix : [1, 0, 0, 1, 0, 0];
14474    }
14475    return this.transformMatrix;
14476};
14477
14478NodeContainer.prototype.parseBounds = function() {
14479    return this.bounds || (this.bounds = this.hasTransform() ? offsetBounds(this.node) : getBounds(this.node));
14480};
14481
14482NodeContainer.prototype.hasTransform = function() {
14483    return this.parseTransformMatrix().join(",") !== "1,0,0,1,0,0" || (this.parent && this.parent.hasTransform());
14484};
14485
14486NodeContainer.prototype.getValue = function() {
14487    var value = this.node.value || "";
14488    if (this.node.tagName === "SELECT") {
14489        value = selectionValue(this.node);
14490    } else if (this.node.type === "password") {
14491        value = Array(value.length + 1).join('\u2022'); // jshint ignore:line
14492    }
14493    return value.length === 0 ? (this.node.placeholder || "") : value;
14494};
14495
14496NodeContainer.prototype.MATRIX_PROPERTY = /(matrix|matrix3d)\((.+)\)/;
14497NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g;
14498NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;
14499NodeContainer.prototype.CLIP = /^rect\((\d+)px,? (\d+)px,? (\d+)px,? (\d+)px\)$/;
14500
14501function selectionValue(node) {
14502    var option = node.options[node.selectedIndex || 0];
14503    return option ? (option.text || "") : "";
14504}
14505
14506function parseMatrix(match) {
14507    if (match && match[1] === "matrix") {
14508        return match[2].split(",").map(function(s) {
14509            return parseFloat(s.trim());
14510        });
14511    } else if (match && match[1] === "matrix3d") {
14512        var matrix3d = match[2].split(",").map(function(s) {
14513          return parseFloat(s.trim());
14514        });
14515        return [matrix3d[0], matrix3d[1], matrix3d[4], matrix3d[5], matrix3d[12], matrix3d[13]];
14516    }
14517}
14518
14519function isPercentage(value) {
14520    return value.toString().indexOf("%") !== -1;
14521}
14522
14523function removePx(str) {
14524    return str.replace("px", "");
14525}
14526
14527function asFloat(str) {
14528    return parseFloat(str);
14529}
14530
14531module.exports = NodeContainer;
14532
14533},{"./color":3,"./utils":26}],15:[function(_dereq_,module,exports){
14534var log = _dereq_('./log');
14535var punycode = _dereq_('punycode');
14536var NodeContainer = _dereq_('./nodecontainer');
14537var TextContainer = _dereq_('./textcontainer');
14538var PseudoElementContainer = _dereq_('./pseudoelementcontainer');
14539var FontMetrics = _dereq_('./fontmetrics');
14540var Color = _dereq_('./color');
14541var StackingContext = _dereq_('./stackingcontext');
14542var utils = _dereq_('./utils');
14543var bind = utils.bind;
14544var getBounds = utils.getBounds;
14545var parseBackgrounds = utils.parseBackgrounds;
14546var offsetBounds = utils.offsetBounds;
14547
14548function NodeParser(element, renderer, support, imageLoader, options) {
14549    log("Starting NodeParser");
14550    this.renderer = renderer;
14551    this.options = options;
14552    this.range = null;
14553    this.support = support;
14554    this.renderQueue = [];
14555    this.stack = new StackingContext(true, 1, element.ownerDocument, null);
14556    var parent = new NodeContainer(element, null);
14557    if (options.background) {
14558        renderer.rectangle(0, 0, renderer.width, renderer.height, new Color(options.background));
14559    }
14560    if (element === element.ownerDocument.documentElement) {
14561        // http://www.w3.org/TR/css3-background/#special-backgrounds
14562        var canvasBackground = new NodeContainer(parent.color('backgroundColor').isTransparent() ? element.ownerDocument.body : element.ownerDocument.documentElement, null);
14563        renderer.rectangle(0, 0, renderer.width, renderer.height, canvasBackground.color('backgroundColor'));
14564    }
14565    parent.visibile = parent.isElementVisible();
14566    this.createPseudoHideStyles(element.ownerDocument);
14567    this.disableAnimations(element.ownerDocument);
14568    this.nodes = flatten([parent].concat(this.getChildren(parent)).filter(function(container) {
14569        return container.visible = container.isElementVisible();
14570    }).map(this.getPseudoElements, this));
14571    this.fontMetrics = new FontMetrics();
14572    log("Fetched nodes, total:", this.nodes.length);
14573    log("Calculate overflow clips");
14574    this.calculateOverflowClips();
14575    log("Start fetching images");
14576    this.images = imageLoader.fetch(this.nodes.filter(isElement));
14577    this.ready = this.images.ready.then(bind(function() {
14578        log("Images loaded, starting parsing");
14579        log("Creating stacking contexts");
14580        this.createStackingContexts();
14581        log("Sorting stacking contexts");
14582        this.sortStackingContexts(this.stack);
14583        this.parse(this.stack);
14584        log("Render queue created with " + this.renderQueue.length + " items");
14585        return new Promise(bind(function(resolve) {
14586            if (!options.async) {
14587                this.renderQueue.forEach(this.paint, this);
14588                resolve();
14589            } else if (typeof(options.async) === "function") {
14590                options.async.call(this, this.renderQueue, resolve);
14591            } else if (this.renderQueue.length > 0){
14592                this.renderIndex = 0;
14593                this.asyncRenderer(this.renderQueue, resolve);
14594            } else {
14595                resolve();
14596            }
14597        }, this));
14598    }, this));
14599}
14600
14601NodeParser.prototype.calculateOverflowClips = function() {
14602    this.nodes.forEach(function(container) {
14603        if (isElement(container)) {
14604            if (isPseudoElement(container)) {
14605                container.appendToDOM();
14606            }
14607            container.borders = this.parseBorders(container);
14608            var clip = (container.css('overflow') === "hidden") ? [container.borders.clip] : [];
14609            var cssClip = container.parseClip();
14610            if (cssClip && ["absolute", "fixed"].indexOf(container.css('position')) !== -1) {
14611                clip.push([["rect",
14612                        container.bounds.left + cssClip.left,
14613                        container.bounds.top + cssClip.top,
14614                        cssClip.right - cssClip.left,
14615                        cssClip.bottom - cssClip.top
14616                ]]);
14617            }
14618            container.clip = hasParentClip(container) ? container.parent.clip.concat(clip) : clip;
14619            container.backgroundClip = (container.css('overflow') !== "hidden") ? container.clip.concat([container.borders.clip]) : container.clip;
14620            if (isPseudoElement(container)) {
14621                container.cleanDOM();
14622            }
14623        } else if (isTextNode(container)) {
14624            container.clip = hasParentClip(container) ? container.parent.clip : [];
14625        }
14626        if (!isPseudoElement(container)) {
14627            container.bounds = null;
14628        }
14629    }, this);
14630};
14631
14632function hasParentClip(container) {
14633    return container.parent && container.parent.clip.length;
14634}
14635
14636NodeParser.prototype.asyncRenderer = function(queue, resolve, asyncTimer) {
14637    asyncTimer = asyncTimer || Date.now();
14638    this.paint(queue[this.renderIndex++]);
14639    if (queue.length === this.renderIndex) {
14640        resolve();
14641    } else if (asyncTimer + 20 > Date.now()) {
14642        this.asyncRenderer(queue, resolve, asyncTimer);
14643    } else {
14644        setTimeout(bind(function() {
14645            this.asyncRenderer(queue, resolve);
14646        }, this), 0);
14647    }
14648};
14649
14650NodeParser.prototype.createPseudoHideStyles = function(document) {
14651    this.createStyles(document, '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + ':before { content: "" !important; display: none !important; }' +
14652        '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER + ':after { content: "" !important; display: none !important; }');
14653};
14654
14655NodeParser.prototype.disableAnimations = function(document) {
14656    this.createStyles(document, '* { -webkit-animation: none !important; -moz-animation: none !important; -o-animation: none !important; animation: none !important; ' +
14657        '-webkit-transition: none !important; -moz-transition: none !important; -o-transition: none !important; transition: none !important;}');
14658};
14659
14660NodeParser.prototype.createStyles = function(document, styles) {
14661    var hidePseudoElements = document.createElement('style');
14662    hidePseudoElements.innerHTML = styles;
14663    document.body.appendChild(hidePseudoElements);
14664};
14665
14666NodeParser.prototype.getPseudoElements = function(container) {
14667    var nodes = [[container]];
14668    if (container.node.nodeType === Node.ELEMENT_NODE) {
14669        var before = this.getPseudoElement(container, ":before");
14670        var after = this.getPseudoElement(container, ":after");
14671
14672        if (before) {
14673            nodes.push(before);
14674        }
14675
14676        if (after) {
14677            nodes.push(after);
14678        }
14679    }
14680    return flatten(nodes);
14681};
14682
14683function toCamelCase(str) {
14684    return str.replace(/(\-[a-z])/g, function(match){
14685        return match.toUpperCase().replace('-','');
14686    });
14687}
14688
14689NodeParser.prototype.getPseudoElement = function(container, type) {
14690    var style = container.computedStyle(type);
14691    if(!style || !style.content || style.content === "none" || style.content === "-moz-alt-content" || style.display === "none") {
14692        return null;
14693    }
14694
14695    var content = stripQuotes(style.content);
14696    var isImage = content.substr(0, 3) === 'url';
14697    var pseudoNode = document.createElement(isImage ? 'img' : 'html2canvaspseudoelement');
14698    var pseudoContainer = new PseudoElementContainer(pseudoNode, container, type);
14699
14700    for (var i = style.length-1; i >= 0; i--) {
14701        var property = toCamelCase(style.item(i));
14702        pseudoNode.style[property] = style[property];
14703    }
14704
14705    pseudoNode.className = PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + " " + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER;
14706
14707    if (isImage) {
14708        pseudoNode.src = parseBackgrounds(content)[0].args[0];
14709        return [pseudoContainer];
14710    } else {
14711        var text = document.createTextNode(content);
14712        pseudoNode.appendChild(text);
14713        return [pseudoContainer, new TextContainer(text, pseudoContainer)];
14714    }
14715};
14716
14717
14718NodeParser.prototype.getChildren = function(parentContainer) {
14719    return flatten([].filter.call(parentContainer.node.childNodes, renderableNode).map(function(node) {
14720        var container = [node.nodeType === Node.TEXT_NODE ? new TextContainer(node, parentContainer) : new NodeContainer(node, parentContainer)].filter(nonIgnoredElement);
14721        return node.nodeType === Node.ELEMENT_NODE && container.length && node.tagName !== "TEXTAREA" ? (container[0].isElementVisible() ? container.concat(this.getChildren(container[0])) : []) : container;
14722    }, this));
14723};
14724
14725NodeParser.prototype.newStackingContext = function(container, hasOwnStacking) {
14726    var stack = new StackingContext(hasOwnStacking, container.getOpacity(), container.node, container.parent);
14727    container.cloneTo(stack);
14728    var parentStack = hasOwnStacking ? stack.getParentStack(this) : stack.parent.stack;
14729    parentStack.contexts.push(stack);
14730    container.stack = stack;
14731};
14732
14733NodeParser.prototype.createStackingContexts = function() {
14734    this.nodes.forEach(function(container) {
14735        if (isElement(container) && (this.isRootElement(container) || hasOpacity(container) || isPositionedForStacking(container) || this.isBodyWithTransparentRoot(container) || container.hasTransform())) {
14736            this.newStackingContext(container, true);
14737        } else if (isElement(container) && ((isPositioned(container) && zIndex0(container)) || isInlineBlock(container) || isFloating(container))) {
14738            this.newStackingContext(container, false);
14739        } else {
14740            container.assignStack(container.parent.stack);
14741        }
14742    }, this);
14743};
14744
14745NodeParser.prototype.isBodyWithTransparentRoot = function(container) {
14746    return container.node.nodeName === "BODY" && container.parent.color('backgroundColor').isTransparent();
14747};
14748
14749NodeParser.prototype.isRootElement = function(container) {
14750    return container.parent === null;
14751};
14752
14753NodeParser.prototype.sortStackingContexts = function(stack) {
14754    stack.contexts.sort(zIndexSort(stack.contexts.slice(0)));
14755    stack.contexts.forEach(this.sortStackingContexts, this);
14756};
14757
14758NodeParser.prototype.parseTextBounds = function(container) {
14759    return function(text, index, textList) {
14760        if (container.parent.css("textDecoration").substr(0, 4) !== "none" || text.trim().length !== 0) {
14761            if (this.support.rangeBounds && !container.parent.hasTransform()) {
14762                var offset = textList.slice(0, index).join("").length;
14763                return this.getRangeBounds(container.node, offset, text.length);
14764            } else if (container.node && typeof(container.node.data) === "string") {
14765                var replacementNode = container.node.splitText(text.length);
14766                var bounds = this.getWrapperBounds(container.node, container.parent.hasTransform());
14767                container.node = replacementNode;
14768                return bounds;
14769            }
14770        } else if(!this.support.rangeBounds || container.parent.hasTransform()){
14771            container.node = container.node.splitText(text.length);
14772        }
14773        return {};
14774    };
14775};
14776
14777NodeParser.prototype.getWrapperBounds = function(node, transform) {
14778    var wrapper = node.ownerDocument.createElement('html2canvaswrapper');
14779    var parent = node.parentNode,
14780        backupText = node.cloneNode(true);
14781
14782    wrapper.appendChild(node.cloneNode(true));
14783    parent.replaceChild(wrapper, node);
14784    var bounds = transform ? offsetBounds(wrapper) : getBounds(wrapper);
14785    parent.replaceChild(backupText, wrapper);
14786    return bounds;
14787};
14788
14789NodeParser.prototype.getRangeBounds = function(node, offset, length) {
14790    var range = this.range || (this.range = node.ownerDocument.createRange());
14791    range.setStart(node, offset);
14792    range.setEnd(node, offset + length);
14793    return range.getBoundingClientRect();
14794};
14795
14796function ClearTransform() {}
14797
14798NodeParser.prototype.parse = function(stack) {
14799    // http://www.w3.org/TR/CSS21/visuren.html#z-index
14800    var negativeZindex = stack.contexts.filter(negativeZIndex); // 2. the child stacking contexts with negative stack levels (most negative first).
14801    var descendantElements = stack.children.filter(isElement);
14802    var descendantNonFloats = descendantElements.filter(not(isFloating));
14803    var nonInlineNonPositionedDescendants = descendantNonFloats.filter(not(isPositioned)).filter(not(inlineLevel)); // 3 the in-flow, non-inline-level, non-positioned descendants.
14804    var nonPositionedFloats = descendantElements.filter(not(isPositioned)).filter(isFloating); // 4. the non-positioned floats.
14805    var inFlow = descendantNonFloats.filter(not(isPositioned)).filter(inlineLevel); // 5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
14806    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.
14807    var text = stack.children.filter(isTextNode).filter(hasText);
14808    var positiveZindex = stack.contexts.filter(positiveZIndex); // 7. the child stacking contexts with positive stack levels (least positive first).
14809    negativeZindex.concat(nonInlineNonPositionedDescendants).concat(nonPositionedFloats)
14810        .concat(inFlow).concat(stackLevel0).concat(text).concat(positiveZindex).forEach(function(container) {
14811            this.renderQueue.push(container);
14812            if (isStackingContext(container)) {
14813                this.parse(container);
14814                this.renderQueue.push(new ClearTransform());
14815            }
14816        }, this);
14817};
14818
14819NodeParser.prototype.paint = function(container) {
14820    try {
14821        if (container instanceof ClearTransform) {
14822            this.renderer.ctx.restore();
14823        } else if (isTextNode(container)) {
14824            if (isPseudoElement(container.parent)) {
14825                container.parent.appendToDOM();
14826            }
14827            this.paintText(container);
14828            if (isPseudoElement(container.parent)) {
14829                container.parent.cleanDOM();
14830            }
14831        } else {
14832            this.paintNode(container);
14833        }
14834    } catch(e) {
14835        log(e);
14836        if (this.options.strict) {
14837            throw e;
14838        }
14839    }
14840};
14841
14842NodeParser.prototype.paintNode = function(container) {
14843    if (isStackingContext(container)) {
14844        this.renderer.setOpacity(container.opacity);
14845        this.renderer.ctx.save();
14846        if (container.hasTransform()) {
14847            this.renderer.setTransform(container.parseTransform());
14848        }
14849    }
14850
14851    if (container.node.nodeName === "INPUT" && container.node.type === "checkbox") {
14852        this.paintCheckbox(container);
14853    } else if (container.node.nodeName === "INPUT" && container.node.type === "radio") {
14854        this.paintRadio(container);
14855    } else {
14856        this.paintElement(container);
14857    }
14858};
14859
14860NodeParser.prototype.paintElement = function(container) {
14861    var bounds = container.parseBounds();
14862    this.renderer.clip(container.backgroundClip, function() {
14863        this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth));
14864    }, this);
14865
14866    this.renderer.clip(container.clip, function() {
14867        this.renderer.renderBorders(container.borders.borders);
14868    }, this);
14869
14870    this.renderer.clip(container.backgroundClip, function() {
14871        switch (container.node.nodeName) {
14872        case "svg":
14873        case "IFRAME":
14874            var imgContainer = this.images.get(container.node);
14875            if (imgContainer) {
14876                this.renderer.renderImage(container, bounds, container.borders, imgContainer);
14877            } else {
14878                log("Error loading <" + container.node.nodeName + ">", container.node);
14879            }
14880            break;
14881        case "IMG":
14882            var imageContainer = this.images.get(container.node.src);
14883            if (imageContainer) {
14884                this.renderer.renderImage(container, bounds, container.borders, imageContainer);
14885            } else {
14886                log("Error loading <img>", container.node.src);
14887            }
14888            break;
14889        case "CANVAS":
14890            this.renderer.renderImage(container, bounds, container.borders, {image: container.node});
14891            break;
14892        case "SELECT":
14893        case "INPUT":
14894        case "TEXTAREA":
14895            this.paintFormValue(container);
14896            break;
14897        }
14898    }, this);
14899};
14900
14901NodeParser.prototype.paintCheckbox = function(container) {
14902    var b = container.parseBounds();
14903
14904    var size = Math.min(b.width, b.height);
14905    var bounds = {width: size - 1, height: size - 1, top: b.top, left: b.left};
14906    var r = [3, 3];
14907    var radius = [r, r, r, r];
14908    var borders = [1,1,1,1].map(function(w) {
14909        return {color: new Color('#A5A5A5'), width: w};
14910    });
14911
14912    var borderPoints = calculateCurvePoints(bounds, radius, borders);
14913
14914    this.renderer.clip(container.backgroundClip, function() {
14915        this.renderer.rectangle(bounds.left + 1, bounds.top + 1, bounds.width - 2, bounds.height - 2, new Color("#DEDEDE"));
14916        this.renderer.renderBorders(calculateBorders(borders, bounds, borderPoints, radius));
14917        if (container.node.checked) {
14918            this.renderer.font(new Color('#424242'), 'normal', 'normal', 'bold', (size - 3) + "px", 'arial');
14919            this.renderer.text("\u2714", bounds.left + size / 6, bounds.top + size - 1);
14920        }
14921    }, this);
14922};
14923
14924NodeParser.prototype.paintRadio = function(container) {
14925    var bounds = container.parseBounds();
14926
14927    var size = Math.min(bounds.width, bounds.height) - 2;
14928
14929    this.renderer.clip(container.backgroundClip, function() {
14930        this.renderer.circleStroke(bounds.left + 1, bounds.top + 1, size, new Color('#DEDEDE'), 1, new Color('#A5A5A5'));
14931        if (container.node.checked) {
14932            this.renderer.circle(Math.ceil(bounds.left + size / 4) + 1, Math.ceil(bounds.top + size / 4) + 1, Math.floor(size / 2), new Color('#424242'));
14933        }
14934    }, this);
14935};
14936
14937NodeParser.prototype.paintFormValue = function(container) {
14938    var value = container.getValue();
14939    if (value.length > 0) {
14940        var document = container.node.ownerDocument;
14941        var wrapper = document.createElement('html2canvaswrapper');
14942        var properties = ['lineHeight', 'textAlign', 'fontFamily', 'fontWeight', 'fontSize', 'color',
14943            'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom',
14944            'width', 'height', 'borderLeftStyle', 'borderTopStyle', 'borderLeftWidth', 'borderTopWidth',
14945            'boxSizing', 'whiteSpace', 'wordWrap'];
14946
14947        properties.forEach(function(property) {
14948            try {
14949                wrapper.style[property] = container.css(property);
14950            } catch(e) {
14951                // Older IE has issues with "border"
14952                log("html2canvas: Parse: Exception caught in renderFormValue: " + e.message);
14953            }
14954        });
14955        var bounds = container.parseBounds();
14956        wrapper.style.position = "fixed";
14957        wrapper.style.left = bounds.left + "px";
14958        wrapper.style.top = bounds.top + "px";
14959        wrapper.textContent = value;
14960        document.body.appendChild(wrapper);
14961        this.paintText(new TextContainer(wrapper.firstChild, container));
14962        document.body.removeChild(wrapper);
14963    }
14964};
14965
14966NodeParser.prototype.paintText = function(container) {
14967    container.applyTextTransform();
14968    var characters = punycode.ucs2.decode(container.node.data);
14969    var textList = (!this.options.letterRendering || noLetterSpacing(container)) && !hasUnicode(container.node.data) ? getWords(characters) : characters.map(function(ch
14969aracter) {
14970        return punycode.ucs2.encode([character]);
14971    });
14972
14973    var weight = container.parent.fontWeight();
14974    var size = container.parent.css('fontSize');
14975    var family = container.parent.css('fontFamily');
14976    var shadows = container.parent.parseTextShadows();
14977
14978    this.renderer.font(container.parent.color('color'), container.parent.css('fontStyle'), container.parent.css('fontVariant'), weight, size, family);
14979    if (shadows.length) {
14980        // TODO: support multiple text shadows
14981        this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur);
14982    } else {
14983        this.renderer.clearShadow();
14984    }
14985
14986    this.renderer.clip(container.parent.clip, function() {
14987        textList.map(this.parseTextBounds(container), this).forEach(function(bounds, index) {
14988            if (bounds) {
14989                this.renderer.text(textList[index], bounds.left, bounds.bottom);
14990                this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));
14991            }
14992        }, this);
14993    }, this);
14994};
14995
14996NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) {
14997    switch(container.css("textDecoration").split(" ")[0]) {
14998    case "underline":
14999        // Draws a line at the baseline of the font
15000        // 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
15001        this.renderer.rectangle(bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, container.color("color"));
15002        break;
15003    case "overline":
15004        this.renderer.rectangle(bounds.left, Math.round(bounds.top), bounds.width, 1, container.color("color"));
15005        break;
15006    case "line-through":
15007        // TODO try and find exact position for line-through
15008        this.renderer.rectangle(bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, container.color("color"));
15009        break;
15010    }
15011};
15012
15013var borderColorTransforms = {
15014    inset: [
15015        ["darken", 0.60],
15016        ["darken", 0.10],
15017        ["darken", 0.10],
15018        ["darken", 0.60]
15019    ]
15020};
15021
15022NodeParser.prototype.parseBorders = function(container) {
15023    var nodeBounds = container.parseBounds();
15024    var radius = getBorderRadiusData(container);
15025    var borders = ["Top", "Right", "Bottom", "Left"].map(function(side, index) {
15026        var style = container.css('border' + side + 'Style');
15027        var color = container.color('border' + side + 'Color');
15028        if (style === "inset" && color.isBlack()) {
15029            color = new Color([255, 255, 255, color.a]); // this is wrong, but
15030        }
15031        var colorTransform = borderColorTransforms[style] ? borderColorTransforms[style][index] : null;
15032        return {
15033            width: container.cssInt('border' + side + 'Width'),
15034            color: colorTransform ? color[colorTransform[0]](colorTransform[1]) : color,
15035            args: null
15036        };
15037    });
15038    var borderPoints = calculateCurvePoints(nodeBounds, radius, borders);
15039
15040    return {
15041        clip: this.parseBackgroundClip(container, borderPoints, borders, radius, nodeBounds),
15042        borders: calculateBorders(borders, nodeBounds, borderPoints, radius)
15043    };
15044};
15045
15046function calculateBorders(borders, nodeBounds, borderPoints, radius) {
15047    return borders.map(function(border, borderSide) {
15048        if (border.width > 0) {
15049            var bx = nodeBounds.left;
15050            var by = nodeBounds.top;
15051            var bw = nodeBounds.width;
15052            var bh = nodeBounds.height - (borders[2].width);
15053
15054            switch(borderSide) {
15055            case 0:
15056                // top border
15057                bh = borders[0].width;
15058                border.args = drawSide({
15059                        c1: [bx, by],
15060                        c2: [bx + bw, by],
15061                        c3: [bx + bw - borders[1].width, by + bh],
15062                        c4: [bx + borders[3].width, by + bh]
15063                    }, radius[0], radius[1],
15064                    borderPoints.topLeftOuter, borderPoints.topLeftInner, borderPoints.topRightOuter, borderPoints.topRightInner);
15065                break;
15066            case 1:
15067                // right border
15068                bx = nodeBounds.left + nodeBounds.width - (borders[1].width);
15069                bw = borders[1].width;
15070
15071                border.args = drawSide({
15072                        c1: [bx + bw, by],
15073                        c2: [bx + bw, by + bh + borders[2].width],
15074                        c3: [bx, by + bh],
15075                        c4: [bx, by + borders[0].width]
15076                    }, radius[1], radius[2],
15077                    borderPoints.topRightOuter, borderPoints.topRightInner, borderPoints.bottomRightOuter, borderPoints.bottomRightInner);
15078                break;
15079            case 2:
15080                // bottom border
15081                by = (by + nodeBounds.height) - (borders[2].width);
15082                bh = borders[2].width;
15083                border.args = drawSide({
15084                        c1: [bx + bw, by + bh],
15085                        c2: [bx, by + bh],
15086                        c3: [bx + borders[3].width, by],
15087                        c4: [bx + bw - borders[3].width, by]
15088                    }, radius[2], radius[3],
15089                    borderPoints.bottomRightOuter, borderPoints.bottomRightInner, borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner);
15090                break;
15091            case 3:
15092                // left border
15093                bw = borders[3].width;
15094                border.args = drawSide({
15095                        c1: [bx, by + bh + borders[2].width],
15096                        c2: [bx, by],
15097                        c3: [bx + bw, by + borders[0].width],
15098                        c4: [bx + bw, by + bh]
15099                    }, radius[3], radius[0],
15100                    borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner, borderPoints.topLeftOuter, borderPoints.topLeftInner);
15101                break;
15102            }
15103        }
15104        return border;
15105    });
15106}
15107
15108NodeParser.prototype.parseBackgroundClip = function(container, borderPoints, borders, radius, bounds) {
15109    var backgroundClip = container.css('backgroundClip'),
15110        borderArgs = [];
15111
15112    switch(backgroundClip) {
15113    case "content-box":
15114    case "padding-box":
15115        parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftInner, borderPoints.topRightInner, bounds.left + borders[3].width, bounds.top + borders[0].width);
15116        parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightInner, borderPoints.bottomRightInner, bounds.left + bounds.width - borders[1].width, bounds.top + borders[0].width);
15117        parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightInner, borderPoints.bottomLeftInner, bounds.left + bounds.width - borders[1].width, bounds.top + bounds.height - borders[2].width);
15118        parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftInner, borderPoints.topLeftInner, bounds.left + borders[3].width, bounds.top + bounds.height - borders[2].width);
15119        break;
15120
15121    default:
15122        parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftOuter, borderPoints.topRightOuter, bounds.left, bounds.top);
15123        parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightOuter, borderPoints.bottomRightOuter, bounds.left + bounds.width, bounds.top);
15124        parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightOuter, borderPoints.bottomLeftOuter, bounds.left + bounds.width, bounds.top + bounds.height);
15125        parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftOuter, borderPoints.topLeftOuter, bounds.left, bounds.top + bounds.height);
15126        break;
15127    }
15128
15129    return borderArgs;
15130};
15131
15132function getCurvePoints(x, y, r1, r2) {
15133    var kappa = 4 * ((Math.sqrt(2) - 1) / 3);
15134    var ox = (r1) * kappa, // control point offset horizontal
15135        oy = (r2) * kappa, // control point offset vertical
15136        xm = x + r1, // x-middle
15137        ym = y + r2; // y-middle
15138    return {
15139        topLeft: bezierCurve({x: x, y: ym}, {x: x, y: ym - oy}, {x: xm - ox, y: y}, {x: xm, y: y}),
15140        topRight: bezierCurve({x: x, y: y}, {x: x + ox,y: y}, {x: xm, y: ym - oy}, {x: xm, y: ym}),
15141        bottomRight: bezierCurve({x: xm, y: y}, {x: xm, y: y + oy}, {x: x + ox, y: ym}, {x: x, y: ym}),
15142        bottomLeft: bezierCurve({x: xm, y: ym}, {x: xm - ox, y: ym}, {x: x, y: y + oy}, {x: x, y:y})
15143    };
15144}
15145
15146function calculateCurvePoints(bounds, borderRadius, borders) {
15147    var x = bounds.left,
15148        y = bounds.top,
15149        width = bounds.width,
15150        height = bounds.height,
15151
15152        tlh = borderRadius[0][0] < width / 2 ? borderRadius[0][0] : width / 2,
15153        tlv = borderRadius[0][1] < height / 2 ? borderRadius[0][1] : height / 2,
15154        trh = borderRadius[1][0] < width / 2 ? borderRadius[1][0] : width / 2,
15155        trv = borderRadius[1][1] < height / 2 ? borderRadius[1][1] : height / 2,
15156        brh = borderRadius[2][0] < width / 2 ? borderRadius[2][0] : width / 2,
15157        brv = borderRadius[2][1] < height / 2 ? borderRadius[2][1] : height / 2,
15158        blh = borderRadius[3][0] < width / 2 ? borderRadius[3][0] : width / 2,
15159        blv = borderRadius[3][1] < height / 2 ? borderRadius[3][1] : height / 2;
15160
15161    var topWidth = width - trh,
15162        rightHeight = height - brv,
15163        bottomWidth = width - brh,
15164        leftHeight = height - blv;
15165
15166    return {
15167        topLeftOuter: getCurvePoints(x, y, tlh, tlv).topLeft.subdivide(0.5),
15168        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),
15169        topRightOuter: getCurvePoints(x + topWidth, y, trh, trv).topRight.subdivide(0.5),
15170        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),
15171        bottomRightOuter: getCurvePoints(x + bottomWidth, y + rightHeight, brh, brv).bottomRight.subdivide(0.5),
15172        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),
15173        bottomLeftOuter: getCurvePoints(x, y + leftHeight, blh, blv).bottomLeft.subdivide(0.5),
15174        bottomLeftInner: getCurvePoints(x + borders[3].width, y + leftHeight, Math.max(0, blh - borders[3].width), blv - borders[2].width).bottomLeft.subdivide(0.5)
15175    };
15176}
15177
15178function bezierCurve(start, startControl, endControl, end) {
15179    var lerp = function (a, b, t) {
15180        return {
15181            x: a.x + (b.x - a.x) * t,
15182            y: a.y + (b.y - a.y) * t
15183        };
15184    };
15185
15186    return {
15187        start: start,
15188        startControl: startControl,
15189        endControl: endControl,
15190        end: end,
15191        subdivide: function(t) {
15192            var ab = lerp(start, startControl, t),
15193                bc = lerp(startControl, endControl, t),
15194                cd = lerp(endControl, end, t),
15195                abbc = lerp(ab, bc, t),
15196                bccd = lerp(bc, cd, t),
15197                dest = lerp(abbc, bccd, t);
15198            return [bezierCurve(start, ab, abbc, dest), bezierCurve(dest, bccd, cd, end)];
15199        },
15200        curveTo: function(borderArgs) {
15201            borderArgs.push(["bezierCurve", startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y]);
15202        },
15203        curveToReversed: function(borderArgs) {
15204            borderArgs.push(["bezierCurve", endControl.x, endControl.y, startControl.x, startControl.y, start.x, start.y]);
15205        }
15206    };
15207}
15208
15209function drawSide(borderData, radius1, radius2, outer1, inner1, outer2, inner2) {
15210    var borderArgs = [];
15211
15212    if (radius1[0] > 0 || radius1[1] > 0) {
15213        borderArgs.push(["line", outer1[1].start.x, outer1[1].start.y]);
15214        outer1[1].curveTo(borderArgs);
15215    } else {
15216        borderArgs.push([ "line", borderData.c1[0], borderData.c1[1]]);
15217    }
15218
15219    if (radius2[0] > 0 || radius2[1] > 0) {
15220        borderArgs.push(["line", outer2[0].start.x, outer2[0].start.y]);
15221        outer2[0].curveTo(borderArgs);
15222        borderArgs.push(["line", inner2[0].end.x, inner2[0].end.y]);
15223        inner2[0].curveToReversed(borderArgs);
15224    } else {
15225        borderArgs.push(["line", borderData.c2[0], borderData.c2[1]]);
15226        borderArgs.push(["line", borderData.c3[0], borderData.c3[1]]);
15227    }
15228
15229    if (radius1[0] > 0 || radius1[1] > 0) {
15230        borderArgs.push(["line", inner1[1].end.x, inner1[1].end.y]);
15231        inner1[1].curveToReversed(borderArgs);
15232    } else {
15233        borderArgs.push(["line", borderData.c4[0], borderData.c4[1]]);
15234    }
15235
15236    return borderArgs;
15237}
15238
15239function parseCorner(borderArgs, radius1, radius2, corner1, corner2, x, y) {
15240    if (radius1[0] > 0 || radius1[1] > 0) {
15241        borderArgs.push(["line", corner1[0].start.x, corner1[0].start.y]);
15242        corner1[0].curveTo(borderArgs);
15243        corner1[1].curveTo(borderArgs);
15244    } else {
15245        borderArgs.push(["line", x, y]);
15246    }
15247
15248    if (radius2[0] > 0 || radius2[1] > 0) {
15249        borderArgs.push(["line", corner2[0].start.x, corner2[0].start.y]);
15250    }
15251}
15252
15253function negativeZIndex(container) {
15254    return container.cssInt("zIndex") < 0;
15255}
15256
15257function positiveZIndex(container) {
15258    return container.cssInt("zIndex") > 0;
15259}
15260
15261function zIndex0(container) {
15262    return container.cssInt("zIndex") === 0;
15263}
15264
15265function inlineLevel(container) {
15266    return ["inline", "inline-block", "inline-table"].indexOf(container.css("display")) !== -1;
15267}
15268
15269function isStackingContext(container) {
15270    return (container instanceof StackingContext);
15271}
15272
15273function hasText(container) {
15274    return container.node.data.trim().length > 0;
15275}
15276
15277function noLetterSpacing(container) {
15278    return (/^(normal|none|0px)$/.test(container.parent.css("letterSpacing")));
15279}
15280
15281function getBorderRadiusData(container) {
15282    return ["TopLeft", "TopRight", "BottomRight", "BottomLeft"].map(function(side) {
15283        var value = container.css('border' + side + 'Radius');
15284        var arr = value.split(" ");
15285        if (arr.length <= 1) {
15286            arr[1] = arr[0];
15287        }
15288        return arr.map(asInt);
15289    });
15290}
15291
15292function renderableNode(node) {
15293    return (node.nodeType === Node.TEXT_NODE || node.nodeType === Node.ELEMENT_NODE);
15294}
15295
15296function isPositionedForStacking(container) {
15297    var position = container.css("position");
15298    var zIndex = (["absolute", "relative", "fixed"].indexOf(position) !== -1) ? container.css("zIndex") : "auto";
15299    return zIndex !== "auto";
15300}
15301
15302function isPositioned(container) {
15303    return container.css("position") !== "static";
15304}
15305
15306function isFloating(container) {
15307    return container.css("float") !== "none";
15308}
15309
15310function isInlineBlock(container) {
15311    return ["inline-block", "inline-table"].indexOf(container.css("display")) !== -1;
15312}
15313
15314function not(callback) {
15315    var context = this;
15316    return function() {
15317        return !callback.apply(context, arguments);
15318    };
15319}
15320
15321function isElement(container) {
15322    return container.node.nodeType === Node.ELEMENT_NODE;
15323}
15324
15325function isPseudoElement(container) {
15326    return container.isPseudoElement === true;
15327}
15328
15329function isTextNode(container) {
15330    return container.node.nodeType === Node.TEXT_NODE;
15331}
15332
15333function zIndexSort(contexts) {
15334    return function(a, b) {
15335        return (a.cssInt("zIndex") + (contexts.indexOf(a) / contexts.length)) - (b.cssInt("zIndex") + (contexts.indexOf(b) / contexts.length));
15336    };
15337}
15338
15339function hasOpacity(container) {
15340    return container.getOpacity() < 1;
15341}
15342
15343function asInt(value) {
15344    return parseInt(value, 10);
15345}
15346
15347function getWidth(border) {
15348    return border.width;
15349}
15350
15351function nonIgnoredElement(nodeContainer) {
15352    return (nodeContainer.node.nodeType !== Node.ELEMENT_NODE || ["SCRIPT", "HEAD", "TITLE", "OBJECT", "BR", "OPTION"].indexOf(nodeContainer.node.nodeName) === -1);
15353}
15354
15355function flatten(arrays) {
15356    return [].concat.apply([], arrays);
15357}
15358
15359function stripQuotes(content) {
15360    var first = content.substr(0, 1);
15361    return (first === content.substr(content.length - 1) && first.match(/'|"/)) ? content.substr(1, content.length - 2) : content;
15362}
15363
15364function getWords(characters) {
15365    var words = [], i = 0, onWordBoundary = false, word;
15366    while(characters.length) {
15367        if (isWordBoundary(characters[i]) === onWordBoundary) {
15368            word = characters.splice(0, i);
15369            if (word.length) {
15370                words.push(punycode.ucs2.encode(word));
15371            }
15372            onWordBoundary =! onWordBoundary;
15373            i = 0;
15374        } else {
15375            i++;
15376        }
15377
15378        if (i >= characters.length) {
15379            word = characters.splice(0, i);
15380            if (word.length) {
15381                words.push(punycode.ucs2.encode(word));
15382            }
15383        }
15384    }
15385    return words;
15386}
15387
15388function isWordBoundary(characterCode) {
15389    return [
15390        32, // <space>
15391        13, // \r
15392        10, // \n
15393        9, // \t
15394        45 // -
15395    ].indexOf(characterCode) !== -1;
15396}
15397
15398function hasUnicode(string) {
15399    return (/[^\u0000-\u00ff]/).test(string);
15400}
15401
15402module.exports = NodeParser;
15403
15404},{"./color":3,"./fontmetrics":7,"./log":13,"./nodecontainer":14,"./pseudoelementcontainer":18,"./stackingcontext":21,"./textcontainer":25,"./utils":26,"pu
15404nycode":1}],16:[function(_dereq_,module,exports){
15405var XHR = _dereq_('./xhr');
15406var utils = _dereq_('./utils');
15407var log = _dereq_('./log');
15408var createWindowClone = _dereq_('./clone');
15409var decode64 = utils.decode64;
15410
15411function Proxy(src, proxyUrl, document) {
15412    var supportsCORS = ('withCredentials' in new XMLHttpRequest());
15413    if (!proxyUrl) {
15414        return Promise.reject("No proxy configured");
15415    }
15416    var callback = createCallback(supportsCORS);
15417    var url = createProxyUrl(proxyUrl, src, callback);
15418
15419    return supportsCORS ? XHR(url) : (jsonp(document, url, callback).then(function(response) {
15420        return decode64(response.content);
15421    }));
15422}
15423var proxyCount = 0;
15424
15425function ProxyURL(src, proxyUrl, document) {
15426    var supportsCORSImage = ('crossOrigin' in new Image());
15427    var callback = createCallback(supportsCORSImage);
15428    var url = createProxyUrl(proxyUrl, src, callback);
15429    return (supportsCORSImage ? Promise.resolve(url) : jsonp(document, url, callback).then(function(response) {
15430        return "data:" + response.type + ";base64," + response.content;
15431    }));
15432}
15433
15434function jsonp(document, url, callback) {
15435    return new Promise(function(resolve, reject) {
15436        var s = document.createElement("script");
15437        var cleanup = function() {
15438            delete window.html2canvas.proxy[callback];
15439            document.body.removeChild(s);
15440        };
15441        window.html2canvas.proxy[callback] = function(response) {
15442            cleanup();
15443            resolve(response);
15444        };
15445        s.src = url;
15446        s.onerror = function(e) {
15447            cleanup();
15448            reject(e);
15449        };
15450        document.body.appendChild(s);
15451    });
15452}
15453
15454function createCallback(useCORS) {
15455    return !useCORS ? "html2canvas_" + Date.now() + "_" + (++proxyCount) + "_" + Math.round(Math.random() * 100000) : "";
15456}
15457
15458function createProxyUrl(proxyUrl, src, callback) {
15459    return proxyUrl + "?url=" + encodeURIComponent(src) + (callback.length ? "&callback=html2canvas.proxy." + callback : "");
15460}
15461
15462function documentFromHTML(src) {
15463    return function(html) {
15464        var parser = new DOMParser(), doc;
15465        try {
15466            doc = parser.parseFromString(html, "text/html");
15467        } catch(e) {
15468            log("DOMParser not supported, falling back to createHTMLDocument");
15469            doc = document.implementation.createHTMLDocument("");
15470            try {
15471                doc.open();
15472                doc.write(html);
15473                doc.close();
15474            } catch(ee) {
15475                log("createHTMLDocument write not supported, falling back to document.body.innerHTML");
15476                doc.body.innerHTML = html; // ie9 doesnt support writing to documentElement
15477            }
15478        }
15479
15480        var b = doc.querySelector("base");
15481        if (!b || !b.href.host) {
15482            var base = doc.createElement("base");
15483            base.href = src;
15484            doc.head.insertBefore(base, doc.head.firstChild);
15485        }
15486
15487        return doc;
15488    };
15489}
15490
15491function loadUrlDocument(src, proxy, document, width, height, options) {
15492    return new Proxy(src, proxy, window.document).then(documentFromHTML(src)).then(function(doc) {
15493        return createWindowClone(doc, document, width, height, options, 0, 0);
15494    });
15495}
15496
15497exports.Proxy = Proxy;
15498exports.ProxyURL = ProxyURL;
15499exports.loadUrlDocument = loadUrlDocument;
15500
15501},{"./clone":2,"./log":13,"./utils":26,"./xhr":28}],17:[function(_dereq_,module,exports){
15502var ProxyURL = _dereq_('./proxy').ProxyURL;
15503
15504function ProxyImageContainer(src, proxy) {
15505    var link = document.createElement("a");
15506    link.href = src;
15507    src = link.href;
15508    this.src = src;
15509    this.image = new Image();
15510    var self = this;
15511    this.promise = new Promise(function(resolve, reject) {
15512        self.image.crossOrigin = "Anonymous";
15513        self.image.onload = resolve;
15514        self.image.onerror = reject;
15515
15516        new ProxyURL(src, proxy, document).then(function(url) {
15517            self.image.src = url;
15518        })['catch'](reject);
15519    });
15520}
15521
15522module.exports = ProxyImageContainer;
15523
15524},{"./proxy":16}],18:[function(_dereq_,module,exports){
15525var NodeContainer = _dereq_('./nodecontainer');
15526
15527function PseudoElementContainer(node, parent, type) {
15528    NodeContainer.call(this, node, parent);
15529    this.isPseudoElement = true;
15530    this.before = type === ":before";
15531}
15532
15533PseudoElementContainer.prototype.cloneTo = function(stack) {
15534    PseudoElementContainer.prototype.cloneTo.call(this, stack);
15535    stack.isPseudoElement = true;
15536    stack.before = this.before;
15537};
15538
15539PseudoElementContainer.prototype = Object.create(NodeContainer.prototype);
15540
15541PseudoElementContainer.prototype.appendToDOM = function() {
15542    if (this.before) {
15543        this.parent.node.insertBefore(this.node, this.parent.node.firstChild);
15544    } else {
15545        this.parent.node.appendChild(this.node);
15546    }
15547    this.parent.node.className += " " + this.getHideClass();
15548};
15549
15550PseudoElementContainer.prototype.cleanDOM = function() {
15551    this.node.parentNode.removeChild(this.node);
15552    this.parent.node.className = this.parent.node.className.replace(this.getHideClass(), "");
15553};
15554
15555PseudoElementContainer.prototype.getHideClass = function() {
15556    return this["PSEUDO_HIDE_ELEMENT_CLASS_" + (this.before ? "BEFORE" : "AFTER")];
15557};
15558
15559PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE = "___html2canvas___pseudoelement_before";
15560PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER = "___html2canvas___pseudoelement_after";
15561
15562module.exports = PseudoElementContainer;
15563
15564},{"./nodecontainer":14}],19:[function(_dereq_,module,exports){
15565var log = _dereq_('./log');
15566
15567function Renderer(width, height, images, options, document) {
15568    this.width = width;
15569    this.height = height;
15570    this.images = images;
15571    this.options = options;
15572    this.document = document;
15573}
15574
15575Renderer.prototype.renderImage = function(container, bounds, borderData, imageContainer) {
15576    var paddingLeft = container.cssInt('paddingLeft'),
15577        paddingTop = container.cssInt('paddingTop'),
15578        paddingRight = container.cssInt('paddingRight'),
15579        paddingBottom = container.cssInt('paddingBottom'),
15580        borders = borderData.borders;
15581
15582    var width = bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight);
15583    var height = bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom);
15584    this.drawImage(
15585        imageContainer,
15586        0,
15587        0,
15588        imageContainer.image.width || width,
15589        imageContainer.image.height || height,
15590        bounds.left + paddingLeft + borders[3].width,
15591        bounds.top + paddingTop + borders[0].width,
15592        width,
15593        height
15594    );
15595};
15596
15597Renderer.prototype.renderBackground = function(container, bounds, borderData) {
15598    if (bounds.height > 0 && bounds.width > 0) {
15599        this.renderBackgroundColor(container, bounds);
15600        this.renderBackgroundImage(container, bounds, borderData);
15601    }
15602};
15603
15604Renderer.prototype.renderBackgroundColor = function(container, bounds) {
15605    var color = container.color("backgroundColor");
15606    if (!color.isTransparent()) {
15607        this.rectangle(bounds.left, bounds.top, bounds.width, bounds.height, color);
15608    }
15609};
15610
15611Renderer.prototype.renderBorders = function(borders) {
15612    borders.forEach(this.renderBorder, this);
15613};
15614
15615Renderer.prototype.renderBorder = function(data) {
15616    if (!data.color.isTransparent() && data.args !== null) {
15617        this.drawShape(data.args, data.color);
15618    }
15619};
15620
15621Renderer.prototype.renderBackgroundImage = function(container, bounds, borderData) {
15622    var backgroundImages = container.parseBackgroundImages();
15623    backgroundImages.reverse().forEach(function(backgroundImage, index, arr) {
15624        switch(backgroundImage.method) {
15625        case "url":
15626            var image = this.images.get(backgroundImage.args[0]);
15627            if (image) {
15628                this.renderBackgroundRepeating(container, bounds, image, arr.length - (index+1), borderData);
15629            } else {
15630                log("Error loading background-image", backgroundImage.args[0]);
15631            }
15632            break;
15633        case "linear-gradient":
15634        case "gradient":
15635            var gradientImage = this.images.get(backgroundImage.value);
15636            if (gradientImage) {
15637                this.renderBackgroundGradient(gradientImage, bounds, borderData);
15638            } else {
15639                log("Error loading background-image", backgroundImage.args[0]);
15640            }
15641            break;
15642        case "none":
15643            break;
15644        default:
15645            log("Unknown background-image type", backgroundImage.args[0]);
15646        }
15647    }, this);
15648};
15649
15650Renderer.prototype.renderBackgroundRepeating = function(container, bounds, imageContainer, index, borderData) {
15651    var size = container.parseBackgroundSize(bounds, imageContainer.image, index);
15652    var position = container.parseBackgroundPosition(bounds, imageContainer.image, index, size);
15653    var repeat = container.parseBackgroundRepeat(index);
15654    switch (repeat) {
15655    case "repeat-x":
15656    case "repeat no-repeat":
15657        this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + borderData[3], bounds.top + position.top + borderData[0], 99999, size.height, borderData);
15658        break;
15659    case "repeat-y":
15660    case "no-repeat repeat":
15661        this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + position.left + borderData[3], bounds.top + borderData[0], size.width, 99999, borderData);
15662        break;
15663    case "no-repeat":
15664        this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + position.left + borderData[3], bounds.top + position.top + borderData[0], size.width, size.height, borderData);
15665        break;
15666    default:
15667        this.renderBackgroundRepeat(imageContainer, position, size, {top: bounds.top, left: bounds.left}, borderData[3], borderData[0]);
15668        break;
15669    }
15670};
15671
15672module.exports = Renderer;
15673
15674},{"./log":13}],20:[function(_dereq_,module,exports){
15675var Renderer = _dereq_('../renderer');
15676var LinearGradientContainer = _dereq_('../lineargradientcontainer');
15677var log = _dereq_('../log');
15678
15679function CanvasRenderer(width, height) {
15680    Renderer.apply(this, arguments);
15681    this.canvas = this.options.canvas || this.document.createElement("canvas");
15682    if (!this.options.canvas) {
15683        this.canvas.width = width;
15684        this.canvas.height = height;
15685    }
15686    this.ctx = this.canvas.getContext("2d");
15687    this.taintCtx = this.document.createElement("canvas").getContext("2d");
15688    this.ctx.textBaseline = "bottom";
15689    this.variables = {};
15690    log("Initialized CanvasRenderer with size", width, "x", height);
15691}
15692
15693CanvasRenderer.prototype = Object.create(Renderer.prototype);
15694
15695CanvasRenderer.prototype.setFillStyle = function(fillStyle) {
15696    this.ctx.fillStyle = typeof(fillStyle) === "object" && !!fillStyle.isColor ? fillStyle.toString() : fillStyle;
15697    return this.ctx;
15698};
15699
15700CanvasRenderer.prototype.rectangle = function(left, top, width, height, color) {
15701    this.setFillStyle(color).fillRect(left, top, width, height);
15702};
15703
15704CanvasRenderer.prototype.circle = function(left, top, size, color) {
15705    this.setFillStyle(color);
15706    this.ctx.beginPath();
15707    this.ctx.arc(left + size / 2, top + size / 2, size / 2, 0, Math.PI*2, true);
15708    this.ctx.closePath();
15709    this.ctx.fill();
15710};
15711
15712CanvasRenderer.prototype.circleStroke = function(left, top, size, color, stroke, strokeColor) {
15713    this.circle(left, top, size, color);
15714    this.ctx.strokeStyle = strokeColor.toString();
15715    this.ctx.stroke();
15716};
15717
15718CanvasRenderer.prototype.drawShape = function(shape, color) {
15719    this.shape(shape);
15720    this.setFillStyle(color).fill();
15721};
15722
15723CanvasRenderer.prototype.taints = function(imageContainer) {
15724    if (imageContainer.tainted === null) {
15725        this.taintCtx.drawImage(imageContainer.image, 0, 0);
15726        try {
15727            this.taintCtx.getImageData(0, 0, 1, 1);
15728            imageContainer.tainted = false;
15729        } catch(e) {
15730            this.taintCtx = document.createElement("canvas").getContext("2d");
15731            imageContainer.tainted = true;
15732        }
15733    }
15734
15735    return imageContainer.tainted;
15736};
15737
15738CanvasRenderer.prototype.drawImage = function(imageContainer, sx, sy, sw, sh, dx, dy, dw, dh) {
15739    if (!this.taints(imageContainer) || this.options.allowTaint) {
15740        this.ctx.drawImage(imageContainer.image, sx, sy, sw, sh, dx, dy, dw, dh);
15741    }
15742};
15743
15744CanvasRenderer.prototype.clip = function(shapes, callback, context) {
15745    this.ctx.save();
15746    shapes.filter(hasEntries).forEach(function(shape) {
15747        this.shape(shape).clip();
15748    }, this);
15749    callback.call(context);
15750    this.ctx.restore();
15751};
15752
15753CanvasRenderer.prototype.shape = function(shape) {
15754    this.ctx.beginPath();
15755    shape.forEach(function(point, index) {
15756        if (point[0] === "rect") {
15757            this.ctx.rect.apply(this.ctx, point.slice(1));
15758        } else {
15759            this.ctx[(index === 0) ? "moveTo" : point[0] + "To" ].apply(this.ctx, point.slice(1));
15760        }
15761    }, this);
15762    this.ctx.closePath();
15763    return this.ctx;
15764};
15765
15766CanvasRenderer.prototype.font = function(color, style, variant, weight, size, family) {
15767    this.setFillStyle(color).font = [style, variant, weight, size, family].join(" ").split(",")[0];
15768};
15769
15770CanvasRenderer.prototype.fontShadow = function(color, offsetX, offsetY, blur) {
15771    this.setVariable("shadowColor", color.toString())
15772        .setVariable("shadowOffsetY", offsetX)
15773        .setVariable("shadowOffsetX", offsetY)
15774        .setVariable("shadowBlur", blur);
15775};
15776
15777CanvasRenderer.prototype.clearShadow = function() {
15778    this.setVariable("shadowColor", "rgba(0,0,0,0)");
15779};
15780
15781CanvasRenderer.prototype.setOpacity = function(opacity) {
15782    this.ctx.globalAlpha = opacity;
15783};
15784
15785CanvasRenderer.prototype.setTransform = function(transform) {
15786    this.ctx.translate(transform.origin[0], transform.origin[1]);
15787    this.ctx.transform.apply(this.ctx, transform.matrix);
15788    this.ctx.translate(-transform.origin[0], -transform.origin[1]);
15789};
15790
15791CanvasRenderer.prototype.setVariable = function(property, value) {
15792    if (this.variables[property] !== value) {
15793        this.variables[property] = this.ctx[property] = value;
15794    }
15795
15796    return this;
15797};
15798
15799CanvasRenderer.prototype.text = function(text, left, bottom) {
15800    this.ctx.fillText(text, left, bottom);
15801};
15802
15803CanvasRenderer.prototype.backgroundRepeatShape = function(imageContainer, backgroundPosition, size, bounds, left, top, width, height, borderData) {
15804    var shape = [
15805        ["line", Math.round(left), Math.round(top)],
15806        ["line", Math.round(left + width), Math.round(top)],
15807        ["line", Math.round(left + width), Math.round(height + top)],
15808        ["line", Math.round(left), Math.round(height + top)]
15809    ];
15810    this.clip([shape], function() {
15811        this.renderBackgroundRepeat(imageContainer, backgroundPosition, size, bounds, borderData[3], borderData[0]);
15812    }, this);
15813};
15814
15815CanvasRenderer.prototype.renderBackgroundRepeat = function(imageContainer, backgroundPosition, size, bounds, borderLeft, borderTop) {
15816    var offsetX = Math.round(bounds.left + backgroundPosition.left + borderLeft), offsetY = Math.round(bounds.top + backgroundPosition.top + borderTop);
15817    this.setFillStyle(this.ctx.createPattern(this.resizeImage(imageContainer, size), "repeat"));
15818    this.ctx.translate(offsetX, offsetY);
15819    this.ctx.fill();
15820    this.ctx.translate(-offsetX, -offsetY);
15821};
15822
15823CanvasRenderer.prototype.renderBackgroundGradient = function(gradientImage, bounds) {
15824    if (gradientImage instanceof LinearGradientContainer) {
15825        var gradient = this.ctx.createLinearGradient(
15826            bounds.left + bounds.width * gradientImage.x0,
15827            bounds.top + bounds.height * gradientImage.y0,
15828            bounds.left +  bounds.width * gradientImage.x1,
15829            bounds.top +  bounds.height * gradientImage.y1);
15830        gradientImage.colorStops.forEach(function(colorStop) {
15831            gradient.addColorStop(colorStop.stop, colorStop.color.toString());
15832        });
15833        this.rectangle(bounds.left, bounds.top, bounds.width, bounds.height, gradient);
15834    }
15835};
15836
15837CanvasRenderer.prototype.resizeImage = function(imageContainer, size) {
15838    var image = imageContainer.image;
15839    if(image.width === size.width && image.height === size.height) {
15840        return image;
15841    }
15842
15843    var ctx, canvas = document.createElement('canvas');
15844    canvas.width = size.width;
15845    canvas.height = size.height;
15846    ctx = canvas.getContext("2d");
15847    ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, size.width, size.height );
15848    return canvas;
15849};
15850
15851function hasEntries(array) {
15852    return array.length > 0;
15853}
15854
15855module.exports = CanvasRenderer;
15856
15857},{"../lineargradientcontainer":12,"../log":13,"../renderer":19}],21:[function(_dereq_,module,exports){
15858var NodeContainer = _dereq_('./nodecontainer');
15859
15860function StackingContext(hasOwnStacking, opacity, element, parent) {
15861    NodeContainer.call(this, element, parent);
15862    this.ownStacking = hasOwnStacking;
15863    this.contexts = [];
15864    this.children = [];
15865    this.opacity = (this.parent ? this.parent.stack.opacity : 1) * opacity;
15866}
15867
15868StackingContext.prototype = Object.create(NodeContainer.prototype);
15869
15870StackingContext.prototype.getParentStack = function(context) {
15871    var parentStack = (this.parent) ? this.parent.stack : null;
15872    return parentStack ? (parentStack.ownStacking ? parentStack : parentStack.getParentStack(context)) : context.stack;
15873};
15874
15875module.exports = StackingContext;
15876
15877},{"./nodecontainer":14}],22:[function(_dereq_,module,exports){
15878function Support(document) {
15879    this.rangeBounds = this.testRangeBounds(document);
15880    this.cors = this.testCORS();
15881    this.svg = this.testSVG();
15882}
15883
15884Support.prototype.testRangeBounds = function(document) {
15885    var range, testElement, rangeBounds, rangeHeight, support = false;
15886
15887    if (document.createRange) {
15888        range = document.createRange();
15889        if (range.getBoundingClientRect) {
15890            testElement = document.createElement('boundtest');
15891            testElement.style.height = "123px";
15892            testElement.style.display = "block";
15893            document.body.appendChild(testElement);
15894
15895            range.selectNode(testElement);
15896            rangeBounds = range.getBoundingClientRect();
15897            rangeHeight = rangeBounds.height;
15898
15899            if (rangeHeight === 123) {
15900                support = true;
15901            }
15902            document.body.removeChild(testElement);
15903        }
15904    }
15905
15906    return support;
15907};
15908
15909Support.prototype.testCORS = function() {
15910    return typeof((new Image()).crossOrigin) !== "undefined";
15911};
15912
15913Support.prototype.testSVG = function() {
15914    var img = new Image();
15915    var canvas = document.createElement("canvas");
15916    var ctx =  canvas.getContext("2d");
15917    img.src = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>";
15918
15919    try {
15920        ctx.drawImage(img, 0, 0);
15921        canvas.toDataURL();
15922    } catch(e) {
15923        return false;
15924    }
15925    return true;
15926};
15927
15928module.exports = Support;
15929
15930},{}],23:[function(_dereq_,module,exports){
15931var XHR = _dereq_('./xhr');
15932var decode64 = _dereq_('./utils').decode64;
15933
15934function SVGContainer(src) {
15935    this.src = src;
15936    this.image = null;
15937    var self = this;
15938
15939    this.promise = this.hasFabric().then(function() {
15940        return (self.isInline(src) ? Promise.resolve(self.inlineFormatting(src)) : XHR(src));
15941    }).then(function(svg) {
15942        return new Promise(function(resolve) {
15943            window.html2canvas.svg.fabric.loadSVGFromString(svg, self.createCanvas.call(self, resolve));
15944        });
15945    });
15946}
15947
15948SVGContainer.prototype.hasFabric = function() {
15949    return !window.html2canvas.svg || !window.html2canvas.svg.fabric ? Promise.reject(new Error("html2canvas.svg.js is not loaded, cannot render svg")) : Promise.resolve();
15950};
15951
15952SVGContainer.prototype.inlineFormatting = function(src) {
15953    return (/^data:image\/svg\+xml;base64,/.test(src)) ? this.decode64(this.removeContentType(src)) : this.removeContentType(src);
15954};
15955
15956SVGContainer.prototype.removeContentType = function(src) {
15957    return src.replace(/^data:image\/svg\+xml(;base64)?,/,'');
15958};
15959
15960SVGContainer.prototype.isInline = function(src) {
15961    return (/^data:image\/svg\+xml/i.test(src));
15962};
15963
15964SVGContainer.prototype.createCanvas = function(resolve) {
15965    var self = this;
15966    return function (objects, options) {
15967        var canvas = new window.html2canvas.svg.fabric.StaticCanvas('c');
15968        self.image = canvas.lowerCanvasEl;
15969        canvas
15970            .setWidth(options.width)
15971            .setHeight(options.height)
15972            .add(window.html2canvas.svg.fabric.util.groupSVGElements(objects, options))
15973            .renderAll();
15974        resolve(canvas.lowerCanvasEl);
15975    };
15976};
15977
15978SVGContainer.prototype.decode64 = function(str) {
15979    return (typeof(window.atob) === "function") ? window.atob(str) : decode64(str);
15980};
15981
15982module.exports = SVGContainer;
15983
15984},{"./utils":26,"./xhr":28}],24:[function(_dereq_,module,exports){
15985var SVGContainer = _dereq_('./svgcontainer');
15986
15987function SVGNodeContainer(node, _native) {
15988    this.src = node;
15989    this.image = null;
15990    var self = this;
15991
15992    this.promise = _native ? new Promise(function(resolve, reject) {
15993        self.image = new Image();
15994        self.image.onload = resolve;
15995        self.image.onerror = reject;
15996        self.image.src = "data:image/svg+xml," + (new XMLSerializer()).serializeToString(node);
15997        if (self.image.complete === true) {
15998            resolve(self.image);
15999        }
16000    }) : this.hasFabric().then(function() {
16001        return new Promise(function(resolve) {
16002            window.html2canvas.svg.fabric.parseSVGDocument(node, self.createCanvas.call(self, resolve));
16003        });
16004    });
16005}
16006
16007SVGNodeContainer.prototype = Object.create(SVGContainer.prototype);
16008
16009module.exports = SVGNodeContainer;
16010
16011},{"./svgcontainer":23}],25:[function(_dereq_,module,exports){
16012var NodeContainer = _dereq_('./nodecontainer');
16013
16014function TextContainer(node, parent) {
16015    NodeContainer.call(this, node, parent);
16016}
16017
16018TextContainer.prototype = Object.create(NodeContainer.prototype);
16019
16020TextContainer.prototype.applyTextTransform = function() {
16021    this.node.data = this.transform(this.parent.css("textTransform"));
16022};
16023
16024TextContainer.prototype.transform = function(transform) {
16025    var text = this.node.data;
16026    switch(transform){
16027        case "lowercase":
16028            return text.toLowerCase();
16029        case "capitalize":
16030            return text.replace(/(^|\s|:|-|\(|\))([a-z])/g, capitalize);
16031        case "uppercase":
16032            return text.toUpperCase();
16033        default:
16034            return text;
16035    }
16036};
16037
16038function capitalize(m, p1, p2) {
16039    if (m.length > 0) {
16040        return p1 + p2.toUpperCase();
16041    }
16042}
16043
16044module.exports = TextContainer;
16045
16046},{"./nodecontainer":14}],26:[function(_dereq_,module,exports){
16047exports.smallImage = function smallImage() {
16048    return "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
16049};
16050
16051exports.bind = function(callback, context) {
16052    return function() {
16053        return callback.apply(context, arguments);
16054    };
16055};
16056
16057/*
16058 * base64-arraybuffer
16059 * https://github.com/niklasvh/base64-arraybuffer
16060 *
16061 * Copyright (c) 2012 Niklas von Hertzen
16062 * Licensed under the MIT license.
16063 */
16064
16065exports.decode64 = function(base64) {
16066    var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
16066+/";
16067    var len = base64.length, i, encoded1, encoded2, encoded3, encoded4, byte1, byte2, byte3;
16068
16069    var output = "";
16070
16071    for (i = 0; i < len; i+=4) {
16072        encoded1 = chars.indexOf(base64[i]);
16073        encoded2 = chars.indexOf(base64[i+1]);
16074        encoded3 = chars.indexOf(base64[i+2]);
16075        encoded4 = chars.indexOf(base64[i+3]);
16076
16077        byte1 = (encoded1 << 2) | (encoded2 >> 4);
16078        byte2 = ((encoded2 & 15) << 4) | (encoded3 >> 2);
16079        byte3 = ((encoded3 & 3) << 6) | encoded4;
16080        if (encoded3 === 64) {
16081            output += String.fromCharCode(byte1);
16082        } else if (encoded4 === 64 || encoded4 === -1) {
16083            output += String.fromCharCode(byte1, byte2);
16084        } else{
16085            output += String.fromCharCode(byte1, byte2, byte3);
16086        }
16087    }
16088
16089    return output;
16090};
16091
16092exports.getBounds = function(node) {
16093    if (node.getBoundingClientRect) {
16094        var clientRect = node.getBoundingClientRect();
16095        var width = node.offsetWidth == null ? clientRect.width : node.offsetWidth;
16096        return {
16097            top: clientRect.top,
16098            bottom: clientRect.bottom || (clientRect.top + clientRect.height),
16099            right: clientRect.left + width,
16100            left: clientRect.left,
16101            width:  width,
16102            height: node.offsetHeight == null ? clientRect.height : node.offsetHeight
16103        };
16104    }
16105    return {};
16106};
16107
16108exports.offsetBounds = function(node) {
16109    var parent = node.offsetParent ? exports.offsetBounds(node.offsetParent) : {top: 0, left: 0};
16110
16111    return {
16112        top: node.offsetTop + parent.top,
16113        bottom: node.offsetTop + node.offsetHeight + parent.top,
16114        right: node.offsetLeft + parent.left + node.offsetWidth,
16115        left: node.offsetLeft + parent.left,
16116        width: node.offsetWidth,
16117        height: node.offsetHeight
16118    };
16119};
16120
16121exports.parseBackgrounds = function(backgroundImage) {
16122    var whitespace = ' \r\n\t',
16123        method, definition, prefix, prefix_i, block, results = [],
16124        mode = 0, numParen = 0, quote, args;
16125    var appendResult = function() {
16126        if(method) {
16127            if (definition.substr(0, 1) === '"') {
16128                definition = definition.substr(1, definition.length - 2);
16129            }
16130            if (definition) {
16131                args.push(definition);
16132            }
16133            if (method.substr(0, 1) === '-' && (prefix_i = method.indexOf('-', 1 ) + 1) > 0) {
16134                prefix = method.substr(0, prefix_i);
16135                method = method.substr(prefix_i);
16136            }
16137            results.push({
16138                prefix: prefix,
16139                method: method.toLowerCase(),
16140                value: block,
16141                args: args,
16142                image: null
16143            });
16144        }
16145        args = [];
16146        method = prefix = definition = block = '';
16147    };
16148    args = [];
16149    method = prefix = definition = block = '';
16150    backgroundImage.split("").forEach(function(c) {
16151        if (mode === 0 && whitespace.indexOf(c) > -1) {
16152            return;
16153        }
16154        switch(c) {
16155        case '"':
16156            if(!quote) {
16157                quote = c;
16158            } else if(quote === c) {
16159                quote = null;
16160            }
16161            break;
16162        case '(':
16163            if(quote) {
16164                break;
16165            } else if(mode === 0) {
16166                mode = 1;
16167                block += c;
16168                return;
16169            } else {
16170                numParen++;
16171            }
16172            break;
16173        case ')':
16174            if (quote) {
16175                break;
16176            } else if(mode === 1) {
16177                if(numParen === 0) {
16178                    mode = 0;
16179                    block += c;
16180                    appendResult();
16181                    return;
16182                } else {
16183                    numParen--;
16184                }
16185            }
16186            break;
16187
16188        case ',':
16189            if (quote) {
16190                break;
16191            } else if(mode === 0) {
16192                appendResult();
16193                return;
16194            } else if (mode === 1) {
16195                if (numParen === 0 && !method.match(/^url$/i)) {
16196                    args.push(definition);
16197                    definition = '';
16198                    block += c;
16199                    return;
16200                }
16201            }
16202            break;
16203        }
16204
16205        block += c;
16206        if (mode === 0) {
16207            method += c;
16208        } else {
16209            definition += c;
16210        }
16211    });
16212
16213    appendResult();
16214    return results;
16215};
16216
16217},{}],27:[function(_dereq_,module,exports){
16218var GradientContainer = _dereq_('./gradientcontainer');
16219
16220function WebkitGradientContainer(imageData) {
16221    GradientContainer.apply(this, arguments);
16222    this.type = imageData.args[0] === "linear" ? GradientContainer.TYPES.LINEAR 
16222: GradientContainer.TYPES.RADIAL;
16223}
16224
16225WebkitGradientContainer.prototype = Object.create(GradientContainer.prototype);
16226
16227module.exports = WebkitGradientContainer;
16228
16229},{"./gradientcontainer":9}],28:[function(_dereq_,module,exports){
16230function XHR(url) {
16231    return new Promise(function(resolve, reject) {
16232        var xhr = new XMLHttpRequest();
16233        xhr.open('GET', url);
16234
16235        xhr.onload = function() {
16236            if (xhr.status === 200) {
16237                resolve(xhr.responseText);
16238            } else {
16239                reject(new Error(xhr.statusText));
16240            }
16241        };
16242
16243        xhr.onerror = function() {
16244            reject(new Error("Network Error"));
16245        };
16246
16247        xhr.send();
16248    });
16249}
16250
16251module.exports = XHR;
16252
16253},{}]},{},[4])(4)
16254});
16255
16256// Generated by CoffeeScript 1.4.0
16257
16258/*
16259# PNG.js
16260# Copyright (c) 2011 Devon Govett
16261# MIT LICENSE
16262# 
16263# 
16264*/
16265
16266
16267(function(global) {
16268  var PNG;
16269
16270  PNG = (function() {
16271    var APNG_BLEND_OP_OVER, APNG_BLEND_OP_SOURCE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_NONE, APNG_DISPOSE_OP_PREVIOUS, makeImage, scratchCanvas, scratchCtx;
16272
16273    PNG.load = function(url, canvas, callback) {
16274      var xhr,
16275        _this = this;
16276      if (typeof canvas === 'function') {
16277        callback = canvas;
16278      }
16279      xhr = new XMLHttpRequest;
16280      xhr.open("GET", url, true);
16281      xhr.responseType = "arraybuffer";
16282      xhr.onload = function() {
16283        var data, png;
16284        data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
16285        png = new PNG(data);
16286        if (typeof (canvas != null ? canvas.getContext : void 0) === 'function') {
16287          png.render(canvas);
16288        }
16289        return typeof callback === "function" ? callback(png) : void 0;
16290      };
16291      return xhr.send(null);
16292    };
16293
16294    APNG_DISPOSE_OP_NONE = 0;
16295
16296    APNG_DISPOSE_OP_BACKGROUND = 1;
16297
16298    APNG_DISPOSE_OP_PREVIOUS = 2;
16299
16300    APNG_BLEND_OP_SOURCE = 0;
16301
16302    APNG_BLEND_OP_OVER = 1;
16303
16304    function PNG(data) {
16305      var chunkSize, colors, palLen, delayDen, delayNum, frame, i, index, key, section, palShort, text, _i, _j, _ref;
16306      this.data = data;
16307      this.pos = 8;
16308      this.palette = [];
16309      this.imgData = [];
16310      this.transparency = {};
16311      this.animation = null;
16312      this.text = {};
16313      frame = null;
16314      while (true) {
16315        chunkSize = this.readUInt32();
16316        section = ((function() {
16317          var _i, _results;
16318          _results = [];
16319          for (i = _i = 0; _i < 4; i = ++_i) {
16320            _results.push(String.fromCharCode(this.data[this.pos++]));
16321          }
16322          return _results;
16323        }).call(this)).join('');
16324        switch (section) {
16325          case 'IHDR':
16326            this.width = this.readUInt32();
16327            this.height = this.readUInt32();
16328            this.bits = this.data[this.pos++];
16329            this.colorType = this.data[this.pos++];
16330            this.compressionMethod = this.data[this.pos++];
16331            this.filterMethod = this.data[this.pos++];
16332            this.interlaceMethod = this.data[this.pos++];
16333            break;
16334          case 'acTL':
16335            this.animation = {
16336              numFrames: this.readUInt32(),
16337              numPlays: this.readUInt32() || Infinity,
16338              frames: []
16339            };
16340            break;
16341          case 'PLTE':
16342            this.palette = this.read(chunkSize);
16343            break;
16344          case 'fcTL':
16345            if (frame) {
16346              this.animation.frames.push(frame);
16347            }
16348            this.pos += 4;
16349            frame = {
16350              width: this.readUInt32(),
16351              height: this.readUInt32(),
16352              xOffset: this.readUInt32(),
16353              yOffset: this.readUInt32()
16354            };
16355            delayNum = this.readUInt16();
16356            delayDen = this.readUInt16() || 100;
16357            frame.delay = 1000 * delayNum / delayDen;
16358            frame.disposeOp = this.data[this.pos++];
16359            frame.blendOp = this.data[this.pos++];
16360            frame.data = [];
16361            break;
16362          case 'IDAT':
16363          case 'fdAT':
16364            if (section === 'fdAT') {
16365              this.pos += 4;
16366              chunkSize -= 4;
16367            }
16368            data = (frame != null ? frame.data : void 0) || this.imgData;
16369            for (i = _i = 0; 0 <= chunkSize ? _i < chunkSize : _i > chunkSize; i = 0 <= chunkSize ? ++_i : --_i) {
16370              data.push(this.data[this.pos++]);
16371            }
16372            break;
16373          case 'tRNS':
16374            this.transparency = {};
16375            switch (this.colorType) {
16376              case 3:
16377            	palLen = this.palette.length/3;
16378                this.transparency.indexed = this.read(chunkSize);
16379                if(this.transparency.indexed.length > palLen)
16380                	throw new Error('More transparent colors than palette size');
16381                /*
16382                 * According to the PNG spec trns should be increased to the same size as palette if shorter
16383                 */
16384                //palShort = 255 - this.transparency.indexed.length;
16385                palShort = palLen - this.transparency.indexed.length;
16386                if (palShort > 0) {
16387                  for (i = _j = 0; 0 <= palShort ? _j < palShort : _j > palShort; i = 0 <= palShort ? ++_j : --_j) {
16388                    this.transparency.indexed.push(255);
16389                  }
16390                }
16391                break;
16392              case 0:
16393                this.transparency.grayscale = this.read(chunkSize)[0];
16394                break;
16395              case 2:
16396                this.transparency.rgb = this.read(chunkSize);
16397            }
16398            break;
16399          case 'tEXt':
16400            text = this.read(chunkSize);
16401            index = text.indexOf(0);
16402            key = String.fromCharCode.apply(String, text.slice(0, index));
16403            this.text[key] = String.fromCharCode.apply(String, text.slice(index + 1));
16404            break;
16405          case 'IEND':
16406            if (frame) {
16407              this.animation.frames.push(frame);
16408            }
16409            this.colors = (function() {
16410              switch (this.colorType) {
16411                case 0:
16412                case 3:
16413                case 4:
16414                  return 1;
16415                case 2:
16416                case 6:
16417                  return 3;
16418              }
16419            }).call(this);
16420            this.hasAlphaChannel = (_ref = this.colorType) === 4 || _ref === 6;
16421            colors = this.colors + (this.hasAlphaChannel ? 1 : 0);
16422            this.pixelBitlength = this.bits * colors;
16423            this.colorSpace = (function() {
16424              switch (this.colors) {
16425                case 1:
16426                  return 'DeviceGray';
16427                case 3:
16428                  return 'DeviceRGB';
16429              }
16430            }).call(this);
16431            this.imgData = new Uint8Array(this.imgData);
16432            return;
16433          default:
16434            this.pos += chunkSize;
16435        }
16436        this.pos += 4;
16437        if (this.pos > this.data.length) {
16438          throw new Error("Incomplete or corrupt PNG file");
16439        }
16440      }
16441      return;
16442    }
16443
16444    PNG.prototype.read = function(bytes) {
16445      var i, _i, _results;
16446      _results = [];
16447      for (i = _i = 0; 0 <= bytes ? _i < bytes : _i > bytes; i = 0 <= bytes ? ++_i : --_i) {
16448        _results.push(this.data[this.pos++]);
16449      }
16450      return _results;
16451    };
16452
16453    PNG.prototype.readUInt32 = function() {
16454      var b1, b2, b3, b4;
16455      b1 = this.data[this.pos++] << 24;
16456      b2 = this.data[this.pos++] << 16;
16457      b3 = this.data[this.pos++] << 8;
16458      b4 = this.data[this.pos++];
16459      return b1 | b2 | b3 | b4;
16460    };
16461
16462    PNG.prototype.readUInt16 = function() {
16463      var b1, b2;
16464      b1 = this.data[this.pos++] << 8;
16465      b2 = this.data[this.pos++];
16466      return b1 | b2;
16467    };
16468
16469    PNG.prototype.decodePixels = function(data) {
16470      var abyte, c, col, i, left, length, p, pa, paeth, pb, pc, pixelBytes, pixels, pos, row, scanlineLength, upper, upperLeft, _i, _j, _k, _l, _m;
16471      if (data == null) {
16472        data = this.imgData;
16473      }
16474      if (data.length === 0) {
16475        return new Uint8Array(0);
16476      }
16477      data = new FlateStream(data);
16478      data = data.getBytes();
16479      pixelBytes = this.pixelBitlength / 8;
16480      scanlineLength = pixelBytes * this.width;
16481      pixels = new Uint8Array(scanlineLength * this.height);
16482      length = data.length;
16483      row = 0;
16484      pos = 0;
16485      c = 0;
16486      while (pos < length) {
16487        switch (data[pos++]) {
16488          case 0:
16489            for (i = _i = 0; _i < scanlineLength; i = _i += 1) {
16490              pixels[c++] = data[pos++];
16491            }
16492            break;
16493          case 1:
16494            for (i = _j = 0; _j < scanlineLength; i = _j += 1) {
16495              abyte = data[pos++];
16496              left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
16497              pixels[c++] = (abyte + left) % 256;
16498            }
16499            break;
16500          case 2:
16501            for (i = _k = 0; _k < scanlineLength; i = _k += 1) {
16502              abyte = data[pos++];
16503              col = (i - (i % pixelBytes)) / pixelBytes;
16504              upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
16505              pixels[c++] = (upper + abyte) % 256;
16506            }
16507            break;
16508          case 3:
16509            for (i = _l = 0; _l < scanlineLength; i = _l += 1) {
16510              abyte = data[pos++];
16511              col = (i - (i % pixelBytes)) / pixelBytes;
16512              left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
16513              upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
16514              pixels[c++] = (abyte + Math.floor((left + upper) / 2)) % 256;
16515            }
16516            break;
16517          case 4:
16518            for (i = _m = 0; _m < scanlineLength; i = _m += 1) {
16519              abyte = data[pos++];
16520              col = (i - (i % pixelBytes)) / pixelBytes;
16521              left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
16522              if (row === 0) {
16523                upper = upperLeft = 0;
16524              } else {
16525                upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
16526                upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)];
16527              }
16528              p = left + upper - upperLeft;
16529              pa = Math.abs(p - left);
16530              pb = Math.abs(p - upper);
16531              pc = Math.abs(p - upperLeft);
16532              if (pa <= pb && pa <= pc) {
16533                paeth = left;
16534              } else if (pb <= pc) {
16535                paeth = upper;
16536              } else {
16537                paeth = upperLeft;
16538              }
16539              pixels[c++] = (abyte + paeth) % 256;
16540            }
16541            break;
16542          default:
16543            throw new Error("Invalid filter algorithm: " + data[pos - 1]);
16544        }
16545        row++;
16546      }
16547      return pixels;
16548    };
16549
16550    PNG.prototype.decodePalette = function() {
16551      var c, i, length, palette, pos, ret, transparency, _i, _ref, _ref1;
16552      palette = this.palette;
16553      transparency = this.transparency.indexed || [];
16554      ret = new Uint8Array((transparency.length || 0) + palette.length);
16555      pos = 0;
16556      length = palette.length;
16557      c = 0;
16558      for (i = _i = 0, _ref = palette.length; _i < _ref; i = _i += 3) {
16559        ret[pos++] = palette[i];
16560        ret[pos++] = palette[i + 1];
16561        ret[pos++] = palette[i + 2];
16562        ret[pos++] = (_ref1 = transparency[c++]) != null ? _ref1 : 255;
16563      }
16564      return ret;
16565    };
16566
16567    PNG.prototype.copyToImageData = function(imageData, pixels) {
16568      var alpha, colors, data, i, input, j, k, length, palette, v, _ref;
16569      colors = this.colors;
16570      palette = null;
16571      alpha = this.hasAlphaChannel;
16572      if (this.palette.length) {
16573        palette = (_ref = this._decodedPalette) != null ? _ref : this._decodedPalette = this.decodePalette();
16574        colors = 4;
16575        alpha = true;
16576      }
16577      data = imageData.data || imageData;
16578      length = data.length;
16579      input = palette || pixels;
16580      i = j = 0;
16581      if (colors === 1) {
16582        while (i < length) {
16583          k = palette ? pixels[i / 4] * 4 : j;
16584          v = input[k++];
16585          data[i++] = v;
16586          data[i++] = v;
16587          data[i++] = v;
16588          data[i++] = alpha ? input[k++] : 255;
16589          j = k;
16590        }
16591      } else {
16592        while (i < length) {
16593          k = palette ? pixels[i / 4] * 4 : j;
16594          data[i++] = input[k++];
16595          data[i++] = input[k++];
16596          data[i++] = input[k++];
16597          data[i++] = alpha ? input[k++] : 255;
16598          j = k;
16599        }
16600      }
16601    };
16602
16603    PNG.prototype.decode = function() {
16604      var ret;
16605      ret = new Uint8Array(this.width * this.height * 4);
16606      this.copyToImageData(ret, this.decodePixels());
16607      return ret;
16608    };
16609
16610    try {
16611        scratchCanvas = global.document.createElement('canvas');
16612        scratchCtx = scratchCanvas.getContext('2d');
16613    } catch(e) {
16614        return -1;
16615    }
16616
16617    makeImage = function(imageData) {
16618      var img;
16619      scratchCtx.width = imageData.width;
16620      scratchCtx.height = imageData.height;
16621      scratchCtx.clearRect(0, 0, imageData.width, imageData.height);
16622      scratchCtx.putImageData(imageData, 0, 0);
16623      img = new Image;
16624      img.src = scratchCanvas.toDataURL();
16625      return img;
16626    };
16627
16628    PNG.prototype.decodeFrames = function(ctx) {
16629      var frame, i, imageData, pixels, _i, _len, _ref, _results;
16630      if (!this.animation) {
16631        return;
16632      }
16633      _ref = this.animation.frames;
16634      _results = [];
16635      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
16636        frame = _ref[i];
16637        imageData = ctx.createImageData(frame.width, frame.height);
16638        pixels = this.decodePixels(new Uint8Array(frame.data));
16639        this.copyToImageData(imageData, pixels);
16640        frame.imageData = imageData;
16641        _results.push(frame.image = makeImage(imageData));
16642      }
16643      return _results;
16644    };
16645
16646    PNG.prototype.renderFrame = function(ctx, number) {
16647      var frame, frames, prev;
16648      frames = this.animation.frames;
16649      frame = frames[number];
16650      prev = frames[number - 1];
16651      if (number === 0) {
16652        ctx.clearRect(0, 0, this.width, this.height);
16653      }
16654      if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_BACKGROUND) {
16655        ctx.clearRect(prev.xOffset, prev.yOffset, prev.width, prev.height);
16656      } else if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_PREVIOUS) {
16657        ctx.putImageData(prev.imageData, prev.xOffset, prev.yOffset);
16658      }
16659      if (frame.blendOp === APNG_BLEND_OP_SOURCE) {
16660        ctx.clearRect(frame.xOffset, frame.yOffset, frame.width, frame.height);
16661      }
16662      return ctx.drawImage(frame.image, frame.xOffset, frame.yOffset);
16663    };
16664
16665    PNG.prototype.animate = function(ctx) {
16666      var doFrame, frameNumber, frames, numFrames, numPlays, _ref,
16667        _this = this;
16668      frameNumber = 0;
16669      _ref = this.animation, numFrames = _ref.numFrames, frames = _ref.frames, numPlays = _ref.numPlays;
16670      return (doFrame = function() {
16671        var f, frame;
16672        f = frameNumber++ % numFrames;
16673        frame = frames[f];
16674        _this.renderFrame(ctx, f);
16675        if (numFrames > 1 && frameNumber / numFrames < numPlays) {
16676          return _this.animation._timeout = setTimeout(doFrame, frame.delay);
16677        }
16678      })();
16679    };
16680
16681    PNG.prototype.stopAnimation = function() {
16682      var _ref;
16683      return clearTimeout((_ref = this.animation) != null ? _ref._timeout : void 0);
16684    };
16685
16686    PNG.prototype.render = function(canvas) {
16687      var ctx, data;
16688      if (canvas._png) {
16689        canvas._png.stopAnimation();
16690      }
16691      canvas._png = this;
16692      canvas.width = this.width;
16693      canvas.height = this.height;
16694      ctx = canvas.getContext("2d");
16695      if (this.animation) {
16696        this.decodeFrames(ctx);
16697        return this.animate(ctx);
16698      } else {
16699        data = ctx.createImageData(this.width, this.height);
16700        this.copyToImageData(data, this.decodePixels());
16701        return ctx.putImageData(data, 0, 0);
16702      }
16703    };
16704
16705    return PNG;
16706
16707  })();
16708
16709  global.PNG = PNG;
16710
16711})(typeof window !== "undefined" && window || undefined);
16712
16713/*
16714 * Extracted from pdf.js
16715 * https://github.com/andreasgal/pdf.js
16716 *
16717 * Copyright (c) 2011 Mozilla Foundation
16718 *
16719 * Contributors: Andreas Gal <[email protected]>
16720 *               Chris G Jones <[email protected]>
16721 *               Shaon Barman <[email protected]>
16722 *               Vivien Nicolas <[email protected]>
16723 *               Justin D'Arcangelo <[email protected]>
16724 *               Yury Delendik
16725 *
16726 * 
16727 */
16728
16729var DecodeStream = (function() {
16730  function constructor() {
16731    this.pos = 0;
16732    this.bufferLength = 0;
16733    this.eof = false;
16734    this.buffer = null;
16735  }
16736
16737  constructor.prototype = {
16738    ensureBuffer: function decodestream_ensureBuffer(requested) {
16739      var buffer = this.buffer;
16740      var current = buffer ? buffer.byteLength : 0;
16741      if (requested < current)
16742        return buffer;
16743      var size = 512;
16744      while (size < requested)
16745        size <<= 1;
16746      var buffer2 = new Uint8Array(size);
16747      for (var i = 0; i < current; ++i)
16748        buffer2[i] = buffer[i];
16749      return this.buffer = buffer2;
16750    },
16751    getByte: function decodestream_getByte() {
16752      var pos = this.pos;
16753      while (this.bufferLength <= pos) {
16754        if (this.eof)
16755          return null;
16756        this.readBlock();
16757      }
16758      return this.buffer[this.pos++];
16759    },
16760    getBytes: function decodestream_getBytes(length) {
16761      var pos = this.pos;
16762
16763      if (length) {
16764        this.ensureBuffer(pos + length);
16765        var end = pos + length;
16766
16767        while (!this.eof && this.bufferLength < end)
16768          this.readBlock();
16769
16770        var bufEnd = this.bufferLength;
16771        if (end > bufEnd)
16772          end = bufEnd;
16773      } else {
16774        while (!this.eof)
16775          this.readBlock();
16776
16777        var end = this.bufferLength;
16778      }
16779
16780      this.pos = end;
16781      return this.buffer.subarray(pos, end);
16782    },
16783    lookChar: function decodestream_lookChar() {
16784      var pos = this.pos;
16785      while (this.bufferLength <= pos) {
16786        if (this.eof)
16787          return null;
16788        this.readBlock();
16789      }
16790      return String.fromCharCode(this.buffer[this.pos]);
16791    },
16792    getChar: function decodestream_getChar() {
16793      var pos = this.pos;
16794      while (this.bufferLength <= pos) {
16795        if (this.eof)
16796          return null;
16797        this.readBlock();
16798      }
16799      return String.fromCharCode(this.buffer[this.pos++]);
16800    },
16801    makeSubStream: function decodestream_makeSubstream(start, length, dict) {
16802      var end = start + length;
16803      while (this.bufferLength <= end && !this.eof)
16804        this.readBlock();
16805      return new Stream(this.buffer, start, length, dict);
16806    },
16807    skip: function decodestream_skip(n) {
16808      if (!n)
16809        n = 1;
16810      this.pos += n;
16811    },
16812    reset: function decodestream_reset() {
16813      this.pos = 0;
16814    }
16815  };
16816
16817  return constructor;
16818})();
16819
16820var FlateStream = (function() {
16821  if (typeof Uint32Array === 'undefined') {
16822    return undefined;
16823  }
16824  var codeLenCodeMap = new Uint32Array([
16825    16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
16826  ]);
16827
16828  var lengthDecode = new Uint32Array([
16829    0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,
16830    0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,
16831    0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073,
16832    0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102
16833  ]);
16834
16835  var distDecode = new Uint32Array([
16836    0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,
16837    0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,
16838    0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01,
16839    0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001
16840  ]);
16841
16842  var fixedLitCodeTab = [new Uint32Array([
16843    0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,
16844    0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,
16845    0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0,
16846    0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0,
16847    0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8,
16848    0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8,
16849    0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8,
16850    0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8,
16851    0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4,
16852    0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4,
16853    0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4,
16854    0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4,
16855    0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc,
16856    0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec,
16857    0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc,
16858    0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc,
16859    0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2,
16860    0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2,
16861    0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2,
16862    0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2,
16863    0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca,
16864    0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea,
16865    0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da,
16866    0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa,
16867    0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6,
16868    0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6,
16869    0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6,
16870    0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6,
16871    0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce,
16872    0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee,
16873    0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de,
16874    0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe,
16875    0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1,
16876    0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1,
16877    0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1,
16878    0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1,
16879    0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9,
16880    0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9,
16881    0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9,
16882    0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9,
16883    0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5,
16884    0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5,
16885    0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5,
16886    0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5,
16887    0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd,
16888    0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed,
16889    0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd,
16890    0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd,
16891    0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3,
16892    0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3,
16893    0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3,
16894    0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3,
16895    0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb,
16896    0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb,
16897    0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db,
16898    0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb,
16899    0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7,
16900    0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7,
16901    0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7,
16902    0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7,
16903    0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf,
16904    0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef,
16905    0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df,
16906    0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff
16907  ]), 9];
16908
16909  var fixedDistCodeTab = [new Uint32Array([
16910    0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,
16911    0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,
16912    0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d,
16913    0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
16914  ]), 5];
16915  
16916  function error(e) {
16917      throw new Error(e)
16918  }
16919
16920  function constructor(bytes) {
16921    //var bytes = stream.getBytes();
16922    var bytesPos = 0;
16923
16924    var cmf = bytes[bytesPos++];
16925    var flg = bytes[bytesPos++];
16926    if (cmf == -1 || flg == -1)
16927      error('Invalid header in flate stream');
16928    if ((cmf & 0x0f) != 0x08)
16929      error('Unknown compression method in flate stream');
16930    if ((((cmf << 8) + flg) % 31) != 0)
16931      error('Bad FCHECK in flate stream');
16932    if (flg & 0x20)
16933      error('FDICT bit set in flate stream');
16934
16935    this.bytes = bytes;
16936    this.bytesPos = bytesPos;
16937
16938    this.codeSize = 0;
16939    this.codeBuf = 0;
16940
16941    DecodeStream.call(this);
16942  }
16943
16944  constructor.prototype = Object.create(DecodeStream.prototype);
16945
16946  constructor.prototype.getBits = function(bits) {
16947    var codeSize = this.codeSize;
16948    var codeBuf = this.codeBuf;
16949    var bytes = this.bytes;
16950    var bytesPos = this.bytesPos;
16951
16952    var b;
16953    while (codeSize < bits) {
16954      if (typeof (b = bytes[bytesPos++]) == 'undefined')
16955        error('Bad encoding in flate stream');
16956      codeBuf |= b << codeSize;
16957      codeSize += 8;
16958    }
16959    b = codeBuf & ((1 << bits) - 1);
16960    this.codeBuf = codeBuf >> bits;
16961    this.codeSize = codeSize -= bits;
16962    this.bytesPos = bytesPos;
16963    return b;
16964  };
16965
16966  constructor.prototype.getCode = function(table) {
16967    var codes = table[0];
16968    var maxLen = table[1];
16969    var codeSize = this.codeSize;
16970    var codeBuf = this.codeBuf;
16971    var bytes = this.bytes;
16972    var bytesPos = this.bytesPos;
16973
16974    while (codeSize < maxLen) {
16975      var b;
16976      if (typeof (b = bytes[bytesPos++]) == 'undefined')
16977        error('Bad encoding in flate stream');
16978      codeBuf |= (b << codeSize);
16979      codeSize += 8;
16980    }
16981    var code = codes[codeBuf & ((1 << maxLen) - 1)];
16982    var codeLen = code >> 16;
16983    var codeVal = code & 0xffff;
16984    if (codeSize == 0 || codeSize < codeLen || codeLen == 0)
16985      error('Bad encoding in flate stream');
16986    this.codeBuf = (codeBuf >> codeLen);
16987    this.codeSize = (codeSize - codeLen);
16988    this.bytesPos = bytesPos;
16989    return codeVal;
16990  };
16991
16992  constructor.prototype.generateHuffmanTable = function(lengths) {
16993    var n = lengths.length;
16994
16995    // find max code length
16996    var maxLen = 0;
16997    for (var i = 0; i < n; ++i) {
16998      if (lengths[i] > maxLen)
16999        maxLen = lengths[i];
17000    }
17001
17002    // build the table
17003    var size = 1 << maxLen;
17004    var codes = new Uint32Array(size);
17005    for (var len = 1, code = 0, skip = 2;
17006         len <= maxLen;
17007         ++len, code <<= 1, skip <<= 1) {
17008      for (var val = 0; val < n; ++val) {
17009        if (lengths[val] == len) {
17010          // bit-reverse the code
17011          var code2 = 0;
17012          var t = code;
17013          for (var i = 0; i < len; ++i) {
17014            code2 = (code2 << 1) | (t & 1);
17015            t >>= 1;
17016          }
17017
17018          // fill the table entries
17019          for (var i = code2; i < size; i += skip)
17020            codes[i] = (len << 16) | val;
17021
17022          ++code;
17023        }
17024      }
17025    }
17026
17027    return [codes, maxLen];
17028  };
17029
17030  constructor.prototype.readBlock = function() {
17031    function repeat(stream, array, len, offset, what) {
17032      var repeat = stream.getBits(len) + offset;
17033      while (repeat-- > 0)
17034        array[i++] = what;
17035    }
17036
17037    // read block header
17038    var hdr = this.getBits(3);
17039    if (hdr & 1)
17040      this.eof = true;
17041    hdr >>= 1;
17042
17043    if (hdr == 0) { // uncompressed block
17044      var bytes = this.bytes;
17045      var bytesPos = this.bytesPos;
17046      var b;
17047
17048      if (typeof (b = bytes[bytesPos++]) == 'undefined')
17049        error('Bad block header in flate stream');
17050      var blockLen = b;
17051      if (typeof (b = bytes[bytesPos++]) == 'undefined')
17052        error('Bad block header in flate stream');
17053      blockLen |= (b << 8);
17054      if (typeof (b = bytes[bytesPos++]) == 'undefined')
17055        error('Bad block header in flate stream');
17056      var check = b;
17057      if (typeof (b = bytes[bytesPos++]) == 'undefined')
17058        error('Bad block header in flate stream');
17059      check |= (b << 8);
17060      if (check != (~blockLen & 0xffff))
17061        error('Bad uncompressed block length in flate stream');
17062
17063      this.codeBuf = 0;
17064      this.codeSize = 0;
17065
17066      var bufferLength = this.bufferLength;
17067      var buffer = this.ensureBuffer(bufferLength + blockLen);
17068      var end = bufferLength + blockLen;
17069      this.bufferLength = end;
17070      for (var n = bufferLength; n < end; ++n) {
17071        if (typeof (b = bytes[bytesPos++]) == 'undefined') {
17072          this.eof = true;
17073          break;
17074        }
17075        buffer[n] = b;
17076      }
17077      this.bytesPos = bytesPos;
17078      return;
17079    }
17080
17081    var litCodeTable;
17082    var distCodeTable;
17083    if (hdr == 1) { // compressed block, fixed codes
17084      litCodeTable = fixedLitCodeTab;
17085      distCodeTable = fixedDistCodeTab;
17086    } else if (hdr == 2) { // compressed block, dynamic codes
17087      var numLitCodes = this.getBits(5) + 257;
17088      var numDistCodes = this.getBits(5) + 1;
17089      var numCodeLenCodes = this.getBits(4) + 4;
17090
17091      // build the code lengths code table
17092      var codeLenCodeLengths = Array(codeLenCodeMap.length);
17093      var i = 0;
17094      while (i < numCodeLenCodes)
17095        codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3);
17096      var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
17097
17098      // build the literal and distance code tables
17099      var len = 0;
17100      var i = 0;
17101      var codes = numLitCodes + numDistCodes;
17102      var codeLengths = new Array(codes);
17103      while (i < codes) {
17104        var code = this.getCode(codeLenCodeTab);
17105        if (code == 16) {
17106          repeat(this, codeLengths, 2, 3, len);
17107        } else if (code == 17) {
17108          repeat(this, codeLengths, 3, 3, len = 0);
17109        } else if (code == 18) {
17110          repeat(this, codeLengths, 7, 11, len = 0);
17111        } else {
17112          codeLengths[i++] = len = code;
17113        }
17114      }
17115
17116      litCodeTable =
17117        this.generateHuffmanTable(codeLengths.slice(0, numLitCodes));
17118      distCodeTable =
17119        this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes));
17120    } else {
17121      error('Unknown block type in flate stream');
17122    }
17123
17124    var buffer = this.buffer;
17125    var limit = buffer ? buffer.length : 0;
17126    var pos = this.bufferLength;
17127    while (true) {
17128      var code1 = this.getCode(litCodeTable);
17129      if (code1 < 256) {
17130        if (pos + 1 >= limit) {
17131          buffer = this.ensureBuffer(pos + 1);
17132          limit = buffer.length;
17133        }
17134        buffer[pos++] = code1;
17135        continue;
17136      }
17137      if (code1 == 256) {
17138        this.bufferLength = pos;
17139        return;
17140      }
17141      code1 -= 257;
17142      code1 = lengthDecode[code1];
17143      var code2 = code1 >> 16;
17144      if (code2 > 0)
17145        code2 = this.getBits(code2);
17146      var len = (code1 & 0xffff) + code2;
17147      code1 = this.getCode(distCodeTable);
17148      code1 = distDecode[code1];
17149      code2 = code1 >> 16;
17150      if (code2 > 0)
17151        code2 = this.getBits(code2);
17152      var dist = (code1 & 0xffff) + code2;
17153      if (pos + len >= limit) {
17154        buffer = this.ensureBuffer(pos + len);
17155        limit = buffer.length;
17156      }
17157      for (var k = 0; k < len; ++k, ++pos)
17158        buffer[pos] = buffer[pos - dist];
17159    }
17160  };
17161
17162  return constructor;
17163})();
17164
17165/**
17166 * JavaScript Polyfill functions for jsPDF
17167 * Collected from public resources by
17168 * https://github.com/diegocr
17169 */
17170
17171(function (global) {
17172	var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
17173
17174	if (typeof global.btoa === 'undefined') {
17175		global.btoa = function(data) {
17176			//  discuss at: http://phpjs.org/functions/base64_encode/
17177			// original by: Tyler Akins (http://rumkin.com)
17178			// improved by: Bayron Guevara
17179			// improved by: Thunder.m
17180			// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
17181			// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
17182			// improved by: Rafal Kukawski (http://kukawski.pl)
17183			// bugfixed by: Pellentesque Malesuada
17184			//   example 1: base64_encode('Kevin van Zonneveld');
17185			//   returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
17186
17187			var o1,o2,o3,h1,h2,h3,h4,bits,i = 0,ac = 0,enc = '',tmp_arr = [];
17188
17189			if (!data) {
17190				return data;
17191			}
17192
17193			do { // pack three octets into four hexets
17194				o1 = data.charCodeAt(i++);
17195				o2 = data.charCodeAt(i++);
17196				o3 = data.charCodeAt(i++);
17197
17198				bits = o1 << 16 | o2 << 8 | o3;
17199
17200				h1 = bits >> 18 & 0x3f;
17201				h2 = bits >> 12 & 0x3f;
17202				h3 = bits >> 6 & 0x3f;
17203				h4 = bits & 0x3f;
17204
17205				// use hexets to index into b64, and append result to encoded string
17206				tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
17207			} while (i < data.length);
17208
17209			enc = tmp_arr.join('');
17210
17211			var r = data.length % 3;
17212
17213			return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
17214		};
17215	}
17216
17217	if (typeof global.atob === 'undefined') {
17218		global.atob = function(data) {
17219			//  discuss at: http://phpjs.org/functions/base64_decode/
17220			// original by: Tyler Akins (http://rumkin.com)
17221			// improved by: Thunder.m
17222			// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
17223			// improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
17224			//    input by: Aman Gupta
17225			//    input by: Brett Zamir (http://brett-zamir.me)
17226			// bugfixed by: Onno Marsman
17227			// bugfixed by: Pellentesque Malesuada
17228			// bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
17229			//   example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
17230			//   returns 1: 'Kevin van Zonneveld'
17231
17232			var o1,o2,o3,h1,h2,h3,h4,bits,i = 0,ac = 0,dec = '',tmp_arr = [];
17233
17234			if (!data) {
17235				return data;
17236			}
17237
17238			data += '';
17239
17240			do { // unpack four hexets into three octets using index points in b64
17241				h1 = b64.indexOf(data.charAt(i++));
17242				h2 = b64.indexOf(data.charAt(i++));
17243				h3 = b64.indexOf(data.charAt(i++));
17244				h4 = b64.indexOf(data.charAt(i++));
17245
17246				bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
17247
17248				o1 = bits >> 16 & 0xff;
17249				o2 = bits >> 8 & 0xff;
17250				o3 = bits & 0xff;
17251
17252				if (h3 == 64) {
17253					tmp_arr[ac++] = String.fromCharCode(o1);
17254				} else if (h4 == 64) {
17255					tmp_arr[ac++] = String.fromCharCode(o1, o2);
17256				} else {
17257					tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
17258				}
17259			} while (i < data.length);
17260
17261			dec = tmp_arr.join('');
17262
17263			return dec;
17264		};
17265	}
17266
17267	if (!Array.prototype.map) {
17268		Array.prototype.map = function(fun /*, thisArg */) {
17269			if (this === void 0 || this === null || typeof fun !== "function")
17270				throw new TypeError();
17271
17272			var t = Object(this), len = t.length >>> 0, res = new Array(len);
17273			var thisArg = arguments.length > 1 ? arguments[1] : void 0;
17274			for (var i = 0; i < len; i++) {
17275				// NOTE: Absolute correctness would demand Object.defineProperty
17276				//       be used.  But this method is fairly new, and failure is
17277				//       possible only if Object.prototype or Array.prototype
17278				//       has a property |i| (very unlikely), so use a less-correct
17279				//       but more portable alternative.
17280				if (i in t)
17281					res[i] = fun.call(thisArg, t[i], i, t);
17282			}
17283
17284			return res;
17285		};
17286	}
17287
17288
17289	if(!Array.isArray) {
17290		Array.isArray = function(arg) {
17291			return Object.prototype.toString.call(arg) === '[object Array]';
17292		};
17293	}
17294
17295	if (!Array.prototype.forEach) {
17296		Array.prototype.forEach = function(fun, thisArg) {
17297			"use strict";
17298
17299			if (this === void 0 || this === null || typeof fun !== "function")
17300				throw new TypeError();
17301
17302			var t = Object(this), len = t.length >>> 0;
17303			for (var i = 0; i < len; i++) {
17304				if (i in t)
17305					fun.call(thisArg, t[i], i, t);
17306			}
17307		};
17308	}
17309
17310	if (!Object.keys) {
17311		Object.keys = (function () {
17312			'use strict';
17313
17314			var hasOwnProperty = Object.prototype.hasOwnProperty,
17315				hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
17316				dontEnums = ['toString','toLocaleString','valueOf','hasOwnProperty',
17317					'isPrototypeOf','propertyIsEnumerable','constructor'],
17318				dontEnumsLength = dontEnums.length;
17319
17320			return function (obj) {
17321				if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
17322					throw new TypeError();
17323				}
17324				var result = [], prop, i;
17325
17326				for (prop in obj) {
17327					if (hasOwnProperty.call(obj, prop)) {
17328						result.push(prop);
17329					}
17330				}
17331
17332				if (hasDontEnumBug) {
17333					for (i = 0; i < dontEnumsLength; i++) {
17334						if (hasOwnProperty.call(obj, dontEnums[i])) {
17335							result.push(dontEnums[i]);
17336						}
17337					}
17338				}
17339				return result;
17340			};
17341		}());
17342	}
17343
17344	if (!String.prototype.trim) {
17345		String.prototype.trim = function () {
17346			return this.replace(/^\s+|\s+$/g, '');
17347		};
17348	}
17349	if (!String.prototype.trimLeft) {
17350		String.prototype.trimLeft = function() {
17351			return this.replace(/^\s+/g, "");
17352		};
17353	}
17354	if (!String.prototype.trimRight) {
17355		String.prototype.trimRight = function() {
17356			return this.replace(/\s+$/g, "");
17357		};
17358	}
17359
17360})(typeof self !== "undefined" && self || typeof window !== "undefined" && window || undefined);
17361
17362return jsPDF;
17363
17364})));

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.