PageSourceSearch

https://xn--18-6kcau5c3a9c.xn--p1ai/bitrix/templates/megamart_defa…/bodymovin/bodymovin.js?1627300958543667

js xn--18-6kcau5c3a9c.xn--p1ai collected 2026-10-08 16:57:38 UTC 543,667 bytes, 14,353 lines download raw bytes

1(function(root, factory) {
2    if (typeof define === "function" && define.amd) {
3        define(function() {
4            return factory(root);
5        });
6    } else if (typeof module === "object" && module.exports) {
7        module.exports = factory(root);
8    } else {
9        root.bodymovin = factory(root);
10    }
11}((window || {}), function(window) {
12    var svgNS = "http://www.w3.org/2000/svg";
13
14var locationHref = '';
15
16var subframeEnabled = true;
17var expressionsPlugin;
18var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
19var cachedColors = {};
20var bm_rounder = Math.round;
21var bm_rnd;
22var bm_pow = Math.pow;
23var bm_sqrt = Math.sqrt;
24var bm_abs = Math.abs;
25var bm_floor = Math.floor;
26var bm_max = Math.max;
27var bm_min = Math.min;
28var blitter = 10;
29
30var BMMath = {};
31(function(){
32    var propertyNames = Object.getOwnPropertyNames(Math);
33    var i, len = propertyNames.length;
34    for(i=0;i<len;i+=1){
35        BMMath[propertyNames[i]] = Math[propertyNames[i]];
36    }
37}());
38
39function ProjectInterface(){return {}};
40
41BMMath.random = Math.random;
42BMMath.abs = function(val){
43    var tOfVal = typeof val;
44    if(tOfVal === 'object' && val.length){
45        var absArr = Array.apply(null,{length:val.length});
46        var i, len = val.length;
47        for(i=0;i<len;i+=1){
48            absArr[i] = Math.abs(val[i]);
49        }
50        return absArr;
51    }
52    return Math.abs(val);
53
54}
55var defaultCurveSegments = 150;
56var degToRads = Math.PI/180;
57var roundCorner = 0.5519;
58
59function roundValues(flag){
60    if(flag){
61        bm_rnd = Math.round;
62    }else{
63        bm_rnd = function(val){
64            return val;
65        };
66    }
67}
68roundValues(false);
69
70function roundTo2Decimals(val){
71    return Math.round(val*10000)/10000;
72}
73
74function roundTo3Decimals(val){
75    return Math.round(val*100)/100;
76}
77
78function styleDiv(element){
79    element.style.position = 'absolute';
80    element.style.top = 0;
81    element.style.left = 0;
82    element.style.display = 'block';
83    element.style.transformOrigin = element.style.webkitTransformOrigin = '0 0';
84    element.style.backfaceVisibility  = element.style.webkitBackfaceVisibility = 'visible';
85    element.style.transformStyle = element.style.webkitTransformStyle = element.style.mozTransformStyle = "preserve-3d";
86}
87
88function styleUnselectableDiv(element){
89    element.style.userSelect = 'none';
90    element.style.MozUserSelect = 'none';
91    element.style.webkitUserSelect = 'none';
92    element.style.oUserSelect = 'none';
93
94}
95
96function BMEnterFrameEvent(n,c,t,d){
97    this.type = n;
98    this.currentTime = c;
99    this.totalTime = t;
100    this.direction = d < 0 ? -1:1;
101}
102
103function BMCompleteEvent(n,d){
104    this.type = n;
105    this.direction = d < 0 ? -1:1;
106}
107
108function BMCompleteLoopEvent(n,c,t,d){
109    this.type = n;
110    this.currentLoop = c;
111    this.totalLoops = t;
112    this.direction = d < 0 ? -1:1;
113}
114
115function BMSegmentStartEvent(n,f,t){
116    this.type = n;
117    this.firstFrame = f;
118    this.totalFrames = t;
119}
120
121function BMDestroyEvent(n,t){
122    this.type = n;
123    this.target = t;
124}
125
126function _addEventListener(eventName, callback){
127
128    if (!this._cbs[eventName]){
129        this._cbs[eventName] = [];
130    }
131    this._cbs[eventName].push(callback);
132
133	return function() {
134		this.removeEventListener(eventName, callback);
135	}.bind(this);
136}
137
138function _removeEventListener(eventName,callback){
139
140    if (!callback){
141        this._cbs[eventName] = null;
142    }else if(this._cbs[eventName]){
143        var i = 0, len = this._cbs[eventName].length;
144        while(i<len){
145            if(this._cbs[eventName][i] === callback){
146                this._cbs[eventName].splice(i,1);
147                i -=1;
148                len -= 1;
149            }
150            i += 1;
151        }
152        if(!this._cbs[eventName].length){
153            this._cbs[eventName] = null;
154        }
155    }
156
157}
158
159function _triggerEvent(eventName, args){
160    if (this._cbs[eventName]) {
161        var len = this._cbs[eventName].length;
162        for (var i = 0; i < len; i++){
163            this._cbs[eventName][i](args);
164        }
165    }
166}
167
168function randomString(length, chars){
169    if(chars === undefined){
170        chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
171    }
172    var i;
173    var result = '';
174    for (i = length; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))];
175    return result;
176}
177
178function HSVtoRGB(h, s, v) {
179    var r, g, b, i, f, p, q, t;
180    if (arguments.length === 1) {
181        s = h.s, v = h.v, h = h.h;
182    }
183    i = Math.floor(h * 6);
184    f = h * 6 - i;
185    p = v * (1 - s);
186    q = v * (1 - f * s);
187    t = v * (1 - (1 - f) * s);
188    switch (i % 6) {
189        case 0: r = v, g = t, b = p; break;
190        case 1: r = q, g = v, b = p; break;
191        case 2: r = p, g = v, b = t; break;
192        case 3: r = p, g = q, b = v; break;
193        case 4: r = t, g = p, b = v; break;
194        case 5: r = v, g = p, b = q; break;
195    }
196    return [ r,
197        g,
198         b ];
199}
200
201function RGBtoHSV(r, g, b) {
202    if (arguments.length === 1) {
203        g = r.g, b = r.b, r = r.r;
204    }
205    var max = Math.max(r, g, b), min = Math.min(r, g, b),
206        d = max - min,
207        h,
208        s = (max === 0 ? 0 : d / max),
209        v = max / 255;
210
211    switch (max) {
212        case min: h = 0; break;
213        case r: h = (g - b) + d * (g < b ? 6: 0); h /= 6 * d; break;
214        case g: h = (b - r) + d * 2; h /= 6 * d; break;
215        case b: h = (r - g) + d * 4; h /= 6 * d; break;
216    }
217
218    return [
219         h,
220         s,
221         v
222    ];
223}
224
225function addSaturationToRGB(color,offset){
226    var hsv = RGBtoHSV(color[0]*255,color[1]*255,color[2]*255);
227    hsv[1] += offset;
228    if (hsv[1] > 1) {
229        hsv[1] = 1;
230    }
231    else if (hsv[1] <= 0) {
232        hsv[1] = 0;
233    }
234    return HSVtoRGB(hsv[0],hsv[1],hsv[2]);
235}
236
237function addBrightnessToRGB(color,offset){
238    var hsv = RGBtoHSV(color[0]*255,color[1]*255,color[2]*255);
239    hsv[2] += offset;
240    if (hsv[2] > 1) {
241        hsv[2] = 1;
242    }
243    else if (hsv[2] < 0) {
244        hsv[2] = 0;
245    }
246    return HSVtoRGB(hsv[0],hsv[1],hsv[2]);
247}
248
249function addHueToRGB(color,offset) {
250    var hsv = RGBtoHSV(color[0]*255,color[1]*255,color[2]*255);
251    hsv[0] += offset/360;
252    if (hsv[0] > 1) {
253        hsv[0] -= 1;
254    }
255    else if (hsv[0] < 0) {
256        hsv[0] += 1;
257    }
258    return HSVtoRGB(hsv[0],hsv[1],hsv[2]);
259}
260
261function componentToHex(c) {
262    var hex = c.toString(16);
263    return hex.length == 1 ? '0' + hex : hex;
264}
265
266var rgbToHex = (function(){
267    var colorMap = [];
268    var i;
269    var hex;
270    for(i=0;i<256;i+=1){
271        hex = i.toString(16);
272        colorMap[i] = hex.length == 1 ? '0' + hex : hex;
273    }
274
275    return function(r, g, b) {
276        if(r<0){
277            r = 0;
278        }
279        if(g<0){
280            g = 0;
281        }
282        if(b<0){
283            b = 0;
284        }
285        return '#' + colorMap[r] + colorMap[g] + colorMap[b];
286    };
287}());
288
289function fillToRgba(hex,alpha){
290    if(!cachedColors[hex]){
291        var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
292        cachedColors[hex] = parseInt(result[1], 16)+','+parseInt(result[2], 16)+','+parseInt(result[3], 16);
293    }
294    return 'rgba('+cachedColors[hex]+','+alpha+')';
295}
296
297var fillColorToString = (function(){
298
299    var colorMap = [];
300    return function(colorArr,alpha){
301        if(alpha !== undefined){
302            colorArr[3] = alpha;
303        }
304        if(!colorMap[colorArr[0]]){
305            colorMap[colorArr[0]] = {};
306        }
307        if(!colorMap[colorArr[0]][colorArr[1]]){
308            colorMap[colorArr[0]][colorArr[1]] = {};
309        }
310        if(!colorMap[colorArr[0]][colorArr[1]][colorArr[2]]){
311            colorMap[colorArr[0]][colorArr[1]][colorArr[2]] = {};
312        }
313        if(!colorMap[colorArr[0]][colorArr[1]][colorArr[2]][colorArr[3]]){
314            colorMap[colorArr[0]][colorArr[1]][colorArr[2]][colorArr[3]] = 'rgba(' + colorArr.join(',')+')';
315        }
316        return colorMap[colorArr[0]][colorArr[1]][colorArr[2]][colorArr[3]];
317    };
318}());
319
320function RenderedFrame(tr,o) {
321    this.tr = tr;
322    this.o = o;
323}
324
325function iterateDynamicProperties(num){
326    var i, len = this.dynamicProperties;
327    for(i=0;i<len;i+=1){
328        this.dynamicProperties[i].getValue(num);
329    }
330}
331
332function reversePath(paths){
333    var newI = [], newO = [], newV = [];
334    var i, len, newPaths = {};
335    var init = 0;
336    if (paths.c) {
337        newI[0] = paths.o[0];
338        newO[0] = paths.i[0];
339        newV[0] = paths.v[0];
340        init = 1;
341    }
342    len = paths.i.length;
343    var cnt = len - 1;
344
345    for (i = init; i < len; i += 1) {
346        newI.push(paths.o[cnt]);
347        newO.push(paths.i[cnt]);
348        newV.push(paths.v[cnt]);
349        cnt -= 1;
350    }
351
352    newPaths.i = newI;
353    newPaths.o = newO;
354    newPaths.v = newV;
355
356    return newPaths;
357}
358/*!
359 Transformation Matrix v2.0
360 (c) Epistemex 2014-2015
361 www.epistemex.com
362 By Ken Fyrstenberg
363 Contributions by leeoniya.
364 License: MIT, header required.
365 */
366
367/**
368 * 2D transformation matrix object initialized with identity matrix.
369 *
370 * The matrix can synchronize a canvas context by supplying the context
371 * as an argument, or later apply current absolute transform to an
372 * existing context.
373 *
374 * All values are handled as floating point values.
375 *
376 * @param {CanvasRenderingContext2D} [context] - Optional context to sync with Matrix
377 * @prop {number} a - scale x
378 * @prop {number} b - shear y
379 * @prop {number} c - shear x
380 * @prop {number} d - scale y
381 * @prop {number} e - translate x
382 * @prop {number} f - translate y
383 * @prop {CanvasRenderingContext2D|null} [context=null] - set or get current canvas context
384 * @constructor
385 */
386
387var Matrix = (function(){
388
389    function reset(){
390        this.props[0] = 1;
391        this.props[1] = 0;
392        this.props[2] = 0;
393        this.props[3] = 0;
394        this.props[4] = 0;
395        this.props[5] = 1;
396        this.props[6] = 0;
397        this.props[7] = 0;
398        this.props[8] = 0;
399        this.props[9] = 0;
400        this.props[10] = 1;
401        this.props[11] = 0;
402        this.props[12] = 0;
403        this.props[13] = 0;
404        this.props[14] = 0;
405        this.props[15] = 1;
406        return this;
407    }
408
409    function rotate(angle) {
410        if(angle === 0){
411            return this;
412        }
413        var mCos = Math.cos(angle);
414        var mSin = Math.sin(angle);
415        return this._t(mCos, -mSin,  0, 0
416            , mSin,  mCos, 0, 0
417            , 0,  0,  1, 0
418            , 0, 0, 0, 1);
419    }
420
421    function rotateX(angle){
422        if(angle === 0){
423            return this;
424        }
425        var mCos = Math.cos(angle);
426        var mSin = Math.sin(angle);
427        return this._t(1, 0, 0, 0
428            , 0, mCos, -mSin, 0
429            , 0, mSin,  mCos, 0
430            , 0, 0, 0, 1);
431    }
432
433    function rotateY(angle){
434        if(angle === 0){
435            return this;
436        }
437        var mCos = Math.cos(angle);
438        var mSin = Math.sin(angle);
439        return this._t(mCos,  0,  mSin, 0
440            , 0, 1, 0, 0
441            , -mSin,  0,  mCos, 0
442            , 0, 0, 0, 1);
443    }
444
445    function rotateZ(angle){
446        if(angle === 0){
447            return this;
448        }
449        var mCos = Math.cos(angle);
450        var mSin = Math.sin(angle);
451        return this._t(mCos, -mSin,  0, 0
452            , mSin,  mCos, 0, 0
453            , 0,  0,  1, 0
454            , 0, 0, 0, 1);
455    }
456
457    function shear(sx,sy){
458        return this._t(1, sy, sx, 1, 0, 0);
459    }
460
461    function skew(ax, ay){
462        return this.shear(Math.tan(ax), Math.tan(ay));
463    }
464
465    function skewFromAxis(ax, angle){
466        var mCos = Math.cos(angle);
467        var mSin = Math.sin(angle);
468        return this._t(mCos, mSin,  0, 0
469            , -mSin,  mCos, 0, 0
470            , 0,  0,  1, 0
471            , 0, 0, 0, 1)
472            ._t(1, 0,  0, 0
473            , Math.tan(ax),  1, 0, 0
474            , 0,  0,  1, 0
475            , 0, 0, 0, 1)
476            ._t(mCos, -mSin,  0, 0
477            , mSin,  mCos, 0, 0
478            , 0,  0,  1, 0
479            , 0, 0, 0, 1);
480        //return this._t(mCos, mSin, -mSin, mCos, 0, 0)._t(1, 0, Math.tan(ax), 1, 0, 0)._t(mCos, -mSin, mSin, mCos, 0, 0);
481    }
482
483    function scale(sx, sy, sz) {
484        sz = isNaN(sz) ? 1 : sz;
485        if(sx == 1 && sy == 1 && sz == 1){
486            return this;
487        }
488        return this._t(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1);
489    }
490
491    function setTransform(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {
492        this.props[0] = a;
493        this.props[1] = b;
494        this.props[2] = c;
495        this.props[3] = d;
496        this.props[4] = e;
497        this.props[5] = f;
498        this.props[6] = g;
499        this.props[7] = h;
500        this.props[8] = i;
501        this.props[9] = j;
502        this.props[10] = k;
503        this.props[11] = l;
504        this.props[12] = m;
505        this.props[13] = n;
506        this.props[14] = o;
507        this.props[15] = p;
508        return this;
509    }
510
511    function translate(tx, ty, tz) {
512        tz = tz || 0;
513        if(tx !== 0 || ty !== 0 || tz !== 0){
514            return this._t(1,0,0,0,0,1,0,0,0,0,1,0,tx,ty,tz,1);
515        }
516        return this;
517    }
518
519    function transform(a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2, o2, p2) {
520
521        if(a2 === 1 && b2 === 0 && c2 === 0 && d2 === 0 && e2 === 0 && f2 === 1 && g2 === 0 && h2 === 0 && i2 === 0 && j2 === 0 && k2 === 1 && l2 === 0){
522            if(m2 !== 0 || n2 !== 0 || o2 !== 0){
523
524                this.props[12] = this.props[12] * a2 + this.props[13] * e2 + this.props[14] * i2 + this.props[15] * m2 ;
525                this.props[13] = this.props[12] * b2 + this.props[13] * f2 + this.props[14] * j2 + this.props[15] * n2 ;
526                this.props[14] = this.props[12] * c2 + this.props[13] * g2 + this.props[14] * k2 + this.props[15] * o2 ;
527                this.props[15] = this.props[12] * d2 + this.props[13] * h2 + this.props[14] * l2 + this.props[15] * p2 ;
528            }
529            this._identityCalculated = false;
530            return this;
531        }
532
533        var a1 = this.props[0];
534        var b1 = this.props[1];
535        var c1 = this.props[2];
536        var d1 = this.props[3];
537        var e1 = this.props[4];
538        var f1 = this.props[5];
539        var g1 = this.props[6];
540        var h1 = this.props[7];
541        var i1 = this.props[8];
542        var j1 = this.props[9];
543        var k1 = this.props[10];
544        var l1 = this.props[11];
545        var m1 = this.props[12];
546        var n1 = this.props[13];
547        var o1 = this.props[14];
548        var p1 = this.props[15];
549
550        /* matrix order (canvas compatible):
551         * ace
552         * bdf
553         * 001
554         */
555        this.props[0] = a1 * a2 + b1 * e2 + c1 * i2 + d1 * m2;
556        this.props[1] = a1 * b2 + b1 * f2 + c1 * j2 + d1 * n2 ;
557        this.props[2] = a1 * c2 + b1 * g2 + c1 * k2 + d1 * o2 ;
558        this.props[3] = a1 * d2 + b1 * h2 + c1 * l2 + d1 * p2 ;
559
560        this.props[4] = e1 * a2 + f1 * e2 + g1 * i2 + h1 * m2 ;
561        this.props[5] = e1 * b2 + f1 * f2 + g1 * j2 + h1 * n2 ;
562        this.props[6] = e1 * c2 + f1 * g2 + g1 * k2 + h1 * o2 ;
563        this.props[7] = e1 * d2 + f1 * h2 + g1 * l2 + h1 * p2 ;
564
565        this.props[8] = i1 * a2 + j1 * e2 + k1 * i2 + l1 * m2 ;
566        this.props[9] = i1 * b2 + j1 * f2 + k1 * j2 + l1 * n2 ;
567        this.props[10] = i1 * c2 + j1 * g2 + k1 * k2 + l1 * o2 ;
568        this.props[11] = i1 * d2 + j1 * h2 + k1 * l2 + l1 * p2 ;
569
570        this.props[12] = m1 * a2 + n1 * e2 + o1 * i2 + p1 * m2 ;
571        this.props[13] = m1 * b2 + n1 * f2 + o1 * j2 + p1 * n2 ;
572        this.props[14] = m1 * c2 + n1 * g2 + o1 * k2 + p1 * o2 ;
573        this.props[15] = m1 * d2 + n1 * h2 + o1 * l2 + p1 * p2 ;
574
575        this._identityCalculated = false;
576        return this;
577    }
578
579    function isIdentity() {
580        if(!this._identityCalculated){
581            this._identity = !(this.props[0] !== 1 || this.props[1] !== 0 || this.props[2] !== 0 || this.props[3] !== 0
582                || this.props[4] !== 0 || this.props[5] !== 1 || this.props[6] !== 0 || this.props[7] !== 0
583                || this.props[8] !== 0 || this.props[9] !== 0 || this.props[10] !== 1 || this.props[11] !== 0
584                || this.props[12] !== 0 || this.props[13] !== 0 || this.props[14] !== 0 || this.props[15] !== 1);
585            this._identityCalculated = true;
586        }
587        return this._identity;
588    }
589
590    function clone(matr){
591        var i;
592        for(i=0;i<16;i+=1){
593            matr.props[i] = this.props[i];
594        }
595    }
596
597    function cloneFromProps(props){
598        var i;
599        for(i=0;i<16;i+=1){
600            this.props[i] = props[i];
601        }
602    }
603
604    function applyToPoint(x, y, z) {
605
606        return {
607            x: x * this.props[0] + y * this.props[4] + z * this.props[8] + this.props[12],
608            y: x * this.props[1] + y * this.props[5] + z * this.props[9] + this.props[13],
609            z: x * this.props[2] + y * this.props[6] + z * this.props[10] + this.props[14]
610        };
611        /*return {
612         x: x * me.a + y * me.c + me.e,
613         y: x * me.b + y * me.d + me.f
614         };*/
615    }
616    function applyToX(x, y, z) {
617        return x * this.props[0] + y * this.props[4] + z * this.props[8] + this.props[12];
618    }
619    function applyToY(x, y, z) {
620        return x * this.props[1] + y * this.props[5] + z * this.props[9] + this.props[13];
621    }
622    function applyToZ(x, y, z) {
623        return x * this.props[2] + y * this.props[6] + z * this.props[10] + this.props[14];
624    }
625
626    function inversePoint(pt) {
627        var determinant = this.props[0] * this.props[5] - this.props[1] * this.props[4];
628        var a = this.props[5]/determinant;
629        var b = - this.props[1]/determinant;
630        var c = - this.props[4]/determinant;
631        var d = this.props[0]/determinant;
632        var e = (this.props[4] * this.props[13] - this.props[5] * this.props[12])/determinant;
633        var f = - (this.props[0] * this.props[13] - this.props[1] * this.props[12])/determinant;
634        return [pt[0] * a + pt[1] * c + e, pt[0] * b + pt[1] * d + f, 0];
635    }
636
637    function inversePoints(pts){
638        var i, len = pts.length, retPts = [];
639        for(i=0;i<len;i+=1){
640            retPts[i] = inversePoint(pts[i]);
641        }
642        return retPts;
643    }
644
645    function applyToPointArray(x,y,z,dimensions){
646        if(dimensions && dimensions === 2) {
647            var arr = point_pool.newPoint();
648            arr[0] = x * this.props[0] + y * this.props[4] + z * this.props[8] + this.props[12]; 
649            arr[1] = x * this.props[1] + y * this.props[5] + z * this.props[9] + this.props[13]; 
650            return arr;    
651        }
652        return [x * this.props[0] + y * this.props[4] + z * this.props[8] + this.props[12],x * this.props[1] + y * this.props[5] + z * this.props[9] + this.props[13],x * this.props[2] + y * this.props[6] + z * this.props[10] + this.props[14]];
653    }
654    function applyToPointStringified(x, y) {
655        if(this.isIdentity()) {
656            return x + ',' + y;
657        }
658        return (bm_rnd(x * this.props[0] + y * this.props[4] + this.props[12]))+','+(bm_rnd(x * this.props[1] + y * this.props[5] + this.props[13]));
659    }
660
661    function toArray() {
662        return [this.props[0],this.props[1],this.props[2],this.props[3],this.props[4],this.props[5],this.props[6],this.props[7],this.props[8],this.props[9],this.props[10],this.props[11],this.props[12],this.props[13],this.props[14],this.props[15]];
663    }
664
665    function toCSS() {
666        if(isSafari){
667            return "matrix3d(" + roundTo2Decimals(this.props[0]) + ',' + roundTo2Decimals(this.props[1]) + ',' + roundTo2Decimals(this.props[2]) + ',' + roundTo2Decimals(this.props[3]) + ',' + roundTo2Decimals(this.props[4]) + ',' + roundTo2Decimals(this.props[5]) + ',' + roundTo2Decimals(this.props[6]) + ',' + roundTo2Decimals(this.props[7]) + ',' + roundTo2Decimals(this.props[8]) + ',' + roundTo2Decimals(this.props[9]) + ',' + roundTo2Decimals(this.props[10]) + ',' + roundTo2Decimals(this.props[11]) + ',' + roundTo2Decimals(this.props[12]) + ',' + roundTo2Decimals(this.props[13]) + ',' + roundTo2Decimals(this.props[14]) + ',' + roundTo2Decimals(this.props[15]) + ')';
668        } else {
669            this.cssParts[1] = this.props.join(',');
670            return this.cssParts.join('');
671        }
672    }
673
674    function to2dCSS() {
675        return "matrix(" + roundTo2Decimals(this.props[0]) + ',' + roundTo2Decimals(this.props[1]) + ',' + roundTo2Decimals(this.props[4]) + ',' + roundTo2Decimals(this.props[5]) + ',' + roundTo2Decimals(this.props[12]) + ',' + roundTo2Decimals(this.props[13]) + ")";
676    }
677
678    function toString() {
679        return "" + this.toArray();
680    }
681
682    return function(){
683        this.reset = reset;
684        this.rotate = rotate;
685        this.rotateX = rotateX;
686        this.rotateY = rotateY;
687        this.rotateZ = rotateZ;
688        this.skew = skew;
689        this.skewFromAxis = skewFromAxis;
690        this.shear = shear;
691        this.scale = scale;
692        this.setTransform = setTransform;
693        this.translate = translate;
694        this.transform = transform;
695        this.applyToPoint = applyToPoint;
696        this.applyToX = applyToX;
697        this.applyToY = applyToY;
698        this.applyToZ = applyToZ;
699        this.applyToPointArray = applyToPointArray;
700        this.applyToPointStringified = applyToPointStringified;
701        this.toArray = toArray;
702        this.toCSS = toCSS;
703        this.to2dCSS = to2dCSS;
704        this.toString = toString;
705        this.clone = clone;
706        this.cloneFromProps = cloneFromProps;
707        this.inversePoints = inversePoints;
708        this.inversePoint = inversePoint;
709        this._t = this.transform;
710        this.isIdentity = isIdentity;
711        this._identity = true;
712        this._identityCalculated = false;
713
714        this.props = [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1];
715
716        this.cssParts = ['matrix3d(','',')'];
717    }
718}());
719
720function Matrix() {
721
722
723}
724
725/*
726 Copyright 2014 David Bau.
727
728 Permission is hereby granted, free of charge, to any person obtaining
729 a copy of this software and associated documentation files (the
730 "Software"), to deal in the Software without restriction, including
731 without limitation the rights to use, copy, modify, merge, publish,
732 distribute, sublicense, and/or sell copies of the Software, and to
733 permit persons to whom the Software is furnished to do so, subject to
734 the following conditions:
735
736 The above copyright notice and this permission notice shall be
737 included in all copies or substantial portions of the Software.
738
739 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
740 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
741 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
742 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
743 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
744 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
745 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
746
747 */
748
749(function (pool, math) {
750//
751// The following constants are related to IEEE 754 limits.
752//
753    var global = this,
754        width = 256,        // each RC4 output is 0 <= x < 256
755        chunks = 6,         // at least six RC4 outputs for each double
756        digits = 52,        // there are 52 significant digits in a double
757        rngname = 'random', // rngname: name for Math.random and Math.seedrandom
758        startdenom = math.pow(width, chunks),
759        significance = math.pow(2, digits),
760        overflow = significance * 2,
761        mask = width - 1,
762        nodecrypto;         // node.js crypto module, initialized at the bottom.
763
764//
765// seedrandom()
766// This is the seedrandom function described above.
767//
768    function seedrandom(seed, options, callback) {
769        var key = [];
770        options = (options == true) ? { entropy: true } : (options || {});
771
772        // Flatten the seed string or build one from local entropy if needed.
773        var shortseed = mixkey(flatten(
774            options.entropy ? [seed, tostring(pool)] :
775                (seed == null) ? autoseed() : seed, 3), key);
776
777        // Use the seed to initialize an ARC4 generator.
778        var arc4 = new ARC4(key);
779
780        // This function returns a random double in [0, 1) that contains
781        // randomness in every bit of the mantissa of the IEEE 754 value.
782        var prng = function() {
783            var n = arc4.g(chunks),             // Start with a numerator n < 2 ^ 48
784                d = startdenom,                 //   and denominator d = 2 ^ 48.
785                x = 0;                          //   and no 'extra last byte'.
786            while (n < significance) {          // Fill up all significant digits by
787                n = (n + x) * width;              //   shifting numerator and
788                d *= width;                       //   denominator and generating a
789                x = arc4.g(1);                    //   new least-significant-byte.
790            }
791            while (n >= overflow) {             // To avoid rounding up, before adding
792                n /= 2;                           //   last byte, shift everything
793                d /= 2;                           //   right using integer math until
794                x >>>= 1;                         //   we have exactly the desired bits.
795            }
796            return (n + x) / d;
vendor: 3,276 bytes, lines 796-886
796                 // Form the number within [0, 1).
797        };
798
799        prng.int32 = function() { return arc4.g(4) | 0; }
800        prng.quick = function() { return arc4.g(4) / 0x100000000; }
801        prng.double = prng;
802
803        // Mix the randomness into accumulated entropy.
804        mixkey(tostring(arc4.S), pool);
805
806        // Calling convention: what to return as a function of prng, seed, is_math.
807        return (options.pass || callback ||
808        function(prng, seed, is_math_call, state) {
809            if (state) {
810                // Load the arc4 state from the given state if it has an S array.
811                if (state.S) { copy(state, arc4); }
812                // Only provide the .state method if requested via options.state.
813                prng.state = function() { return copy(arc4, {}); }
814            }
815
816            // If called as a method of Math (Math.seedrandom()), mutate
817            // Math.random because that is how seedrandom.js has worked since v1.0.
818            if (is_math_call) { math[rngname] = prng; return seed; }
819
820            // Otherwise, it is a newer calling convention, so return the
821            // prng directly.
822            else return prng;
823        })(
824            prng,
825            shortseed,
826            'global' in options ? options.global : (this == math),
827            options.state);
828    }
829    math['seed' + rngname] = seedrandom;
830
831//
832// ARC4
833//
834// An ARC4 implementation.  The constructor takes a key in the form of
835// an array of at most (width) integers that should be 0 <= x < (width).
836//
837// The g(count) method returns a pseudorandom integer that concatenates
838// the next (count) outputs from ARC4.  Its return value is a number x
839// that is in the range 0 <= x < (width ^ count).
840//
841    function ARC4(key) {
842        var t, keylen = key.length,
843            me = this, i = 0, j = me.i = me.j = 0, s = me.S = [];
844
845        // The empty key [] is treated as [0].
846        if (!keylen) { key = [keylen++]; }
847
848        // Set up S using the standard key scheduling algorithm.
849        while (i < width) {
850            s[i] = i++;
851        }
852        for (i = 0; i < width; i++) {
853            s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))];
854            s[j] = t;
855        }
856
857        // The "g" method returns the next (count) outputs as one number.
858        (me.g = function(count) {
859            // Using instance members instead of closure state nearly doubles speed.
860            var t, r = 0,
861                i = me.i, j = me.j, s = me.S;
862            while (count--) {
863                t = s[i = mask & (i + 1)];
864                r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))];
865            }
866            me.i = i; me.j = j;
867            return r;
868            // For robust unpredictability, the function call below automatically
869            // discards an initial batch of values.  This is called RC4-drop[256].
870            // See http://google.com/search?q=rsa+fluhrer+response&btnI
871        })(width);
872    }
873
874//
875// copy()
876// Copies internal state of ARC4 to or from a plain object.
877//
878    function copy(f, t) {
879        t.i = f.i;
880        t.j = f.j;
881        t.S = f.S.slice();
882        return t;
883    };
884
885//
886// flatten()
vendor: 6,163 bytes, lines 887-1068
887// Converts an object tree to nested arrays of strings.
888//
889    function flatten(obj, depth) {
890        var result = [], typ = (typeof obj), prop;
891        if (depth && typ == 'object') {
892            for (prop in obj) {
893                try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {}
894            }
895        }
896        return (result.length ? result : typ == 'string' ? obj : obj + '\0');
897    }
898
899//
900// mixkey()
901// Mixes a string seed into a key that is an array of integers, and
902// returns a shortened string seed that is equivalent to the result key.
903//
904    function mixkey(seed, key) {
905        var stringseed = seed + '', smear, j = 0;
906        while (j < stringseed.length) {
907            key[mask & j] =
908                mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++));
909        }
910        return tostring(key);
911    }
912
913//
914// autoseed()
915// Returns an object for autoseeding, using window.crypto and Node crypto
916// module if available.
917//
918    function autoseed() {
919        try {
920            if (nodecrypto) { return tostring(nodecrypto.randomBytes(width)); }
921            var out = new Uint8Array(width);
922            (global.crypto || global.msCrypto).getRandomValues(out);
923            return tostring(out);
924        } catch (e) {
925            var browser = global.navigator,
926                plugins = browser && browser.plugins;
927            return [+new Date, global, plugins, global.screen, tostring(pool)];
928        }
929    }
930
931//
932// tostring()
933// Converts an array of charcodes to a string
934//
935    function tostring(a) {
936        return String.fromCharCode.apply(0, a);
937    }
938
939//
940// When seedrandom.js is loaded, we immediately mix a few bits
941// from the built-in RNG into the entropy pool.  Because we do
942// not want to interfere with deterministic PRNG state later,
943// seedrandom will not call math.random on its own again after
944// initialization.
945//
946    mixkey(math.random(), pool);
947
948//
949// Nodejs and AMD support: export the implementation as a module using
950// either convention.
951//
952
953// End anonymous scope, and pass initial values.
954})(
955    [],     // pool: entropy pool starts empty
956    BMMath    // math: package containing random, pow, and seedrandom
957);
958var BezierFactory = (function(){
959    /**
960     * BezierEasing - use bezier curve for transition easing function
961     * by Gaëtan Renaudeau 2014 - 2015 – MIT License
962     *
963     * Credits: is based on Firefox's nsSMILKeySpline.cpp
964     * Usage:
965     * var spline = BezierEasing([ 0.25, 0.1, 0.25, 1.0 ])
966     * spline.get(x) => returns the easing value | x must be in [0, 1] range
967     *
968     */
969
970        var ob = {};
971    ob.getBezierEasing = getBezierEasing;
972    var beziers = {};
973
974    function getBezierEasing(a,b,c,d,nm){
975        var str = nm || ('bez_' + a+'_'+b+'_'+c+'_'+d).replace(/\./g, 'p');
976        if(beziers[str]){
977            return beziers[str];
978        }
979        var bezEasing = new BezierEasing([a,b,c,d]);
980        beziers[str] = bezEasing;
981        return bezEasing;
982    }
983
984// These values are established by empiricism with tests (tradeoff: performance VS precision)
985    var NEWTON_ITERATIONS = 4;
986    var NEWTON_MIN_SLOPE = 0.001;
987    var SUBDIVISION_PRECISION = 0.0000001;
988    var SUBDIVISION_MAX_ITERATIONS = 10;
989
990    var kSplineTableSize = 11;
991    var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
992
993    var float32ArraySupported = typeof Float32Array === "function";
994
995    function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; }
996    function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; }
997    function C (aA1)      { return 3.0 * aA1; }
998
999// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
1000    function calcBezier (aT, aA1, aA2) {
1001        return ((A(aA1, aA2)*aT + B(aA1, aA2))*aT + C(aA1))*aT;
1002    }
1003
1004// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
1005    function getSlope (aT, aA1, aA2) {
1006        return 3.0 * A(aA1, aA2)*aT*aT + 2.0 * B(aA1, aA2) * aT + C(aA1);
1007    }
1008
1009    function binarySubdivide (aX, aA, aB, mX1, mX2) {
1010        var currentX, currentT, i = 0;
1011        do {
1012            currentT = aA + (aB - aA) / 2.0;
1013            currentX = calcBezier(currentT, mX1, mX2) - aX;
1014            if (currentX > 0.0) {
1015                aB = currentT;
1016            } else {
1017                aA = currentT;
1018            }
1019        } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
1020        return currentT;
1021    }
1022
1023    function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) {
1024        for (var i = 0; i < NEWTON_ITERATIONS; ++i) {
1025            var currentSlope = getSlope(aGuessT, mX1, mX2);
1026            if (currentSlope === 0.0) return aGuessT;
1027            var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
1028            aGuessT -= currentX / currentSlope;
1029        }
1030        return aGuessT;
1031    }
1032
1033    /**
1034     * points is an array of [ mX1, mY1, mX2, mY2 ]
1035     */
1036    function BezierEasing (points) {
1037        this._p = points;
1038        this._mSampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize);
1039        this._precomputed = false;
1040
1041        this.get = this.get.bind(this);
1042    }
1043
1044    BezierEasing.prototype = {
1045
1046        get: function (x) {
1047            var mX1 = this._p[0],
1048                mY1 = this._p[1],
1049                mX2 = this._p[2],
1050                mY2 = this._p[3];
1051            if (!this._precomputed) this._precompute();
1052            if (mX1 === mY1 && mX2 === mY2) return x; // linear
1053            // Because JavaScript number are imprecise, we should guarantee the extremes are right.
1054            if (x === 0) return 0;
1055            if (x === 1) return 1;
1056            return calcBezier(this._getTForX(x), mY1, mY2);
1057        },
1058
1059        // Private part
1060
1061        _precompute: function () {
1062            var mX1 = this._p[0],
1063                mY1 = this._p[1],
1064                mX2 = this._p[2],
1065                mY2 = this._p[3];
1066            this._precomputed = true;
1067            if (mX1 !== mY1 || mX2 !== mY2)
1068                this._calcSampleValues();
1069        },
1070
1071        _calcSampleValues: function () {
1072            var mX1 = this._p[0],
1073                mX2 = this._p[2];
1074            for (var i = 0; i < kSplineTableSize; ++i) {
1075                this._mSampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
1076            }
1077        },
1078
1079        /**
1080         * getTForX chose the fastest heuristic to determine the percentage value precisely from a given X projection.
1081         */
1082        _getTForX: function (aX) {
1083            var mX1 = this._p[0],
1084                mX2 = this._p[2],
1085                mSampleValues = this._mSampleValues;
1086
1087            var intervalStart = 0.0;
1088            var currentSample = 1;
1089            var lastSample = kSplineTableSize - 1;
1090
1091            for (; currentSample !== lastSample && mSampleValues[currentSample] <= aX; ++currentSample) {
1092                intervalStart += kSampleStepSize;
1093            }
1094            --currentSample;
1095
1096            // Interpolate to provide an initial guess for t
1097            var dist = (aX - mSampleValues[currentSample]) / (mSampleValues[currentSample+1] - mSampleValues[currentSample]);
1098            var guessForT = intervalStart + dist * kSampleStepSize;
1099
1100            var initialSlope = getSlope(guessForT, mX1, mX2);
1101            if (initialSlope >= NEWTON_MIN_SLOPE) {
1102                return newtonRaphsonIterate(aX, guessForT, mX1, mX2);
1103            } else if (initialSlope === 0.0) {
1104                return guessForT;
1105            } else {
1106                return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2);
1107            }
1108        }
1109    };
1110
1111    return ob;
1112
1113}());
1114(function () {
1115    var lastTime = 0;
1116    var vendors = ['ms', 'moz', 'webkit', 'o'];
1117    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
1118        window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
1119        window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
1120    }
1121    if(!window.requestAnimationFrame)
1122        window.requestAnimationFrame = function (callback, element) {
1123            var currTime = new Date().getTime();
1124            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
1125            var id = setTimeout(function () {
1126                    callback(currTime + timeToCall);
1127                },
1128                timeToCall);
1129            lastTime = currTime + timeToCall;
1130            return id;
1131        };
1132    if(!window.cancelAnimationFrame)
1133        window.cancelAnimationFrame = function (id) {
1134            clearTimeout(id);
1135        };
1136}());
1137
1138function createElement(parent,child,params){
1139    if(child){
1140        child.prototype = Object.create(parent.prototype);
1141        child.prototype.constructor = child;
1142        child.prototype._parent = parent.prototype;
1143    }else{
1144        var instance = Object.create(parent.prototype,params);
1145        var getType = {};
1146        if(instance && getType.toString.call(instance.init) === '[object Function]'){
1147            instance.init();
1148        }
1149        return instance;
1150    }
1151}
1152
1153function extendPrototype(source,destination){
1154    for (var attr in source.prototype) {
1155        if (source.prototype.hasOwnProperty(attr)) destination.prototype[attr] = source.prototype[attr];
1156    }
1157}
1158function bezFunction(){
1159
1160    var easingFunctions = [];
1161    var math = Math;
1162
1163    function pointOnLine2D(x1,y1, x2,y2, x3,y3){
1164        var det1 = (x1*y2) + (y1*x3) + (x2*y3) - (x3*y2) - (y3*x1) - (x2*y1);
1165        return det1 > -0.0001 && det1 < 0.0001;
1166    }
1167
1168    function pointOnLine3D(x1,y1,z1, x2,y2,z2, x3,y3,z3){
1169        if(z1 === 0 && z2 === 0 && z3 === 0) {
1170            return pointOnLine2D(x1,y1, x2,y2, x3,y3);
1171        }
1172        var dist1 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2));
1173        var dist2 = Math.sqrt(Math.pow(x3 - x1, 2) + Math.pow(y3 - y1, 2) + Math.pow(z3 - z1, 2));
1174        var dist3 = Math.sqrt(Math.pow(x3 - x2, 2) + Math.pow(y3 - y2, 2) + Math.pow(z3 - z2, 2));
1175        var diffDist;
1176        if(dist1 > dist2){
1177            if(dist1 > dist3){
1178                diffDist = dist1 - dist2 - dist3;
1179            } else {
1180                diffDist = dist3 - dist2 - dist1;
1181            }
1182        } else if(dist3 > dist2){
1183            diffDist = dist3 - dist2 - dist1;
1184        } else {
1185            diffDist = dist2 - dist1 - dist3;
1186        }
1187        return diffDist > -0.0001 && diffDist < 0.0001;
1188    }
1189
1190    /*function getEasingCurve(aa,bb,cc,dd,encodedFuncName) {
1191        if(!encodedFuncName){
1192            encodedFuncName = ('bez_' + aa+'_'+bb+'_'+cc+'_'+dd).replace(/\./g, 'p');
1193        }
1194        if(easingFunctions[encodedFuncName]){
1195            return easingFunctions[encodedFuncName];
1196        }
1197        var A0, B0, C0;
1198        var A1, B1, C1;
1199        easingFunctions[encodedFuncName] = function(tt) {
1200            var x = tt;
1201            var i = 0, z;
1202            while (++i < 20) {
1203                C0 = 3 * aa;
1204                B0 = 3 * (cc - aa) - C0;
1205                A0 = 1 - C0 - B0;
1206                z = (x * (C0 + x * (B0 + x * A0))) - tt;
1207                if (bm_abs(z) < 1e-3) break;
1208                x -= z / (C0 + x * (2 * B0 + 3 * A0 * x));
1209            }
1210            C1 = 3 * bb;
1211            B1 = 3 * (dd - bb) - C1;
1212            A1 = 1 - C1 - B1;
1213            var polyB = x * (C1 + x * (B1 + x * A1));
1214            //return c * polyB + b;
1215            return polyB;
1216        };
1217        return easingFunctions[encodedFuncName];
1218    }*/
1219    var getBezierLength = (function(){
1220
1221        function Segment(l,p){
1222            this.l = l;
1223            this.p = p;
1224        }
1225
1226        return function(pt1,pt2,pt3,pt4){
1227            var curveSegments = defaultCurveSegments;
1228            var k;
1229            var i, len;
1230            var ptCoord,perc,addedLength = 0;
1231            var ptDistance;
1232            var point = [],lastPoint = [];
1233            var lengthData = {
1234                addedLength: 0,
1235                segments: []
1236            };
1237            len = pt3.length;
1238            for(k=0;k<curveSegments;k+=1){
1239                perc = k/(curveSegments-1);
1240                ptDistance = 0;
1241                for(i=0;i<len;i+=1){
1242                    ptCoord = bm_pow(1-perc,3)*pt1[i]+3*bm_pow(1-perc,2)*perc*pt3[i]+3*(1-perc)*bm_pow(perc,2)*pt4[i]+bm_pow(perc,3)*pt2[i];
1243                    point[i] = ptCoord;
1244                    if(lastPoint[i] !== null){
1245                        ptDistance += bm_pow(point[i] - lastPoint[i],2);
1246                    }
1247                    lastPoint[i] = point[i];
1248                }
1249                if(ptDistance){
1250                    ptDistance = bm_sqrt(ptDistance);
1251                    addedLength += ptDistance;
1252                }
1253                lengthData.segments.push(new Segment(addedLength,perc));
1254            }
1255            lengthData.addedLength = addedLength;
1256            return lengthData;
1257        };
1258    }());
1259
1260    function getSegmentsLength(shapeData) {
1261        var closed = shapeData.c;
1262        var pathV = shapeData.v;
1263        var pathO = shapeData.o;
1264        var pathI = shapeData.i;
1265        var i, len = shapeData._length;
1266        var lengths = [];
1267        var totalLength = 0;
1268        for(i=0;i<len-1;i+=1){
1269            lengths[i] = getBezierLength(pathV[i],pathV[i+1],pathO[i],pathI[i+1]);
1270            totalLength += lengths[i].addedLength;
1271        }
1272        if(closed){
1273            lengths[i] = getBezierLength(pathV[i],pathV[0],pathO[i],pathI[0]);
1274            totalLength += lengths[i].addedLength;
1275        }
1276        return {lengths:lengths,totalLength:totalLength};
1277    }
1278
1279    function BezierData(length){
1280        this.segmentLength = 0;
1281        this.points = new Array(length);
1282    }
1283
1284    function PointData(partial,point){
1285        this.partialLength = partial;
1286        this.point = point;
1287    }
1288
1289    var buildBezierData = (function(){
1290
1291        var storedData = {};
1292
1293        return function (keyData){
1294            var pt1 = keyData.s;
1295            var pt2 = keyData.e;
1296            var pt3 = keyData.to;
1297            var pt4 = keyData.ti;
1298            var bezierName = (pt1.join('_')+'_'+pt2.join('_')+'_'+pt3.join('_')+'_'+pt4.join('_')).replace(/\./g, 'p');
1299            if(storedData[bezierName]){
1300                keyData.bezierData = storedData[bezierName];
1301                return;
1302            }
1303        var curveSegments = defaultCurveSegments;
1304        var k, i, len;
1305            var ptCoord,perc,addedLength = 0;
1306            var ptDistance;
1307            var point,lastPoint = null;
1308            if(pt1.length === 2 && (pt1[0] != pt2[0] || pt1[1] != pt2[1]) && pointOnLine2D(pt1[0],pt1[1],pt2[0],pt2[1],pt1[0]+pt3[0],pt1[1]+pt3[1]) && pointOnLine2D(pt1[0],pt1[1],pt2[0],pt2[1],pt2[0]+pt4[0],pt2[1]+pt4[1])){
1309                curveSegments = 2;
1310            }
1311            var bezierData = new BezierData(curveSegments);
1312            len = pt3.length;
1313            for(k=0;k<curveSegments;k+=1){
1314            point = new Array(len);
1315                perc = k/(curveSegments-1);
1316                ptDistance = 0;
1317                for(i=0;i<len;i+=1){
1318                ptCoord = bm_pow(1-perc,3)*pt1[i]+3*bm_pow(1-perc,2)*perc*(pt1[i] + pt3[i])+3*(1-perc)*bm_pow(perc,2)*(pt2[i] + pt4[i])+bm_pow(perc,3)*pt2[i];
1319                point[i] = ptCoord;
1320                    if(lastPoint !== null){
1321                    ptDistance += bm_pow(point[i] - lastPoint[i],2);
1322                    }
1323                }
1324            ptDistance = bm_sqrt(ptDistance);
1325                addedLength += ptDistance;
1326                bezierData.points[k] = new PointData(ptDistance,point);
1327                lastPoint = point;
1328            }
1329            bezierData.segmentLength = addedLength;
1330            keyData.bezierData = bezierData;
1331            storedData[bezierName] = bezierData;
1332
1333        }
1334    }());
1335
1336    function getDistancePerc(perc,bezierData){
1337        var segments = bezierData.segments;
1338        var len = segments.length;
1339        var initPos = bm_floor((len-1)*perc);
1340        var lengthPos = perc*bezierData.addedLength;
1341        var lPerc = 0;
1342        if(lengthPos == segments[initPos].l){
1343            return segments[initPos].p;
1344        }else{
1345            var dir = segments[initPos].l > lengthPos ? -1 : 1;
1346            var flag = true;
1347            while(flag){
1348                if(segments[initPos].l <= lengthPos && segments[initPos+1].l > lengthPos){
1349                    lPerc = (lengthPos - segments[initPos].l)/(segments[initPos+1].l-segments[initPos].l);
1350                    flag = false;
1351                }else{
1352                    initPos += dir;
1353                }
1354                if(initPos < 0 || initPos >= len - 1){
1355                    flag = false;
1356                }
1357            }
1358            return segments[initPos].p + (segments[initPos+1].p - segments[initPos].p)*lPerc;
1359        }
1360    }
1361
1362    function SegmentPoints(){
1363        this.pt1 = new Array(2);
1364        this.pt2 = new Array(2);
1365        this.pt3 = new Array(2);
1366        this.pt4 = new Array(2);
1367    }
1368
1369    function getPointInSegment(pt1, pt2, pt3, pt4, percent, bezierData) {
1370        var t1 = getDistancePerc(percent,bezierData);
1371        var u0 = 1;
1372        var u1 = 1 - t1;
1373        var ptX = Math.round((u1*u1*u1* pt1[0] + (t1*u1*u1 + u1*t1*u1 + u1*u1*t1)* pt3[0] + (t1*t1*u1 + u1*t1*t1 + t1*u1*t1)*pt4[0] + t1*t1*t1* pt2[0])* 1000) / 1000;
1374        var ptY = Math.round((u1*u1*u1* pt1[1] + (t1*u1*u1 + u1*t1*u1 + u1*u1*t1)* pt3[1] + (t1*t1*u1 + u1*t1*t1 + t1*u1*t1)*pt4[1] + t1*t1*t1* pt2[1])* 1000) / 1000;
1375        return [ptX, ptY];
1376    }
1377
1378    function getNewSegment(pt1,pt2,pt3,pt4,startPerc,endPerc, bezierData){
1379
1380        var pts = new SegmentPoints();
1381        startPerc = startPerc < 0 ? 0 : startPerc > 1 ? 1 : startPerc;
1382        var t0 = getDistancePerc(startPerc,bezierData);
1383        endPerc = endPerc > 1 ? 1 : endPerc;
1384        var t1 = getDistancePerc(endPerc,bezierData);
1385        var i, len = pt1.length;
1386        var u0 = 1 - t0;
1387        var u1 = 1 - t1;
1388        //Math.round(num * 100) / 100
1389        for(i=0;i<len;i+=1){
1390            pts.pt1[i] =  Math.round((u0*u0*u0* pt1[i] + (t0*u0*u0 + u0*t0*u0 + u0*u0*t0) * pt3[i] + (t0*t0*u0 + u0*t0*t0 + t0*u0*t0)* pt4[i] + t0*t0*t0* pt2[i])* 1000) / 1000;
1391            pts.pt3[i] = Math.round((u0*u0*u1*pt1[i] + (t0*u0*u1 + u0*t0*u1 + u0*u0*t1)* pt3[i] + (t0*t0*u1 + u0*t0*t1 + t0*u0*t1)* pt4[i] + t0*t0*t1* pt2[i])* 1000) / 1000;
1392            pts.pt4[i] = Math.round((u0*u1*u1* pt1[i] + (t0*u1*u1 + u0*t1*u1 + u0*u1*t1)* pt3[i] + (t0*t1*u1 + u0*t1*t1 + t0*u1*t1)* pt4[i] + t0*t1*t1* pt2[i])* 1000) / 1000;
1393            pts.pt2[i] = Math.round((u1*u1*u1* pt1[i] + (t1*u1*u1 + u1*t1*u1 + u1*u1*t1)* pt3[i] + (t1*t1*u1 + u1*t1*t1 + t1*u1*t1)*pt4[i] + t1*t1*t1* pt2[i])* 1000) / 1000;
1394        }
1395        return pts;
1396    }
1397
1398    return {
1399        //getEasingCurve : getEasingCurve,
1400        getBezierLength : getBezierLength,
1401        getSegmentsLength : getSegmentsLength,
1402        getNewSegment : getNewSegment,
1403        getPointInSegment : getPointInSegment,
1404        buildBezierData : buildBezierData,
1405        pointOnLine2D : pointOnLine2D,
1406        pointOnLine3D : pointOnLine3D
1407    };
1408}
1409
1410var bez = bezFunction();
1411function dataFunctionManager(){
1412
1413    //var tCanvasHelper = document.createElement('canvas').getContext('2d');
1414
1415    function completeLayers(layers, comps, fontManager){
1416        var layerData;
1417        var animArray, lastFrame;
1418        var i, len = layers.length;
1419        var j, jLen, k, kLen;
1420        for(i=0;i<len;i+=1){
1421            layerData = layers[i];
1422            if(!('ks' in layerData) || layerData.completed){
1423                continue;
1424            }
1425            layerData.completed = true;
1426            if(layerData.tt){
1427                layers[i-1].td = layerData.tt;
1428            }
1429            animArray = [];
1430            lastFrame = -1;
1431            if(layerData.hasMask){
1432                var maskProps = layerData.masksProperties;
1433                jLen = maskProps.length;
1434                for(j=0;j<jLen;j+=1){
1435                    if(maskProps[j].pt.k.i){
1436                        convertPathsToAbsoluteValues(maskProps[j].pt.k);
1437                    }else{
1438                        kLen = maskProps[j].pt.k.length;
1439                        for(k=0;k<kLen;k+=1){
1440                            if(maskProps[j].pt.k[k].s){
1441                                convertPathsToAbsoluteValues(maskProps[j].pt.k[k].s[0]);
1442                            }
1443                            if(maskProps[j].pt.k[k].e){
1444                                convertPathsToAbsoluteValues(maskProps[j].pt.k[k].e[0]);
1445                            }
1446                        }
1447                    }
1448                }
1449            }
1450            if(layerData.ty===0){
1451                layerData.layers = findCompLayers(layerData.refId, comps);
1452                completeLayers(layerData.layers,comps, fontManager);
1453            }else if(layerData.ty === 4){
1454                completeShapes(layerData.shapes);
1455            }else if(layerData.ty == 5){
1456                completeText(layerData, fontManager);
1457            }
1458        }
1459    }
1460
1461    function findCompLayers(id,comps){
1462        var i = 0, len = comps.length;
1463        while(i<len){
1464            if(comps[i].id === id){
1465                if(!comps[i].layers.__used) {
1466                    comps[i].layers.__used = true;
1467                    return comps[i].layers;
1468                }
1469                return JSON.parse(JSON.stringify(comps[i].layers));
1470            }
1471            i += 1;
1472        }
1473    }
1474
1475    function completeShapes(arr){
1476        var i, len = arr.length;
1477        var j, jLen;
1478        var hasPaths = false;
1479        for(i=len-1;i>=0;i-=1){
1480            if(arr[i].ty == 'sh'){
1481                if(arr[i].ks.k.i){
1482                    convertPathsToAbsoluteValues(arr[i].ks.k);
1483                }else{
1484                    jLen = arr[i].ks.k.length;
1485                    for(j=0;j<jLen;j+=1){
1486                        if(arr[i].ks.k[j].s){
1487                            convertPathsToAbsoluteValues(arr[i].ks.k[j].s[0]);
1488                        }
1489                        if(arr[i].ks.k[j].e){
1490                            convertPathsToAbsoluteValues(arr[i].ks.k[j].e[0]);
1491                        }
1492                    }
1493                }
1494                hasPaths = true;
1495            }else if(arr[i].ty == 'gr'){
1496                completeShapes(arr[i].it);
1497            }
1498        }
1499        /*if(hasPaths){
1500            //mx: distance
1501            //ss: sensitivity
1502            //dc: decay
1503            arr.splice(arr.length-1,0,{
1504                "ty": "ms",
1505                "mx":20,
1506                "ss":10,
1507                 "dc":0.001,
1508                "maxDist":200
1509            });
1510        }*/
1511    }
1512
1513    function convertPathsToAbsoluteValues(path){
1514        var i, len = path.i.length;
1515        for(i=0;i<len;i+=1){
1516            path.i[i][0] += path.v[i][0];
1517            path.i[i][1] += path.v[i][1];
1518            path.o[i][0] += path.v[i][0];
1519            path.o[i][1] += path.v[i][1];
1520        }
1521    }
1522
1523    function checkVersion(minimum,animVersionString){
1524        var animVersion = animVersionString ? animVersionString.split('.') : [100,100,100];
1525        if(minimum[0]>animVersion[0]){
1526            return true;
1527        } else if(animVersion[0] > minimum[0]){
1528            return false;
1529        }
1530        if(minimum[1]>animVersion[1]){
1531            return true;
1532        } else if(animVersion[1] > minimum[1]){
1533            return false;
1534        }
1535        if(minimum[2]>animVersion[2]){
1536            return true;
1537        } else if(animVersion[2] > minimum[2]){
1538            return false;
1539        }
1540    }
1541
1542    var checkText = (function(){
1543        var minimumVersion = [4,4,14];
1544
1545        function updateTextLayer(textLayer){
1546            var documentData = textLayer.t.d;
1547            textLayer.t.d = {
1548                k: [
1549                    {
1550                        s:documentData,
1551                        t:0
1552                    }
1553                ]
1554            }
1555        }
1556
1557        function iterateLayers(layers){
1558            var i, len = layers.length;
1559            for(i=0;i<len;i+=1){
1560                if(layers[i].ty === 5){
1561                    updateTextLayer(layers[i]);
1562                }
1563            }
1564        }
1565
1566        return function (animationData){
1567            if(checkVersion(minimumVersion,animationData.v)){
1568                iterateLayers(animationData.layers);
1569                if(animationData.assets){
1570                    var i, len = animationData.assets.length;
1571                    for(i=0;i<len;i+=1){
1572                        if(animationData.assets[i].layers){
1573                            iterateLayers(animationData.assets[i].layers);
1574
1575                        }
1576                    }
1577                }
1578            }
1579        }
1580    }())
1581
1582    var checkChars = (function() {
1583        var minimumVersion = [4,7,99];
1584        return function (animationData){
1585            if(animationData.chars && !checkVersion(minimumVersion,animationData.v)){
1586                var i, len = animationData.chars.length, j, jLen, k, kLen;
1587                var pathData, paths;
1588                for(i = 0; i < len; i += 1) {
1589                    if(animationData.chars[i].data && animationData.chars[i].data.shapes) {
1590                        paths = animationData.chars[i].data.shapes[0].it;
1591                        jLen = paths.length;
1592
1593                        for(j = 0; j < jLen; j += 1) {
1594                            pathData = paths[j].ks.k;
1595                            if(!pathData.__converted) {
1596                                convertPathsToAbsoluteValues(paths[j].ks.k);
1597                                pathData.__converted = true;
1598                            }
1599                        }
1600                    }
1601                }
1602            }
1603        }
1604
1605    }())
1606
1607    var checkColors = (function(){
1608        var minimumVersion = [4,1,9];
1609
1610        function iterateShapes(shapes){
1611            var i, len = shapes.length;
1612            var j, jLen;
1613            for(i=0;i<len;i+=1){
1614                if(shapes[i].ty === 'gr'){
1615                    iterateShapes(shapes[i].it);
1616                }else if(shapes[i].ty === 'fl' || shapes[i].ty === 'st'){
1617                    if(shapes[i].c.k && shapes[i].c.k[0].i){
1618                        jLen = shapes[i].c.k.length;
1619                        for(j=0;j<jLen;j+=1){
1620                            if(shapes[i].c.k[j].s){
1621                                shapes[i].c.k[j].s[0] /= 255;
1622                                shapes[i].c.k[j].s[1] /= 255;
1623                                shapes[i].c.k[j].s[2] /= 255;
1624                                shapes[i].c.k[j].s[3] /= 255;
1625                            }
1626                            if(shapes[i].c.k[j].e){
1627                                shapes[i].c.k[j].e[0] /= 255;
1628                                shapes[i].c.k[j].e[1] /= 255;
1629                                shapes[i].c.k[j].e[2] /= 255;
1630                                shapes[i].c.k[j].e[3] /= 255;
1631                            }
1632                        }
1633                    } else {
1634                        shapes[i].c.k[0] /= 255;
1635                        shapes[i].c.k[1] /= 255;
1636                        shapes[i].c.k[2] /= 255;
1637                        shapes[i].c.k[3] /= 255;
1638                    }
1639                }
1640            }
1641        }
1642
1643        function iterateLayers(layers){
1644            var i, len = layers.length;
1645            for(i=0;i<len;i+=1){
1646                if(layers[i].ty === 4){
1647                    iterateShapes(layers[i].shapes);
1648                }
1649            }
1650        }
1651
1652        return function (animationData){
1653            if(checkVersion(minimumVersion,animationData.v)){
1654                iterateLayers(animationData.layers);
1655                if(animationData.assets){
1656                    var i, len = animationData.assets.length;
1657                    for(i=0;i<len;i+=1){
1658                        if(animationData.assets[i].layers){
1659                            iterateLayers(animationData.assets[i].layers);
1660
1661                        }
1662                    }
1663                }
1664            }
1665        }
1666    }());
1667
1668    var checkShapes = (function(){
1669        var minimumVersion = [4,4,18];
1670
1671
1672
1673        function completeShapes(arr){
1674            var i, len = arr.length;
1675            var j, jLen;
1676            var hasPaths = false;
1677            for(i=len-1;i>=0;i-=1){
1678                if(arr[i].ty == 'sh'){
1679                    if(arr[i].ks.k.i){
1680                        arr[i].ks.k.c = arr[i].closed;
1681                    }else{
1682                        jLen = arr[i].ks.k.length;
1683                        for(j=0;j<jLen;j+=1){
1684                            if(arr[i].ks.k[j].s){
1685                                arr[i].ks.k[j].s[0].c = arr[i].closed;
1686                            }
1687                            if(arr[i].ks.k[j].e){
1688                                arr[i].ks.k[j].e[0].c = arr[i].closed;
1689                            }
1690                        }
1691                    }
1692                    hasPaths = true;
1693                }else if(arr[i].ty == 'gr'){
1694                    completeShapes(arr[i].it);
1695                }
1696            }
1697        }
1698
1699        function iterateLayers(layers){
1700            var layerData;
1701            var i, len = layers.length;
1702            var j, jLen, k, kLen;
1703            for(i=0;i<len;i+=1){
1704                layerData = layers[i];
vendor: 4,835 bytes, lines 1705-1846
1705                if(layerData.hasMask){
1706                    var maskProps = layerData.masksProperties;
1707                    jLen = maskProps.length;
1708                    for(j=0;j<jLen;j+=1){
1709                        if(maskProps[j].pt.k.i){
1710                            maskProps[j].pt.k.c = maskProps[j].cl;
1711                        }else{
1712                            kLen = maskProps[j].pt.k.length;
1713                            for(k=0;k<kLen;k+=1){
1714                                if(maskProps[j].pt.k[k].s){
1715                                    maskProps[j].pt.k[k].s[0].c = maskProps[j].cl;
1716                                }
1717                                if(maskProps[j].pt.k[k].e){
1718                                    maskProps[j].pt.k[k].e[0].c = maskProps[j].cl;
1719                                }
1720                            }
1721                        }
1722                    }
1723                }
1724                if(layerData.ty === 4){
1725                    completeShapes(layerData.shapes);
1726                }
1727            }
1728        }
1729
1730        return function (animationData){
1731            if(checkVersion(minimumVersion,animationData.v)){
1732                iterateLayers(animationData.layers);
1733                if(animationData.assets){
1734                    var i, len = animationData.assets.length;
1735                    for(i=0;i<len;i+=1){
1736                        if(animationData.assets[i].layers){
1737                            iterateLayers(animationData.assets[i].layers);
1738
1739                        }
1740                    }
1741                }
1742            }
1743        }
1744    }());
1745
1746    /*function blitPaths(path){
1747        var i, len = path.i.length;
1748        for(i=0;i<len;i+=1){
1749            path.i[i][0] /= blitter;
1750            path.i[i][1] /= blitter;
1751            path.o[i][0] /= blitter;
1752            path.o[i][1] /= blitter;
1753            path.v[i][0] /= blitter;
1754            path.v[i][1] /= blitter;
1755        }
1756    }
1757
1758    function blitShapes(arr){
1759        var i, len = arr.length;
1760        var j, jLen;
1761        var hasPaths = false;
1762        for(i=len-1;i>=0;i-=1){
1763            if(arr[i].ty == 'sh'){
1764                if(arr[i].ks.k.i){
1765                    blitPaths(arr[i].ks.k);
1766                }else{
1767                    jLen = arr[i].ks.k.length;
1768                    for(j=0;j<jLen;j+=1){
1769                        if(arr[i].ks.k[j].s){
1770                            blitPaths(arr[i].ks.k[j].s[0]);
1771                        }
1772                        if(arr[i].ks.k[j].e){
1773                            blitPaths(arr[i].ks.k[j].e[0]);
1774                        }
1775                    }
1776                }
1777                hasPaths = true;
1778            }else if(arr[i].ty == 'gr'){
1779                blitShapes(arr[i].it);
1780            }else if(arr[i].ty == 'rc'){
1781                blitProperty(arr[i].p);
1782                blitProperty(arr[i].s);
1783            }else if(arr[i].ty == 'st'){
1784                blitProperty(arr[i].w);
1785            }else if(arr[i].ty == 'tr'){
1786                blitProperty(arr[i].p);
1787                blitProperty(arr[i].sk);
1788                blitProperty(arr[i].a);
1789            }else if(arr[i].ty == 'el'){
1790                blitProperty(arr[i].p);
1791                blitProperty(arr[i].s);
1792            }else if(arr[i].ty == 'rd'){
1793                blitProperty(arr[i].r);
1794            }else{
1795
1796                //console.log(arr[i].ty );
1797            }
1798        }
1799    }
1800
1801    function blitText(data, fontManager){
1802
1803    }
1804
1805    function blitValue(val){
1806        if(typeof(val) === 'number'){
1807            val /= blitter;
1808        } else {
1809            var i = val.length-1;
1810            while(i>=0){
1811                val[i] /= blitter;
1812                i-=1;
1813            }
1814        }
1815        return val;
1816    }
1817
1818    function blitProperty(data){
1819        if(!data.k.length){
1820            data.k = blitValue(data.k);
1821        }else if(typeof(data.k[0]) === 'number'){
1822            data.k = blitValue(data.k);
1823        } else {
1824            var i, len = data.k.length;
1825            for(i=0;i<len;i+=1){
1826                if(data.k[i].s){
1827                    //console.log('pre S: ', data.k[i].s);
1828                    data.k[i].s = blitValue(data.k[i].s);
1829                    //console.log('post S: ', data.k[i].s);
1830                }
1831                if(data.k[i].e){
1832                    //console.log('pre E: ', data.k[i].e);
1833                    data.k[i].e = blitValue(data.k[i].e);
1834                    //console.log('post E: ', data.k[i].e);
1835                }
1836            }
1837        }
1838    }
1839
1840    function blitLayers(layers,comps, fontManager){
1841        var layerData;
1842        var animArray, lastFrame;
1843        var i, len = layers.length;
1844        var j, jLen, k, kLen;
1845        for(i=0;i<len;i+=1){
1846            layerData = layers[i];
1847            if(!('ks' in layerData)){
1848                continue;
1849            }
1850            blitProperty(layerData.ks.a);
1851            blitProperty(layerData.ks.p);
1852            layerData.completed = true;
1853            if(layerData.tt){
1854                layers[i-1].td = layerData.tt;
1855            }
1856            animArray = [];
1857            lastFrame = -1;
1858            if(layerData.hasMask){
1859                var maskProps = layerData.masksProperties;
1860                jLen = maskProps.length;
1861                for(j=0;j<jLen;j+=1){
1862                    if(maskProps[j].pt.k.i){
1863                        blitPaths(maskProps[j].pt.k);
1864                    }else{
1865                        kLen = maskProps[j].pt.k.length;
1866                        for(k=0;k<kLen;k+=1){
1867                            if(maskProps[j].pt.k[k].s){
1868                                blitPaths(maskProps[j].pt.k[k].s[0]);
1869                            }
1870                            if(maskProps[j].pt.k[k].e){
1871                                blitPaths(maskProps[j].pt.k[k].e[0]);
1872                            }
1873                        }
1874                    }
1875                }
1876            }
1877            if(layerData.ty===0){
1878                layerData.w = Math.round(layerData.w/blitter);
1879                layerData.h = Math.round(layerData.h/blitter);
1880                blitLayers(layerData.layers,comps, fontManager);
1881            }else if(layerData.ty === 4){
1882                blitShapes(layerData.shapes);
1883            }else if(layerData.ty == 5){
1884                blitText(layerData, fontManager);
1885            }else if(layerData.ty == 1){
1886                layerData.sh /= blitter;
1887                layerData.sw /= blitter;
1888            } else {
1889            }
1890        }
1891    }
1892
1893    function blitAnimation(animationData,comps, fontManager){
1894        blitLayers(animationData.layers,comps, fontManager);
1895    }*/
1896
1897    function completeData(animationData, fontManager){
1898        if(animationData.__complete){
1899            return;
1900        }
1901        checkColors(animationData);
1902        checkText(animationData);
1903        checkChars(animationData);
1904        checkShapes(animationData);
1905        completeLayers(animationData.layers, animationData.assets, fontManager);
1906        animationData.__complete = true;
1907        //blitAnimation(animationData, animationData.assets, fontManager);
1908    }
1909
1910    function completeText(data, fontManager){
1911        if(data.t.a.length === 0 && !('m' in data.t.p)){
1912            data.singleShape = true;
1913        }
1914    }
1915
1916    var moduleOb = {};
1917    moduleOb.completeData = completeData;
1918
1919    return moduleOb;
1920}
1921
1922var dataManager = dataFunctionManager();
1923var FontManager = (function(){
1924
1925    var maxWaitingTime = 5000;
1926
1927    function setUpNode(font, family){
1928        var parentNode = document.createElement('span');
1929        parentNode.style.fontFamily    = family;
1930        var node = document.createElement('span');
1931        // Characters that vary significantly among different fonts
1932        node.innerHTML = 'giItT1WQy@!-/#';
1933        // Visible - so we can measure it - but not on the screen
1934        parentNode.style.position      = 'absolute';
1935        parentNode.style.left          = '-10000px';
1936        parentNode.style.top           = '-10000px';
1937        // Large font size makes even subtle changes obvious
1938        parentNode.style.fontSize      = '300px';
1939        // Reset any font properties
1940        parentNode.style.fontVariant   = 'normal';
1941        parentNode.style.fontStyle     = 'normal';
1942        parentNode.style.fontWeight    = 'normal';
1943        parentNode.style.letterSpacing = '0';
1944        parentNode.appendChild(node);
1945        document.body.appendChild(parentNode);
1946
1947        // Remember width with no applied web font
1948        var width = node.offsetWidth;
1949        node.style.fontFamily = font + ', '+family;
1950        return {node:node, w:width, parent:parentNode};
1951    }
1952
1953    function checkLoadedFonts() {
1954        var i, len = this.fonts.length;
1955        var node, w;
1956        var loadedCount = len;
1957        for(i=0;i<len; i+= 1){
1958            if(this.fonts[i].loaded){
1959                loadedCount -= 1;
1960                continue;
1961            }
1962            if(this.fonts[i].fOrigin === 't' || this.fonts[i].origin === 2){
1963                if(window.Typekit && window.Typekit.load && this.typekitLoaded === 0){
1964                    this.typekitLoaded = 1;
1965                    try{window.Typekit.load({
1966                        async: true,
1967                        active: function() {
1968                            this.typekitLoaded = 2;
1969                        }.bind(this)
1970                    });}catch(e){}
1971                }
1972                if(this.typekitLoaded === 2) {
1973                    this.fonts[i].loaded = true;
1974                }
1975            } else if(this.fonts[i].fOrigin === 'n' || this.fonts[i].origin === 0){
1976                this.fonts[i].loaded = true;
1977            } else{
1978                node = this.fonts[i].monoCase.node;
1979                w = this.fonts[i].monoCase.w;
1980                if(node.offsetWidth !== w){
1981                    loadedCount -= 1;
1982                    this.fonts[i].loaded = true;
1983                }else{
1984                    node = this.fonts[i].sansCase.node;
1985                    w = this.fonts[i].sansCase.w;
1986                    if(node.offsetWidth !== w){
1987                        loadedCount -= 1;
1988                        this.fonts[i].loaded = true;
1989                    }
1990                }
1991                if(this.fonts[i].loaded){
1992                    this.fonts[i].sansCase.parent.parentNode.removeChild(this.fonts[i].sansCase.parent);
1993                    this.fonts[i].monoCase.parent.parentNode.removeChild(this.fonts[i].monoCase.parent);
1994                }
1995            }
1996        }
1997
1998        if(loadedCount !== 0 && Date.now() - this.initTime < maxWaitingTime){
1999            setTimeout(checkLoadedFonts.bind(this),20);
2000        }else{
2001            setTimeout(function(){this.loaded = true;}.bind(this),0);
2002
2003        }
2004    };
2005
2006    function createHelper(def, fontData){
2007        var tHelper = document.createElementNS(svgNS,'text');
2008        tHelper.style.fontSize = '100px';
2009        tHelper.style.fontFamily = fontData.fFamily;
2010        tHelper.textContent = '1';
2011        if(fontData.fClass){
2012            tHelper.style.fontFamily = 'inherit';
2013            tHelper.className = fontData.fClass;
2014        } else {
2015            tHelper.style.fontFamily = fontData.fFamily;
2016        }
2017        def.appendChild(tHelper);
2018        var tCanvasHelper = document.createElement('canvas').getContext('2d');
2019        tCanvasHelper.font = '100px '+ fontData.fFamily;
2020        return tCanvasHelper;
2021    }
2022
2023    function addFonts(fontData, defs){
2024        if(!fontData){
2025            this.loaded = true;
2026            return;
2027        }
2028        if(this.chars){
2029            this.loaded = true;
2030            this.fonts = fontData.list;
2031            return;
2032        }
2033
2034        var fontArr = fontData.list;
2035        var i, len = fontArr.length;
2036        for(i=0; i<len; i+= 1){
2037            fontArr[i].loaded = false;
2038            fontArr[i].monoCase = setUpNode(fontArr[i].fFamily,'monospace');
2039            fontArr[i].sansCase = setUpNode(fontArr[i].fFamily,'sans-serif');
2040            if(!fontArr[i].fPath) {
2041                fontArr[i].loaded = true;
2042            }else if(fontArr[i].fOrigin === 'p' || fontArr[i].origin === 3){
2043                var s = document.createElement('style');
2044                s.type = "text/css";
2045                s.innerHTML = "@font-face {" + "font-family: "+fontArr[i].fFamily+"; font-style: normal; src: url('"+fontArr[i].fPath+"');}";
2046                defs.appendChild(s);
2047            } else if(fontArr[i].fOrigin === 'g' || fontArr[i].origin === 1){
2048                //<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css'>
2049                var l = document.createElement('link');
2050                l.type = "text/css";
2051                l.rel = "stylesheet";
2052                l.href = fontArr[i].fPath;
2053                defs.appendChild(l);
2054            } else if(fontArr[i].fOrigin === 't' || fontArr[i].origin === 2){
2055                //<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css'>
2056                var sc = document.createElement('script');
2057                sc.setAttribute('src',fontArr[i].fPath);
2058                defs.appendChild(sc);
2059            }
2060            fontArr[i].helper = createHelper(defs,fontArr[i]);
2061            this.fonts.push(fontArr[i]);
2062        }
2063        checkLoadedFonts.bind(this)();
2064    }
2065
2066    function addChars(chars){
2067        if(!chars){
2068            return;
2069        }
2070        if(!this.chars){
2071            this.chars = [];
2072        }
2073        var i, len = chars.length;
2074        var j, jLen = this.chars.length, found;
2075        for(i=0;i<len;i+=1){
2076            j = 0;
2077            found = false;
2078            while(j<jLen){
2079                if(this.chars[j].style === chars[i].style && this.chars[j].fFamily === chars[i].fFamily && this.chars[j].ch === chars[i].ch){
2080                    found = true;
2081                }
2082                j += 1;
2083            }
2084            if(!found){
2085                this.chars.push(chars[i]);
2086                jLen += 1;
2087            }
2088        }
2089    }
2090
2091    function getCharData(char, style, font){
2092        var i = 0, len = this.chars.length;
2093        while( i < len) {
2094            if(this.chars[i].ch === char && this.chars[i].style === style && this.chars[i].fFamily === font){
2095                return this.chars[i];
2096            }
2097            i+= 1;
2098        }
2099    }
2100
2101    function measureText(char, fontName, size){
2102        var fontData = this.getFontByName(fontName);
2103        var tHelper = fontData.helper;
2104        //tHelper.textContent = char;
2105        return tHelper.measureText(char).width*size/100;
2106        //return tHelper.getComputedTextLength()*size/100;
2107    }
2108
2109    function getFontByName(name){
2110        var i = 0, len = this.fonts.length;
2111        while(i<len){
2112            if(this.fonts[i].fName === name) {
2113                return this.fonts[i];
2114            }
2115            i += 1;
2116        }
2117        return 'sans-serif';
2118    }
2119
2120    var Font = function(){
2121        this.fonts = [];
2122        this.chars = null;
2123        this.typekitLoaded = 0;
2124        this.loaded = false;
2125        this.initTime = Date.now();
2126    };
2127    Font.prototype.addChars = addChars;
2128    Font.prototype.addFonts = addFonts;
2129    Font.prototype.getCharData = getCharData;
2130    Font.prototype.getFontByName = getFontByName;
2131    Font.prototype.measureText = measureText;
2132
2133    return Font;
2134
2135}());
2136var PropertyFactory = (function(){
2137
2138    var initFrame = -999999;
2139
2140    function interpolateValue(frameNum, iterationIndex, previousValue, caching){
2141        var offsetTime = this.offsetTime;
2142        var newValue;
2143        if(previousValue.constructor === Array) {
2144            newValue = Array.apply(null,{length:previousValue.length})
2145        }
2146        var i = iterationIndex;
2147        var len = this.keyframes.length- 1,flag = true;
2148        var keyData, nextKeyData;
2149
2150        while(flag){
2151            keyData = this.keyframes[i];
2152            nextKeyData = this.keyframes[i+1];
2153            if(i == len-1 && frameNum >= nextKeyData.t - offsetTime){
2154                if(keyData.h){
2155                    keyData = nextKeyData;
2156                }
2157                iterationIndex = 0;
2158                break;
2159            }
2160            if((nextKeyData.t - offsetTime) > frameNum){
2161                iterationIndex = i;
2162                break;
2163            }
2164            if(i < len - 1){
2165                i += 1;
2166            }else{
2167                iterationIndex = 0;
2168                flag = false;
2169            }
2170        }
2171
2172        var k, kLen,perc,jLen, j, fnc;
2173        if(keyData.to){
2174
2175            if(!keyData.bezierData){
2176                bez.buildBezierData(keyData);
2177            }
2178            var bezierData = keyData.bezierData;
2179            if(frameNum >= nextKeyData.t-offsetTime || frameNum < keyData.t-offsetTime){
2180                var ind = frameNum >= nextKeyData.t-offsetTime ? bezierData.points.length - 1 : 0;
2181                kLen = bezierData.points[ind].point.length;
2182                for(k = 0; k < kLen; k += 1){
2183                    newValue[k] = bezierData.points[ind].point[k];
2184                }
2185                caching._lastBezierData = null;
2186            }else{
2187                if(keyData.__fnct){
2188                    fnc = keyData.__fnct;
2189                }else{
2190                    fnc = BezierFactory.getBezierEasing(keyData.o.x,keyData.o.y,keyData.i.x,keyData.i.y,keyData.n).get;
2191                    keyData.__fnct = fnc;
2192                }
2193                perc = fnc((frameNum-(keyData.t-offsetTime))/((nextKeyData.t-offsetTime)-(keyData.t-offsetTime)));
2194                var distanceInLine = bezierData.segmentLength*perc;
2195
2196                var segmentPerc;
2197                var addedLength =  (caching.lastFrame < frameNum && caching._lastBezierData === bezierData) ? caching._lastAddedLength : 0;
2198                j =  (caching.lastFrame < frameNum && caching._lastBezierData === bezierData) ? caching._lastPoint : 0;
2199                flag = true;
2200                jLen = bezierData.points.length;
2201                while(flag){
2202                    addedLength +=bezierData.points[j].partialLength;
2203                    if(distanceInLine === 0 || perc === 0 || j == bezierData.points.length - 1){
2204                        kLen = bezierData.points[j].point.length;
2205                        for(k=0;k<kLen;k+=1){
2206                            newValue[k] = bezierData.points[j].point[k];
2207                        }
2208                        break;
2209                    }else if(distanceInLine >= addedLength && distanceInLine < addedLength + bezierData.points[j+1].partialLength){
2210                        segmentPerc = (distanceInLine-addedLength)/(bezierData.points[j+1].partialLength);
2211                        kLen = bezierData.points[j].point.length;
2212                        for(k=0;k<kLen;k+=1){
2213                            newValue[k] = bezierData.points[j].point[k] + (bezierData.points[j+1].point[k] - bezierData.points[j].point[k])*segmentPerc;
2214                        }
2215                        break;
2216                    }
2217                    if(j < jLen - 1){
2218                        j += 1;
2219                    }else{
2220                        flag = false;
2221                    }
2222                }
2223                caching._lastPoint = j;
2224                caching._lastAddedLength = addedLength - bezierData.points[j].partialLength;
2225                caching._lastBezierData = bezierData;
2226            }
2227        }else{
2228            var outX,outY,inX,inY, keyValue;
2229            len = keyData.s.length;
2230            for(i=0;i<len;i+=1){
2231                if(keyData.h !== 1){
2232                    if(frameNum >= nextKeyData.t-offsetTime){
2233                        perc = 1;
2234                    }else if(frameNum < keyData.t-offsetTime){
2235                        perc = 0;
2236                    }else{
2237                        if(keyData.o.x.constructor === Array){
2238                            if(!keyData.__fnct){
2239                                keyData.__fnct = [];
2240                            }
2241                            if (!keyData.__fnct[i]) {
2242                                outX = keyData.o.x[i] || keyData.o.x[0];
2243                                outY = keyData.o.y[i] || keyData.o.y[0];
2244                                inX = keyData.i.x[i] || keyData.i.x[0];
2245                                inY = keyData.i.y[i] || keyData.i.y[0];
2246                                fnc = BezierFactory.getBezierEasing(outX,outY,inX,inY).get;
2247                                keyData.__fnct[i] = fnc;
2248                            } else {
2249                                fnc = keyData.__fnct[i];
2250                            }
2251                        } else {
2252                            if (!keyData.__fnct) {
2253                                outX = keyData.o.x;
2254                                outY = keyData.o.y;
2255                                inX = keyData.i.x;
2256                                inY = keyData.i.y;
2257                                fnc = BezierFactory.getBezierEasing(outX,outY,inX,inY).get;
2258                                keyData.__fnct = fnc;
2259                            } else{
2260                                fnc = keyData.__fnct;
2261                            }
2262                        }
2263                        perc = fnc((frameNum-(keyData.t-offsetTime))/((nextKeyData.t-offsetTime)-(keyData.t-offsetTime)));
2264                    }
2265                }
2266                if(this.sh && keyData.h !== 1){
2267                    var initP = keyData.s[i];
2268                    var endP = keyData.e[i];
2269                    if(initP-endP < -180){
2270                        initP += 360;
2271                    } else if(initP-endP > 180){
2272                        initP -= 360;
2273                    }
2274                    keyValue = initP+(endP-initP)*perc;
2275                } else {
2276                    keyValue = keyData.h === 1 ? keyData.s[i] : keyData.s[i]+(keyData.e[i]-keyData.s[i])*perc;
2277                }
2278                if(len === 1){
2279                    newValue = keyValue;
2280                }else{
2281                    newValue[i] = keyValue;
2282                }
2283            }
2284        }
2285        return {
2286            value: newValue,
2287            iterationIndex: iterationIndex
2288        }
2289    }
2290
2291    function getValueAtCurrentTime(){
2292        if(this.elem.globalData.frameId === this.frameId){
2293            return;
2294        }
2295        this.mdf = false;
2296        var frameNum = this.comp.renderedFrame - this.offsetTime;
2297        var initTime = this.keyframes[0].t-this.offsetTime;
2298        var endTime = this.keyframes[this.keyframes.length- 1].t-this.offsetTime;
2299        if(!(frameNum === this._caching.lastFrame || (this._caching.lastFrame !== initFrame && ((this._caching.lastFrame >= endTime && frameNum >= endTime) || (this._caching.lastFrame < initTime && frameNum < initTime))))){
2300            var i = this._caching.lastFrame < frameNum ? this._caching.lastIndex : 0;
2301            var renderResult = this.interpolateValue(frameNum, i, this.pv, this._caching);
2302            this._caching.lastIndex = renderResult.iterationIndex;
2303            if(this.pv.constructor === Array){
2304                i = 0;
2305                while(i<this.v.length){
2306                    this.pv[i] = renderResult.value[i];
2307                    this.v[i] = this.mult ? this.pv[i] * this.mult : this.pv[i];
2308                    if(this.lastPValue[i] !== this.pv[i]) {
2309                        this.mdf = true;
2310                        this.lastPValue[i] = this.pv[i];
2311                    }
2312                    i += 1;
2313                }
2314            } else {
2315                this.pv = renderResult.value;
2316                this.v = this.mult ? this.pv*this.mult : this.pv;
2317                if(this.lastPValue != this.pv){
2318                    this.mdf = true;
2319                    this.lastPValue = this.pv;
2320                }
2321            }
2322            
2323        }
2324        this._caching.lastFrame = frameNum;
2325        this.frameId = this.elem.globalData.frameId;
2326    }
2327
2328    function getNoValue(){}
2329
2330    function ValueProperty(elem,data, mult){
2331        this.mult = mult;
2332        this.v = mult ? data.k * mult : data.k;
2333        this.pv = data.k;
2334        this.mdf = false;
2335        this.comp = elem.comp;
2336        this.k = false;
2337        this.kf = false;
2338        this.vel = 0;
2339        this.getValue = getNoValue;
2340    }
2341
2342    function MultiDimensionalProperty(elem,data, mult){
2343        this.mult = mult;
2344        this.data = data;
2345        this.mdf = false;
2346        this.comp = elem.comp;
2347        this.k = false;
2348        this.kf = false;
2349        this.frameId = -1;
2350        this.v = Array.apply(null, {length:data.k.length});
2351        this.pv = Array.apply(null, {length:data.k.length});
2352        this.lastValue = Array.apply(null, {length:data.k.length});
2353        var arr = Array.apply(null, {length:data.k.length});
2354        this.vel = arr.map(function () { return 0 });
2355        var i, len = data.k.length;
2356        for(i = 0;i<len;i+=1){
2357            this.v[i] = mult ? data.k[i] * mult : data.k[i];
2358            this.pv[i] = data.k[i];
2359        }
2360        this.getValue = getNoValue;
2361    }
2362
2363    function KeyframedValueProperty(elem, data, mult){
2364        this.keyframes = data.k;
2365        this.offsetTime = elem.data.st;
2366        this.lastValue = -99999;
2367        this.lastPValue = -99999;
2368        this.frameId = -1;
2369        this._caching={lastFrame:initFrame,lastIndex:0};
2370        this.k = true;
2371        this.kf = true;
2372        this.data = data;
2373        this.mult = mult;
2374        this.elem = elem;
2375        this.comp = elem.comp;
2376        this.v = mult ? data.k[0].s[0]*mult : data.k[0].s[0];
2377        this.pv = data.k[0].s[0];
2378        this.getValue = getValueAtCurrentTime;
2379        this.interpolateValue = interpolateValue;
2380    }
2381
2382    function KeyframedMultidimensionalProperty(elem, data, mult){
2383        var i, len = data.k.length;
2384        var s, e,to,ti;
2385        for(i=0;i<len-1;i+=1){
2386            if(data.k[i].to && data.k[i].s && data.k[i].e){
2387                s = data.k[i].s;
2388                e = data.k[i].e;
2389                to = data.k[i].to;
2390                ti = data.k[i].ti;
2391                if((s.length === 2 && !(s[0] === e[0] && s[1] === e[1]) && bez.pointOnLine2D(s[0],s[1],e[0],e[1],s[0] + to[0],s[1] + to[1]) && bez.pointOnLine2D(s[0],s[1],e[0],e[1],e[0] + ti[0],e[1] + ti[1])) || (s.length === 3 && !(s[0] === e[0] && s[1] === e[1] && s[2] === e[2]) && bez.pointOnLine3D(s[0],s[1],s[2],e[0],e[1],e[2],s[0] + to[0],s[1] + to[1],s[2] + to[2]) && bez.pointOnLine3D(s[0],s[1],s[2],e[0],e[1],e[2],e[0] + ti[0],e[1] + ti[1],e[2] + ti[2]))){
2392                    data.k[i].to = null;
2393                    data.k[i].ti = null;
2394                }
2395            }
2396        }
2397        this.keyframes = data.k;
2398        this.offsetTime = elem.data.st;
2399        this.k = true;
2400        this.kf = true;
2401        this.mult = mult;
2402        this.elem = elem;
2403        this.comp = elem.comp;
2404        this._caching={lastFrame:initFrame,lastIndex:0};
2405        this.getValue = getValueAtCurrentTime;
2406        this.interpolateValue = interpolateValue;
2407        this.frameId = -1;
2408        this.v = Array.apply(null, {length:data.k[0].s.length});
2409        this.pv = Array.apply(null, {length:data.k[0].s.length});
2410        this.lastValue = Array.apply(null, {length:data.k[0].s.length});
2411        this.lastPValue = Array.apply(null, {length:data.k[0].s.length});
2412    }
2413
2414    var TransformProperty = (function() {
2415        function positionGetter() {
2416            if(this.p) {
2417                return ExpressionValue(this.p);
2418            } else {
2419                return [this.px.v, this.py.v, this.pz ? this.pz.v : 0];
2420            }
2421        }
2422        function xPositionGetter() {
2423            return ExpressionValue(this.px);
2424        }
2425        function yPositionGetter() {
2426            return ExpressionValue(this.py);
2427        }
2428        function zPositionGetter() {
2429            return ExpressionValue(this.pz);
2430        }
2431        function anchorGetter() {
2432            return ExpressionValue(this.a);
2433        }
2434        function orientationGetter() {
2435            return ExpressionValue(this.or);
2436        }
2437        function rotationGetter() {
2438            if(this.r) {
2439                return ExpressionValue(this.r, 1/degToRads);
2440            } else {
2441                return ExpressionValue(this.rz, 1/degToRads);
2442            }
2443        }
2444        function scaleGetter() {
2445            return ExpressionValue(this.s, 100);
2446        }
2447        function opacityGetter() {
2448            return ExpressionValue(this.o, 100);
2449        }
2450        function skewGetter() {
2451            return ExpressionValue(this.sk);
2452        }
2453        function skewAxisGetter() {
2454            return ExpressionValue(this.sa);
2455        }
2456        function applyToMatrix(mat) {
2457            var i, len = this.dynamicProperties.length;
2458            for(i = 0; i < len; i += 1) {
2459                this.dynamicProperties[i].getValue();
2460                if (this.dynamicProperties[i].mdf) {
2461                    this.mdf = true;
2462                }
2463            }
2464            if (this.a) {
2465                mat.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]);
2466            }
2467            if (this.s) {
2468                mat.scale(this.s.v[0], this.s.v[1], this.s.v[2]);
2469            }
2470            if (this.r) {
2471                mat.rotate(-this.r.v);
2472            } else {
2473                mat.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]);
2474            }
2475            if (this.data.p.s) {
2476                if (this.data.p.z) {
2477                    mat.translate(this.px.v, this.py.v, -this.pz.v);
2478                } else {
2479                    mat.translate(this.px.v, this.py.v, 0);
2480                }
2481            } else {
2482                mat.translate(this.p.v[0], this.p.v[1], -this.p.v[2]);
2483            }
2484        }
2485        function processKeys(){
2486            if (this.elem.globalData.frameId === this.frameId) {
2487                return;
2488            }
2489
2490            this.mdf = false;
2491            var i, len = this.dynamicProperties.length;
2492
2493            for(i = 0; i < len; i += 1) {
2494                this.dynamicProperties[i].getValue();
2495                if (this.dynamicProperties[i].mdf) {
2496                    this.mdf = true;
2497                }
2498            }
2499            if (this.mdf) {
2500                this.v.reset();
2501                if (this.a) {
2502                    this.v.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]);
2503                }
2504                if(this.s) {
2505                    this.v.scale(this.s.v[0], this.s.v[1], this.s.v[2]);
2506                }
2507                if (this.sk) {
2508                    this.v.skewFromAxis(-this.sk.v, this.sa.v);
2509                }
2510                if (this.r) {
2511                    this.v.rotate(-this.r.v);
2512                } else {
2513                    this.v.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]);
2514                }
2515                if (this.autoOriented && this.p.keyframes && this.p.getValueAtTime) {
2516                    var v1,v2;
2517                    if (this.p._caching.lastFrame+this.p.offsetTime <= this.p.keyframes[0].t) {
2518                        v1 = this.p.getValueAtTime((this.p.keyframes[0].t + 0.01) / this.elem.globalData.frameRate,0);
2519                        v2 = this.p.getValueAtTime(this.p.keyframes[0].t / this.elem.globalData.frameRate, 0);
2520                    } else if(this.p._caching.lastFrame+this.p.offsetTime >= this.p.keyframes[this.p.keyframes.length - 1].t) {
2521                        v1 = this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length - 1].t / this.elem.globalData.frameRate), 0);
2522                        v2 = this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length - 1].t - 0.01) / this.elem.globalData.frameRate, 0);
2523                    } else {
2524                        v1 = this.p.pv;
2525                        v2 = this.p.getValueAtTime((this.p._caching.lastFrame+this.p.offsetTime - 0.01) / this.elem.globalData.frameRate, this.p.offsetTime);
2526                    }
2527                    this.v.rotate(-Math.atan2(v1[1] - v2[1], v1[0] - v2[0]));
2528                }
2529                if(this.data.p.s){
2530                    if(this.data.p.z) {
2531                        this.v.translate(this.px.v, this.py.v, -this.pz.v);
2532                    } else {
2533                        this.v.translate(this.px.v, this.py.v, 0);
2534                    }
2535                }else{
2536                    this.v.translate(this.p.v[0],this.p.v[1],-this.p.v[2]);
2537                }
2538            }
2539            this.frameId = this.elem.globalData.frameId;
2540        }
2541
2542        function setInverted(){
2543            this.inverted = true;
2544            this.iv = new Matrix();
2545            if(!this.k){
2546                if(this.data.p.s){
2547                    this.iv.translate(this.px.v,this.py.v,-this.pz.v);
2548                }else{
2549                    this.iv.translate(this.p.v[0],this.p.v[1],-this.p.v[2]);
2550                }
2551                if(this.r){
2552                    this.iv.rotate(-this.r.v);
2553                }else{
2554                    this.iv.rotateX(-this.rx.v).rotateY(-this.ry.v).rotateZ(this.rz.v);
2555                }
2556                if(this.s){
2557                    this.iv.scale(this.s.v[0],this.s.v[1],1);
2558                }
2559                if(this.a){
2560                    this.iv.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]);
2561                }
2562            }
2563        }
2564
2565        function autoOrient(){
2566            //
2567            //var prevP = this.getValueAtTime();
2568        }
2569
2570        return function TransformProperty(elem,data,arr){
2571            this.elem = elem;
2572            this.frameId = -1;
2573            this.type = 'transform';
2574            this.dynamicProperties = [];
2575            this.mdf = false;
2576            this.data = data;
2577            this.getValue = processKeys;
2578            this.applyToMatrix = applyToMatrix;
2579            this.setInverted = setInverted;
2580            this.autoOrient = autoOrient;
2581            this.v = new Matrix();
2582            if(data.p.s){
2583                this.px = PropertyFactory.getProp(elem,data.p.x,0,0,this.dynamicProperties);
2584                this.py = PropertyFactory.getProp(elem,data.p.y,0,0,this.dynamicProperties);
2585                if(data.p.z){
2586                    this.pz = PropertyFactory.getProp(elem,data.p.z,0,0,this.dynamicProperties);
2587                }
2588            }else{
2589                this.p = PropertyFactory.getProp(elem,data.p,1,0,this.dynamicProperties);
2590            }
2591            if(data.r) {
2592                this.r = PropertyFactory.getProp(elem, data.r, 0, degToRads, this.dynamicProperties);
2593            } else if(data.rx) {
2594                this.rx = PropertyFactory.getProp(elem, data.rx, 0, degToRads, this.dynamicProperties);
2595                this.ry = PropertyFactory.getProp(elem, data.ry, 0, degToRads, this.dynamicProperties);
2596                this.rz = PropertyFactory.getProp(elem, data.rz, 0, degToRads, this.dynamicProperties);
2597                this.or = PropertyFactory.getProp(elem, data.or, 1, degToRads, this.dynamicProperties);
2598                //sh Indicates it needs to be capped between -180 and 180
2599                this.or.sh = true;
2600            }
2601            if(data.sk){
2602                this.sk = PropertyFactory.getProp(elem, data.sk, 0, degToRads, this.dynamicProperties);
2603                this.sa = PropertyFactory.getProp(elem, data.sa, 0, degToRads, this.dynamicProperties);
2604            }
2605            if(data.a) {
2606                this.a = PropertyFactory.getProp(elem,data.a,1,0,this.dynamicProperties);
2607            }
2608            if(data.s) {
2609                this.s = PropertyFactory.getProp(elem,data.s,1,0.01,this.dynamicProperties);
2610            }
2611            if(data.o){
2612                this.o = PropertyFactory.getProp(elem,data.o,0,0.01,this.dynamicProperties);
2613            } else {
2614                this.o = {mdf:false,v:1};
2615            }
2616            if(this.dynamicProperties.length){
2617                arr.push(this);
2618            }else{
2619                if(this.a){
2620                    this.v.translate(-this.a.v[0],-this.a.v[1],this.a.v[2]);
2621                }
2622                if(this.s){
2623                    this.v.scale(this.s.v[0],this.s.v[1],this.s.v[2]);
2624                }
2625                if(this.sk){
2626                    this.v.skewFromAxis(-this.sk.v,this.sa.v);
2627                }
2628                if(this.r){
2629                    this.v.rotate(-this.r.v);
2630                }else{
2631                    this.v.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]);
2632                }
2633                if(this.data.p.s){
2634                    if(data.p.z) {
2635                        this.v.translate(this.px.v, this.py.v, -this.pz.v);
2636                    } else {
2637                        this.v.translate(this.px.v, this.py.v, 0);
2638                    }
2639                }else{
2640                    this.v.translate(this.p.v[0],this.p.v[1],-this.p.v[2]);
2641                }
2642            }
2643            Object.defineProperty(this, "position", { get: positionGetter});
2644            Object.defineProperty(this, "xPosition", { get: xPositionGetter});
2645            Object.defineProperty(this, "yPosition", { get: yPositionGetter});
2646            Object.defineProperty(this, "orientation", { get: orientationGetter});
2647            Object.defineProperty(this, "anchorPoint", { get: anchorGetter});
2648            Object.defineProperty(this, "rotation", { get: rotationGetter});
2649            Object.defineProperty(this, "scale", { get: scaleGetter});
2650            Object.defineProperty(this, "opacity", { get: opacityGetter});
2651            Object.defineProperty(this, "skew", { get: skewGetter});
2652            Object.defineProperty(this, "skewAxis", { get: skewAxisGetter});
2653        }
2654    }());
2655
2656    function getProp(elem,data,type, mult, arr) {
2657        var p;
2658        if(type === 2){
2659            p = new TransformProperty(elem, data, arr);
2660        } else if(data.a === 0){
2661            if(type === 0) {
2662                p = new ValueProperty(elem,data,mult);
2663            } else {
2664                p = new MultiDimensionalProperty(elem,data, mult);
2665            }
2666        } else if(data.a === 1){
2667            if(type === 0) {
2668                p = new KeyframedValueProperty(elem,data,mult);
2669            } else {
2670                p = new KeyframedMultidimensionalProperty(elem,data, mult);
2671            }
2672        } else if(!data.k.length){
2673            p = new ValueProperty(elem,data, mult);
2674        }else if(typeof(data.k[0]) === 'number'){
2675            p = new MultiDimensionalProperty(elem,data, mult);
2676        }else{
2677            switch(type){
2678                case 0:
2679                    p = new KeyframedValueProperty(elem,data,mult);
2680                    break;
2681                case 1:
2682                    p = new KeyframedMultidimensionalProperty(elem,data,mult);
2683                    break;
2684            }
2685        }
2686        if(p.k){
2687            arr.push(p);
2688        }
2689        return p;
2690    }
2691
2692    var getGradientProp = (function(){
2693
2694        function getValue(forceRender){
2695            this.prop.getValue();
2696            this.cmdf = false;
2697            this.omdf = false;
2698            if(this.prop.mdf || forceRender){
2699                var i, len = this.data.p*4;
2700                var mult, val;
2701                for(i=0;i<len;i+=1){
2702                    mult = i%4 === 0 ? 100 : 255;
2703                    val = Math.round(this.prop.v[i]*mult);
2704                    if(this.c[i] !== val){
2705                        this.c[i] = val;
2706                        this.cmdf = true;
2707                    }
2708                }
2709                if(this.o.length){
2710                    len = this.prop.v.length;
2711                    for(i=this.data.p*4;i<len;i+=1){
2712                        mult = i%2 === 0 ? 100 : 1;
2713                        val = i%2 === 0 ?  Math.round(this.prop.v[i]*100):this.prop.v[i];
2714                        if(this.o[i-this.data.p*4] !== val){
2715                            this.o[i-this.data.p*4] = val;
2716                            this.omdf = true;
2717                        }
2718                    }
2719                }
2720            }
2721
2722        }
2723
2724        function gradientProp(elem,data,arr){
2725            this.prop = getProp(elem,data.k,1,null,[]);
2726            this.data = data;
2727            this.k = this.prop.k;
2728            this.c = Array.apply(null,{length:data.p*4});
2729            var cLength = data.k.k[0].s ? (data.k.k[0].s.length - data.p*4) : data.k.k.length - data.p*4;
2730            this.o = Array.apply(null,{length:cLength});
2731            this.cmdf = false;
2732            this.omdf = false;
2733            this.getValue = getValue;
2734            if(this.prop.k){
2735                arr.push(this);
2736            }
2737            this.getValue(true);
2738        }
2739
2740        return function getGradientProp(elem,data,arr){
2741            return new gradientProp(elem,data,arr);
2742        }
2743    }());
2744
2745
2746
2747
2748    var DashProperty = (function(){
2749
2750        function processKeys(forceRender){
2751            var i = 0, len = this.dataProps.length;
2752
2753            if(this.elem.globalData.frameId === this.frameId && !forceRender){
2754                return;
2755            }
2756            this.mdf = false;
2757            this.frameId = this.elem.globalData.frameId;
2758            while(i<len){
2759                if(this.dataProps[i].p.mdf){
2760                    this.mdf = true;
2761                    break;
2762                }
2763                i+=1;
2764            }
2765            if(this.mdf || forceRender){
2766                if(this.renderer === 'svg') {
2767                    this.dasharray = '';
2768                }
2769                for(i=0;i<len;i+=1){
2770                    if(this.dataProps[i].n != 'o'){
2771                        if(this.renderer === 'svg') {
2772                            this.dasharray += ' ' + this.dataProps[i].p.v;
2773                        }else{
2774                            this.dasharray[i] = this.dataProps[i].p.v;
2775                        }
2776                    }else{
2777                        this.dashoffset = this.dataProps[i].p.v;
2778                    }
2779                }
2780            }
2781        }
2782
2783        return function(elem, data,renderer, dynamicProperties){
2784            this.elem = elem;
2785            this.frameId = -1;
2786            this.dataProps = new Array(data.length);
2787            this.renderer = renderer;
2788            this.mdf = false;
2789            this.k = false;
2790            if(this.renderer === 'svg'){
2791                this.dasharray = '';
2792            }else{
2793
2794                this.dasharray = new Array(data.length - 1);
2795            }
2796            this.dashoffset = 0;
2797            var i, len = data.length, prop;
2798            for(i=0;i<len;i+=1){
2799                prop = PropertyFactory.getProp(elem,data[i].v,0, 0, dynamicProperties);
2800                this.k = prop.k ? true : this.k;
2801                this.dataProps[i] = {n:data[i].n,p:prop};
2802            }
2803            this.getValue = processKeys;
2804            if(this.k){
2805                dynamicProperties.push(this);
2806            }else{
2807                this.getValue(true);
2808            }
2809
2810        }
2811    }());
2812
2813    function getDashProp(elem, data,renderer, dynamicProperties) {
2814        return new DashProperty(elem, data,renderer, dynamicProperties);
2815    };
2816
2817    var TextSelectorProp = (function(){
2818        var max = Math.max;
2819        var min = Math.min;
2820        var floor = Math.floor;
2821        function updateRange(newCharsFlag){
2822            this.mdf = newCharsFlag || false;
2823            if(this.dynamicProperties.length){
2824                var i, len = this.dynamicProperties.length;
2825                for(i=0;i<len;i+=1){
2826                    this.dynamicProperties[i].getValue();
2827                    if(this.dynamicProperties[i].mdf){
2828                        this.mdf = true;
2829                    }
2830                }
2831            }
2832            var totalChars = this.elem.textProperty.currentData ? this.elem.textProperty.currentData.l.length : 0;
2833            if(newCharsFlag && this.data.r === 2) {
2834                this.e.v = totalChars;
2835            }
2836            var divisor = this.data.r === 2 ? 1 : 100 / totalChars;
2837            var o = this.o.v/divisor;
2838            var s = this.s.v/divisor + o;
2839            var e = (this.e.v/divisor) + o;
2840            if(s>e){
2841                var _s = s;
2842                s = e;
2843                e = _s;
2844            }
2845            this.finalS = s;
2846            this.finalE = e;
2847        }
2848
2849        function getMult(ind){
2850            //var easer = bez.getEasingCurve(this.ne.v/100,0,1-this.xe.v/100,1);
2851            var easer = BezierFactory.getBezierEasing(this.ne.v/100,0,1-this.xe.v/100,1).get;
2852            var mult = 0;
2853            var s = this.finalS;
2854            var e = this.finalE;
2855            var type = this.data.sh;
2856            if(type == 2){
2857                if(e === s){
2858                    mult = ind >= e ? 1 : 0;
2859                }else{
2860                    mult = max(0,min(0.5/(e-s) + (ind-s)/(e-s),1));
2861                }
2862                mult = easer(mult);
2863            }else if(type == 3){
2864                if(e === s){
2865                    mult = ind >= e ? 0 : 1;
2866                }else{
2867                    mult = 1 - max(0,min(0.5/(e-s) + (ind-s)/(e-s),1));
2868                }
2869
2870                mult = easer(mult);
2871            }else if(type == 4){
2872                if(e === s){
2873                    mult = 0;
2874                }else{
2875                    mult = max(0,min(0.5/(e-s) + (ind-s)/(e-s),1));
2876                    if(mult<.5){
2877                        mult *= 2;
2878                    }else{
2879                        mult = 1 - 2*(mult-0.5);
2880                    }
2881                }
2882                mult = easer(mult);
2883            }else if(type == 5){
2884                if(e === s){
2885                    mult = 0;
2886                }else{
2887                    var tot = e - s;
2888                    /*ind += 0.5;
2889                    mult = -4/(tot*tot)*(ind*ind)+(4/tot)*ind;*/
2890                    ind = min(max(0,ind+0.5-s),e-s);
2891                    var x = -tot/2+ind;
2892                    var a = tot/2;
2893                    mult = Math.sqrt(1 - (x*x)/(a*a));
2894                }
2895                mult = easer(mult);
2896            }else if(type == 6){
2897                if(e === s){
2898                    mult = 0;
2899                }else{
2900                    ind = min(max(0,ind+0.5-s),e-s);
2901                    mult = (1+(Math.cos((Math.PI+Math.PI*2*(ind)/(e-s)))))/2;
2902                    /*
2903                     ind = Math.min(Math.max(s,ind),e-1);
2904                     mult = (1+(Math.cos((Math.PI+Math.PI*2*(ind-s)/(e-1-s)))))/2;
2905                     mult = Math.max(mult,(1/(e-1-s))/(e-1-s));*/
2906                }
2907                mult = easer(mult);
2908            }else {
2909                if(ind >= floor(s)){
2910                    if(ind-s < 0){
2911                        mult = 1 - (s - ind);
2912                    }else{
2913                        mult = max(0,min(e-ind,1));
2914                    }
2915                }
2916                mult = easer(mult);
2917            }
2918            return mult*this.a.v;
2919        }
2920
2921        return function TextSelectorProp(elem,data, arr){
2922            this.mdf = false;
2923            this.k = false;
2924            this.data = data;
2925            this.dynamicProperties = [];
2926            this.getValue = updateRange;
2927            this.getMult = getMult;
2928            this.elem = elem;
2929            this.comp = elem.comp;
2930            this.finalS = 0;
2931            this.finalE = 0;
2932            this.s = PropertyFactory.getProp(elem,data.s || {k:0},0,0,this.dynamicProperties);
2933            if('e' in data){
2934                this.e = PropertyFactory.getProp(elem,data.e,0,0,this.dynamicProperties);
2935            }else{
2936                this.e = {v:100};
2937            }
2938            this.o = PropertyFactory.getProp(elem,data.o || {k:0},0,0,this.dynamicProperties);
2939            this.xe = PropertyFactory.getProp(elem,data.xe || {k:0},0,0,this.dynamicProperties);
2940            this.ne = PropertyFactory.getProp(elem,data.ne || {k:0},0,0,this.dynamicProperties);
2941            this.a = PropertyFactory.getProp(elem,data.a,0,0.01,this.dynamicProperties);
2942            if(this.dynamicProperties.length){
2943                arr.push(this);
2944            }else{
2945                this.getValue();
2946            }
2947        }
2948    }());
2949
2950    function getTextSelectorProp(elem, data,arr) {
2951        return new TextSelectorProp(elem, data, arr);
2952    };
2953
2954    var ob = {
2955        getProp: getProp,
2956        getDashProp: getDashProp,
2957        getTextSelectorProp: getTextSelectorProp,
2958        getGradientProp: getGradientProp
2959    };
2960    return ob;
2961}());
2962function ShapePath(){
2963	this.c = false;
2964	this._length = 0;
2965	this._maxLength = 8;
2966	this.v = Array.apply(null,{length:this._maxLength});
2967	this.o = Array.apply(null,{length:this._maxLength});
2968	this.i = Array.apply(null,{length:this._maxLength});
2969};
2970
2971ShapePath.prototype.setPathData = function(closed, len) {
2972	this.c = closed;
2973	this.setLength(len);
2974	var i = 0;
2975	while(i < len){
2976		this.v[i] = point_pool.newPoint();
2977		this.o[i] = point_pool.newPoint();
2978		this.i[i] = point_pool.newPoint();
2979		i += 1;
2980	}
2981};
2982
2983ShapePath.prototype.setLength = function(len) {
2984	while(this._maxLength < len) {
2985		this.doubleArrayLength();
2986	}
2987	this._length = len;
2988}
2989
2990ShapePath.prototype.doubleArrayLength = function() {
2991	this.v = this.v.concat(Array.apply(null,{length:this._maxLength}))
2992	this.i = this.i.concat(Array.apply(null,{length:this._maxLength}))
2993	this.o = this.o.concat(Array.apply(null,{length:this._maxLength}))
2994	this._maxLength *= 2;
2995};
2996
2997ShapePath.prototype.setXYAt = function(x, y, type, pos, replace) {
2998	var arr;
2999	this._length = Math.max(this._length, pos + 1);
3000	if(this._length >= this._maxLength) {
3001		this.doubleArrayLength();
3002	}
3003	switch(type){
3004		case 'v':
3005			arr = this.v;
3006			break;
3007		case 'i':
3008			arr = this.i;
3009			break;
3010		case 'o':
3011			arr = this.o;
3012			break;
3013	}
3014	if(!arr[pos] || (arr[pos] && !replace)){
3015		arr[pos] = point_pool.newPoint();
3016	}
3017	arr[pos][0] = x;
3018	arr[pos][1] = y;
3019};
3020
3021ShapePath.prototype.setTripleAt = function(vX,vY,oX,oY,iX,iY,pos, replace) {
3022	this.setXYAt(vX,vY,'v',pos, replace);
3023	this.setXYAt(oX,oY,'o',pos, replace);
3024	this.setXYAt(iX,iY,'i',pos, replace);
3025};
3026var ShapePropertyFactory = (function(){
3027
3028    var initFrame = -999999;
3029
3030    function interpolateShape(frameNum, iterationIndex, previousValue, isCurrentRender) {
3031        var keyPropS,keyPropE,isHold;
3032        if(frameNum < this.keyframes[0].t-this.offsetTime){
3033            keyPropS = this.keyframes[0].s[0];
3034            isHold = true;
3035            iterationIndex = 0;
3036        }else if(frameNum >= this.keyframes[this.keyframes.length - 1].t-this.offsetTime){
3037            if(this.keyframes[this.keyframes.length - 2].h === 1){
3038                keyPropS = this.keyframes[this.keyframes.length - 1].s[0];
3039            }else{
3040                keyPropS = this.keyframes[this.keyframes.length - 2].e[0];
3041            }
3042            isHold = true;
3043        }else{
3044            var i = iterationIndex;
3045            var len = this.keyframes.length- 1,flag = true,keyData,nextKeyData, j, jLen, k, kLen;
3046            while(flag){
3047                keyData = this.keyframes[i];
3048                nextKeyData = this.keyframes[i+1];
3049                if((nextKeyData.t - this.offsetTime) > frameNum){
3050                    break;
3051                }
3052                if(i < len - 1){
3053                    i += 1;
3054                }else{
3055                    flag = false;
3056                }
3057            }
3058            isHold = keyData.h === 1;
3059            iterationIndex = i;
3060
3061            var perc;
3062            if(!isHold){
3063                if(frameNum >= nextKeyData.t-this.offsetTime){
3064                    perc = 1;
3065                }else if(frameNum < keyData.t-this.offsetTime){
3066                    perc = 0;
3067                }else{
3068                    var fnc;
3069                    if(keyData.__fnct){
3070                        fnc = keyData.__fnct;
3071                    }else{
3072                        fnc = BezierFactory.getBezierEasing(keyData.o.x,keyData.o.y,keyData.i.x,keyData.i.y).get;
3073                        keyData.__fnct = fnc;
3074                    }
3075                    perc = fnc((frameNum-(keyData.t-this.offsetTime))/((nextKeyData.t-this.offsetTime)-(keyData.t-this.offsetTime)));
3076                }
3077                keyPropE = keyData.e[0];
3078            }
3079            keyPropS = keyData.s[0];
3080        }
3081        jLen = previousValue._length;
3082        kLen = keyPropS.i[0].length;
3083        var hasModified = false;
3084        var vertexValue;
3085        for(j=0;j<jLen;j+=1){
3086            for(k=0;k<kLen;k+=1){
3087                if(isHold){
3088                    vertexValue = keyPropS.i[j][k];
3089                    if(previousValue.i[j][k] !== vertexValue){
3090                        previousValue.i[j][k] = vertexValue;
3091                        if(isCurrentRender) {
3092                            this.pv.i[j][k] = vertexValue;
3093                        }
3094                        hasModified = true;
3095                    }
3096                    vertexValue = keyPropS.o[j][k];
3097                    if(previousValue.o[j][k] !== vertexValue){
3098                        previousValue.o[j][k] = vertexValue;
3099                        if(isCurrentRender) {
3100                            this.pv.o[j][k] = vertexValue;
3101                        }
3102                        hasModified = true;
3103                    }
3104                    vertexValue = keyPropS.v[j][k];
3105                    if(previousValue.v[j][k] !== vertexValue){
3106                        previousValue.v[j][k] = vertexValue;
3107                        if(isCurrentRender) {
3108                            this.pv.v[j][k] = vertexValue;
3109                        }
3110                        hasModified = true;
3111                    }
3112                }else{
3113                    vertexValue = keyPropS.i[j][k]+(keyPropE.i[j][k]-keyPropS.i[j][k])*perc;
3114                    if(previousValue.i[j][k] !== vertexValue){
3115                        previousValue.i[j][k] = vertexValue;
3116                        if(isCurrentRender) {
3117                            this.pv.i[j][k] = vertexValue;
3118                        }
3119                        hasModified = true;
3120                    }
3121                    vertexValue = keyPropS.o[j][k]+(keyPropE.o[j][k]-keyPropS.o[j][k])*perc;
3122                    if(previousValue.o[j][k] !== vertexValue){
3123                        previousValue.o[j][k] = vertexValue;
3124                        if(isCurrentRender) {
3125                            this.pv.o[j][k] = vertexValue;
3126                        }
3127                        hasModified = true;
3128                    }
3129                    vertexValue = keyPropS.v[j][k]+(keyPropE.v[j][k]-keyPropS.v[j][k])*perc;
3130                    if(previousValue.v[j][k] !== vertexValue){
3131                        previousValue.v[j][k] = vertexValue;
3132                        if(isCurrentRender) {
3133                            this.pv.v[j][k] = vertexValue;
3134                        }
3135                        hasModified = true;
3136                    }
3137                }
3138            }
3139        }
3140        if(hasModified) {
3141            previousValue.c = keyPropS.c;
3142        }
3143        return {
3144            iterationIndex: iterationIndex,
3145            hasModified: hasModified
3146        }
3147    }
3148
3149    function interpolateShapeCurrentTime(){
3150        if(this.elem.globalData.frameId === this.frameId){
3151            return;
3152        }
3153        this.mdf = false;
3154        var frameNum = this.comp.renderedFrame - this.offsetTime;
3155        var initTime = this.keyframes[0].t - this.offsetTime;
3156        var endTime = this.keyframes[this.keyframes.length - 1].t - this.offsetTime;
3157        if(!(this.lastFrame !== initFrame && ((this.lastFrame < initTime && frameNum < initTime) || (this.lastFrame > endTime && frameNum > endTime)))){
3158            ////
3159            var i = this.lastFrame < frameNum ? this._lastIndex : 0;
3160            var renderResult = this.interpolateShape(frameNum, i, this.v, true);
3161            ////
3162            this._lastIndex = renderResult.iterationIndex;
3163            this.mdf = renderResult.hasModified;
3164            if(renderResult.hasModified) {
3165                this.paths = this.localShapeCollection;
3166            }
3167        }
3168        this.lastFrame = frameNum;
3169        this.frameId = this.elem.globalData.frameId;
3170    }
3171
3172    function getShapeValue(){
3173        return this.v;
3174    }
3175
3176    function resetShape(){
3177        this.paths = this.localShapeCollection;
3178        if(!this.k){
3179            this.mdf = false;
3180        }
3181    }
3182
3183    function ShapeProperty(elem, data, type){
3184        this.__shapeObject = 1;
3185        this.comp = elem.comp;
3186        this.k = false;
3187        this.mdf = false;
3188        var pathData = type === 3 ? data.pt.k : data.ks.k;
3189        this.v = shape_pool.clone(pathData);
3190        this.pv = shape_pool.clone(this.v);
3191        this.localShapeCollection = shapeCollection_pool.newShapeCollection();
3192        this.paths = this.localShapeCollection;
3193        this.paths.addShape(this.v);
3194        this.reset = resetShape;
3195    }
3196    ShapeProperty.prototype.interpolateShape = interpolateShape;
3197    ShapeProperty.prototype.getValue = getShapeValue;
3198
3199    function KeyframedShapeProperty(elem,data,type){
3200        this.__shapeObject = 1;
3201        this.comp = elem.comp;
3202        this.elem = elem;
3203        this.offsetTime = elem.data.st;
3204        this._lastIndex = 0;
3205        this.keyframes = type === 3 ? data.pt.k : data.ks.k;
3206        this.k = true;
3207        this.kf = true;
3208        var i, len = this.keyframes[0].s[0].i.length;
3209        var jLen = this.keyframes[0].s[0].i[0].length;
3210        this.v = shape_pool.newShape();
3211        this.v.setPathData(this.keyframes[0].s[0].c, len);
3212        this.pv = shape_pool.clone(this.v);
3213        this.localShapeCollection = shapeCollection_pool.newShapeCollection();
3214        this.paths = this.localShapeCollection;
3215        this.paths.addShape(this.v);
3216        this.lastFrame = initFrame;
3217        this.reset = resetShape;
3218    }
3219    KeyframedShapeProperty.prototype.getValue = interpolateShapeCurrentTime;
3220    KeyframedShapeProperty.prototype.interpolateShape = interpolateShape;
3221
3222    var EllShapeProperty = (function(){
3223
3224        var cPoint = roundCorner;
3225
3226        function convertEllToPath(){
3227            var p0 = this.p.v[0], p1 = this.p.v[1], s0 = this.s.v[0]/2, s1 = this.s.v[1]/2;
3228            if(this.d !== 3){
3229                this.v.v[0][0] = p0;
3230                this.v.v[0][1] = p1-s1;
3231                this.v.v[1][0] = p0 + s0;
3232                this.v.v[1][1] = p1;
3233                this.v.v[2][0] = p0;
3234                this.v.v[2][1] = p1+s1;
3235                this.v.v[3][0] = p0 - s0;
3236                this.v.v[3][1] = p1;
3237                this.v.i[0][0] = p0 - s0*cPoint;
3238                this.v.i[0][1] = p1 - s1;
3239                this.v.i[1][0] = p0 + s0;
3240                this.v.i[1][1] = p1 - s1*cPoint;
3241                this.v.i[2][0] = p0 + s0*cPoint;
3242                this.v.i[2][1] = p1 + s1;
3243                this.v.i[3][0] = p0 - s0;
3244                this.v.i[3][1] = p1 + s1*cPoint;
3245                this.v.o[0][0] = p0 + s0*cPoint;
3246                this.v.o[0][1] = p1 - s1;
3247                this.v.o[1][0] = p0 + s0;
3248                this.v.o[1][1] = p1 + s1*cPoint;
3249                this.v.o[2][0] = p0 - s0*cPoint;
3250                this.v.o[2][1] = p1 + s1;
3251                this.v.o[3][0] = p0 - s0;
3252                this.v.o[3][1] = p1 - s1*cPoint;
3253            }else{
3254                this.v.v[0][0] = p0;
3255                this.v.v[0][1] = p1-s1;
3256                this.v.v[1][0] = p0 - s0;
3257                this.v.v[1][1] = p1;
3258                this.v.v[2][0] = p0;
3259                this.v.v[2][1] = p1+s1;
3260                this.v.v[3][0] = p0 + s0;
3261                this.v.v[3][1] = p1;
3262                this.v.i[0][0] = p0 + s0*cPoint;
3263                this.v.i[0][1] = p1 - s1;
3264                this.v.i[1][0] = p0 - s0;
3265                this.v.i[1][1] = p1 - s1*cPoint;
3266                this.v.i[2][0] = p0 - s0*cPoint;
3267                this.v.i[2][1] = p1 + s1;
3268                this.v.i[3][0] = p0 + s0;
3269                this.v.i[3][1] = p1 + s1*cPoint;
3270                this.v.o[0][0] = p0 - s0*cPoint;
3271                this.v.o[0][1] = p1 - s1;
3272                this.v.o[1][0] = p0 - s0;
3273                this.v.o[1][1] = p1 + s1*cPoint;
3274                this.v.o[2][0] = p0 + s0*cPoint;
3275                this.v.o[2][1] = p1 + s1;
3276                this.v.o[3][0] = p0 + s0;
3277                this.v.o[3][1] = p1 - s1*cPoint;
3278            }
3279        }
3280
3281        function processKeys(frameNum){
3282            var i, len = this.dynamicProperties.length;
3283            if(this.elem.globalData.frameId === this.frameId){
3284                return;
3285            }
3286            this.mdf = false;
3287            this.frameId = this.elem.globalData.frameId;
3288
3289            for(i=0;i<len;i+=1){
3290                this.dynamicProperties[i].getValue(frameNum);
3291                if(this.dynamicProperties[i].mdf){
3292                    this.mdf = true;
3293                }
3294            }
3295            if(this.mdf){
3296                this.convertEllToPath();
3297            }
3298        }
3299
3300        return function EllShapeProperty(elem,data) {
3301            /*this.v = {
3302                v: Array.apply(null,{length:4}),
3303                i: Array.apply(null,{length:4}),
3304                o: Array.apply(null,{length:4}),
3305                c: true
3306            };*/
3307            this.v = shape_pool.newShape();
3308            this.v.setPathData(true, 4);
3309            this.localShapeCollection = shapeCollection_pool.newShapeCollection();
3310            this.paths = this.localShapeCollection;
3311            this.localShapeCollection.addShape(this.v);
3312            this.d = data.d;
3313            this.dynamicProperties = [];
3314            this.elem = elem;
3315            this.comp = elem.comp;
3316            this.frameId = -1;
3317            this.mdf = false;
3318            this.getValue = processKeys;
3319            this.convertEllToPath = convertEllToPath;
3320            this.reset = resetShape;
3321            this.p = PropertyFactory.getProp(elem,data.p,1,0,this.dynamicProperties);
3322            this.s = PropertyFactory.getProp(elem,data.s,1,0,this.dynamicProperties);
3323            if(this.dynamicProperties.length){
3324                this.k = true;
3325            }else{
3326                this.convertEllToPath();
3327            }
3328        }
3329    }());
3330
3331    var StarShapeProperty = (function() {
3332
3333        function convertPolygonToPath(){
3334            var numPts = Math.floor(this.pt.v);
3335            var angle = Math.PI*2/numPts;
3336            /*this.v.v.length = numPts;
3337            this.v.i.length = numPts;
3338            this.v.o.length = numPts;*/
3339            var rad = this.or.v;
3340            var roundness = this.os.v;
3341            var perimSegment = 2*Math.PI*rad/(numPts*4);
3342            var i, currentAng = -Math.PI/ 2;
3343            var dir = this.data.d === 3 ? -1 : 1;
3344            currentAng += this.r.v;
3345            this.v._length = 0;
3346            for(i=0;i<numPts;i+=1){
3347                var x = rad * Math.cos(currentAng);
3348                var y = rad * Math.sin(currentAng);
3349                var ox = x === 0 && y === 0 ? 0 : y/Math.sqrt(x*x + y*y);
3350                var oy = x === 0 && y === 0 ? 0 : -x/Math.sqrt(x*x + y*y);
3351                x +=  + this.p.v[0];
3352                y +=  + this.p.v[1];
3353                this.v.setTripleAt(x,y,x-ox*perimSegment*roundness*dir,y-oy*perimSegment*roundness*dir,x+ox*perimSegment*roundness*dir,y+oy*perimSegment*roundness*dir, i, true);
3354                /*this.v.v[i] = [x,y];
3355                this.v.i[i] = [x+ox*perimSegment*roundness*dir,y+oy*perimSegment*roundness*dir];
3356                this.v.o[i] = [x-ox*perimSegment*roundness*dir,y-oy*perimSegment*roundness*dir];*/
3357                currentAng += angle*dir;
3358            }
3359            this.paths.length = 0;
3360            this.paths[0] = this.v;
3361        }
3362
3363        function convertStarToPath() {
3364            var numPts = Math.floor(this.pt.v)*2;
3365            var angle = Math.PI*2/numPts;
3366            /*this.v.v.length = numPts;
3367            this.v.i.length = numPts;
3368            this.v.o.length = numPts;*/
3369            var longFlag = true;
3370            var longRad = this.or.v;
3371            var shortRad = this.ir.v;
3372            var longRound = this.os.v;
3373            var shortRound = this.is.v;
3374            var longPerimSegment = 2*Math.PI*longRad/(numPts*2);
3375            var shortPerimSegment = 2*Math.PI*shortRad/(numPts*2);
3376            var i, rad,roundness,perimSegment, currentAng = -Math.PI/ 2;
3377            currentAng += this.r.v;
3378            var dir = this.data.d === 3 ? -1 : 1;
3379            this.v._length = 0;
3380            for(i=0;i<numPts;i+=1){
3381                rad = longFlag ? longRad : shortRad;
3382                roundness = longFlag ? longRound : shortRound;
3383                perimSegment = longFlag ? longPerimSegment : shortPerimSegment;
3384                var x = rad * Math.cos(currentAng);
3385                var y = rad * Math.sin(currentAng);
3386                var ox = x === 0 && y === 0 ? 0 : y/Math.sqrt(x*x + y*y);
3387                var oy = x === 0 && y === 0 ? 0 : -x/Math.sqrt(x*x + y*y);
3388                x +=  + this.p.v[0];
3389                y +=  + this.p.v[1];
3390                this.v.setTripleAt(x,y,x-ox*perimSegment*roundness*dir,y-oy*perimSegment*roundness*dir,x+ox*perimSegment*roundness*dir,y+oy*perimSegment*roundness*dir, i, true);
3391
3392                /*this.v.v[i] = [x,y];
3393                this.v.i[i] = [x+ox*perimSegment*roundness*dir,y+oy*perimSegment*roundness*dir];
3394                this.v.o[i] = [x-ox*perimSegment*roundness*dir,y-oy*perimSegment*roundness*dir];
3395                this.v._length = numPts;*/
3396                longFlag = !longFlag;
3397                currentAng += angle*dir;
3398            }
3399        }
3400
3401        function processKeys() {
3402            if(this.elem.globalData.frameId === this.frameId){
3403                return;
3404            }
3405            this.mdf = false;
3406            this.frameId = this.elem.globalData.frameId;
3407            var i, len = this.dynamicProperties.length;
3408
3409            for(i=0;i<len;i+=1){
3410                this.dynamicProperties[i].getValue();
3411                if(this.dynamicProperties[i].mdf){
3412                    this.mdf = true;
3413                }
3414            }
3415            if(this.mdf){
3416                this.convertToPath();
3417            }
3418        }
3419
3420        return function StarShapeProperty(elem,data) {
3421            /*this.v = {
3422                v: [],
3423                i: [],
3424                o: [],
3425                c: true
3426            };*/
3427            this.v = shape_pool.newShape();
3428            this.v.setPathData(true, 0);
3429            this.elem = elem;
3430            this.comp = elem.comp;
3431            this.data = data;
3432            this.frameId = -1;
3433            this.d = data.d;
3434            this.dynamicProperties = [];
3435            this.mdf = false;
3436            this.getValue = processKeys;
3437            this.reset = resetShape;
3438            if(data.sy === 1){
3439                this.ir = PropertyFactory.getProp(elem,data.ir,0,0,this.dynamicProperties);
3440                this.is = PropertyFactory.getProp(elem,data.is,0,0.01,this.dynamicProperties);
3441                this.convertToPath = convertStarToPath;
3442            } else {
3443                this.convertToPath = convertPolygonToPath;
3444            }
3445            this.pt = PropertyFactory.getProp(elem,data.pt,0,0,this.dynamicProperties);
3446            this.p = PropertyFactory.getProp(elem,data.p,1,0,this.dynamicProperties);
3447            this.r = PropertyFactory.getProp(elem,data.r,0,degToRads,this.dynamicProperties);
3448            this.or = PropertyFactory.getProp(elem,data.or,0,0,this.dynamicProperties);
3449            this.os = PropertyFactory.getProp(elem,data.os,0,0.01,this.dynamicProperties);
3450            this.localShapeCollection = shapeCollection_pool.newShapeCollection();
3451            this.localShapeCollection.addShape(this.v);
3452            this.paths = this.localShapeCollection;
3453            if(this.dynamicProperties.length){
3454                this.k = true;
3455            }else{
3456                this.convertToPath();
3457            }
3458        }
3459    }());
3460
3461    var RectShapeProperty = (function() {
3462        function processKeys(frameNum){
3463            if(this.elem.globalData.frameId === this.frameId){
3464                return;
3465            }
3466            this.mdf = false;
3467            this.frameId = this.elem.globalData.frameId;
3468            var i, len = this.dynamicProperties.length;
3469
3470            for(i=0;i<len;i+=1){
3471                this.dynamicProperties[i].getValue(frameNum);
3472                if(this.dynamicProperties[i].mdf){
3473                    this.mdf = true;
3474                }
3475            }
3476            if(this.mdf){
3477                this.convertRectToPath();
3478            }
3479
3480        }
3481
3482        function convertRectToPath(){
3483            var p0 = this.p.v[0], p1 = this.p.v[1], v0 = this.s.v[0]/2, v1 = this.s.v[1]/2;
3484            var round = bm_min(v0,v1,this.r.v);
3485            var cPoint = round*(1-roundCorner);
3486            this.v._length = 0;
3487
3488            if(this.d === 2 || this.d === 1) {
3489                this.v.setTripleAt(p0+v0, p1-v1+round,p0+v0, p1-v1+round,p0+v0,p1-v1+cPoint,0, true);
3490                this.v.setTripleAt(p0+v0, p1+v1-round,p0+v0, p1+v1-cPoint,p0+v0, p1+v1-round,1, true);
3491                if(round!== 0){
3492                    this.v.setTripleAt(p0+v0-round, p1+v1,p0+v0-round,p1+v1,p0+v0-cPoint,p1+v1,2, true);
3493                    this.v.setTripleAt(p0-v0+round,p1+v1,p0-v0+cPoint,p1+v1,p0-v0+round,p1+v1,3, true);
3494                    this.v.setTripleAt(p0-v0,p1+v1-round,p0-v0,p1+v1-round,p0-v0,p1+v1-cPoint,4, true);
3495                    this.v.setTripleAt(p0-v0,p1-v1+round,p0-v0,p1-v1+cPoint,p0-v0,p1-v1+round,5, true);
3496                    this.v.setTripleAt(p0-v0+round,p1-v1,p0-v0+round,p1-v1,p0-v0+cPoint,p1-v1,6, true);
3497                    this.v.setTripleAt(p0+v0-round,p1-v1,p0+v0-cPoint,p1-v1,p0+v0-round,p1-v1,7, true);
3498                } else {
3499                    this.v.setTripleAt(p0-v0,p1+v1,p0-v0+cPoint,p1+v1,p0-v0,p1+v1,2);
3500                    this.v.setTripleAt(p0-v0,p1-v1,p0-v0,p1-v1+cPoint,p0-v0,p1-v1,3);
3501                }
3502            }else{
3503                this.v.setTripleAt(p0+v0,p1-v1+round,p0+v0,p1-v1+cPoint,p0+v0,p1-v1+round,0, true);
3504                if(round!== 0){
3505                    this.v.setTripleAt(p0+v0-round,p1-v1,p0+v0-round,p1-v1,p0+v0-cPoint,p1-v1,1, true);
3506                    this.v.setTripleAt(p0-v0+round,p1-v1,p0-v0+cPoint,p1-v1,p0-v0+round,p1-v1,2, true);
3507                    this.v.setTripleAt(p0-v0,p1-v1+round,p0-v0,p1-v1+round,p0-v0,p1-v1+cPoint,3, true);
3508                    this.v.setTripleAt(p0-v0,p1+v1-round,p0-v0,p1+v1-cPoint,p0-v0,p1+v1-round,4, true);
3509                    this.v.setTripleAt(p0-v0+round,p1+v1,p0-v0+round,p1+v1,p0-v0+cPoint,p1+v1,5, true);
3510                    this.v.setTripleAt(p0+v0-round,p1+v1,p0+v0-cPoint,p1+v1,p0+v0-round,p1+v1,6, true);
3511                    this.v.setTripleAt(p0+v0,p1+v1-round,p0+v0,p1+v1-round,p0+v0,p1+v1-cPoint,7, true);
3512                } else {
3513                    this.v.setTripleAt(p0-v0,p1-v1,p0-v0+cPoint,p1-v1,p0-v0,p1-v1,1, true);
3514                    this.v.setTripleAt(p0-v0,p1+v1,p0-v0,p1+v1-cPoint,p0-v0,p1+v1,2, true);
3515                    this.v.setTripleAt(p0+v0,p1+v1,p0+v0-cPoint,p1+v1,p0+v0,p1+v1,3, true);
3516
3517                }
3518            }
3519        }
3520
3521        return function RectShapeProperty(elem,data) {
3522            this.v = shape_pool.newShape();
3523            this.v.c = true;
3524            this.localShapeCollection = shapeCollection_pool.newShapeCollection();
3525            this.localShapeCollection.addShape(this.v);
3526            this.paths = this.localShapeCollection;
3527            this.elem = elem;
3528            this.comp = elem.comp;
3529            this.frameId = -1;
3530            this.d = data.d;
3531            this.dynamicProperties = [];
3532            this.mdf = false;
3533            this.getValue = processKeys;
3534            this.convertRectToPath = convertRectToPath;
3535            this.reset = resetShape;
3536            this.p = PropertyFactory.getProp(elem,data.p,1,0,this.dynamicProperties);
3537            this.s = PropertyFactory.getProp(elem,data.s,1,0,this.dynamicProperties);
3538            this.r = PropertyFactory.getProp(elem,data.r,0,0,this.dynamicProperties);
3539            if(this.dynamicProperties.length){
3540                this.k = true;
3541            }else{
3542                this.convertRectToPath();
3543            }
3544        }
3545    }());
3546
3547    function getShapeProp(elem,data,type, arr){
3548        var prop;
3549        if(type === 3 || type === 4){
3550            var dataProp = type === 3 ? data.pt : data.ks;
3551            var keys = dataProp.k;
3552            if(dataProp.a === 1 || keys.length){
3553                prop = new KeyframedShapeProperty(elem, data, type);
3554            }else{
3555                prop = new ShapeProperty(elem, data, type);
3556            }
3557        }else if(type === 5){
3558            prop = new RectShapeProperty(elem, data);
3559        }else if(type === 6){
3560            prop = new EllShapeProperty(elem, data);
3561        }else if(type === 7){
3562            prop = new StarShapeProperty(elem, data);
3563        }
3564        if(prop.k){
3565            arr.push(prop);
3566        }
3567        return prop;
3568    }
3569
3570    function getConstructorFunction() {
3571        return ShapeProperty;
3572    }
3573
3574    function getKeyframedConstructorFunction() {
3575        return KeyframedShapeProperty;
3576    }
3577
3578    var ob = {};
3579    ob.getShapeProp = getShapeProp;
3580    ob.getConstructorFunction = getConstructorFunction;
3581    ob.getKeyframedConstructorFunction = getKeyframedConstructorFunction;
3582    return ob;
3583}());
3584var ShapeModifiers = (function(){
3585    var ob = {};
3586    var modifiers = {};
3587    ob.registerModifier = registerModifier;
3588    ob.getModifier = getModifier;
3589
3590    function registerModifier(nm,factory){
3591        if(!modifiers[nm]){
3592            modifiers[nm] = factory;
3593        }
3594    }
3595
3596    function getModifier(nm,elem, data, dynamicProperties){
3597        return new modifiers[nm](elem, data, dynamicProperties);
3598    }
3599
3600    return ob;
3601}());
3602
3603function ShapeModifier(){}
3604ShapeModifier.prototype.initModifierProperties = function(){};
3605ShapeModifier.prototype.addShapeToModifier = function(){};
3606ShapeModifier.prototype.addShape = function(data){
3607    if(!this.closed){
3608        this.shapes.push({shape:data.sh, data: data, localShapeCollection:shapeCollection_pool.newShapeCollection()});
3609        this.addShapeToModifier(data.sh);
3610    }
3611}
3612ShapeModifier.prototype.init = function(elem,data,dynamicProperties){
3613    this.elem = elem;
3614    this.frameId = -1;
3615    this.shapes = [];
3616    this.dynamicProperties = [];
3617    this.mdf = false;
3618    this.closed = false;
3619    this.k = false;
3620    this.comp = elem.comp;
3621    this.initModifierProperties(elem,data);
3622    if(this.dynamicProperties.length){
3623        this.k = true;
3624        dynamicProperties.push(this);
3625    }else{
3626        this.getValue(true);
3627    }
3628}
3629function TrimModifier(){};
3630extendPrototype(ShapeModifier,TrimModifier);
3631TrimModifier.prototype.processKeys = function(forceRender){
3632    if(this.elem.globalData.frameId === this.frameId && !forceRender){
3633        return;
3634    }
3635    this.mdf = forceRender ? true : false;
3636    this.frameId = this.elem.globalData.frameId;
3637    var i, len = this.dynamicProperties.length;
3638
3639    for(i=0;i<len;i+=1){
3640        this.dynamicProperties[i].getValue();
3641        if(this.dynamicProperties[i].mdf){
3642            this.mdf = true;
3643        }
3644    }
3645    if(this.mdf || forceRender){
3646        var o = (this.o.v%360)/360;
3647        if(o < 0){
3648            o += 1;
3649        }
3650        var s = this.s.v + o;
3651        var e = this.e.v + o;
3652        if(s == e){
3653
3654        }
3655        if(s>e){
3656            var _s = s;
3657            s = e;
3658            e = _s;
3659        }
3660        this.sValue = s;
3661        this.eValue = e;
3662        this.oValue = o;
3663    }
3664}
3665TrimModifier.prototype.initModifierProperties = function(elem,data){
3666    this.sValue = 0;
3667    this.eValue = 0;
3668    this.oValue = 0;
3669    this.getValue = this.processKeys;
3670    this.s = PropertyFactory.getProp(elem,data.s,0,0.01,this.dynamicProperties);
3671    this.e = PropertyFactory.getProp(elem,data.e,0,0.01,this.dynamicProperties);
3672    this.o = PropertyFactory.getProp(elem,data.o,0,0,this.dynamicProperties);
3673    this.m = data.m;
3674    if(!this.dynamicProperties.length){
3675        this.getValue(true);
3676    }
3677};
3678
3679TrimModifier.prototype.calculateShapeEdges = function(s, e, shapeLength, addedLength, totalModifierLength) {
3680    var segments = []
3681    if(e <= 1){
3682        segments.push({
3683            s: s,
3684            e: e
3685        })
3686    }else if(s >= 1){
3687        segments.push({
3688            s: s - 1,
3689            e: e - 1
3690        })
3691    }else{
3692        segments.push({
3693            s: s,
3694            e: 1
3695        })
3696        segments.push({
3697            s: 0,
3698            e: e - 1
3699        })
3700    }
3701    var shapeSegments = [];
3702    var i, len = segments.length, segmentOb;
3703    for(i = 0; i < len; i += 1) {
3704        segmentOb = segments[i];
3705        if (segmentOb.e * totalModifierLength < addedLength || segmentOb.s * totalModifierLength > addedLength + shapeLength) {
3706            
3707        } else {
3708            var shapeS, shapeE;
3709            if(segmentOb.s * totalModifierLength <= addedLength) {
3710                shapeS = 0;
3711            } else {
3712                shapeS = (segmentOb.s * totalModifierLength - addedLength) / shapeLength;
3713            }
3714            if(segmentOb.e * totalModifierLength >= addedLength + shapeLength) {
3715                shapeE = 1;
3716            } else {
3717                shapeE = ((segmentOb.e * totalModifierLength - addedLength) / shapeLength);
3718            }
3719            shapeSegments.push([shapeS, shapeE]);
3720        }
3721    }
3722    if(!shapeSegments.length){
3723        shapeSegments.push([0,0]);
3724    }
3725    return shapeSegments;
3726}
3727
3728TrimModifier.prototype.processShapes = function(firstFrame){
3729    var shapePaths;
3730    var i, len = this.shapes.length;
3731    var j, jLen;
3732    var s = this.sValue;
3733    var e = this.eValue;
3734    var pathsData,pathData, totalShapeLength, totalModifierLength = 0;
3735
3736    if(e === s){
3737        for(i=0;i<len;i+=1){
3738            this.shapes[i].localShapeCollection.releaseShapes();
3739            this.shapes[i].shape.mdf = true;
3740            this.shapes[i].shape.paths = this.shapes[i].localShapeCollection;
3741        }
3742    } else if(!((e === 1 && s === 0) || (e===0 && s === 1))){
3743        var segments = [], shapeData, localShapeCollection;
3744        for(i=0;i<len;i+=1){
3745            shapeData = this.shapes[i];
3746            if(!shapeData.shape.mdf && !this.mdf && !firstFrame && this.m !== 2){
3747                shapeData.shape.paths = shapeData.localShapeCollection;
3748            } else {
3749                shapePaths = shapeData.shape.paths;
3750                jLen = shapePaths._length;
3751                totalShapeLength = 0;
3752                if(!shapeData.shape.mdf && shapeData.pathsData){
3753                    totalShapeLength = shapeData.totalShapeLength;
3754                } else {
3755                    pathsData = [];
3756                    for(j=0;j<jLen;j+=1){
3757                        pathData = bez.getSegmentsLength(shapePaths.shapes[j]);
3758                        pathsData.push(pathData);
3759                        totalShapeLength += pathData.totalLength;
3760                    }
3761                    shapeData.totalShapeLength = totalShapeLength;
3762                    shapeData.pathsData = pathsData;
3763                }
3764
3765                totalModifierLength += totalShapeLength;
3766                shapeData.shape.mdf = true;
3767            }
3768        }
3769        var shapeS = s, shapeE = e, addedLength = 0;
3770        var j, jLen;
3771        for(i = len - 1; i >= 0; i -= 1){
3772            shapeData = this.shapes[i];
3773            if (shapeData.shape.mdf) {
3774                localShapeCollection = shapeData.localShapeCollection;
3775                localShapeCollection.releaseShapes();
3776                if(this.m === 2 && len > 1) {
3777                    var edges = this.calculateShapeEdges(s, e, shapeData.totalShapeLength, addedLength, totalModifierLength);
3778                    addedLength += shapeData.totalShapeLength;
3779                } else {
3780                    edges = [[shapeS, shapeE]]
3781                }
3782                jLen = edges.length;
3783                for (j = 0; j < jLen; j += 1) {
3784                    shapeS = edges[j][0];
3785                    shapeE = edges[j][1];
3786                    segments.length = 0;
3787                    if(shapeE <= 1){
3788                        segments.push({
3789                            s:shapeData.totalShapeLength * shapeS,
3790                            e:shapeData.totalShapeLength * shapeE
3791                        })
3792                    }else if(shapeS >= 1){
3793                        segments.push({
3794                            s:shapeData.totalShapeLength * (shapeS - 1),
3795                            e:shapeData.totalShapeLength * (shapeE - 1)
3796                        })
3797                    }else{
3798                        segments.push({
3799                            s:shapeData.totalShapeLength * shapeS,
3800                            e:shapeData.totalShapeLength
3801                        })
3802                        segments.push({
3803                            s:0,
3804                            e:shapeData.totalShapeLength*(shapeE - 1)
3805                        })
3806                    }
3807                    var newShapesData = this.addShapes(shapeData,segments[0]);
3808                    if (segments[0].s !== segments[0].e) {
3809                        var lastPos;
3810                        if(segments.length > 1){
3811                            if(shapeData.shape.v.c){
3812                                var lastShape = newShapesData.pop();
3813                                this.addPaths(newShapesData, localShapeCollection);
3814                                newShapesData = this.addShapes(shapeData,segments[1], lastShape);
3815                            } else {
3816                                this.addPaths(newShapesData, localShapeCollection);
3817                                newShapesData = this.addShapes(shapeData,segments[1]);
3818                            }
3819                        } 
3820                        this.addPaths(newShapesData, localShapeCollection);
3821                    }
3822                    
3823                }
3824                shapeData.shape.paths = localShapeCollection;
3825            }
3826        }
3827    } else if(this.mdf){
3828        for(i=0;i<len;i+=1){
3829            this.shapes[i].shape.mdf = true;
3830        }
3831    }
3832    if(!this.dynamicProperties.length){
3833        this.mdf = false;
3834    }
3835}
3836
3837TrimModifier.prototype.addPaths = function(newPaths, localShapeCollection) {
3838    var i, len = newPaths.length;
3839    for(i = 0; i < len; i += 1) {
3840        localShapeCollection.addShape(newPaths[i])
3841    }
3842}
3843
3844TrimModifier.prototype.addSegment = function(pt1,pt2,pt3,pt4,shapePath,pos, newShape) {
3845    /*console.log(pt1, 'vertex: v, at: ', pos);
3846    console.log(pt2, 'vertex: o, at: ', pos);
3847    console.log(pt3, 'vertex: i, at: ', pos + 1);
3848    console.log(pt4, 'vertex: v, at: ', pos + 1);
3849    console.log('newShape: ', newShape);*/
3850    shapePath.setXYAt(pt2[0],pt2[1],'o',pos);
3851    shapePath.setXYAt(pt3[0],pt3[1],'i',pos + 1);
3852    if(newShape){
3853        shapePath.setXYAt(pt1[0],pt1[1],'v',pos);
3854    }
3855    shapePath.setXYAt(pt4[0],pt4[1],'v',pos + 1);
3856}
3857
3858TrimModifier.prototype.addShapes = function(shapeData, shapeSegment, shapePath){
3859    var pathsData = shapeData.pathsData;
3860    var shapePaths = shapeData.shape.paths.shapes;
3861    var i, len = shapeData.shape.paths._length, j, jLen;
3862    var addedLength = 0;
3863    var currentLengthData,segmentCount;
3864    var lengths;
3865    var segment;
3866    var shapes = [];
3867    var initPos;
3868    var newShape = true;
3869    if(!shapePath){
3870        shapePath = shape_pool.newShape();
3871        segmentCount = 0;
vendor: 4,335 bytes, lines 3872-3968
3872        initPos = 0;
3873    } else {
3874        segmentCount = shapePath._length;
3875        initPos = shapePath._length;
3876    }
3877    shapes.push(shapePath);
3878    for(i=0;i<len;i+=1){
3879        lengths = pathsData[i].lengths;
3880        shapePath.c = shapePaths[i].c;
3881        jLen = shapePaths[i].c ? lengths.length : lengths.length + 1;
3882        for(j=1;j<jLen;j+=1){
3883            currentLengthData = lengths[j-1];
3884            if(addedLength + currentLengthData.addedLength < shapeSegment.s){
3885                addedLength += currentLengthData.addedLength;
3886                shapePath.c = false;
3887            } else if(addedLength > shapeSegment.e){
3888                shapePath.c = false;
3889                break;
3890            } else {
3891                if(shapeSegment.s <= addedLength && shapeSegment.e >= addedLength + currentLengthData.addedLength){
3892                    this.addSegment(shapePaths[i].v[j-1],shapePaths[i].o[j-1],shapePaths[i].i[j],shapePaths[i].v[j],shapePath,segmentCount,newShape);
3893                    newShape = false;
3894                } else {
3895                    segment = bez.getNewSegment(shapePaths[i].v[j-1],shapePaths[i].v[j],shapePaths[i].o[j-1],shapePaths[i].i[j], (shapeSegment.s - addedLength)/currentLengthData.addedLength,(shapeSegment.e - addedLength)/currentLengthData.addedLength, lengths[j-1]);
3896                    this.addSegment(segment.pt1,segment.pt3,segment.pt4,segment.pt2,shapePath,segmentCount,newShape);
3897                    newShape = false;
3898                    shapePath.c = false;
3899                }
3900                addedLength += currentLengthData.addedLength;
3901                segmentCount += 1;
3902            }
3903        }
3904        if(shapePaths[i].c){
3905            currentLengthData = lengths[j-1];
3906            if(addedLength <= shapeSegment.e){
3907                var segmentLength = lengths[j-1].addedLength;
3908                if(shapeSegment.s <= addedLength && shapeSegment.e >= addedLength + segmentLength){
3909                    this.addSegment(shapePaths[i].v[j-1],shapePaths[i].o[j-1],shapePaths[i].i[0],shapePaths[i].v[0],shapePath,segmentCount,newShape);
3910                    newShape = false;
3911                }else{
3912                    segment = bez.getNewSegment(shapePaths[i].v[j-1],shapePaths[i].v[0],shapePaths[i].o[j-1],shapePaths[i].i[0], (shapeSegment.s - addedLength)/segmentLength,(shapeSegment.e - addedLength)/segmentLength, lengths[j-1]);
3913                    this.addSegment(segment.pt1,segment.pt3,segment.pt4,segment.pt2,shapePath,segmentCount,newShape);
3914                    newShape = false;
3915                    shapePath.c = false;
3916                }
3917            } else {
3918                shapePath.c = false;
3919            }
3920            addedLength += currentLengthData.addedLength;
3921            segmentCount += 1;
3922        }
3923        if(shapePath._length){
3924            shapePath.setXYAt(shapePath.v[initPos][0],shapePath.v[initPos][1],'i',initPos);
3925            shapePath.setXYAt(shapePath.v[shapePath._length - 1][0],shapePath.v[shapePath._length - 1][1],'o',shapePath._length - 1);
3926        }
3927        if(addedLength > shapeSegment.e){
3928            break;
3929        }
3930        if(i<len-1){
3931            shapePath = shape_pool.newShape();
3932            newShape = true;
3933            shapes.push(shapePath);
3934            segmentCount = 0;
3935        }
3936    }
3937    return shapes;
3938
3939}
3940
3941
3942ShapeModifiers.registerModifier('tm',TrimModifier);
3943function RoundCornersModifier(){};
3944extendPrototype(ShapeModifier,RoundCornersModifier);
3945RoundCornersModifier.prototype.processKeys = function(forceRender){
3946    if(this.elem.globalData.frameId === this.frameId && !forceRender){
3947        return;
3948    }
3949    this.mdf = forceRender ? true : false;
3950    this.frameId = this.elem.globalData.frameId;
3951    var i, len = this.dynamicProperties.length;
3952
3953    for(i=0;i<len;i+=1){
3954        this.dynamicProperties[i].getValue();
3955        if(this.dynamicProperties[i].mdf){
3956            this.mdf = true;
3957        }
3958    }
3959}
3960RoundCornersModifier.prototype.initModifierProperties = function(elem,data){
3961    this.getValue = this.processKeys;
3962    this.rd = PropertyFactory.getProp(elem,data.r,0,null,this.dynamicProperties);
3963    if(!this.dynamicProperties.length){
3964        this.getValue(true);
3965    }
3966};
3967
3968RoundCornersModifier.prototype.processPath = function(path, roun
3968d){
3969    var cloned_path = shape_pool.newShape();
3970    cloned_path.c = path.c;
3971    var i, len = path._length;
3972    var currentV,currentI,currentO,closerV, newV,newO,newI,distance,newPosPerc,index = 0;
3973    var vX,vY,oX,oY,iX,iY;
3974    for(i=0;i<len;i+=1){
3975        currentV = path.v[i];
3976        currentO = path.o[i];
3977        currentI = path.i[i];
3978        if(currentV[0]===currentO[0] && currentV[1]===currentO[1] && currentV[0]===currentI[0] && currentV[1]===currentI[1]){
3979            if((i===0 || i === len - 1) && !path.c){
3980                cloned_path.setTripleAt(currentV[0],currentV[1],currentO[0],currentO[1],currentI[0],currentI[1],index);
3981                /*cloned_path.v[index] = currentV;
3982                cloned_path.o[index] = currentO;
3983                cloned_path.i[index] = currentI;*/
3984                index += 1;
3985            } else {
3986                if(i===0){
3987                    closerV = path.v[len-1];
3988                } else {
3989                    closerV = path.v[i-1];
3990                }
3991                distance = Math.sqrt(Math.pow(currentV[0]-closerV[0],2)+Math.pow(currentV[1]-closerV[1],2));
3992                newPosPerc = distance ? Math.min(distance/2,round)/distance : 0;
3993                vX = iX = currentV[0]+(closerV[0]-currentV[0])*newPosPerc;
3994                vY = iY = currentV[1]-(currentV[1]-closerV[1])*newPosPerc;
3995                oX = vX-(vX-currentV[0])*roundCorner;
3996                oY = vY-(vY-currentV[1])*roundCorner;
3997                cloned_path.setTripleAt(vX,vY,oX,oY,iX,iY,index);
3998                index += 1;
3999
4000                if(i === len - 1){
4001                    closerV = path.v[0];
4002                } else {
4003                    closerV = path.v[i+1];
4004                }
4005                distance = Math.sqrt(Math.pow(currentV[0]-closerV[0],2)+Math.pow(currentV[1]-closerV[1],2));
4006                newPosPerc = distance ? Math.min(distance/2,round)/distance : 0;
4007                vX = oX = currentV[0]+(closerV[0]-currentV[0])*newPosPerc;
4008                vY = oY = currentV[1]+(closerV[1]-currentV[1])*newPosPerc;
4009                iX = vX-(vX-currentV[0])*roundCorner;
4010                iY = vY-(vY-currentV[1])*roundCorner;
4011                cloned_path.setTripleAt(vX,vY,oX,oY,iX,iY,index);
4012                index += 1;
4013            }
4014        } else {
4015            cloned_path.setTripleAt(path.v[i][0],path.v[i][1],path.o[i][0],path.o[i][1],path.i[i][0],path.i[i][1],index);
4016            index += 1;
4017        }
4018    }
4019    return cloned_path;
4020}
4021
4022RoundCornersModifier.prototype.processShapes = function(firstFrame){
4023    var shapePaths;
4024    var i, len = this.shapes.length;
4025    var j, jLen;
4026    var rd = this.rd.v;
4027
4028    if(rd !== 0){
4029        var shapeData, newPaths, localShapeCollection;
4030        for(i=0;i<len;i+=1){
4031            shapeData = this.shapes[i];
4032            newPaths = shapeData.shape.paths;
4033            localShapeCollection = shapeData.localShapeCollection;
4034            if(!(!shapeData.shape.mdf && !this.mdf && !firstFrame)){
4035                localShapeCollection.releaseShapes();
4036                shapeData.shape.mdf = true;
4037                shapePaths = shapeData.shape.paths.shapes;
4038                jLen = shapeData.shape.paths._length;
4039                for(j=0;j<jLen;j+=1){
4040                    localShapeCollection.addShape(this.processPath(shapePaths[j],rd));
4041                }
4042            }
4043            shapeData.shape.paths = shapeData.localShapeCollection;
4044        }
4045
4046    }
4047    if(!this.dynamicProperties.length){
4048        this.mdf = false;
4049    }
4050}
4051
4052
4053ShapeModifiers.registerModifier('rd',RoundCornersModifier);
4054function RepeaterModifier(){};
4055RepeaterModifier.prototype.processKeys = function(forceRender){
4056    if(this.elem.globalData.frameId === this.frameId && !forceRender){
4057        return;
4058    }
4059    this.mdf = forceRender ? true : false;
4060    var i, len = this.dynamicProperties.length;
4061
4062    for(i=0;i<len;i+=1){
4063        this.dynamicProperties[i].getValue();
4064        if(this.dynamicProperties[i].mdf){
4065            this.mdf = true;
4066        }
4067    }
4068};
4069
4070RepeaterModifier.prototype.initModifierProperties = function(elem,data){
4071    this.getValue = this.processKeys;
4072    this.c = PropertyFactory.getProp(elem,data.c,0,null,this.dynamicProperties);
4073    this.o = PropertyFactory.getProp(elem,data.o,0,null,this.dynamicProperties);
4074    this.tr = PropertyFactory.getProp(elem,data.tr,2,null,this.dynamicProperties);
4075    this.data = data;
4076    if(!this.dynamicProperties.length){
4077        this.getValue(true);
4078    }
4079    this.pMatrix = new Matrix();
4080    this.rMatrix = new Matrix();
4081    this.sMatrix = new Matrix();
4082    this.tMatrix = new Matrix();
4083    this.matrix = new Matrix();
4084};
4085
4086RepeaterModifier.prototype.applyTransforms = function(pMatrix, rMatr
4086ix, sMatrix, transform, perc, inv){
4087    var dir = inv ? -1 : 1;
4088    var scaleX = transform.s.v[0] + (1 - transform.s.v[0]) * (1 - perc);
4089    var scaleY = transform.s.v[1] + (1 - transform.s.v[1]) * (1 - perc);
4090    pMatrix.translate(transform.p.v[0] * dir * perc, transform.p.v[1] * dir * perc, transform.p.v[2]);
4091    rMatrix.translate(-transform.a.v[0], -transform.a.v[1], transform.a.v[2]);
4092    rMatrix.rotate(-transform.r.v * dir * perc);
4093    rMatrix.translate(transform.a.v[0], transform.a.v[1], transform.a.v[2]);
4094    sMatrix.translate(-transform.a.v[0], -transform.a.v[1], transform.a.v[2]);
4095    sMatrix.scale(inv ? 1/scaleX : scaleX, inv ? 1/scaleY : scaleY);
4096    sMatrix.translate(transform.a.v[0], transform.a.v[1], transform.a.v[2]);
4097}
4098
4099RepeaterModifier.prototype.init = function(elem, arr, pos, elemsData, dynamicProperties) {
4100    this.elem = elem;
4101    this.arr = arr;
4102    this.pos = pos;
4103    this.elemsData = elemsData;
4104    this._currentCopies = 0;
4105    this._elements = [];
4106    this._groups = [];
4107    this.dynamicProperties = [];
4108    this.frameId = -1;
4109    this.initModifierProperties(elem,arr[pos]);
4110    var cont = 0;
4111    while(pos>0){
4112        pos -= 1;
4113        //this._elements.unshift(arr.splice(pos,1)[0]);
4114        this._elements.unshift(arr[pos]);
4115        cont += 1;
4116    }
4117    if(this.dynamicProperties.length){
4118        this.k = true;
4119        dynamicProperties.push(this);
4120    }else{
4121        this.getValue(true);
4122    }
4123}
4124
4125RepeaterModifier.prototype.resetElements = function(elements){
4126    var i, len = elements.length;
4127    for(i = 0; i < len; i += 1) {
4128        elements[i]._processed = false;
4129        if(elements[i].ty === 'gr'){
4130            this.resetElements(elements[i].it);
4131        }
4132    }
4133}
4134
4135RepeaterModifier.prototype.cloneElements = function(elements){
4136    var i, len = elements.length;
4137    var newElements = JSON.parse(JSON.stringify(elements));
4138    this.resetElements(newElements);
4139    return newElements;
4140}
4141
4142RepeaterModifier.prototype.changeGroupRender = function(elements, renderFlag) {
4143    var i, len = elements.length;
4144    for(i = 0; i < len ; i += 1) {
4145        elements[i]._render = renderFlag;
4146        if(elements[i].ty === 'gr') {
4147            this.changeGroupRender(elements[i].it, renderFlag);
4148        }
4149    }
4150}
4151
4152RepeaterModifier.prototype.processShapes = function(firstFrame){
4153
4154    if(this.elem.globalData.frameId === this.frameId){
4155        return;
4156    }
4157    this.frameId = this.elem.globalData.frameId;
4158    if(!this.dynamicProperties.length && !firstFrame){
4159        this.mdf = false;
4160    }
4161    if(this.mdf){
4162        var copies = Math.ceil(this.c.v);
4163        if(this._groups.length < copies){
4164            while(this._groups.length < copies){
4165                var group = {
4166                    it:this.cloneElements(this._elements),
4167                    ty:'gr'
4168                }
4169                group.it.push({"a":{"a":0,"ix":1,"k":[0,0]},"nm":"Transform","o":{"a":0,"ix":7,"k":100},"p":{"a":0,"ix":2,"k":[0,0]},"r":{"a":0,"ix":6,"k":0},"s":{"a":0,"ix":3,"k":[100,100]},"sa":{"a":0,"ix":5,"k":0},"sk":{"a":0,"ix":4,"k":0},"ty":"tr"});
4170                
4171                this.arr.splice(0,0,group);
4172                this._groups.splice(0,0,group);
4173                this._currentCopies += 1;
4174            }
4175            this.elem.reloadShapes();
4176        }
4177        var i, cont = 0, renderFlag;
4178        for(i = 0; i  <= this._groups.length - 1; i += 1){
4179            renderFlag = cont < copies;
4180            this._groups[i]._render = renderFlag;
4181            this.changeGroupRender(this._groups[i].it, renderFlag);
4182            cont += 1;
4183        }
4184        
4185        this._currentCopies = copies;
4186        this.elem.firstFrame = true;
4187        ////
4188
4189        var offset = this.o.v;
4190        var offsetModulo = offset%1;
4191        var roundOffset = offset > 0 ? Math.floor(offset) : Math.ceil(offset);
4192        var k;
4193        var tMat = this.tr.v.props;
4194        var pProps = this.pMatrix.props;
4195        var rProps = this.rMatrix.props;
4196        var sProps = this.sMatrix.props;
4197        this.pMatrix.reset();
4198        this.rMatrix.reset();
4199        this.sMatrix.reset();
4200        this.tMatrix.reset();
4201        this.matrix.reset();
4202        var iteration = 0;
4203
4204        if(offset > 0) {
4205            while(iteration<roundOffset){
4206                this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, 1, false);
4207                iteration += 1;
4208            }
4209            if(offsetModulo){
4210                this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, offsetModulo, false);
4211                iteration += offsetModulo;
4212            }
4213        } else if(offset < 0) {
4214            while(iteration>roundOffset){
4215                this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, 1, true);
4216                iteration -= 1;
4217            }
4218            if(offsetModulo){
4219                this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, - offsetModulo, true);
4220                iteration -= offsetModulo;
4221            }
4222        }
4223        i = this.data.m === 1 ? 0 : this._currentCopies - 1;
4224        var dir = this.data.m === 1 ? 1 : -1;
4225        cont = this._currentCopies;
4226        while(cont){
4227            if(iteration !== 0){
4228                if((i !== 0 && dir === 1) || (i !== this._currentCopies - 1 && dir === -1)){
4229                    this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, 1, false);
4230                }
4231                this.matrix.transform(rProps[0],rProps[1],rProps[2],rProps[3],rProps[4],rProps[5],rProps[6],rProps[7],rProps[8],rProps[9],rProps[10],rProps[11],rProps[12],rProps[13],rProps[14],rProps[15]);
4232                this.matrix.transform(sProps[0],sProps[1],sProps[2],sProps[3],sProps[4],sProps[5],sProps[6],sProps[7],sProps[8],sProps[9],sProps[10],sProps[11],sProps[12],sProps[13],sProps[14],sProps[15]);
4233                this.matrix.transform(pProps[0],pProps[1],pProps[2],pProps[3],pProps[4],pProps[5],pProps[6],pProps[7],pProps[8],pProps[9],pProps[10],pProps[11],pProps[12],pProps[13],pProps[14],pProps[15]);
4234                var items = this.elemsData[i].it;
4235                var itemsTransform = items[items.length - 1].transform.mProps.v.props;
4236                var j, jLen = itemsTransform.length;
4237                for(j=0;j<jLen;j+=1) {
4238                    itemsTransform[j] = this.matrix.props[j];
4239                }
4240                this.matrix.reset();
4241            } else {
4242                this.matrix.reset();
4243                var items = this.elemsData[i].it;
4244                var itemsTransform = items[items.length - 1].transform.mProps.v.props;
4245                var j, jLen = itemsTransform.length;
4246                for(j=0;j<jLen;j+=1) {
4247                    itemsTransform[j] = this.matrix.props[j];
4248                }
4249            }
4250            iteration += 1;
4251            cont -= 1;
4252            i += dir;
4253        }
4254    }
4255}
4256
4257RepeaterModifier.prototype.addShape = function(){}
4258
4259ShapeModifiers.registerModifier('rp',RepeaterModifier);
4260function ShapeCollection(){
4261	this._length = 0;
4262	this._maxLength = 4;
4263	this.shapes = Array.apply(null,{length:this._maxLength});
4264};
4265
4266ShapeCollection.prototype.addShape = function(shapeData){
4267	if(this._length === this._maxLength){
4268		this.shapes = this.shapes.concat(Array.apply(null,{length:this._maxLength}));
4269		this._maxLength *= 2;
4270	}
4271	this.shapes[this._length] = shapeData;
4272	this._length += 1;
4273};
4274
4275ShapeCollection.prototype.releaseShapes = function(){
4276	var i;
4277	for(i = 0; i < this._length; i += 1) {
4278		shape_pool.release(this.shapes[i]);
4279	}
4280	this._length = 0;
4281};
4282var ImagePreloader = (function(){
4283
4284    var imagesLoadedCb;
4285
4286    function imageLoaded(){
4287        this.loadedAssets += 1;
4288        if(this.loadedAssets === this.totalImages){
4289            if(imagesLoadedCb) {
4290                imagesLoadedCb(null);
4291            }
4292        }
4293    }
4294
4295    function getAssetsPath(assetData){
4296        var path = '';
4297        if(this.assetsPath){
4298            var imagePath = assetData.p;
4299            if(imagePath.indexOf('images/') !== -1){
4300                imagePath = imagePath.split('/')[1];
4301            }
4302            path = this.assetsPath + imagePath;
4303        } else {
4304            path = this.path;
4305            path += assetData.u ? assetData.u : '';
4306            path += assetData.p;
4307        }
4308        return path;
4309    }
4310
4311    function loadImage(path){
4312        var img = document.createElement('img');
4313        img.addEventListener('load', imageLoaded.bind(this), false);
4314        img.addEventListener('error', imageLoaded.bind(this), false);
4315        img.src = path;
4316    }
4317    function loadAssets(assets, cb){
4318        imagesLoadedCb = cb;
4319        this.totalAssets = assets.length;
4320        var i;
4321        for(i=0;i<this.totalAssets;i+=1){
4322            if(!assets[i].layers){
4323                loadImage.bind(this)(getAssetsPath.bind(this)(assets[i]));
4324                this.totalImages += 1;
4325            }
4326        }
4327    }
4328
4329    function setPath(path){
4330        this.path = path || '';
4331    }
4332
4333    function setAssetsPath(path){
4334        this.assetsPath = path || '';
4335    }
4336
4337    return function ImagePreloader(){
4338        this.loadAssets = loadAssets;
4339        this.setAssetsPath = setAssetsPath;
4340        this.setPath = setPath;
4341        this.assetsPath = '';
4342        this.path = '';
4343        this.totalAssets = 0;
4344        this.totalImages = 0;
4345        this.loadedAssets = 0;
4346    }
4347}());
4348var featureSupport = (function(){
4349	var ob = {
4350		maskType: true
4351	}
4352	if (/MSIE 10/i.test(navigator.userAgent) || /MSIE 9/i.test(navigator.userAgent) || /rv:11.0/i.test(navigator.userAgent) || /Edge\/\d./i.test(navigator.userAgent)) {
4353	   ob.maskType = false;
4354	}
4355	return ob;
4356}());
4357var filtersFactory = (function(){
4358	var ob = {};
4359	ob.createFilter = createFilter;
4360	ob.createAlphaToLuminanceFilter = createAlphaToLuminanceFilter;
4361
4362	function createFilter(filId){
4363        	var fil = document.createElementNS(svgNS,'filter');
4364        	fil.setAttribute('id',filId);
4365                fil.setAttribute('filterUnits','objectBoundingBox');
4366                fil.setAttribute('x','0%');
4367                fil.setAttribute('y','0%');
4368                fil.setAttribute('width','100%');
4369                fil.setAttribute('height','100%');
4370                return fil;
4371	}
4372
4373	function createAlphaToLuminanceFilter(){
4374                var feColorMatrix = document.createElementNS(svgNS,'feColorMatrix');
4375                feColorMatrix.setAttribute('type','matrix');
4376                feColorMatrix.setAttribute('color-interpolation-filters','sRGB');
4377                feColorMatrix.setAttribute('values','0 0 0 1 0  0 0 0 1 0  0 0 0 1 0  0 0 0 1 1');
4378                return feColorMatrix;
4379	}
4380
4381	return ob;
4382}())
4383function TextAnimatorProperty(textData, renderType, elem){
4384    this.mdf = false;
4385    this._firstFrame = true;
4386	this._hasMaskedPath = false;
4387	this._frameId = -1;
4388	this._dynamicProperties = [];
4389	this._textData = textData;
4390	this._renderType = renderType;
4391	this._elem = elem;
4392	this._animatorsData = Array.apply(null,{length:this._textData.a.length});
4393	this._pathData = {}
4394	this._moreOptions = {
4395		alignment: {}
4396	};
4397	this.renderedLetters = [];
4398    this.lettersChangedFlag = false;
4399
4400}
4401
4402TextAnimatorProperty.prototype.searchProperties = function(dynamicProperties){
4403    var i, len = this._textData.a.length, animatorData, animatorProps;
4404    var getProp = PropertyFactory.getProp;
4405    for(i=0;i<len;i+=1){
4406        animatorProps = this._textData.a[i];
4407        animatorData = {
4408            a: {},
4409            s: {}
4410        };
4411        if('r' in animatorProps.a) {
4412            animatorData.a.r = getProp(this._elem,animatorProps.a.r,0,degToRads,this._dynamicProperties);
4413        }
4414        if('rx' in animatorProps.a) {
4415            animatorData.a.rx = getProp(this._elem,animatorProps.a.rx,0,degToRads,this._dynamicProperties);
4416        }
4417        if('ry' in animatorProps.a) {
4418            animatorData.a.ry = getProp(this._elem,animatorProps.a.ry,0,degToRads,this._dynamicProperties);
4419        }
4420        if('sk' in animatorProps.a) {
4421            animatorData.a.sk = getProp(this._elem,animatorProps.a.sk,0,degToRads,this._dynamicProperties);
4422        }
4423        if('sa' in animatorProps.a) {
4424            animatorData.a.sa = getProp(this._elem,animatorProps.a.sa,0,degToRads,this._dynamicProperties);
4425        }
4426        if('s' in animatorProps.a) {
4427            animatorData.a.s = getProp(this._elem,animatorProps.a.s,1,0.01,this._dynamicProperties);
4428        }
4429        if('a' in animatorProps.a) {
4430            animatorData.a.a = getProp(this._elem,animatorProps.a.a,1,0,this._dynamicProperties);
4431        }
4432        if('o' in animatorProps.a) {
4433            animatorData.a.o = getProp(this._elem,animatorProps.a.o,0,0.01,this._dynamicProperties);
4434        }
4435        if('p' in animatorProps.a) {
4436            animatorData.a.p = getProp(this._elem,animatorProps.a.p,1,0,this._dynamicProperties);
4437        }
4438        if('sw' in animatorProps.a) {
4439            animatorData.a.sw = getProp(this._elem,animatorProps.a.sw,0,0,this._dynamicProperties);
4440        }
4441        if('sc' in animatorProps.a) {
4442            animatorData.a.sc = getProp(this._elem,animatorProps.a.sc,1,0,this._dynamicProperties);
4443        }
4444        if('fc' in animatorProps.a) {
4445            animatorData.a.fc = getProp(this._elem,animatorProps.a.fc,1,0,this._dynamicProperties);
4446        }
4447        if('fh' in animatorProps.a) {
4448            animatorData.a.fh = getProp(this._elem,animatorProps.a.fh,0,0,this._dynamicProperties);
4449        }
4450        if('fs' in animatorProps.a) {
4451            animatorData.a.fs = getProp(this._elem,animatorProps.a.fs,0,0.01,this._dynamicProperties);
4452        }
4453        if('fb' in animatorProps.a) {
4454            animatorData.a.fb = getProp(this._elem,animatorProps.a.fb,0,0.01,this._dynamicProperties);
4455        }
4456        if('t' in animatorProps.a) {
4457            animatorData.a.t = getProp(this._elem,animatorProps.a.t,0,0,this._dynamicProperties);
4458        }
4459        animatorData.s = PropertyFactory.getTextSelectorProp(this._elem,animatorProps.s,this._dynamicProperties);
4460        animatorData.s.t = animatorProps.s.t;
4461        this._animatorsData[i] = animatorData;
4462    }
4463    if(this._textData.p && 'm' in this._textData.p){
4464        this._pathData = {
4465            f: getProp(this._elem,this._textData.p.f,0,0,this._dynamicProperties),
4466            l: getProp(this._elem,this._textData.p.l,0,0,this._dynamicProperties),
4467            r: this._textData.p.r,
4468            m: this._elem.maskManager.getMaskProperty(this._textData.p.m)
4469        };
4470        this._hasMaskedPath = true;
4471    } else {
4472        this._hasMaskedPath = false;
4473    }
4474    this._moreOptions.alignment = getProp(this._elem,this._textData.m.a,1,0,this._dynamicProperties);
4475    if(this._dynamicProperties.length) {
4476    	dynamicProperties.push(this);
4477    }
4478}
4479
4480TextAnimatorProperty.prototype.getMeasures = function(documentData, lettersChangedFlag){
4481    this.lettersChangedFlag = lettersChangedFlag;
4482    if(!this.mdf && !this._firstFrame && !lettersChangedFlag && (!this._hasMaskedPath || !this._pathData.m.mdf)) {
4483        return;
4484    }
4485    this._firstFrame = false;
4486    var alignment = this._moreOptions.alignment.v;
4487    var animators = this._animatorsData;
4488    var textData = this._textData;
4489    var matrixHelper = this.mHelper;
4490    var renderType = this._renderType;
4491    var renderedLettersCount = this.renderedLetters.length;
4492    var data = this.data;
4493    var xPos,yPos;
4494    var i, len;
4495    var letters = documentData.l;
4496    if(this._hasMaskedPath) {
4497        var mask = this._pathData.m;
4498        if(!this._pathData.n || this._pathData.mdf){
4499            var paths = mask.v;
4500            if(this._pathData.r){
4501                paths = reversePath(paths);
4502            }
4503            var pathInfo = {
4504                tLength: 0,
4505                segments: []
4506            };
4507            len = paths._length - 1;
4508            var pathData;
4509            var totalLength = 0;
4510            for (i = 0; i < len; i += 1) {
4511                pathData = {
4512                    s: paths.v[i],
4513                    e: paths.v[i + 1],
4514                    to: [paths.o[i][0] - paths.v[i][0], paths.o[i][1] - paths.v[i][1]],
4515                    ti: [paths.i[i + 1][0] - paths.v[i + 1][0], paths.i[i + 1][1] - paths.v[i + 1][1]]
4516                };
4517                bez.buildBezierData(pathData);
4518                pathInfo.tLength += pathData.bezierData.segmentLength;
4519                pathInfo.segments.push(pathData);
4520                totalLength += pathData.bezierData.segmentLength;
4521            }
4522            i = len;
4523            if (mask.v.c) {
4524                pathData = {
4525                    s: paths.v[i],
4526                    e: paths.v[0],
4527                    to: [paths.o[i][0] - paths.v[i][0], paths.o[i][1] - paths.v[i][1]],
4528                    ti: [paths.i[0][0] - paths.v[0][0], paths.i[0][1] - paths.v[0][1]]
4529                };
4530                bez.buildBezierData(pathData);
4531                pathInfo.tLength += pathData.bezierData.segmentLength;
4532                pathInfo.segments.push(pathData);
4533                totalLength += pathData.bezierData.segmentLength;
4534            }
4535            this._pathData.pi = pathInfo;
4536        }
4537        var pathInfo = this._pathData.pi;
4538
4539        var currentLength = this._pathData.f.v, segmentInd = 0, pointInd = 1, currentPoint, prevPoint, points;
4540        var segmentLength = 0, flag = true;
4541        var segments = pathInfo.segments;
4542        if (currentLength < 0 && mask.v.c) {
4543            if (pathInfo.tLength < Math.abs(currentLength)) {
4544                currentLength = -Math.abs(currentLength) % pathInfo.tLength;
4545            }
4546            segmentInd = segments.length - 1;
4547            points = segments[segmentInd].bezierData.points;
4548            pointInd = points.length - 1;
4549            while (currentLength < 0) {
4550                currentLength += points[pointInd].partialLength;
4551                pointInd -= 1;
4552                if (pointInd < 0) {
4553                    segmentInd -= 1;
4554                    points = segments[segmentInd].bezierData.points;
4555                    pointInd = points.length - 1;
4556                }
4557            }
4558
4559        }
4560        points = segments[segmentInd].bezierData.points;
4561        prevPoint = points[pointInd - 1];
4562        currentPoint = points[pointInd];
4563        var partialLength = currentPoint.partialLength;
4564        var perc, tanAngle;
4565    }
4566
4567
4568    len = letters.length;
4569    xPos = 0;
4570    yPos = 0;
4571    var yOff = documentData.s*1.2*.714;
4572    var firstLine = true;
4573    var animatorProps, animatorSelector;
4574    var j, jLen;
4575    var letterValue;
4576
4577    jLen = animators.length;
4578    if (lettersChangedFlag) {
4579        for (j = 0; j < jLen; j += 1) {
4580            animatorSelector = animators[j].s;
4581            animatorSelector.getValue(true);
4582        }
4583    }
4584    var lastLetter;
4585
4586    var mult, ind = -1, offf, xPathPos, yPathPos;
4587    var initPathPos = currentLength,initSegmentInd = segmentInd, initPointInd = pointInd, currentLine = -1;
4588    var elemOpacity;
4589    var sc,sw,fc,k;
4590    var lineLength = 0;
4591    var letterSw,letterSc,letterFc,letterM = '',letterP = this.defaultPropsArray,letterO;
4592    for( i = 0; i < len; i += 1) {
4593        matrixHelper.reset();
4594        elemOpacity = 1;
4595        if(letters[i].n) {
4596            xPos = 0;
4597            yPos += documentData.yOffset;
4598            yPos += firstLine ? 1 : 0;
4599            currentLength = initPathPos ;
4600            firstLine = false;
4601            lineLength = 0;
4602            if(this._hasMaskedPath) {
4603                segmentInd = initSegmentInd;
4604                pointInd = initPointInd;
4605                points = segments[segmentInd].bezierData.points;
4606                prevPoint = points[pointInd - 1];
4607                currentPoint = points[pointInd];
4608                partialLength = currentPoint.partialLength;
4609                segmentLength = 0;
4610            }
4611            letterO = letterSw = letterFc = letterM = '';
4612            letterP = this.defaultPropsArray;
4613        }else{
4614            if(this._hasMaskedPath) {
4615                if(currentLine !== letters[i].line){
4616                    switch(documentData.j){
4617                        case 1:
4618                            currentLength += totalLength - documentData.lineWidths[letters[i].line];
4619                            break;
4620                        case 2:
4621                            currentLength += (totalLength - documentData.lineWidths[letters[i].line])/2;
4622                            break;
4623                    }
4624                    currentLine = letters[i].line;
4625                }
4626                if (ind !== letters[i].ind) {
4627                    if (letters[ind]) {
4628                        currentLength += letters[ind].extra;
4629                    }
4630                    currentLength += letters[i].an / 2;
4631                    ind = letters[i].ind;
4632                }
4633                currentLength += alignment[0] * letters[i].an / 200;
4634                var animatorOffset = 0;
4635                for (j = 0; j < jLen; j += 1) {
4636                    animatorProps = animators[j].a;
4637                    if ('p' in animatorProps) {
4638                        animatorSelector = animators[j].s;
4639                        mult = animatorSelector.getMult(letters[i].anIndexes[j],textData.a[j].s.totalChars);
4640                        if(mult.length){
4641                            animatorOffset += animatorProps.p.v[0] * mult[0];
4642                        } else{
4643                            animatorOffset += animatorProps.p.v[0] * mult;
4644                        }
4645
4646                    }
4647                    if ('a' in animatorProps) {
4648                        animatorSelector = animators[j].s;
4649                        mult = animatorSelector.getMult(letters[i].anIndexes[j],textData.a[j].s.totalChars);
4650                        if(mult.length){
4651                            animatorOffset += animatorProps.a.v[0] * mult[0];
4652                        } else{
4653                            animatorOffset += animatorProps.a.v[0] * mult;
4654                        }
4655
4656                    }
4657                }
4658                flag = true;
4659                while (flag) {
4660                    if (segmentLength + partialLength >= currentLength + animatorOffset || !points) {
4661                        perc = (currentLength + animatorOffset - segmentLength) / currentPoint.partialLength;
4662                        xPathPos = prevPoint.point[0] + (currentPoint.point[0] - prevPoint.point[0]) * perc;
4663                        yPathPos = prevPoint.point[1] + (currentPoint.point[1] - prevPoint.point[1]) * perc;
4664                        matrixHelper.translate(-alignment[0]*letters[i].an/200, -(alignment[1] * yOff / 100));
4665                        flag = false;
4666                    } else if (points) {
4667                        segmentLength += currentPoint.partialLength;
4668                        pointInd += 1;
4669                        if (pointInd >= points.length) {
4670                            pointInd = 0;
4671                            segmentInd += 1;
4672                            if (!segments[segmentInd]) {
4673                                if (mask.v.c) {
4674                                    pointInd = 0;
4675                                    segmentInd = 0;
4676                                    points = segments[segmentInd].bezierData.points;
4677                                } else {
4678                                    segmentLength -= currentPoint.partialLength;
4679                                    points = null;
4680                                }
4681                            } else {
4682                                points = segments[segmentInd].bezierData.points;
4683                            }
4684                        }
4685                        if (points) {
4686                            prevPoint = currentPoint;
4687                            currentPoint = points[pointInd];
4688                            partialLength = currentPoint.partialLength;
4689                        }
4690                    }
4691                }
4692                offf = letters[i].an / 2 - letters[i].add;
4693                matrixHelper.translate(-offf, 0, 0);
4694            } else {
4695                offf = letters[i].an/2 - letters[i].add;
4696                matrixHelper.translate(-offf,0,0);
4697
4698                // Grouping alignment
4699                matrixHelper.translate(-alignment[0]*letters[i].an/200, -alignment[1]*yOff/100, 0);
4700            }
4701
4702            lineLength += letters[i].l/2;
4703            for(j=0;j<jLen;j+=1){
4704                animatorProps = animators[j].a;
4705                if ('t' in animatorProps) {
4706                    animatorSelector = animators[j].s;
4707                    mult = animatorSelector.getMult(letters[i].anIndexes[j],textData.a[j].s.totalChars);
4708                    if(this._hasMaskedPath) {
4709                        if(mult.length) {
4710                            currentLength += animatorProps.t*mult[0];
4711                        } else {
4712                            currentLength += animatorProps.t*mult;
4713                        }
4714                    }else{
4715                        if(mult.length) {
4716                            xPos += animatorProps.t.v*mult[0];
4717                        } else {
4718                            xPos += animatorProps.t.v*mult;
4719                        }
4720                    }
4721                }
4722            }
4723            lineLength += letters[i].l/2;
4724            if(documentData.strokeWidthAnim) {
4725                sw = documentData.sw || 0;
4726            }
4727            if(documentData.strokeColorAnim) {
4728                if(documentData.sc){
4729                    sc = [documentData.sc[0], documentData.sc[1], documentData.sc[2]];
4730                }else{
4731                    sc = [0,0,0];
4732                }
4733            }
4734            if(documentData.fillColorAnim && documentData.fc) {
4735                fc = [documentData.fc[0], documentData.fc[1], documentData.fc[2]];
4736            }
4737            for(j=0;j<jLen;j+=1){
4738                animatorProps = animators[j].a;
4739                if ('a' in animatorProps) {
4740                    animatorSelector = animators[j].s;
4741                    mult = animatorSelector.getMult(letters[i].anIndexes[j],textData.a[j].s.totalChars);
4742
4743                    if(mult.length){
4744                        matrixHelper.translate(-animatorProps.a.v[0]*mult[0], -animatorProps.a.v[1]*mult[1], animatorProps.a.v[2]*mult[2]);
4745                    } else {
4746                        matrixHelper.translate(-animatorProps.a.v[0]*mult, -animatorProps.a.v[1]*mult, animatorProps.a.v[2]*mult);
4747                    }
4748                }
4749            }
4750            for(j=0;j<jLen;j+=1){
4751                animatorProps = animators[j].a;
4752                if ('s' in animatorProps) {
4753                    animatorSelector = animators[j].s;
4754                    mult = animatorSelector.getMult(letters[i].anIndexes[j],textData.a[j].s.totalChars);
4755                    if(mult.length){
4756                        matrixHelper.scale(1+((animatorProps.s.v[0]-1)*mult[0]),1+((animatorProps.s.v[1]-1)*mult[1]),1);
4757                    } else {
4758                        matrixHelper.scale(1+((animatorProps.s.v[0]-1)*mult),1+((animatorProps.s.v[1]-1)*mult),1);
4759                    }
4760                }
4761            }
4762            for(j=0;j<jLen;j+=1) {
4763                animatorProps = animators[j].a;
4764                animatorSelector = animators[j].s;
4765                mult = animatorSelector.getMult(letters[i].anIndexes[j],textData.a[j].s.totalChars);
4766                if ('sk' in animatorProps) {
4767                    if(mult.length) {
4768                        matrixHelper.skewFromAxis(-animatorProps.sk.v * mult[0], animatorProps.sa.v * mult[1]);
4769                    } else {
4770                        matrixHelper.skewFromAxis(-animatorProps.sk.v * mult, animatorProps.sa.v * mult);
4771                    }
4772                }
4773                if ('r' in animatorProps) {
4774                    if(mult.length) {
4775                        matrixHelper.rotateZ(-animatorProps.r.v * mult[2]);
4776                    } else {
4777                        matrixHelper.rotateZ(-animatorProps.r.v * mult);
4778                    }
4779                }
4780                if ('ry' in animatorProps) {
4781
4782                    if(mult.length) {
4783                        matrixHelper.rotateY(animatorProps.ry.v*mult[1]);
4784                    }else{
4785                        matrixHelper.rotateY(animatorProps.ry.v*mult);
4786                    }
4787                }
4788                if ('rx' in animatorProps) {
4789                    if(mult.length) {
4790                        matrixHelper.rotateX(animatorProps.rx.v*mult[0]);
4791                    } else {
4792                        matrixHelper.rotateX(animatorProps.rx.v*mult);
4793                    }
4794                }
4795                if ('o' in animatorProps) {
4796                    if(mult.length) {
4797                        elemOpacity += ((animatorProps.o.v)*mult[0] - elemOpacity)*mult[0];
4798                    } else {
4799                        elemOpacity += ((animatorProps.o.v)*mult - elemOpacity)*mult;
4800                    }
4801                }
4802                if (documentData.strokeWidthAnim && 'sw' in animatorProps) {
4803                    if(mult.length) {
4804                        sw += animatorProps.sw.v*mult[0];
4805                    } else {
4806                        sw += animatorProps.sw.v*mult;
4807                    }
4808                }
4809                if (documentData.strokeColorAnim && 'sc' in animatorProps) {
4810                    for(k=0;k<3;k+=1){
4811                        if(mult.length) {
4812                            sc[k] = sc[k] + (animatorProps.sc.v[k] - sc[k])*mult[0]
4813                        } else {
4814                            sc[k] = sc[k] + (animatorProps.sc.v[k] - sc[k])*mult;
4815                        }
4816                    }
4817                }
4818                if (documentData.fillColorAnim && documentData.fc) {
4819                    if('fc' in animatorProps){
4820                        for(k=0;k<3;k+=1){
4821                            if(mult.length) {
4822                                fc[k] = fc[k] + (animatorProps.fc.v[k] - fc[k])*mult[0];
4823                            } else {
4824                                fc[k] = fc[k] + (animatorProps.fc.v[k] - fc[k])*mult;
4825                            }
4826                        }
4827                    }
4828                    if('fh' in animatorProps){
4829                        if(mult.length) {
4830                            fc = addHueToRGB(fc,animatorProps.fh.v*mult[0]);
4831                        } else {
4832                            fc = addHueToRGB(fc,animatorProps.fh.v*mult);
4833                        }
4834                    }
4835                    if('fs' in animatorProps){
4836                        if(mult.length) {
4837                            fc = addSaturationToRGB(fc,animatorProps.fs.v*mult[0]);
4838                        } else {
4839                            fc = addSaturationToRGB(fc,animatorProps.fs.v*mult);
4840                        }
4841                    }
4842                    if('fb' in animatorProps){
4843                        if(mult.length) {
4844                            fc = addBrightnessToRGB(fc,animatorProps.fb.v*mult[0]);
4845                        } else {
4846                            fc = addBrightnessToRGB(fc,animatorProps.fb.v*mult);
4847                        }
4848                    }
4849                }
4850            }
4851
4852            for(j=0;j<jLen;j+=1){
4853                animatorProps = animators[j].a;
4854
4855                if ('p' in animatorProps) {
4856                    animatorSelector = animators[j].s;
4857                    mult = animatorSelector.getMult(letters[i].anIndexes[j],textData.a[j].s.totalChars);
4858                    if(this._hasMaskedPath) {
4859                        if(mult.length) {
4860                            matrixHelper.translate(0, animatorProps.p.v[1] * mult[0], -animatorProps.p.v[2] * mult[1]);
4861                        } else {
4862                            matrixHelper.translate(0, animatorProps.p.v[1] * mult, -animatorProps.p.v[2] * mult);
4863                        }
4864                    }else{
4865                        if(mult.length) {
4866                            matrixHelper.translate(animatorProps.p.v[0] * mult[0], animatorProps.p.v[1] * mult[1], -animatorProps.p.v[2] * mult[2]);
4867                        } else {
4868                            matrixHelper.translate(animatorProps.p.v[0] * mult, animatorProps.p.v[1] * mult, -animatorProps.p.v[2] * mult);
4869                        }
4870                    }
4871                }
4872            }
4873            if(documentData.strokeWidthAnim){
4874                letterSw = sw < 0 ? 0 : sw;
4875            }
4876            if(documentData.strokeColorAnim){
4877                letterSc = 'rgb('+Math.round(sc[0]*255)+','+Math.round(sc[1]*255)+','+Math.round(sc[2]*255
4877)+')';
4878            }
4879            if(documentData.fillColorAnim && documentData.fc){
4880                letterFc = 'rgb('+Math.round(fc[0]*255)+','+Math.round(fc[1]*255)+','+Math.round(fc[2]*255)+')';
4881            }
4882
4883            if(this._hasMaskedPath) {
4884                matrixHelper.translate(0,-documentData.ls);
4885
4886                matrixHelper.translate(0, alignment[1]*yOff/100 + yPos,0);
4887                if (textData.p.p) {
4888                    tanAngle = (currentPoint.point[1] - prevPoint.point[1]) / (currentPoint.point[0] - prevPoint.point[0]);
4889                    var rot = Math.atan(tanAngle) * 180 / Math.PI;
4890                    if (currentPoint.point[0] < prevPoint.point[0]) {
4891                        rot += 180;
4892                    }
4893                    matrixHelper.rotate(-rot * Math.PI / 180);
4894                }
4895                matrixHelper.translate(xPathPos, yPathPos, 0);
4896                currentLength -= alignment[0]*letters[i].an/200;
4897                if(letters[i+1] && ind !== letters[i+1].ind){
4898                    currentLength += letters[i].an / 2;
4899                    currentLength += documentData.tr/1000*documentData.s;
4900                }
4901            }else{
4902
4903                matrixHelper.translate(xPos,yPos,0);
4904
4905                if(documentData.ps){
4906                    //matrixHelper.translate(documentData.ps[0],documentData.ps[1],0);
4907                    matrixHelper.translate(documentData.ps[0],documentData.ps[1] + documentData.ascent,0);
4908                }
4909                switch(documentData.j){
4910                    case 1:
4911                        matrixHelper.translate(documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[letters[i].line]),0,0);
4912                        break;
4913                    case 2:
4914                        matrixHelper.translate(documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[letters[i].line])/2,0,0);
4915                        break;
4916                }
4917                matrixHelper.translate(0,-documentData.ls);
4918                matrixHelper.translate(offf,0,0);
4919                matrixHelper.translate(alignment[0]*letters[i].an/200,alignment[1]*yOff/100,0);
4920                xPos += letters[i].l + documentData.tr/1000*documentData.s;
4921            }
4922            if(renderType === 'html'){
4923                letterM = matrixHelper.toCSS();
4924            }else if(renderType === 'svg'){
4925                letterM = matrixHelper.to2dCSS();
4926            }else{
4927                letterP = [matrixHelper.props[0],matrixHelper.props[1],matrixHelper.props[2],matrixHelper.props[3],matrixHelper.props[4],matrixHelper.props[5],matrixHelper.props[6],matrixHelper.props[7],matrixHelper.props[8],matrixHelper.props[9],matrixHelper.props[10],matrixHelper.props[11],matrixHelper.props[12],matrixHelper.props[13],matrixHelper.props[14],matrixHelper.props[15]];
4928            }
4929            letterO = elemOpacity;
4930        }
4931
4932        if(renderedLettersCount <= i) {
4933            letterValue = new LetterProps(letterO,letterSw,letterSc,letterFc,letterM,letterP);
4934            this.renderedLetters.push(letterValue);
4935            renderedLettersCount += 1;
4936            this.lettersChangedFlag = true;
4937        } else {
4938            letterValue = this.renderedLetters[i];
4939            this.lettersChangedFlag = letterValue.update(letterO, letterSw, letterSc, letterFc, letterM, letterP) || this.lettersChangedFlag;
4940        }
4941    }
4942}
4943
4944TextAnimatorProperty.prototype.getValue = function(){
4945	if(this._elem.globalData.frameId === this._frameId){
4946        return;
4947    }
4948    this._frameId = this._elem.globalData.frameId;
4949	var i, len = this._dynamicProperties.length;
4950    this.mdf = false;
4951	for(i = 0; i < len; i += 1) {
4952		this._dynamicProperties[i].getValue();
4953        this.mdf = this._dynamicProperties[i].mdf || this.mdf;
4954	}
4955}
4956
4957TextAnimatorProperty.prototype.mHelper = new Matrix();
4958TextAnimatorProperty.prototype.defaultPropsArray = [];
4959function LetterProps(o, sw, sc, fc, m, p){
4960    this.o = o;
4961    this.sw = sw;
4962    this.sc = sc;
4963    this.fc = fc;
4964    this.m = m;
4965    this.p = p;
4966    this.mdf = {
4967    	o: true,
4968    	sw: !!sw,
4969    	sc: !!sc,
4970    	fc: !!fc,
4971    	m: true,
4972    	p: true
4973    };
4974}
4975
4976LetterProps.prototype.update = function(o, sw, sc, fc, m, p) {
4977	this.mdf.o = false;
4978	this.mdf.sw = false;
4979	this.mdf.sc = false;
4980	this.mdf.fc = false;
4981	this.mdf.m = false;
4982	this.mdf.p = false;
4983	var updated = false;
4984
4985	if(this.o !== o) {
4986		this.o = o;
4987		this.mdf.o = true;
4988		updated = true;
4989	}
4990	if(this.sw !== sw) {
4991		this.sw = sw;
4992		this.mdf.sw = true;
4993		updated = true;
4994	}
4995	if(this.sc !== sc) {
4996		this.sc = sc;
4997		this.mdf.sc = true;
4998		updated = true;
4999	}
5000	if(this.fc !== fc) {
5001		this.fc = fc;
5002		this.mdf.fc = true;
5003		updated = true;
5004	}
5005	if(this.m !== m) {
5006		this.m = m;
5007		this.mdf.m = true;
5008		updated = true;
5009	}
5010	if(p.length && (this.p[0] !== p[0] || this.p[1] !== p[1] || this.p[4] !== p[4] || this.p[5] !== p[5] || this.p[12] !== p[12] || this.p[13] !== p[13])) {
5011		this.p = p;
5012		this.mdf.p = true;
5013		updated = true;
5014	}
5015	return updated;
5016}
5017function TextProperty(elem, data, dynamicProperties){
5018	this._frameId = -99999;
5019	this.pv = '';
5020	this.v = '';
5021	this.kf = false;
5022	this.firstFrame = true;
5023	this.mdf = true;
5024	this.data = data;
5025	this.elem = elem;
5026	this.keysIndex = -1;
5027	this.currentData = {
5028		ascent: 0,
5029        boxWidth: [0,0],
5030        f: '',
5031        fStyle: '',
5032        fWeight: '',
5033        fc: '',
5034        j: '',
5035        justifyOffset: '',
5036        l: [],
5037        lh: 0,
5038        lineWidths: [],
5039        ls: '',
5040        of: '',
5041        s: '',
5042        sc: '',
5043        sw: 0,
5044        t: 0,
5045        tr: 0,
5046        fillColorAnim: false,
5047        strokeColorAnim: false,
5048        strokeWidthAnim: false,
5049        yOffset: 0,
5050        __complete: false
5051
5052	}
5053	if(this.searchProperty()) {
5054		dynamicProperties.push(this);
5055	} else {
5056		this.getValue(true);
5057	}
5058}
5059
5060TextProperty.prototype.setCurrentData = function(data){
5061		var currentData = this.currentData;
5062        currentData.ascent = data.ascent;
5063        currentData.boxWidth = data.boxWidth ? data.boxWidth : currentData.boxWidth;
5064        currentData.f = data.f;
5065        currentData.fStyle = data.fStyle;
5066        currentData.fWeight = data.fWeight;
5067        currentData.fc = data.fc;
5068        currentData.j = data.j;
5069        currentData.justifyOffset = data.justifyOffset;
5070        currentData.l = data.l;
5071        currentData.lh = data.lh;
5072        currentData.lineWidths = data.lineWidths;
5073        currentData.ls = data.ls;
5074        currentData.of = data.of;
5075        currentData.s = data.s;
5076        currentData.sc = data.sc;
5077        currentData.sw = data.sw;
5078        currentData.t = data.t;
5079        currentData.tr = data.tr;
5080        currentData.fillColorAnim = data.fillColorAnim || currentData.fillColorAnim;
5081        currentData.strokeColorAnim = data.strokeColorAnim || currentData.strokeColorAnim;
5082        currentData.strokeWidthAnim = data.strokeWidthAnim || currentData.strokeWidthAnim;
5083        currentData.yOffset = data.yOffset;
5084        currentData.__complete = false;
5085}
5086
5087TextProperty.prototype.searchProperty = function() {
5088	this.kf = this.data.d.k.length > 1;
5089	return this.kf;
5090}
5091
5092TextProperty.prototype.getValue = function() {
5093	this.mdf = false;
5094	var frameId = this.elem.globalData.frameId;
5095	if((frameId === this._frameId || !this.kf) && !this.firstFrame) {
5096		return;
5097	}
5098	var textKeys = this.data.d.k, textDocumentData;
5099    var i = 0, len = textKeys.length;
5100    while(i <= len - 1) {
5101        textDocumentData = textKeys[i].s;
5102        if(i === len - 1 || textKeys[i+1].t > frameId){
5103            break;
5104        }
5105        i += 1;
5106    }
5107    if(this.keysIndex !== i) {
5108    	if(!textDocumentData.__complete) {
5109            this.completeTextData(textDocumentData);
5110        }
5111        this.setCurrentData(textDocumentData);
5112        this.mdf = this.firstFrame ? false : true;
5113        this.pv = this.v = this.currentData.t;
5114        this.keysIndex = i;
5115    }
5116	this._frameId = frameId;
5117}
5118
5119TextProperty.prototype.completeTextData = function(documentData) {
5120    documentData.__complete = true;
5121    var fontManager = this.elem.globalData.fontManager;
5122    var data = this.data;
5123    var letters = [];
5124    var i, len;
5125    var newLineFlag, index = 0, val;
5126    var anchorGrouping = data.m.g;
5127    var currentSize = 0, currentPos = 0, currentLine = 0, lineWidths = [];
5128    var lineWidth = 0;
5129    var maxLineWidth = 0;
5130    var j, jLen;
5131    var fontData = fontManager.getFontByName(documentData.f);
5132    var charData, cLength = 0;
5133    var styles = fontData.fStyle.split(' ');
5134
5135    var fWeight = 'normal', fStyle = 'normal';
5136    len = styles.length;
5137    var styleName;
5138    for(i=0;i<len;i+=1){
5139        styleName = styles[i].toLowerCase();
5140        switch(styleName) {
5141            case 'italic':
5142            fStyle = 'italic';
5143            break;
5144            case 'bold':
5145            fWeight = '700';
5146            break;
5147            case 'black':
5148            fWeight = '900';
5149            break;
5150            case 'medium':
5151            fWeight = '500';
5152            break;
5153            case 'regular':
5154            case 'normal':
5155            fWeight = '400';
5156            case 'light':
5157            case 'thin':
5158            fWeight = '200';
5159            break;
5160        }
5161    }
5162    documentData.fWeight = fWeight;
5163    documentData.fStyle = fStyle;
5164    len = documentData.t.length;
5165    var trackingOffset = documentData.tr/1000*documentData.s;
5166    if(documentData.sz){
5167        var boxWidth = documentData.sz[0];
5168        var lastSpaceIndex = -1;
5169        for(i=0;i<len;i+=1){
5170            newLineFlag = false;
5171            if(documentData.t.charAt(i) === ' '){
5172                lastSpaceIndex = i;
5173            }else if(documentData.t.charCodeAt(i) === 13){
5174                lineWidth = 0;
5175                newLineFlag = true;
5176            }
5177            if(fontManager.chars){
5178                charData = fontManager.getCharData(documentData.t.charAt(i), fontData.fStyle, fontData.fFamily);
5179                cLength = newLineFlag ? 0 : charData.w*documentData.s/100;
5180            }else{
5181                //tCanvasHelper.font = documentData.s + 'px '+ fontData.fFamily;
5182                cLength = fontManager.measureText(documentData.t.charAt(i), documentData.f, documentData.s);
5183            }
5184            if(lineWidth + cLength > boxWidth && documentData.t.charAt(i) !== ' '){
5185                if(lastSpaceIndex === -1){
5186                    len += 1;
5187                } else {
5188                    i = lastSpaceIndex;
5189                }
5190                documentData.t = documentData.t.substr(0,i) + "\r" + documentData.t.substr(i === lastSpaceIndex ? i + 1 : i);
5191                lastSpaceIndex = -1;
5192                lineWidth = 0;
5193            }else {
5194                lineWidth += cLength;
5195                lineWidth += trackingOffset;
5196            }
5197        }
5198        len = documentData.t.length;
5199    }
5200    lineWidth = - trackingOffset;
5201    cLength = 0;
5202    var uncollapsedSpaces = 0;
5203    var currentChar;
5204    for (i = 0;i < len ;i += 1) {
5205        newLineFlag = false;
5206        currentChar = documentData.t.charAt(i);
5207        if(currentChar === ' '){
5208            val = '\u00A0';
5209        }else if(currentChar.charCodeAt(0) === 13){
5210            uncollapsedSpaces = 0;
5211            lineWidths.push(lineWidth);
5212            maxLineWidth = lineWidth > maxLineWidth ? lineWidth : maxLineWidth;
5213            lineWidth = - 2 * trackingOffset;
5214            val = '';
5215            newLineFlag = true;
5216            currentLine += 1;
5217        }else{
5218            val = documentData.t.charAt(i);
5219        }
5220        if(fontManager.chars){
5221            charData = fontManager.getCharData(currentChar, fontData.fStyle, fontManager.getFontByName(documentData.f).fFamily);
5222            cLength = newLineFlag ? 0 : charData.w*documentData.s/100;
5223        }else{
5224            //var charWidth = fontManager.measureText(val, documentData.f, documentData.s);
5225            //tCanvasHelper.font = documentData.s + 'px '+ fontManager.getFontByName(documentData.f).fFamily;
5226            cLength = fontManager.measureText(val, documentData.f, documentData.s);
5227        }
5228
5229        //
5230        if(currentChar === ' '){
5231            uncollapsedSpaces += cLength + trackingOffset;
5232        } else {
5233            lineWidth += cLength + trackingOffset + uncollapsedSpaces;
5234            uncollapsedSpaces = 0;
5235        }
5236        letters.push({l:cLength,an:cLength,add:currentSize,n:newLineFlag, anIndexes:[], val: val, line: currentLine});
5237        if(anchorGrouping == 2){
5238            currentSize += cLength;
5239            if(val == '' || val == '\u00A0' || i == len - 1){
5240                if(val == '' || val == '\u00A0'){
5241                    currentSize -= cLength;
5242                }
5243                while(currentPos<=i){
5244                    letters[currentPos].an = currentSize;
5245                    letters[currentPos].ind = index;
5246                    letters[currentPos].extra = cLength;
5247                    currentPos += 1;
5248                }
5249                index += 1;
5250                currentSize = 0;
5251            }
5252        }else if(anchorGrouping == 3){
5253            currentSize += cLength;
5254            if(val == '' || i == len - 1){
5255                if(val == ''){
5256                    currentSize -= cLength;
5257                }
5258                while(currentPos<=i){
5259                    letters[currentPos].an = currentSize;
5260                    letters[currentPos].ind = index;
5261                    letters[currentPos].extra = cLength;
5262                    currentPos += 1;
5263                }
5264                currentSize = 0;
5265                index += 1;
5266            }
5267        }else{
5268            letters[index].ind = index;
5269            letters[index].extra = 0;
5270            index += 1;
5271        }
5272    }
5273    documentData.l = letters;
5274    maxLineWidth = lineWidth > maxLineWidth ? lineWidth : maxLineWidth;
5275    lineWidths.push(lineWidth);
5276    if(documentData.sz){
5277        documentData.boxWidth = documentData.sz[0];
5278        documentData.justifyOffset = 0;
5279    }else{
5280        documentData.boxWidth = maxLineWidth;
5281        switch(documentData.j){
5282            case 1:
5283                documentData.justifyOffset = - documentData.boxWidth;
5284                break;
5285            case 2:
5286                documentData.justifyOffset = - documentData.boxWidth/2;
5287                break;
5288            default:
5289                documentData.justifyOffset = 0;
5290        }
5291    }
5292    documentData.lineWidths = lineWidths;
5293
5294    var animators = data.a, animatorData, letterData;
5295    jLen = animators.length;
5296    var based, ind, indexes = [];
5297    for(j=0;j<jLen;j+=1){
5298        animatorData = animators[j];
5299        if(animatorData.a.sc){
5300            documentData.strokeColorAnim = true;
5301        }
5302        if(animatorData.a.sw){
5303            documentData.strokeWidthAnim = true;
5304        }
5305        if(animatorData.a.fc || animatorData.a.fh || animatorData.a.fs || animatorData.a.fb){
5306            documentData.fillColorAnim = true;
5307        }
5308        ind = 0;
5309        based = animatorData.s.b;
5310        for(i=0;i<len;i+=1){
5311            letterData = letters[i];
5312            letterData.anIndexes[j] = ind;
5313            if((based == 1 && letterData.val != '') || (based == 2 && letterData.val != '' && letterData.val != '\u00A0') || (based == 3 && (letterData.n || letterData.val == '\u00A0' || i == len - 1)) || (based == 4 && (letterData.n || i == len - 1))){
5314                if(animatorData.s.rn === 1){
5315                    indexes.push(ind);
5316                }
5317                ind += 1;
5318            }
5319        }
5320        data.a[j].s.totalChars = ind;
5321        var currentInd = -1, newInd;
5322        if(animatorData.s.rn === 1){
5323            for(i = 0; i < len; i += 1){
5324                letterData = letters[i];
5325                if(currentInd != letterData.anIndexes[j]){
5326                    currentInd = letterData.anIndexes[j];
5327                    newInd = indexes.splice(Math.floor(Math.random()*indexes.length),1)[0];
5328                }
5329                letterData.anIndexes[j] = newInd;
5330            }
5331        }
5332    }
5333    documentData.yOffset = documentData.lh || documentData.s*1.2;
5334    documentData.ls = documentData.ls || 0;
5335    documentData.ascent = fontData.ascent*documentData.s/100;
5336}
5337
5338TextProperty.prototype.updateDocumentData = function(newData, index) {
5339	index = index === undefined ? this.keysIndex : index;
5340    var dData = this.data.d.k[index].s;
5341    dData.__complete = false;
5342    dData.t = newData.t;
5343    this.keysIndex = -1;
5344    this.firstFrame = true;
5345    this.getValue();
5346}
5347
5348var pooling = (function(){
5349
5350	function double(arr){
5351		return arr.concat(Array.apply(null,{length:arr.length}))
5352	}
5353
5354	return {
5355		double: double
5356	}
5357}());
5358var point_pool = (function(){
5359	var ob = {
5360		newPoint: newPoint,
5361		release: release
5362	}
5363
5364	var _length = 0;
5365	var _maxLength = 8;
5366	var pool = Array.apply(null,{length:_maxLength});
5367
5368	function newPoint(){
5369		var point;
5370		if(_length){
5371			_length -= 1;
5372			point = pool[_length];
5373		} else {
5374			point = [0.1,0.1];
5375		}
5376		return point;
5377	}
5378
5379	function release(point) {
5380		if(_length === _maxLength) {
5381			pool = pooling.double(pool);
5382			_maxLength = _maxLength*2;
5383		}
5384		pool[_length] = point;
5385		_length += 1;
5386	}
5387
5388
5389	return ob;
5390}());
5391var shape_pool = (function(){
5392	var ob = {
5393		clone: clone,
5394		newShape: newShape,
5395		release: release,
5396		releaseArray: releaseArray
5397	}
5398
5399	var _length = 0;
5400	var _maxLength = 4;
5401	var pool = Array.apply(null,{length:_maxLength});
5402
5403	function newShape(){
5404		var shapePath;
5405		if(_length){
5406			_length -= 1;
5407			shapePath = pool[_length];
5408		} else {
5409			shapePath = new ShapePath();
5410		}
5411		return shapePath;
5412	}
5413
5414	function release(shapePath) {
5415		if(_length === _maxLength) {
5416			pool = pooling.double(pool);
5417			_maxLength = _maxLength*2;
5418		}
5419		var len = shapePath._length, i;
5420		for(i = 0; i < len; i += 1) {
5421			point_pool.release(shapePath.v[i]);
5422			point_pool.release(shapePath.i[i]);
5423			point_pool.release(shapePath.o[i]);
5424			shapePath.v[i] = null;
5425			shapePath.i[i] = null;
5426			shapePath.o[i] = null;
5427		}
5428		shapePath._length = 0;
5429		shapePath.c = false;
5430		pool[_length] = shapePath;
5431		_length += 1;
5432	}
5433
5434	function releaseArray(shapePathsCollection, length) {
5435		while(length--) {
5436			release(shapePathsCollection[length]);
5437		}
5438	}
5439
5440	function clone(shape, transform) {
5441		var i, len = shape._length === undefined ? shape.v.length : shape._length;
5442		var cloned = newShape();
5443		cloned.setLength(len);
5444		cloned.c = shape.c;
5445
5446		var pt;
5447		
5448		for(i = 0; i < len; i += 1) {
5449			if(transform){
5450				pt = transform.applyToPointArray(shape.v[i][0],shape.v[i][1],0,2);
5451				cloned.setXYAt(pt[0],pt[1],'v',i);
5452				point_pool.release(pt);
5453				pt = transform.applyToPointArray(shape.o[i][0],shape.o[i][1],0,2);
5454				cloned.setXYAt(pt[0],pt[1],'o',i);
5455				point_pool.release(pt);
5456				pt = transform.applyToPointArray(shape.i[i][0],shape.i[i][1],0,2);
5457				cloned.setXYAt(pt[0],pt[1],'i',i);
5458				point_pool.release(pt);
5459			}else{
5460				cloned.setTripleAt(shape.v[i][0],shape.v[i][1],shape.o[i][0],shape.o[i][1],shape.i[i][0],shape.i[i][1], i);
5461			}
5462		}
5463		return cloned
5464	}
5465
5466
5467	return ob;
5468}());
5469var shapeCollection_pool = (function(){
5470	var ob = {
5471		newShapeCollection: newShapeCollection,
5472		release: release,
5473		clone: clone
5474	}
5475
5476	var _length = 0;
5477	var _maxLength = 4;
5478	var pool = Array.apply(null,{length:_maxLength});
5479
5480	var cont = 0;
5481
5482	function newShapeCollection(){
5483		var shapeCollection;
5484		if(_length){
5485			_length -= 1;
5486			shapeCollection = pool[_length];
5487		} else {
5488			shapeCollection = new ShapeCollection();
5489		}
5490		return shapeCollection;
5491	}
5492
5493	function release(shapeCollection) {
5494		var i, len = shapeCollection._length;
5495		for(i = 0; i < len; i += 1) {
5496			shape_pool.release(shapeCollection.shapes[i]);
5497		}
5498		shapeCollection._length = 0;
5499
5500		if(_length === _maxLength) {
5501			pool = pooling.double(pool);
5502			_maxLength = _maxLength*2;
5503		}
5504		pool[_length] = shapeCollection;
5505		_length += 1;
5506	}
5507
5508	function clone(shapeCollection, originCollection) {
5509		release(shapeCollection);
5510		if(_length === _maxLength) {
5511			pool = pooling.double(pool);
5512			_maxLength = _maxLength*2;
5513		}
5514		pool[_length] = shapeCollection;
5515		_length += 1;
5516	}
5517
5518
5519	return ob;
5520}());
5521function BaseRenderer(){}
5522BaseRenderer.prototype.checkLayers = function(num){
5523    var i, len = this.layers.length, data;
5524    this.completeLayers = true;
5525    for (i = len - 1; i >= 0; i--) {
5526        if (!this.elements[i]) {
5527            data = this.layers[i];
5528            if(data.ip - data.st <= (num - this.layers[i].st) && data.op - data.st > (num - this.layers[i].st))
5529            {
5530                this.buildItem(i);
5531            }
5532        }
5533        this.completeLayers = this.elements[i] ? this.completeLayers:false;
5534    }
5535    this.checkPendingElements();
5536};
5537
5538BaseRenderer.prototype.createItem = function(layer){
5539    switch(layer.ty){
5540        case 2:
5541            return this.createImage(layer);
5542        case 0:
5543            return this.createComp(layer);
5544        case 1:
5545            return this.createSolid(layer);
5546        case 4:
5547            return this.createShape(layer);
5548        case 5:
5549            return this.createText(layer);
5550        case 13:
5551            return this.createCamera(layer);
5552        case 99:
5553            return null;
5554    }
5555    return this.createBase(layer);
5556};
5557
5558BaseRenderer.prototype.createCamera = function(){
5559    throw new Error('You\'re using a 3d camera. Try the html renderer.');
5560}
5561
5562BaseRenderer.prototype.buildAllItems = function(){
5563    var i, len = this.layers.length;
5564    for(i=0;i<len;i+=1){
5565        this.buildItem(i);
5566    }
5567    this.checkPendingElements();
5568};
5569
5570BaseRenderer.prototype.includeLayers = function(newLayers){
5571    this.completeLayers = false;
5572    var i, len = newLayers.length;
5573    var j, jLen = this.layers.length;
5574    for(i=0;i<len;i+=1){
5575        j = 0;
5576        while(j<jLen){
5577            if(this.layers[j].id == newLayers[i].id){
5578                this.layers[j] = newLayers[i];
5579                break;
5580            }
5581            j += 1;
5582        }
5583    }
5584};
5585
5586BaseRenderer.prototype.setProjectInterface = function(pInterface){
5587    this.globalData.projectInterface = pInterface;
5588};
5589
5590BaseRenderer.prototype.initItems = function(){
5591    if(!this.globalData.progressiveLoad){
5592        this.buildAllItems();
5593    }
5594};
5595BaseRenderer.prototype.buildElementParenting = function(element, parentName, hierarchy){
5596    hierarchy = hierarchy || [];
5597    var elements = this.elements;
5598    var layers = this.layers;
5599    var i=0, len = layers.length;
5600    while(i<len){
5601        if(layers[i].ind == parentName){
5602            if(!elements[i] || elements[i] === true){
5603                this.buildItem(i);
5604                this.addPendingElement(element);
5605            } else if(layers[i].parent !== undefined){
5606                hierarchy.push(elements[i]);
5607                elements[i]._isParent = true;
5608                this.buildElementParenting(element,layers[i].parent, hierarchy);
5609            } else {
5610                hierarchy.push(elements[i]);
5611                elements[i]._isParent = true;
5612                element.setHierarchy(hierarchy);
5613            }
5614
5615
5616        }
5617        i += 1;
5618    }
5619};
5620
5621BaseRenderer.prototype.addPendingElement = function(element){
5622    this.pendingElements.push(element);
5623};
5624function SVGRenderer(animationItem, config){
5625    this.animationItem = animationItem;
5626    this.layers = null;
5627    this.renderedFrame = -1;
5628    this.globalData = {
5629        frameNum: -1
5630    };
5631    this.renderConfig = {
5632        preserveAspectRatio: (config && config.preserveAspectRatio) || 'xMidYMid meet',
5633        progressiveLoad: (config && config.progressiveLoad) || false,
5634        hideOnTransparent: (config && config.hideOnTransparent === false) ? false : true,
5635        viewBoxOnly: (config && config.viewBoxOnly) || false,
5636        className: (config && config.className) || ''
5637    };
5638    this.globalData.renderConfig = this.renderConfig;
5639    this.elements = [];
5640    this.pendingElements = [];
5641    this.destroyed = false;
5642
5643}
5644
5645extendPrototype(BaseRenderer,SVGRenderer);
5646
5647SVGRenderer.prototype.createBase = function (data) {
5648    return new SVGBaseElement(data, this.layerElement,this.globalData,this);
5649};
5650
5651SVGRenderer.prototype.createShape = function (data) {
5652    return new IShapeElement(data, this.layerElement,this.globalData,this);
5653};
5654
5655SVGRenderer.prototype.createText = function (data) {
5656    return new SVGTextElement(data, this.layerElement,this.globalData,this);
5657
5658};
5659
5660SVGRenderer.prototype.createImage = function (data) {
5661    return new IImageElement(data, this.layerElement,this.globalData,this);
5662};
5663
5664SVGRenderer.prototype.createComp = function (data) {
5665    return new ICompElement(data, this.layerElement,this.globalData,this);
5666
5667};
5668
5669SVGRenderer.prototype.createSolid = function (data) {
5670    return new ISolidElement(data, this.layerElement,this.globalData,this);
5671};
5672
5673SVGRenderer.prototype.configAnimation = function(animData){
5674    this.layerElement = document.createElementNS(svgNS,'svg');
5675    this.layerElement.setAttribute('xmlns','http://www.w3.org/2000/svg');
5676    this.layerElement.setAttribute('viewBox','0 0 '+animData.w+' '+animData.h);
5677    if(!this.renderConfig.viewBoxOnly) {
5678        this.layerElement.setAttribute('width',animData.w);
5679        this.layerElement.setAttribute('height',animData.h);
5680        this.layerElement.style.width = '100%';
5681        this.layerElement.style.height = '100%';
5682    }
5683    if(this.renderConfig.className) {
5684        this.layerElement.setAttribute('class', this.renderConfig.className);
5685    }
5686    this.layerElement.setAttribute('preserveAspectRatio',this.renderConfig.preserveAspectRatio);
5687    //this.layerElement.style.transform = 'translate3d(0,0,0)';
5688    //this.layerElement.style.transformOrigin = this.layerElement.style.mozTransformOrigin = this.layerElement.style.webkitTransformOrigin = this.layerElement.style['-webkit-transform'] = "0px 0px 0px";
5689    this.animationItem.wrapper.appendChild(this.layerElement);
5690    //Mask animation
5691    var defs = document.createElementNS(svgNS, 'defs');
5692    this.globalData.defs = defs;
5693    this.layerElement.appendChild(defs);
5694    this.globalData.getAssetData = this.animationItem.getAssetData.bind(this.animationItem);
5695    this.globalData.getAssetsPath = this.animationItem.getAssetsPath.bind(this.animationItem);
5696    this.globalData.progressiveLoad = this.renderConfig.progressiveLoad;
5697    this.globalData.frameId = 0;
5698    this.globalData.nm = animData.nm;
5699    this.globalData.compSize = {
5700        w: animData.w,
5701        h: animData.h
5702    };
5703    this.data = animData;
5704    this.globalData.frameRate = animData.fr;
5705    var maskElement = document.createElementNS(svgNS, 'clipPath');
5706    var rect = document.createElementNS(svgNS,'rect');
5707    rect.setAttribute('width',animData.w);
5708    rect.setAttribute('height',animData.h);
5709    rect.setAttribute('x',0);
5710    rect.setAttribute('y',0);
5711    var maskId = 'animationMask_'+randomString(10);
5712    maskElement.setAttribute('id', maskId);
5713    maskElement.appendChild(rect);
5714    var maskedElement = document.createElementNS(svgNS,'g');
5715    maskedElement.setAttribute("clip-path", "url(" + locationHref + "#"+maskId+")");
5716    this.layerElement.appendChild(maskedElement);
5717    defs.appendChild(maskElement);
5718    this.layerElement = maskedElement;
5719    this.layers = animData.layers;
5720    this.globalData.fontManager = new FontManager();
5721    this.globalData.fontManager.addChars(animData.chars);
5722    this.globalData.fontManager.addFonts(animData.fonts,defs);
5723    this.elements = Array.apply(null,{length:animData.layers.length});
5724};
5725
5726
5727SVGRenderer.prototype.destroy = function () {
5728    this.animationItem.wrapper.innerHTML = '';
5729    this.layerElement = null;
5730    this.globalData.defs = null;
5731    var i, len = this.layers ? this.layers.length : 0;
5732    for (i = 0; i < len; i++) {
5733        if(this.elements[i]){
5734            this.elements[i].destroy();
5735        }
5736    }
5737    this.elements.length = 0;
5738    this.destroyed = true;
5739    this.animationItem = null;
5740};
5741
5742SVGRenderer.prototype.updateContainerSize = function () {
5743};
5744
5745SVGRenderer.prototype.buildItem  = function(pos){
5746    var elements = this.elements;
5747    if(elements[pos] || this.layers[pos].ty == 99){
5748        return;
5749    }
5750    elements[pos] = true;
5751    var element = this.createItem(this.layers[pos]);
5752
5753    elements[pos] = element;
5754    if(expressionsPlugin){
5755        if(this.layers[pos].ty === 0){
5756            this.globalData.projectInterface.registerComposition(element);
5757        }
5758        element.initExpressions();
5759    }
5760    this.appendElementInPos(element,pos);
5761    if(this.layers[pos].tt){
5762        if(!this.elements[pos - 1] || this.elements[pos - 1] === true){
5763            this.buildItem(pos - 1);
5764            this.addPendingElement(element);
5765        } else {
5766            element.setMatte(elements[pos - 1].layerId);
5767        }
5768    }
5769};
5770
5771SVGRenderer.prototype.checkPendingElements  = function(){
5772    while(this.pendingElements.length){
5773        var element = this.pendingElements.pop();
5774        element.checkParenting();
5775        if(element.data.tt){
5776            var i = 0, len = this.elements.length;
5777            while(i<len){
5778                if(this.elements[i] === element){
5779                    element.setMatte(this.elements[i - 1].layerId);
5780                    break;
5781                }
5782                i += 1;
5783            }
5784        }
5785    }
5786};
5787
5788SVGRenderer.prototype.renderFrame = function(num){
5789    if(this.renderedFrame == num || this.destroyed){
5790        return;
5791    }
5792    if(num === null){
5793        num = this.renderedFrame;
5794    }else{
5795        this.renderedFrame = num;
5796    }
5797    //clearPoints();
5798    /*console.log('-------');
5799    console.log('FRAME ',num);*/
5800    this.globalData.frameNum = num;
5801    this.globalData.frameId += 1;
5802    this.globalData.projectInterface.currentFrame = num;
5803    var i, len = this.layers.length;
5804    if(!this.completeLayers){
5805        this.checkLayers(num);
5806    }
5807    for (i = len - 1; i >= 0; i--) {
5808        if(this.completeLayers || this.elements[i]){
5809            this.elements[i].prepareFrame(num - this.layers[i].st);
5810        }
5811    }
5812    for (i = len - 1; i >= 0; i--) {
5813        if(this.completeLayers || this.elements[i]){
5814            this.elements[i].renderFrame();
5815        }
5816    }
5817};
5818
5819SVGRenderer.prototype.appendElementInPos = function(element, pos){
5820    var newElement = element.getBaseElement();
5821    if(!newElement){
5822        return;
5823    }
5824    var i = 0;
5825    var nextElement;
5826    while(i<pos){
5827        if(this.elements[i] && this.elements[i]!== true && this.elements[i].getBaseElement()){
5828            nextElement = this.elements[i].getBaseElement();
5829        }
5830        i += 1;
5831    }
5832    if(nextElement){
5833        this.layerElement.insertBefore(newElement, nextElement);
5834    } else {
5835        this.layerElement.appendChild(newElement);
5836    }
5837};
5838
5839SVGRenderer.prototype.hide = function(){
5840    this.layerElement.style.display = 'none';
5841};
5842
5843SVGRenderer.prototype.show = function(){
5844    this.layerElement.style.display = 'block';
5845};
5846
5847SVGRenderer.prototype.searchExtraCompositions = function(assets){
5848    var i, len = assets.length;
5849    var floatingContainer = document.createElementNS(svgNS,'g');
5850    for(i=0;i<len;i+=1){
5851        if(assets[i].xt){
5852            var comp = this.createComp(assets[i],floatingContainer,this.globalData.comp,null);
5853            comp.initExpressions();
5854            //comp.compInterface = CompExpressionInterface(comp);
5855            //Expressions.addLayersInterface(comp.elements, this.globalData.projectInterface);
5856            this.globalData.projectInterface.registerComposition(comp);
5857        }
5858    }
5859};
5860
5861function MaskElement(data,element,globalData) {
5862    this.dynamicProperties = [];
5863    this.data = data;
5864    this.element = element;
5865    this.globalData = globalData;
5866    this.storedData = [];
5867    this.masksProperties = this.data.masksProperties;
5868    this.viewData = Array.apply(null,{length:this.masksProperties.length});
5869    this.maskElement = null;
5870    this.firstFrame = true;
5871    var defs = this.globalData.defs;
5872    var i, len = this.masksProperties.length;
5873
5874
5875    var path, properties = this.masksProperties;
5876    var count = 0;
5877    var currentMasks = [];
5878    var j, jLen;
5879    var layerId = randomString(10);
5880    var rect, expansor, feMorph,x;
5881    var maskType = 'clipPath', maskRef = 'clip-path';
5882    for (i = 0; i < len; i++) {
5883
5884        if((properties[i].mode !== 'a' && properties[i].mode !== 'n')|| properties[i].inv || properties[i].o.k !== 100){
5885            maskType = 'mask';
5886            maskRef = 'mask';
5887        }
5888
5889        if((properties[i].mode == 's' || properties[i].mode == 'i') && count == 0){
5890            rect = document.createElementNS(svgNS, 'rect');
5891            rect.setAttribute('fill', '#ffffff');
5892            rect.setAttribute('width', this.element.comp.data.w);
5893            rect.setAttribute('height', this.element.comp.data.h);
5894            currentMasks.push(rect);
5895        } else {
5896            rect = null;
5897        }
5898
5899        path = document.createElementNS(svgNS, 'path');
5900        if(properties[i].mode == 'n') {
5901            this.viewData[i] = {
5902                op: PropertyFactory.getProp(this.element,properties[i].o,0,0.01,this.dynamicProperties),
5903                prop: ShapePropertyFactory.getShapeProp(this.element,properties[i],3,this.dynamicProperties,null),
5904                elem: path
5905            };
5906            defs.appendChild(path);
5907            continue;
5908        }
5909        count += 1;
5910
5911        if(properties[i].mode == 's'){
5912            path.setAttribute('fill', '#000000');
5913        }else{
5914            path.setAttribute('fill', '#ffffff');
5915        }
5916        path.setAttribute('clip-rule','nonzero');
5917
5918        if(properties[i].x.k !== 0){
5919            maskType = 'mask';
5920            maskRef = 'mask';
5921            x = PropertyFactory.getProp(this.element,properties[i].x,
59210,null,this.dynamicProperties);
5922            var filterID = 'fi_'+randomString(10);
5923            expansor = document.createElementNS(svgNS,'filter');
5924            expansor.setAttribute('id',filterID);
5925            feMorph = document.createElementNS(svgNS,'feMorphology');
5926            feMorph.setAttribute('operator','dilate');
5927            feMorph.setAttribute('in','SourceGraphic');
5928            feMorph.setAttribute('radius','0');
5929            expansor.appendChild(feMorph);
5930            defs.appendChild(expansor);
5931            if(properties[i].mode == 's'){
5932                path.setAttribute('stroke', '#000000');
5933            }else{
5934                path.setAttribute('stroke', '#ffffff');
5935            }
5936        }else{
5937            feMorph = null;
5938            x = null;
5939        }
5940
5941
5942        this.storedData[i] = {
5943             elem: path,
5944             x: x,
5945             expan: feMorph,
5946            lastPath: '',
5947            lastOperator:'',
5948            filterId:filterID,
5949            lastRadius:0
5950        };
5951        if(properties[i].mode == 'i'){
5952            jLen = currentMasks.length;
5953            var g = document.createElementNS(svgNS,'g');
5954            for(j=0;j<jLen;j+=1){
5955                g.appendChild(currentMasks[j]);
5956            }
5957            var mask = document.createElementNS(svgNS,'mask');
5958            mask.setAttribute('mask-type','alpha');
5959            mask.setAttribute('id',layerId+'_'+count);
5960            mask.appendChild(path);
5961            defs.appendChild(mask);
5962            g.setAttribute('mask','url(' + locationHref + '#'+layerId+'_'+count+')');
5963
5964            currentMasks.length = 0;
5965            currentMasks.push(g);
5966        }else{
5967            currentMasks.push(path);
5968        }
5969        if(properties[i].inv && !this.solidPath){
5970            this.solidPath = this.createLayerSolidPath();
5971        }
5972        this.viewData[i] = {
5973            elem: path,
5974            lastPath: '',
5975            op: PropertyFactory.getProp(this.element,properties[i].o,0,0.01,this.dynamicProperties),
5976            prop:ShapePropertyFactory.getShapeProp(this.element,properties[i],3,this.dynamicProperties,null)
5977        };
5978        if(rect){
5979            this.viewData[i].invRect = rect;
5980        }
5981        if(!this.viewData[i].prop.k){
5982            this.drawPath(properties[i],this.viewData[i].prop.v,this.viewData[i]);
5983        }
5984    }
5985
5986    this.maskElement = document.createElementNS(svgNS, maskType);
5987
5988    len = currentMasks.length;
5989    for(i=0;i<len;i+=1){
5990        this.maskElement.appendChild(currentMasks[i]);
5991    }
5992
5993    this.maskElement.setAttribute('id', layerId);
5994    if(count > 0){
5995        this.element.maskedElement.setAttribute(maskRef, "url(" + locationHref + "#" + layerId + ")");
5996    }
5997
5998    defs.appendChild(this.maskElement);
5999};
6000
6001MaskElement.prototype.getMaskProperty = function(pos){
6002    return this.viewData[pos].prop;
6003};
6004
6005MaskElement.prototype.prepareFrame = function(){
6006    var i, len = this.dynamicProperties.length;
6007    for(i=0;i<len;i+=1){
6008        this.dynamicProperties[i].getValue();
6009
6010    }
6011};
6012
6013MaskElement.prototype.renderFrame = function (finalMat) {
6014    var i, len = this.masksProperties.length;
6015    for (i = 0; i < len; i++) {
6016        if(this.viewData[i].prop.mdf || this.firstFrame){
6017            this.drawPath(this.masksProperties[i],this.viewData[i].prop.v,this.viewData[i]);
6018        }
6019        if(this.viewData[i].op.mdf || this.firstFrame){
6020            this.viewData[i].elem.setAttribute('fill-opacity',this.viewData[i].op.v);
6021        }
6022        if(this.masksProperties[i].mode !== 'n'){
6023            if(this.viewData[i].invRect && (this.element.finalTransform.mProp.mdf || this.firstFrame)){
6024                this.viewData[i].invRect.setAttribute('x', -finalMat.props[12]);
6025                this.viewData[i].invRect.setAttribute('y', -finalMat.props[13]);
6026            }
6027            if(this.storedData[i].x && (this.storedData[i].x.mdf || this.firstFrame)){
6028                var feMorph = this.storedData[i].expan;
6029                if(this.storedData[i].x.v < 0){
6030                    if(this.storedData[i].lastOperator !== 'erode'){
6031                        this.storedData[i].lastOperator = 'erode';
6032                        this.storedData[i].elem.setAttribute('filter','url(' + locationHref + '#'+this.storedData[i].filterId+')');
6033                    }
6034                    feMorph.setAttribute('radius',-this.storedData[i].x.v);
6035                }else{
6036                    if(this.storedData[i].lastOperator !== 'dilate'){
6037                        this.storedData[i].lastOperator = 'dilate';
6038                        this.storedData[i].elem.setAttribute('filter',null);
6039                    }
6040                    this.storedData[i].elem.setAttribute('stroke-width', this.storedData[i].x.v*2);
6041
6042                }
6043            }
6044        }
6045    }
6046    this.firstFrame = false;
6047};
6048
6049MaskElement.prototype.getMaskelement = function () {
6050    return this.maskElement;
6051};
6052
6053MaskElement.prototype.createLayerSolidPath = function(){
6054    var path = 'M0,0 ';
6055    path += ' h' + this.globalData.compSize.w ;
6056    path += ' v' + this.globalData.compSize.h ;
6057    path += ' h-' + this.globalData.compSize.w ;
6058    path += ' v-' + this.globalData.compSize.h + ' ';
6059    return path;
6060};
6061
6062MaskElement.prototype.drawPath = function(pathData,pathNodes,viewData){
6063    var pathString = " M"+pathNodes.v[0][0]+','+pathNodes.v[0][1];
6064    var i, len;
6065    len = pathNodes._length;
6066    for(i=1;i<len;i+=1){
6067        //pathString += " C"+pathNodes.o[i-1][0]+','+pathNodes.o[i-1][1] + " "+pathNodes.i[i][0]+','+pathNodes.i[i][1] + " "+pathNodes.v[i][0]+','+pathNodes.v[i][1];
6068        pathString += " C"+bm_rnd(pathNodes.o[i-1][0])+','+bm_rnd(pathNodes.o[i-1][1]) + " "+bm_rnd(pathNodes.i[i][0])+','+bm_rnd(pathNodes.i[i][1]) + " "+bm_rnd(pathNodes.v[i][0])+','+bm_rnd(pathNodes.v[i][1]);
6069    }
6070        //pathString += " C"+pathNodes.o[i-1][0]+','+pathNodes.o[i-1][1] + " "+pathNodes.i[0][0]+','+pathNodes.i[0][1] + " "+pathNodes.v[0][0]+','+pathNodes.v[0][1];
6071    if(pathNodes.c && len > 1){
6072        pathString += " C"+bm_rnd(pathNodes.o[i-1][0])+','+bm_rnd(pathNodes.o[i-1][1]) + " "+bm_rnd(pathNodes.i[0][0])+','+bm_rnd(pathNodes.i[0][1]) + " "+bm_rnd(pathNodes.v[0][0])+','+bm_rnd(pathNodes.v[0][1]);
6073    }
6074    //pathNodes.__renderedString = pathString;
6075
6076
6077    if(viewData.lastPath !== pathString){
6078        if(viewData.elem){
6079            if(!pathNodes.c){
6080                viewData.elem.setAttribute('d','');
6081            }else if(pathData.inv){
6082                viewData.elem.setAttribute('d',this.solidPath + pathString);
6083            }else{
6084                viewData.elem.setAttribute('d',pathString);
6085            }
6086        }
6087        viewData.lastPath = pathString;
6088    }
6089};
6090
6091MaskElement.prototype.destroy = function(){
6092    this.element = null;
6093    this.globalData = null;
6094    this.maskElement = null;
6095    this.data = null;
6096    this.masksProperties = null;
6097};
6098function BaseElement(){
6099};
6100BaseElement.prototype.checkMasks = function(){
6101    if(!this.data.hasMask){
6102        return false;
6103    }
6104    var i = 0, len = this.data.masksProperties.length;
6105    while(i<len) {
6106        if((this.data.masksProperties[i].mode !== 'n' && this.data.masksProperties[i].cl !== false)) {
6107            return true;
6108        }
6109        i += 1;
6110    }
6111    return false;
6112}
6113
6114BaseElement.prototype.checkParenting = function(){
6115    if(this.data.parent !== undefined){
6116        this.comp.buildElementParenting(this, this.data.parent);
6117    }
6118}
6119
6120BaseElement.prototype.prepareFrame = function(num){
6121    if(this.data.ip - this.data.st <= num && this.data.op - this.data.st > num)
6122    {
6123        if(this.isVisible !== true){
6124            this.elemMdf = true;
6125            this.globalData.mdf = true;
6126            this.isVisible = true;
6127            this.firstFrame = true;
6128            if(this.data.hasMask){
6129                this.maskManager.firstFrame = true;
6130            }
6131        }
6132    }else{
6133        if(this.isVisible !== false){
6134            this.elemMdf = true;
6135            this.globalData.mdf = true;
6136            this.isVisible = false;
6137        }
6138    }
6139    var i, len = this.dynamicProperties.length;
6140    for(i=0;i<len;i+=1){
6141        if(this.isVisible || (this._isParent && this.dynamicProperties[i].type === 'transform')){
6142            this.dynamicProperties[i].getValue();
6143            if(this.dynamicProperties[i].mdf){
6144                this.elemMdf = true;
6145                this.globalData.mdf = true;
6146            }
6147        }
6148    }
6149    if(this.data.hasMask && this.isVisible){
6150        this.maskManager.prepareFrame(num*this.data.sr);
6151    }
6152    
6153    /* TODO check this
6154    if(this.data.sy){
6155        if(this.data.sy[0].renderedData[num]){
6156            if(this.data.sy[0].renderedData[num].c){
6157                this.feFlood.setAttribute('flood-color','rgb('+Math.round(this.data.sy[0].renderedData[num].c[0])+','+Math.round(this.data.sy[0].renderedData[num].c[1])+','+Math.round(this.data.sy[0].renderedData[num].c[2])+')');
6158            }
6159            if(this.data.sy[0].renderedData[num].s){
6160                this.feMorph.setAttribute('radius',this.data.sy[0].renderedData[num].s);
6161            }
6162        }
6163    }
6164    */
6165
6166
6167    this.currentFrameNum = num*this.data.sr;
6168    return this.isVisible;
6169};
6170
6171BaseElement.prototype.globalToLocal = function(pt){
6172    var transforms = [];
6173    transforms.push(this.finalTransform);
6174    var flag = true;
6175    var comp = this.comp;
6176    while(flag){
6177        if(comp.finalTransform){
6178            if(comp.data.hasMask){
6179                transforms.splice(0,0,comp.finalTransform);
6180            }
6181            comp = comp.comp;
6182        } else {
6183            flag = false;
6184        }
6185    }
6186    var i, len = transforms.length,ptNew;
6187    for(i=0;i<len;i+=1){
6188        ptNew = transforms[i].mat.applyToPointArray(0,0,0);
6189        //ptNew = transforms[i].mat.applyToPointArray(pt[0],pt[1],pt[2]);
6190        pt = [pt[0] - ptNew[0],pt[1] - ptNew[1],0];
6191    }
6192    return pt;
6193};
6194
6195BaseElement.prototype.initExpressions = function(){
6196    this.layerInterface = LayerExpressionInterface(this);
6197    //layers[i].layerInterface = LayerExpressionInterface(layers[i]);
6198    //layers[i].layerInterface = LayerExpressionInterface(layers[i]);
6199    if(this.data.hasMask){
6200        this.layerInterface.registerMaskInterface(this.maskManager);
6201    }
6202    var effectsInterface = EffectsExpressionInterface.createEffe
6202ctsInterface(this,this.layerInterface);
6203    this.layerInterface.registerEffectsInterface(effectsInterface);
6204
6205    if(this.data.ty === 0 || this.data.xt){
6206        this.compInterface = CompExpressionInterface(this);
6207    } else if(this.data.ty === 4){
6208        this.layerInterface.shapeInterface = ShapeExpressionInterface.createShapeInterface(this.shapesData,this.itemsData,this.layerInterface);
6209    } else if(this.data.ty === 5){
6210        this.layerInterface.textInterface = TextExpressionInterface(this);
6211    }
6212}
6213
6214BaseElement.prototype.setBlendMode = function(){
6215    var blendModeValue = '';
6216    switch(this.data.bm){
6217        case 1:
6218            blendModeValue = 'multiply';
6219            break;
6220        case 2:
6221            blendModeValue = 'screen';
6222            break;
6223        case 3:
6224            blendModeValue = 'overlay';
6225            break;
6226        case 4:
6227            blendModeValue = 'darken';
6228            break;
6229        case 5:
6230            blendModeValue = 'lighten';
6231            break;
6232        case 6:
6233            blendModeValue = 'color-dodge';
6234            break;
6235        case 7:
6236            blendModeValue = 'color-burn';
6237            break;
6238        case 8:
6239            blendModeValue = 'hard-light';
6240            break;
6241        case 9:
6242            blendModeValue = 'soft-light';
6243            break;
6244        case 10:
6245            blendModeValue = 'difference';
6246            break;
6247        case 11:
6248            blendModeValue = 'exclusion';
6249            break;
6250        case 12:
6251            blendModeValue = 'hue';
6252            break;
6253        case 13:
6254            blendModeValue = 'saturation';
6255            break;
6256        case 14:
6257            blendModeValue = 'color';
6258            break;
6259        case 15:
6260            blendModeValue = 'luminosity';
6261            break;
6262    }
6263    var elem = this.baseElement || this.layerElement;
6264
6265    elem.style['mix-blend-mode'] = blendModeValue;
6266}
6267
6268BaseElement.prototype.init = function(){
6269    if(!this.data.sr){
6270        this.data.sr = 1;
6271    }
6272    this.dynamicProperties = this.dynamicProperties || [];
6273    if(this.data.ef){
6274        this.effects = new EffectsManager(this.data,this,this.dynamicProperties);
6275        //this.effect = this.effectsManager.bind(this.effectsManager);
6276    }
6277    //this.elemInterface = buildLayerExpressionInterface(this);
6278    this.hidden = false;
6279    this.firstFrame = true;
6280    this.isVisible = false;
6281    this._isParent = false;
6282    this.currentFrameNum = -99999;
6283    this.lastNum = -99999;
6284    if(this.data.ks){
6285        this.finalTransform = {
6286            mProp: PropertyFactory.getProp(this,this.data.ks,2,null,this.dynamicProperties),
6287            matMdf: false,
6288            opMdf: false,
6289            mat: new Matrix(),
6290            opacity: 1
6291        };
6292        if(this.data.ao){
6293            this.finalTransform.mProp.autoOriented = true;
6294        }
6295        this.finalTransform.op = this.finalTransform.mProp.o;
6296        this.transform = this.finalTransform.mProp;
6297        if(this.data.ty !== 11){
6298            this.createElements();
6299        }
6300        if(this.data.hasMask){
6301            this.addMasks(this.data);
6302        }
6303    }
6304    this.elemMdf = false;
6305};
6306BaseElement.prototype.getType = function(){
6307    return this.type;
6308};
6309
6310BaseElement.prototype.resetHierarchy = function(){
6311    if(!this.hierarchy){
6312        this.hierarchy = [];
6313    }else{
6314        this.hierarchy.length = 0;
6315    }
6316};
6317
6318BaseElement.prototype.getHierarchy = function(){
6319    if(!this.hierarchy){
6320        this.hierarchy = [];
6321    }
6322    return this.hierarchy;
6323};
6324
6325BaseElement.prototype.setHierarchy = function(hierarchy){
6326    this.hierarchy = hierarchy;
6327};
6328
6329BaseElement.prototype.getLayerSize = function(){
6330    if(this.data.ty === 5){
6331        return {w:this.data.textData.width,h:this.data.textData.height};
6332    }else{
6333        return {w:this.data.width,h:this.data.height};
6334    }
6335};
6336
6337BaseElement.prototype.hide = function(){
6338
6339};
6340
6341BaseElement.prototype.sourceRectAtTime = function(){
6342    return {
6343        top:0,
6344        left:0,
6345        width:100,
6346        height:100
6347    }
6348};
6349
6350BaseElement.prototype.mHelper = new Matrix();
6351function SVGBaseElement(data,parentContainer,globalData,comp, placeholder){
6352    this.globalData = globalData;
6353    this.comp = comp;
6354    this.data = data;
6355    this.matteElement = null;
6356    this.transformedElement = null;
6357    this.isTransparent = false;
6358    this.parentContainer = parentContainer;
6359    this.layerId = placeholder ? placeholder.layerId : 'ly_'+randomString(10);
6360    this.placeholder = placeholder;
6361    this._sizeChanged = false;
6362    this.init();
6363};
6364
6365createElement(BaseElement, SVGBaseElement);
6366
6367SVGBaseElement.prototype.createElements = function(){
6368    this.layerElement = document.createElementNS(svgNS,'g');
6369    this.transformedElement = this.layerElement;
6370    if(this.data.hasMask){
6371        this.maskedElement = this.layerElement;
6372    }
6373    var layerElementParent = null;
6374    if(this.data.td){
6375        if(this.data.td == 3 || this.data.td == 1){
6376            var masker = document.createElementNS(svgNS,'mask');
6377            masker.setAttribute('id',this.layerId);
6378            masker.setAttribute('mask-type',this.data.td == 3 ? 'luminance':'alpha');
6379            masker.appendChild(this.layerElement);
6380            layerElementParent = masker;
6381            this.globalData.defs.appendChild(masker);
6382            ////// This is only for IE and Edge when mask if of type alpha
6383            if(!featureSupport.maskType && this.data.td == 1){
6384                masker.setAttribute('mask-type','luminance');
6385                var filId = randomString(10);
6386                var fil = filtersFactory.createFilter(filId);
6387                this.globalData.defs.appendChild(fil);
6388                fil.appendChild(filtersFactory.createAlphaToLuminanceFilter());
6389                var gg = document.createElementNS(svgNS,'g');
6390                gg.appendChild(this.layerElement);
6391                layerElementParent = gg;
6392                masker.appendChild(gg);
6393                gg.setAttribute('filter','url(' + locationHref + '#'+filId+')');
6394            }
6395        }else if(this.data.td == 2){
6396            var maskGroup = document.createElementNS(svgNS,'mask');
6397            maskGroup.setAttribute('id',this.layerId);
6398            maskGroup.setAttribute('mask-type','alpha');
6399            var maskGrouper = document.createElementNS(svgNS,'g');
6400            maskGroup.appendChild(maskGrouper);
6401            var filId = randomString(10);
6402            var fil = filtersFactory.createFilter(filId);
6403            ////
6404
6405            var feColorMatrix = document.createElementNS(svgNS,'feColorMatrix');
6406            feColorMatrix.setAttribute('type','matrix');
6407            feColorMatrix.setAttribute('color-interpolation-filters','sRGB');
6408            feColorMatrix.setAttribute('values','1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 -1 1');
6409            fil.appendChild(feColorMatrix);
6410
6411            ////
6412            /*var feCTr = document.createElementNS(svgNS,'feComponentTransfer');
6413            feCTr.setAttribute('in','SourceGraphic');
6414            fil.appendChild(feCTr);
6415            var feFunc = document.createElementNS(svgNS,'feFuncA');
6416            feFunc.setAttribute('type','table');
6417            feFunc.setAttribute('tableValues','1.0 0.0');
6418            feCTr.appendChild(feFunc);*/
6419            this.globalData.defs.appendChild(fil);
6420            var alphaRect = document.createElementNS(svgNS,'rect');
6421            alphaRect.setAttribute('width',this.comp.data.w);
6422            alphaRect.setAttribute('height',this.comp.data.h);
6423            alphaRect.setAttribute('x','0');
6424            alphaRect.setAttribute('y','0');
6425            alphaRect.setAttribute('fill','#ffffff');
6426            alphaRect.setAttribute('opacity','0');
6427            maskGrouper.setAttribute('filter','url(' + locationHref + '#'+filId+')');
6428            maskGrouper.appendChild(alphaRect);
6429            maskGrouper.appendChild(this.layerElement);
6430            layerElementParent = maskGrouper;
6431            if(!featureSupport.maskType){
6432                maskGroup.setAttribute('mask-type','luminance');
6433                fil.appendChild(filtersFactory.createAlphaToLuminanceFilter());
6434                var gg = document.createElementNS(svgNS,'g');
6435                maskGrouper.appendChild(alphaRect);
6436                gg.appendChild(this.layerElement);
6437                layerElementParent = gg;
6438                maskGrouper.appendChild(gg);
6439            }
6440            this.globalData.defs.appendChild(maskGroup);
6441        }
6442    }else if(this.data.hasMask || this.data.tt){
6443        if(this.data.tt){
6444            this.matteElement = document.createElementNS(svgNS,'g');
6445            this.matteElement.appendChild(this.layerElement);
6446            layerElementParent = this.matteElement;
6447            this.baseElement = this.matteElement;
6448        }else{
6449            this.baseElement = this.layerElement;
6450        }
6451    }else{
6452        this.baseElement = this.layerElement;
6453    }
6454    if((this.data.ln || this.data.cl) && (this.data.ty === 4 || this.data.ty === 0)){
6455        if(this.data.ln){
6456            this.layerElement.setAttribute('id',this.data.ln);
6457        }
6458        if(this.data.cl){
6459            this.layerElement.setAttribute('class',this.data.cl);
6460        }
6461    }
6462    if(this.data.ty === 0){
6463            var cp = document.createElementNS(svgNS, 'clipPath');
6464            var pt = document.createElementNS(svgNS,'path');
6465            pt.setAttribute('d','M0,0 L'+this.data.w+',0'+' L'+this.data.w+','+this.data.h+' L0,'+this.data.h+'z');
6466            var clipId = 'cp_'+randomString(8);
6467            cp.setAttribute('id',clipId);
6468            cp.appendChild(pt);
6469            this.globalData.defs.appendChild(cp);
6470        if(this.checkMasks()){
6471            var cpGroup = document.createElementNS(svgNS,'g');
6472            cpGroup.setAttribute('clip-path','url(' + locationHref + '#'+clipId+')');
6473            cpGroup.appendChild(this.layerElement);
6474            this.transformedElement = cpGroup;
6475            if(layerElementParent){
6476                layerElementParent.appendChild(this.transformedElement);
6477            } else {
6478                this.baseElement = this.transformedElement;
6479            }
6480        } else {
6481            this.layerElement.setAttribute('clip-path','url(' + locationHref + '#'+clipId+')');
6482        }
6483        
6484    }
6485    if(this.data.bm !== 0){
6486        this.setBlendMode();
6487    }
6488    if(this.layerElement !== this.parentContainer){
6489        this.placeholder = null;
6490    }
6491    /* Todo performance killer
6492    if(this.data.sy){
6493        var filterID = 'st_'+randomString(10);
6494        var c = this.data.sy[0].c.k;
6495        var r = this.data.sy[0].s.k;
6496        var expansor = document.createElementNS(svgNS,'filter');
6497        expansor.setAttribute('id',filterID);
6498        var feFlood = document.createElementNS(svgNS,'feFlood');
6499        this.feFlood = feFlood;
6500        if(!c[0].e){
6501            feFlood.setAttribute('flood-color','rgb('+c[0]+','+c[1]+','+c[2]+')');
6502        }
6503        feFlood.setAttribute('result','base');
6504        expansor.appendChild(feFlood);
6505        var feMorph = document.createElementNS(svgNS,'feMorphology');
6506        feMorph.setAttribute('operator','dilate');
6507        feMorph.setAttribute('in','SourceGraphic');
6508        feMorph.setAttribute('result','bigger');
6509        this.feMorph = feMorph;
6510        if(!r.length){
6511            feMorph.setAttribute('radius',this.data.sy[0].s.k);
6512        }
6513        expansor.appendChild(feMorph);
6514        var feColorMatrix = document.createElementNS(svgNS,'feColorMatrix');
6515        feColorMatrix.setAttribute('result','mask');
6516        feColorMatrix.setAttribute('in','bigger');
6517        feColorMatrix.setAttribute('type','matrix');
6518        feColorMatrix.setAttribute('values','0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0');
6519        expansor.appendChild(feColorMatrix);
6520        var feComposite = document.createElementNS(svgNS,'feComposite');
6521        feComposite.setAttribute('result','drop');
6522        feComposite.setAttribute('in','base');
6523        feComposite.setAttribute('in2','mask');
6524        feComposite.setAttribute('operator','in');
6525        expansor.appendChild(feComposite);
6526        var feBlend = document.createElementNS(svgNS,'feBlend');
6527        feBlend.setAttribute('in','SourceGraphic');
6528        feBlend.setAttribute('in2','drop');
6529        feBlend.setAttribute('mode','normal');
6530        expansor.appendChild(feBlend);
6531        this.globalData.defs.appendChild(expansor);
6532        var cont = document.createElementNS(svgNS,'g');
6533        if(this.layerElement === this.parentContainer){
6534            this.layerElement = cont;
6535        }else{
6536            cont.appendChild(this.layerElement);
6537        }
6538        cont.setAttribute('filter','url(#'+filterID+')');
6539        if(this.data.td){
6540            cont.setAttribute('data-td',this.data.td);
6541        }
6542        if(this.data.td == 3){
6543            this.globalData.defs.appendChild(cont);
6544        }else if(this.data.td == 2){
6545            maskGrouper.appendChild(cont);
6546        }else if(this.data.td == 1){
6547            masker.appendChild(cont);
6548        }else{
6549            if(this.data.hasMask && this.data.tt){
6550                this.matteElement.appendChild(cont);
6551            }else{
6552                this.appendNodeToParent(cont);
6553            }
6554        }
6555    }*/
6556    if(this.data.ef){
6557        this.effectsManager = new SVGEffects(this);
6558    }
6559    this.checkParenting();
6560};
6561
6562
6563SVGBaseElement.prototype.setBlendMode = BaseElement.prototype.setBlendMode;
6564
6565SVGBaseElement.prototype.renderFrame = function(parentTransform){
6566    if(this.data.ty === 3 || this.data.hd || !this.isVisible){
6567        return false;
6568    }
6569
6570    this.lastNum = this.currentFrameNum;
6571    this.finalTransform.opMdf = this.firstFrame || this.finalTransform.op.mdf;
6572    this.finalTransform.matMdf = this.firstFrame || this.finalTransform.mProp.mdf;
6573    this.finalTransform.opacity = this.finalTransform.op.v;
6574
6575    var mat;
6576    var finalMat = this.finalTransform.mat;
6577
6578    if(this.hierarchy){
6579        var i = 0, len = this.hierarchy.length;
6580        if(!this.finalTransform.matMdf) {
6581            while(i < len) {
6582                if(this.hierarchy[i].finalTransform.mProp.mdf) {
6583                    this.finalTransform.matMdf = true;
6584                    break;
6585                }
6586                i += 1;
6587            }
6588        }
6589        
6590        if(this.finalTransform.matMdf) {
6591            mat = this.finalTransform.mProp.v.props;
6592            finalMat.cloneFromProps(mat);
6593            for(i=0;i<len;i+=1){
6594                mat = this.hierarchy[i].finalTransform.mProp.v.props;
6595                finalMat.transform(mat[0],mat[1],mat[2],mat[3],mat[4],mat[5],mat[6],mat[7],mat[8],mat[9],mat[10],mat[11],mat[12],mat[13],mat[14],mat[15]);
6596            }
6597        }
6598        
6599    }else if(this.isVisible){
6600        finalMat = this.finalTransform.mProp.v;
6601    }
6602    if(this.finalTransform.matMdf && this.layerElement){
6603        this.transformedElement.setAttribute('transform',finalMat.to2dCSS());
6604    }
6605    if(this.finalTransform.opMdf && this.layerElement){
6606        if(this.finalTransform.op.v <= 0) {
6607            if(!this.isTransparent && this.globalData.renderConfig.hideOnTransparent){
6608                this.isTransparent = true;
6609                this.hide();
6610            }
6611        } else if(this.hidden && this.isTransparent){
6612            this.isTransparent = false;
6613            this.show();
6614        }
6615        this.transformedElement.setAttribute('opacity',this.finalTransform.op.v);
6616    }
6617
6618    if(this.data.hasMask){
6619        this.maskManager.renderFrame(finalMat);
6620    }
6621    if(this.effectsManager){
6622        this.effectsManager.renderFrame(this.firstFrame);
6623    }
6624    return this.isVisible;
6625};
6626
6627SVGBaseElement.prototype.destroy = function(){
6628    this.layerElement = null;
6629    this.parentContainer = null;
6630    if(this.matteElement) {
6631        this.matteElement = null;
6632    }
6633    if(this.maskManager) {
6634        this.maskManager.destroy();
6635    }
6636};
6637
6638SVGBaseElement.prototype.getBaseElement = function(){
6639    return this.baseElement;
6640};
6641SVGBaseElement.prototype.addMasks = function(data){
6642    this.maskManager = new MaskElement(data,this,this.globalData);
6643};
6644
6645SVGBaseElement.prototype.setMatte = function(id){
6646    if(!this.matteElement){
6647        return;
6648    }
6649    this.matteElement.setAttribute("mask", "url(" + locationHref + "#" + id + ")");
6650};
6651
6652SVGBaseElement.prototype.hide = function(){
6653    if(!this.hidden){
6654        this.layerElement.style.display = 'none';
6655        this.hidden = true;
6656    }
6657};
6658
6659SVGBaseElement.prototype.show = function(){
6660    if(this.isVisible && !this.isTransparent){
6661        this.hidden = false;
6662        this.layerElement.style.display = 'block';
6663    }
6664};
6665
6666function IShapeElement(data,parentContainer,globalData,comp, placeholder){
6667    this.shapes = [];
6668    this.shapesData = data.shapes;
6669    this.stylesList = [];
6670    this.itemsData = [];
6671    this.prevViewData = [];
6672    this.shapeModifiers = [];
6673    this.processedElements = [];
6674    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
6675}
6676createElement(SVGBaseElement, IShapeElement);
6677
6678IShapeElement.prototype.identityMatrix = new Matrix();
6679
6680IShapeElement.prototype.lcEnum = {
6681    '1': 'butt',
6682    '2': 'round',
6683    '3': 'square'
6684}
6685
6686IShapeElement.prototype.ljEnum = {
6687    '1': 'miter',
6688    '2': 'round',
6689    '3': 'butt'
6690}
6691
6692IShapeElement.prototype.searchProcessedElement = function(elem){
6693    var i = this.processedElements.length;
6694    while(i){
6695        i -= 1;
6696        if(this.processedElements[i].elem === elem){
6697            return this.processedElements[i].pos;
6698        }
6699    }
6700    return 0;
6701};
6702
6703IShapeElement.prototype.addProcessedElement = function(elem, pos){
6704    var i = this.processedElements.length;
6705    while(i){
6706        i -= 1;
6707        if(this.processedElements[i].elem === elem){
6708            this.processedElements[i].pos = pos;
6709            break;
6710        }
6711    }
6712    if(i === 0){
6713        this.processedElements.push({
6714            elem: elem,
6715            pos: pos
6716        })
6717    }
6718};
6719
6720IShapeElement.prototype.buildExpressionInterface = function(){};
6721
6722IShapeElement.prototype.createElements = function(){
6723    //TODO check if I can use symbol so i can set its viewBox
6724    this._parent.createElements.call(this);
6725    this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,this.layerElement,this.dynamicProperties, 0, [], true);
6726    if(!this.data.hd || this.data.td){
6727        styleUnselectableDiv(this.layerElement);
6728    }
6729};
6730
6731IShapeElement.prototype.setGradientData = function(pathElement,arr,data){
6732
6733    var gradientId = 'gr_'+randomString(10);
6734    var gfill;
6735    if(arr.t === 1){
6736        gfill = document.createElementNS(svgNS,'linearGradient');
6737    } else {
6738        gfill = document.createElementNS(svgNS,'radialGradient');
6739    }
6740    gfill.setAttribute('id',gradientId);
6741    gfill.setAttribute('spreadMethod','pad');
6742    gfill.setAttribute('gradientUnits','userSpaceOnUse');
6743    var stops = [];
6744    var stop, j, jLen;
6745    jLen = arr.g.p*4;
6746    for(j=0;j<jLen;j+=4){
6747        stop = document.createElementNS(svgNS,'stop');
6748        gfill.appendChild(stop);
6749        stops.push(stop);
6750    }
6751    pathElement.setAttribute( arr.ty === 'gf' ? 'fill':'stroke','url(#'+gradientId+')');
6752    this.globalData.defs.appendChild(gfill);
6753    data.gf = gfill;
6754    data.cst = stops;
6755}
6756
6757IShapeElement.prototype.setGradientOpacity = function(arr, data, styleOb){
6758    if((arr.g.k.k[0].s && arr.g.k.k[0].s.length > arr.g.p*4) || arr.g.k.k.length > arr.g.p*4){
6759        var opFill;
6760        var stop, j, jLen;
6761        var mask = document.createElementNS(svgNS,"mask");
6762        var maskElement = document.createElementNS(svgNS, 'path');
6763        mask.appendChild(maskElement);
6764        var opacityId = 'op_'+randomString(10);
6765        var maskId = 'mk_'+randomString(10);
6766        mask.setAttribute('id',maskId);
6767        if(arr.t === 1){
6768            opFill = document.createElementNS(svgNS,'linearGradient');
6769        } else {
6770            opFill = document.createElementNS(svgNS,'radialGradient');
6771        }
6772        opFill.setAttribute('id',opacityId);
6773        opFill.setAttribute('spreadMethod','pad');
6774        opFill.setAttribute('gradientUnits','userSpaceOnUse');
6775        jLen = arr.g.k.k[0].s ? arr.g.k.k[0].s.length : arr.g.k.k.length;
6776        var stops = [];
6777        for(j=arr.g.p*4;j<jLen;j+=2){
6778            stop = document.createElementNS(svgNS,'stop');
6779            stop.setAttribute('stop-color','rgb(255,255,255)');
6780            //stop.setAttribute('offset',Math.round(arr.y[j][0]*100)+'%');
6781            //stop.setAttribute('style','stop-color:rgb(255,255,255);stop-opacity:'+arr.y[j][1]);
6782            opFill.appendChild(stop);
6783            stops.push(stop);
6784        }
6785        maskElement.setAttribute( arr.ty === 'gf' ? 'fill':'stroke','url(#'+opacityId+')');
6786        this.globalData.defs.appendChild(opFill);
6787        this.globalData.defs.appendChild(mask);
6788        data.of = opFill;
6789        data.ost = stops;
6790        styleOb.msElem = maskElement;
6791        return maskId;
6792    }
6793};
6794
6795IShapeElement.prototype.createStyleElement = function(data, level, dynamicProperties){
6796    var elementData = {
6797    };
6798    var styleOb = {
6799        data: data,
6800        type: data.ty,
6801        d: '',
6802        ld: '',
6803        lvl: level,
6804        mdf: false,
6805        closed: false
6806    };
6807    var pathElement = document.createElementNS(svgNS, "path");
6808    elementData.o = PropertyFactory.getProp(this,data.o,0,0.01,dynamicProperties);
6809    if(data.ty == 'st' || data.ty == 'gs') {
6810        pathElement.setAttribute('stroke-linecap', this.lcEnum[data.lc] || 'round');
6811        ////pathElement.style.strokeLinecap = this.lcEnum[data.lc] || 'round';
6812        pathElement.setAttribute('stroke-linejoin',this.ljEnum[data.lj] || 'round');
6813        ////pathElement.style.strokeLinejoin = this.ljEnum[data.lj] || 'round';
6814        pathElement.setAttribute('fill-opacity','0');
6815        ////pathElement.style.fillOpacity = 0;
6816        if(data.lj == 1) {
6817            pathElement.setAttribute('stroke-miterlimit',data.ml);
6818            ////pathElement.style.strokeMiterlimit = data.ml;
6819        }
6820
6821        elementData.w = PropertyFactory.getProp(this,data.w,0,null,dynamicProperties);
6822        if(data.d){
6823            var d = PropertyFactory.getDashProp(this,data.d,'svg',dynamicProperties);
6824            if(!d.k){
6825                pathElement.setAttribute('stroke-dasharray', d.dasharray);
6826                ////pathElement.style.strokeDasharray = d.dasharray;
6827                pathElement.setAttribute('stroke-dashoffset', d.dashoffset);
6828                ////pathElement.style.strokeDashoffset = d.dashoffset;
6829            }
6830            elementData.d = d;
6831        }
6832
6833    }
6834    if(data.ty == 'fl' || data.ty == 'st'){
6835        elementData.c = PropertyFactory.getProp(this,data.c,1,255,dynamicProperties);
6836    } else {
6837        elementData.g = PropertyFactory.getGradientProp(this,data.g,dynamicProperties);
6838        if(data.t == 2){
6839            elementData.h = PropertyFactory.getProp(this,data.h,0,0.01,dynamicProperties);
6840            elementData.a = PropertyFactory.getProp(this,data.a,0,degToRads,dynamicProperties);
6841        }
6842        elementData.s = PropertyFactory.getProp(this,data.s,1,null,dynamicProperties);
6843        elementData.e = PropertyFactory.getProp(this,data.e,1,null,dynamicProperties);
6844        this.setGradientData(pathElement,data,elementData, styleOb);
6845        var maskId = this.setGradientOpacity(data,elementData, styleOb);
6846        if(maskId){
6847            pathElement.setAttribute('mask','url(#'+maskId+')');
6848        }
6849    }
6850    elementData.elem = pathElement;
6851    //container.appendChild(pathElement);
6852    if(data.r === 2) {
6853        pathElement.setAttribute('fill-rule', 'evenodd');
6854    }
6855
6856    if(data.ln){
6857        pathElement.setAttribute('id',data.ln);
6858    }
6859    if(data.cl){
6860        pathElement.setAttribute('class',data.cl);
6861    }
6862    styleOb.pElem = pathElement;
6863    this.stylesList.push(styleOb);
6864    elementData.style = styleOb;
6865    return elementData;
6866}
6867
6868IShapeElement.prototype.createGroupElement = function(data) {
6869    var elementData = {
6870        it: [],
6871        prevViewData: []
6872    };
6873    var g = document.createElementNS(svgNS,'g');
6874    elementData.gr = g;
6875    if(data.ln){
6876        elementData.gr.setAttribute('id',data.ln);
6877    }
6878    return elementData;
6879}
6880
6881IShapeElement.prototype.createTransformElement = function(data, dynamicProperties) {
6882    var elementData = {
6883        transform : {
6884            op: PropertyFactory.getProp(this,data.o,0,0.01,dynamicProperties),
6885            mProps: PropertyFactory.getProp(this,data,2,null,dynamicProperties)
6886        },
6887        elements: []
6888    };
6889    return elementData;
6890}
6891
6892IShapeElement.prototype.createShapeElement = function(data, ownTransformers, level, dynamicProperties) {
6893    var elementData = {
6894        elements : [],
6895        caches:[],
6896        styles : [],
6897        transformers: ownTransformers,
6898        lStr: ''
6899    };
6900    var ty = 4;
6901    if(data.ty == 'rc'){
6902        ty = 5;
6903    }else if(data.ty == 'el'){
6904        ty = 6;
6905    }else if(data.ty == 'sr'){
6906        ty = 7;
6907    }
6908    elementData.sh = ShapePropertyFactory.getShapeProp(this,data,ty,dynamicProperties);
6909    elementData.lvl = level;
6910    this.shapes.push(elementData.sh);
6911    this.addShapeToModifiers(elementData);
6912    return elementData;
6913}
6914
6915var cont = 0;
6916
6917IShapeElement.prototype.setElementStyles = function(){
6918    var j, jLen = this.stylesList.length;
6919    var arr = [];
6920    for(j=0;j<jLen;j+=1){
6921        if(!this.stylesList[j].closed){
6922            arr.push(this.stylesList[j]);
6923        }
6924    }
6925    return arr;
6926}
6927
6928IShapeElement.prototype.reloadShapes = function(){
6929    this.firstFrame = true;
6930    var i, len = this.itemsData.length;
6931    for(i=0;i<len;i+=1){
6932        this.prevViewData[i] = this.itemsData[i];
6933    }
6934    this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,this.layerElement,this.dynamicProperties, 0, [], true);
6935    var i, len = this.dynamicProperties.length;
6936    for(i=0;i<len;i+=1){
6937        this.dynamicProperties[i].getValue();
6938    }
6939    this.renderModifiers();
6940}
6941
6942IShapeElement.prototype.searchShapes = function(arr,itemsData,prevViewData,container,dynamicProperties, level, transformers, render){
6943    var ownTransformers = [].concat(transformers);
6944    var i, len = arr.length - 1;
6945    var j, jLen;
6946    var ownStyles = [], ownModifiers = [], styleOb, currentTransform, modifier, processedPos;
6947    for(i=len;i>=0;i-=1){
6948        processedPos = this.searchProcessedElement(arr[i]);
6949        if(!processedPos){
6950            arr[i]._render = render;
6951        } else {
6952            itemsData[i] = prevViewData[processedPos - 1];
6953        }
6954        if(arr[i].ty == 'fl' || arr[i].ty == 'st' || arr[i].ty == 'gf' || arr[i].ty == 'gs'){
6955            if(!processedPos){
6956                itemsData[i] = this.createStyleElement(arr[i], level, dynamicProperties);
6957            } else {
6958                itemsData[i].style.closed = false;
6959            }
6960            if(arr[i]._render){
6961                container.appendChild(itemsData[i].elem);
6962            }
6963            ownStyles.push(itemsData[i].style);
6964        }else if(arr[i].ty == 'gr'){
6965            if(!processedPos){
6966                itemsData[i] = this.createGroupElement(arr[i]);
6967            } else {
6968                jLen = itemsData[i].it.length;
6969                for(j=0;j<jLen;j+=1){
6970                    itemsData[i].prevViewData[j] = itemsData[i].it[j];
6971                }
6972            }
6973            this.searchShapes(arr[i].it,itemsData[i].it,itemsData[i].prevViewData,itemsData[i].gr,dynamicProperties, level 
6973+ 1, ownTransformers, render);
6974            if(arr[i]._render){
6975                container.appendChild(itemsData[i].gr);
6976            }
6977        }else if(arr[i].ty == 'tr'){
6978            if(!processedPos){
6979                itemsData[i] = this.createTransformElement(arr[i], dynamicProperties);
6980            }
6981            currentTransform = itemsData[i].transform;
6982            ownTransformers.push(currentTransform);
6983        }else if(arr[i].ty == 'sh' || arr[i].ty == 'rc' || arr[i].ty == 'el' || arr[i].ty == 'sr'){
6984            if(!processedPos){
6985                itemsData[i] = this.createShapeElement(arr[i], ownTransformers, level, dynamicProperties);
6986            }
6987            itemsData[i].elements = this.setElementStyles();
6988
6989        }else if(arr[i].ty == 'tm' || arr[i].ty == 'rd' || arr[i].ty == 'ms'){
6990            if(!processedPos){
6991                modifier = ShapeModifiers.getModifier(arr[i].ty);
6992                modifier.init(this,arr[i],dynamicProperties);
6993                itemsData[i] = modifier;
6994                this.shapeModifiers.push(modifier);
6995            } else {
6996                modifier = itemsData[i];
6997                modifier.closed = false;
6998            }
6999            ownModifiers.push(modifier);
7000        }else if(arr[i].ty == 'rp'){
7001            if(!processedPos){
7002                modifier = ShapeModifiers.getModifier(arr[i].ty);
7003                itemsData[i] = modifier;
7004                modifier.init(this,arr,i,itemsData,dynamicProperties);
7005                this.shapeModifiers.push(modifier);
7006                render = false;
7007            }else{
7008                modifier = itemsData[i];
7009                modifier.closed = true;
7010            }
7011            ownModifiers.push(modifier);
7012        }
7013        this.addProcessedElement(arr[i], i + 1);
7014    }
7015    len = ownStyles.length;
7016    for(i=0;i<len;i+=1){
7017        ownStyles[i].closed = true;
7018    }
7019    len = ownModifiers.length;
7020    for(i=0;i<len;i+=1){
7021        ownModifiers[i].closed = true;
7022    }
7023};
7024
7025IShapeElement.prototype.addShapeToModifiers = function(data) {
7026    var i, len = this.shapeModifiers.length;
7027    for(i=0;i<len;i+=1){
7028        this.shapeModifiers[i].addShape(data);
7029    }
7030};
7031
7032IShapeElement.prototype.renderModifiers = function() {
7033    if(!this.shapeModifiers.length){
7034        return;
7035    }
7036    var i, len = this.shapes.length;
7037    for(i=0;i<len;i+=1){
7038        this.shapes[i].reset();
7039    }
7040
7041
7042    len = this.shapeModifiers.length;
7043
7044    for(i=len-1;i>=0;i-=1){
7045        this.shapeModifiers[i].processShapes(this.firstFrame);
7046    }
7047};
7048
7049IShapeElement.prototype.renderFrame = function(parentMatrix){
7050    //this.reloadShapes();
7051    var renderParent = this._parent.renderFrame.call(this,parentMatrix);
7052    if(renderParent===false){
7053        this.hide();
7054        return;
7055    }
7056    if(this.hidden){
7057        this.layerElement.style.display = 'block';
7058        this.hidden = false;
7059    }
7060    this.renderModifiers();
7061    var i, len = this.stylesList.length;
7062    for(i=0;i<len;i+=1){
7063        this.stylesList[i].d = '';
7064        this.stylesList[i].mdf = false;
7065    }
7066    this.renderShape(this.shapesData,this.itemsData, null);
7067
7068    for (i = 0; i < len; i += 1) {
7069        if (this.stylesList[i].ld === '0') {
7070            this.stylesList[i].ld = '1';
7071            this.stylesList[i].pElem.style.display = 'block';
7072            //this.stylesList[i].parent.appendChild(this.stylesList[i].pElem);
7073        }
7074        if (this.stylesList[i].mdf || this.firstFrame) {
7075            this.stylesList[i].pElem.setAttribute('d', this.stylesList[i].d);
7076            if(this.stylesList[i].msElem){
7077                this.stylesList[i].msElem.setAttribute('d', this.stylesList[i].d);
7078            }
7079        }
7080    }
7081    if (this.firstFrame) {
7082        this.firstFrame = false;
7083    }
7084};
7085
7086IShapeElement.prototype.hide = function(){
7087    if(!this.hidden){
7088        this.layerElement.style.display = 'none';
7089        var i, len = this.stylesList.length;
7090        for(i=len-1;i>=0;i-=1){
7091            if(this.stylesList[i].ld !== '0'){
7092                this.stylesList[i].ld = '0';
7093                this.stylesList[i].pElem.style.display = 'none';
7094                if(this.stylesList[i].pElem.parentNode){
7095                    this.stylesList[i].parent = this.stylesList[i].pElem.parentNode;
7096                    //this.stylesList[i].pElem.parentNode.removeChild(this.stylesList[i].pElem);
7097                }
7098            }
7099        }
7100        this.hidden = true;
7101    }
7102};
7103
7104IShapeElement.prototype.renderShape = function(items,data, container){
7105    var i, len = items.length - 1;
7106    var ty;
7107    for(i=len;i>=0;i-=1){
7108        ty = items[i].ty;
7109        if(ty == 'tr'){
7110            if(this.firstFrame || data[i].transform.op.mdf && container){
7111                container.setAttribute('opacity',data[i].transform.op.v);
7112            }
7113            if(this.firstFrame || data[i].transform.mProps.mdf && container){
7114                container.setAttribute('transform',data[i].transform.mProps.v.to2dCSS());
7115            }
7116        }else if(ty == 'sh' || ty == 'el' || ty == 'rc' || ty == 'sr'){
7117            this.renderPath(items[i],data[i]);
7118        }else if(ty == 'fl'){
7119            this.renderFill(items[i],data[i]);
7120        }else if(ty == 'gf'){
7121            this.renderGradient(items[i],data[i]);
7122        }else if(ty == 'gs'){
7123            this.renderGradient(items[i],data[i]);
7124            this.renderStroke(items[i],data[i]);
7125        }else if(ty == 'st'){
7126            this.renderStroke(items[i],data[i]);
7127        }else if(ty == 'gr'){
7128            this.renderShape(items[i].it,data[i].it, data[i].gr);
7129        }else if(ty == 'tm'){
7130            //
7131        }
7132    }
7133
7134};
7135
7136IShapeElement.prototype.buildShapeString = function(pathNodes, length, closed, mat) {
7137    var i, shapeString = '';
7138    for(i = 1; i < length; i += 1) {
7139        if (i === 1) {
7140            shapeString += " M" + mat.applyToPointStringified(pathNodes.v[0][0], pathNodes.v[0][1]);
7141        }
7142        shapeString += " C" + mat.applyToPointStringified(pathNodes.o[i - 1][0], pathNodes.o[i - 1][1]) + " " + mat.applyToPointStringified(pathNodes.i[i][0], pathNodes.i[i][1]) + " " + mat.applyToPointStringified(pathNodes.v[i][0], pathNodes.v[i][1]);
7143    }
7144    if (length === 1) {
7145        shapeString += " M" + mat.applyToPointStringified(pathNodes.v[0][0], pathNodes.v[0][1]);
7146    }
7147    if (closed && length) {
7148        shapeString += " C" + mat.applyToPointStringified(pathNodes.o[i - 1][0], pathNodes.o[i - 1][1]) + " " + mat.applyToPointStringified(pathNodes.i[0][0], pathNodes.i[0][1]) + " " + mat.applyToPointStringified(pathNodes.v[0][0], pathNodes.v[0][1]);
7149        shapeString += 'z';
7150    }
7151    return shapeString;
7152};
7153
7154IShapeElement.prototype.renderPath = function(pathData,itemData){
7155    var len, i, j, jLen,pathStringTransformed,redraw,pathNodes,l, lLen = itemData.elements.length;
7156    var lvl = itemData.lvl;
7157    if(!pathData._render){
7158        return;
7159    }
7160    for(l=0;l<lLen;l+=1){
7161        if(itemData.elements[l].data._render){
7162            redraw = itemData.sh.mdf || this.firstFrame;
7163            pathStringTransformed = 'M0 0';
7164            var paths = itemData.sh.paths;
7165            jLen = paths._length;
7166            if(itemData.elements[l].lvl < lvl){
7167                var mat = this.mHelper.reset(), props;
7168                var iterations = lvl - itemData.elements[l].lvl;
7169                var k = itemData.transformers.length-1;
7170                while(iterations > 0) {
7171                    redraw = itemData.transformers[k].mProps.mdf || redraw;
7172                    props = itemData.transformers[k].mProps.v.props;
7173                    mat.transform(props[0],props[1],props[2],props[3],props[4],props[5],props[6],props[7],props[8],props[9],props[10],props[11],props[12],props[13],props[14],props[15]);
7174                    iterations --;
7175                    k --;
7176                }
7177                if(redraw){
7178                    for(j=0;j<jLen;j+=1){
7179                        pathNodes = paths.shapes[j];
7180                        if(pathNodes && pathNodes._length){
7181                            pathStringTransformed += this.buildShapeString(pathNodes, pathNodes._length, pathNodes.c, mat);
7182                        }
7183                    }
7184                    itemData.caches[l] = pathStringTransformed;
7185                } else {
7186                    pathStringTransformed = itemData.caches[l];
7187                }
7188            } else {
7189                if(redraw){
7190                    for(j=0;j<jLen;j+=1){
7191                        pathNodes = paths.shapes[j];
7192                        if(pathNodes && pathNodes._length){
7193                            pathStringTransformed += this.buildShapeString(pathNodes, pathNodes._length, pathNodes.c, this.identityMatrix);
7194                        }
7195                    }
7196                    itemData.caches[l] = pathStringTransformed;
7197                } else {
7198                    pathStringTransformed = itemData.caches[l];
7199                }
7200            }
7201            itemData.elements[l].d += pathStringTransformed;
7202            itemData.elements[l].mdf = redraw || itemData.elements[l].mdf;
7203        } else {
7204            itemData.elements[l].mdf = true;
7205        }
7206    }
7207};
7208
7209IShapeElement.prototype.renderFill = function(styleData,itemData){
7210    var styleElem = itemData.style;
7211
7212    if(itemData.c.mdf || this.firstFrame){
7213        styleElem.pElem.setAttribute('fill','rgb('+bm_floor(itemData.c.v[0])+','+bm_floor(itemData.c.v[1])+','+bm_floor(itemData.c.v[2])+')');
7214        ////styleElem.pElem.style.fill = 'rgb('+bm_floor(itemData.c.v[0])+','+bm_floor(itemData.c.v[1])+','+bm_floor(itemData.c.v[2])+')';
7215    }
7216    if(itemData.o.mdf || this.firstFrame){
7217        styleElem.pElem.setAttribute('fill-opacity',itemData.o.v);
7218    }
7219};
7220
7221IShapeElement.prototype.renderGradient = function(styleData,itemData){
7222    var gfill = itemData.gf;
7223    var opFill = itemData.of;
7224    var pt1 = itemData.s.v,pt2 = itemData.e.v;
7225
7226    if(itemData.o.mdf || this.firstFrame){
7227        var attr = styleData.ty === 'gf' ? 'fill-opacity':'stroke-opacity';
7228        itemData.elem.setAttribute(attr,itemData.o.v);
7229    }
7230    //clippedElement.setAttribute('transform','matrix(1,0,0,1,-100,0)');
7231    if(itemData.s.mdf || this.firstFrame){
7232        var attr1 = styleData.t === 1 ? 'x1':'cx';
7233        var attr2 = attr1 === 'x1' ? 'y1':'cy';
7234        gfill.setAttribute(attr1,pt1[0]);
7235        gfill.setAttribute(attr2,pt1[1]);
7236        if(opFill){
7237            opFill.setAttribute(attr1,pt1[0]);
7238            opFill.setAttribute(attr2,pt1[1]);
7239        }
7240    }
7241    var stops, i, len, stop;
7242    if(itemData.g.cmdf || this.firstFrame){
7243        stops = itemData.cst;
7244        var cValues = itemData.g.c;
7245        len = stops.length;
7246        for(i=0;i<len;i+=1){
7247            stop = stops[i];
7248            stop.setAttribute('offset',cValues[i*4]+'%');
7249            stop.setAttribute('stop-color','rgb('+cValues[i*4+1]+','+cValues[i*4+2]+','+cValues[i*4+3]+')');
7250        }
7251    }
7252    if(opFill && (itemData.g.omdf || this.firstFrame)){
7253        stops = itemData.ost;
7254        var oValues = itemData.g.o;
7255        len = stops.length;
7256        for(i=0;i<len;i+=1){
7257            stop = stops[i];
7258            stop.setAttribute('offset',oValues[i*2]+'%');
7259            stop.setAttribute('stop-opacity',oValues[i*2+1]);
7260        }
7261    }
7262    if(styleData.t === 1){
7263        if(itemData.e.mdf  || this.firstFrame){
7264            gfill.setAttribute('x2',pt2[0]);
7265            gfill.setAttribute('y2',pt2[1]);
7266            if(opFill){
7267                opFill.setAttribute('x2',pt2[0]);
7268                opFill.setAttribute('y2',pt2[1]);
7269            }
7270        }
7271    } else {
7272        var rad;
7273        if(itemData.s.mdf || itemData.e.mdf || this.firstFrame){
7274            rad = Math.sqrt(Math.pow(pt1[0]-pt2[0],2)+Math.pow(pt1[1]-pt2[1],2));
7275            gfill.setAttribute('r',rad);
7276            if(opFill){
7277                opFill.setAttribute('r',rad);
7278            }
7279        }
7280        if(itemData.e.mdf || itemData.h.mdf || itemData.a.mdf || this.firstFrame){
7281            if(!rad){
7282                rad = Math.sqrt(Math.pow(pt1[0]-pt2[0],2)+Math.pow(pt1[1]-pt2[1],2));
7283            }
7284            var ang = Math.atan2(pt2[1]-pt1[1], pt2[0]-pt1[0]);
7285
7286            var percent = itemData.h.v >= 1 ? 0.99 : itemData.h.v <= -1 ? -0.99:itemData.h.v;
7287            var dist = rad*percent;
7288            var x = Math.cos(ang + itemData.a.v)*dist + pt1[0];
7289            var y = Math.sin(ang + itemData.a.v)*dist + pt1[1];
7290            gfill.setAttribute('fx',x);
7291            gfill.setAttribute('fy',y);
7292            if(opFill){
7293                opFill.setAttribute('fx',x);
7294                opFill.setAttribute('fy',y);
7295            }
7296        }
7297        //gfill.setAttribute('fy','200');
7298    }
7299};
7300
7301IShapeElement.prototype.renderStroke = function(styleData,itemData){
7302    var styleElem = itemData.style;
7303    //TODO fix dashes
7304    var d = itemData.d;
7305    var dasharray,dashoffset;
7306    if(d && d.k && (d.mdf || this.firstFrame)){
7307        styleElem.pElem.setAttribute('stroke-dasharray', d.dasharray);
7308        ////styleElem.pElem.style.strokeDasharray = d.dasharray;
7309        styleElem.pElem.setAttribute('stroke-dashoffset', d.dashoffset);
7310        ////styleElem.pElem.style.strokeDashoffset = d.dashoffset;
7311    }
7312    if(itemData.c && (itemData.c.mdf || this.firstFrame)){
7313        styleElem.pElem.setAttribute('stroke','rgb('+bm_floor(itemData.c.v[0])+','+bm_floor(itemData.c.v[1])+','+bm_floor(itemData.c.v[2])+')');
7314        ////styleElem.pElem.style.stroke = 'rgb('+bm_floor(itemData.c.v[0])+','+bm_floor(itemData.c.v[1])+','+bm_floor(itemData.c.v[2])+')';
7315    }
7316    if(itemData.o.mdf || this.firstFrame){
7317        styleElem.pElem.setAttribute('stroke-opacity',itemData.o.v);
7318    }
7319    if(itemData.w.mdf || this.firstFrame){
7320        styleElem.pElem.setAttribute('stroke-width',itemData.w.v);
7321        if(styleElem.msElem){
7322            styleElem.msElem.setAttribute('stroke-width',itemData.w.v);
7323        }
7324        ////styleElem.pElem.style.strokeWidth = itemData.w.v;
7325    }
7326};
7327
7328IShapeElement.prototype.destroy = function(){
7329    this._parent.destroy.call(this._parent);
7330    this.shapeData = null;
7331    this.itemsData = null;
7332    this.parentContainer = null;
7333    this.placeholder = null;
7334};
7335
7336function ITextElement(data, animationItem,parentContainer,globalData){
7337}
7338ITextElement.prototype.init = function(){
7339    this.lettersChangedFlag = true;
7340    this.dynamicProperties = this.dynamicProperties || [];
7341    this.textAnimator = new TextAnimatorProperty(this.data.t, this.renderType, this);
7342    this.textProperty = new TextProperty(this, this.data.t, this.dynamicProperties);
7343    this._parent.init.call(this);
7344    this.textAnimator.searchProperties(this.dynamicProperties);
7345};
7346
7347ITextElement.prototype.prepareFrame = function(num) {
7348    this._parent.prepareFrame.call(this, num);
7349    if(this.textProperty.mdf || this.textProperty.firstFrame) {
7350        this.buildNewText();
7351        this.textProperty.firstFrame = false;
7352    }
7353}
7354
7355ITextElement.prototype.createPathShape = function(matrixHelper, shapes) {
7356    var j,jLen = shapes.length;
7357    var k, kLen, pathNodes;
7358    var shapeStr = '';
7359    for(j=0;j<jLen;j+=1){
7360        pathNodes = shapes[j].ks.k;
7361        shapeStr += this.buildShapeString(pathNodes, pathNodes.i.length, true, matrixHelper);
7362    }
7363    return shapeStr;
7364};
7365
7366ITextElement.prototype.updateDocumentData = function(newData, index) {
7367    this.textProperty.updateDocumentData(newData, index);
7368}
7369
7370ITextElement.prototype.applyTextPropertiesToMatrix = function(documentData, matrixHelper, lineNumber, xPos, yPos) {
7371    if(documentData.ps){
7372        matrixHelper.translate(documentData.ps[0],documentData.ps[1] + documentData.ascent,0);
7373    }
7374    matrixHelper.translate(0,-documentData.ls,0);
7375    switch(documentData.j){
7376        case 1:
7377            matrixHelper.translate(documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[lineNumber]),0,0);
7378            break;
7379        case 2:
7380            matrixHelper.translate(documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[lineNumber] )/2,0,0);
7381            break;
7382    }
7383    matrixHelper.translate(xPos, yPos, 0);
7384}
7385
7386ITextElement.prototype.buildColor = function(colorData) {
7387    return 'rgb(' + Math.round(colorData[0]*255) + ',' + Math.round(colorData[1]*255) + ',' + Math.round(colorData[2]*255) + ')';
7388}
7389
7390ITextElement.prototype.buildShapeString = IShapeElement.prototype.buildShapeString;
7391
7392ITextElement.prototype.emptyProp = new LetterProps();
7393
7394ITextElement.prototype.destroy = function(){
7395    this._parent.destroy.call(this._parent);
7396};
7397function SVGTextElement(data,parentContainer,globalData,comp, placeholder){
7398    this.textSpans = [];
7399    this.renderType = 'svg';
7400    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
7401}
7402createElement(SVGBaseElement, SVGTextElement);
7403
7404extendPrototype(ITextElement, SVGTextElement);
7405
7406SVGTextElement.prototype.createElements = function(){
7407
7408    this._parent.createElements.call(this);
7409
7410
7411    if(this.data.ln){
7412        this.layerElement.setAttribute('id',this.data.ln);
7413    }
7414    if(this.data.cl){
7415        this.layerElement.setAttribute('class',this.data.cl);
7416    }
7417    if (this.data.singleShape && !this.globalData.fontManager.chars) {
7418        this.textContainer = document.createElementNS(svgNS,'text');
7419    }
7420};
7421
7422SVGTextElement.prototype.buildNewText = function(){
7423    var i, len;
7424
7425    var documentData = this.textProperty.currentData;
7426    this.renderedLetters = Array.apply(null,{length:documentData ? documentData.l.length : 0});
7427    if(documentData.fc) {
7428        this.layerElement.setAttribute('fill', this.buildColor(documentData.fc));
7429    }else{
7430        this.layerElement.setAttribute('fill', 'rgba(0,0,0,0)');
7431    }
7432    if(documentData.sc){
7433        this.layerElement.setAttribute('stroke', this.buildColor(documentData.sc));
7434        this.layerElement.setAttribute('stroke-width', documentData.sw);
7435    }
7436    this.layerElement.setAttribute('font-size', documentData.s);
7437    var fontData = this.globalData.fontManager.getFontByName(documentData.f);
7438    if(fontData.fClass){
7439        this.layerElement.setAttribute('class',fontData.fClass);
7440    } else {
7441        this.layerElement.setAttribute('font-family', fontData.fFamily);
7442        var fWeight = documentData.fWeight, fStyle = documentData.fStyle;
7443        this.layerElement.setAttribute('font-style', fStyle);
7444        this.layerElement.setAttribute('font-weight', fWeight);
7445    }
7446
7447    var letters = documentData.l || [];
7448    var usesGlyphs = this.globalData.fontManager.chars;
7449    len = letters.length;
7450    if(!len){
7451        return;
7452    }
7453    var tSpan;
7454    var matrixHelper = this.mHelper;
7455    var shapes, shapeStr = '', singleShape = this.data.singleShape;
7456    var xPos = 0, yPos = 0, firstLine = true;
7457    var trackingOffset = documentData.tr/1000*documentData.s;
7458    if(singleShape && !usesGlyphs) {
7459        var tElement = this.textContainer;
7460        var justify = '';
7461        switch(documentData.j) {
7462            case 1:
7463                justify = 'end';
7464                break;
7465            case 2:
7466                justify = 'middle';
7467                break;
7468            case 2:
7469                justify = 'start';
7470                break;
7471        }
7472        tElement.setAttribute('text-anchor',justify);
7473        tElement.setAttribute('letter-spacing',trackingOffset);
7474        var textContent = documentData.t.split(String.fromCharCode(13));
7475        len = textContent.length;
7476        var yPos = documentData.ps ? documentData.ps[1] + documentData.ascent : 0;
7477        for ( i = 0; i < len; i += 1) {
7478            tSpan = this.textSpans[i] || document.createElementNS(svgNS,'tspan');
7479            tSpan.textContent = textContent[i];
7480            tSpan.setAttribute('x', 0);
7481            tSpan.setAttribute('y', yPos);
7482            tSpan.style.display = 'inherit';
7483            tElement.appendChild(tSpan);
7484            this.textSpans[i] = tSpan;
7485            yPos += documentData.lh;
7486        }
7487        
7488        this.layerElement.appendChild(tElement);
7489    } else {
7490        var cachedSpansLength = this.textSpans.length;
7491        var shapeData, charData;
7492        for (i = 0; i < len; i += 1) {
7493            if(!usesGlyphs || !singleShape || i === 0){
7494                tSpan = cachedSpansLength > i ? this.textSpans[i] : document.createElementNS(svgNS,usesGlyphs?'path':'text');
7495                if (cachedSpansLength <= i) {
7496                    tSpan.setAttribute('stroke-linecap', 'butt');
7497                    tSpan.setAttribute('stroke-linejoin','round');
7498                    tSpan.setAttribute('stroke-miterlimit','4');
7499                    this.textSpans[i] = tSpan;
7500                    this.layerElement.appendChild(tSpan);
7501                }
7502                tSpan.style.display = 'inherit';
7503            }
7504            
7505            matrixHelper.reset();
7506            if(usesGlyphs) {
7507                matrixHelper.scale(documentData.s / 100, documentData.s / 100);
7508                if (singleShape) {
7509                    if(letters[i].n) {
7510                        xPos = -trackingOffset;
7511                        yPos += documentData.yOffset;
7512                        yPos += firstLine ? 1 : 0;
7513                        firstLine = false;
7514                    }
7515                    this.applyTextPropertiesToMatrix(documentData, matrixHelper, letters[i].line, xPos, yPos);
7516                    xPos += letters[i].l || 0;
7517                    //xPos += letters[i].val === ' ' ? 0 : trackingOffset;
7518                    xPos += trackingOffset;
7519                }
7520                charData = this.globalData.fontManager.getCharData(documentData.t.charAt(i), fontData.fStyle, this.globalData.fontManager.getFontByName(
7520documentData.f).fFamily);
7521                shapeData = charData && charData.data || {};
7522                shapes = shapeData.shapes ? shapeData.shapes[0].it : [];
7523                if(!singleShape){
7524                    tSpan.setAttribute('d',this.createPathShape(matrixHelper,shapes));
7525                } else {
7526                    shapeStr += this.createPathShape(matrixHelper,shapes);
7527                }
7528            } else {
7529                tSpan.textContent = letters[i].val;
7530                tSpan.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space","preserve");
7531            }
7532            //
7533        }
7534        if (singleShape) {
7535            tSpan.setAttribute('d',shapeStr);
7536        }
7537    }
7538    while (i < this.textSpans.length){
7539        this.textSpans[i].style.display = 'none';
7540        i += 1;
7541    }
7542    
7543    this._sizeChanged = true;
7544}
7545
7546SVGTextElement.prototype.sourceRectAtTime = function(time){
7547    this.prepareFrame(this.comp.renderedFrame - this.data.st);
7548    this.renderLetters();
7549    if(this._sizeChanged){
7550        this._sizeChanged = false;
7551        var textBox = this.layerElement.getBBox();
7552        this.bbox = {
7553            top: textBox.y,
7554            left: textBox.x,
7555            width: textBox.width,
7556            height: textBox.height
7557        }
7558    }
7559    return this.bbox;
7560}
7561
7562SVGTextElement.prototype.renderLetters = function(){
7563
7564    if(!this.data.singleShape){
7565        this.textAnimator.getMeasures(this.textProperty.currentData, this.lettersChangedFlag);
7566        if(this.lettersChangedFlag || this.textAnimator.lettersChangedFlag){
7567            this._sizeChanged = true;
7568            var  i,len;
7569            var renderedLetters = this.textAnimator.renderedLetters;
7570
7571            var letters = this.textProperty.currentData.l;
7572
7573            len = letters.length;
7574            var renderedLetter, textSpan;
7575            for(i=0;i<len;i+=1){
7576                if(letters[i].n){
7577                    continue;
7578                }
7579                renderedLetter = renderedLetters[i];
7580                textSpan = this.textSpans[i];
7581                if(renderedLetter.mdf.m) {
7582                    textSpan.setAttribute('transform',renderedLetter.m);
7583                }
7584                if(renderedLetter.mdf.o) {
7585                    textSpan.setAttribute('opacity',renderedLetter.o);
7586                }
7587                if(renderedLetter.mdf.sw){
7588                    textSpan.setAttribute('stroke-width',renderedLetter.sw);
7589                }
7590                if(renderedLetter.mdf.sc){
7591                    textSpan.setAttribute('stroke',renderedLetter.sc);
7592                }
7593                if(renderedLetter.mdf.fc){
7594                    textSpan.setAttribute('fill',renderedLetter.fc);
7595                }
7596            }
7597        }
7598    }
7599}
7600
7601SVGTextElement.prototype.renderFrame = function(parentMatrix){
7602
7603    var renderParent = this._parent.renderFrame.call(this,parentMatrix);
7604    if(renderParent===false){
7605        this.hide();
7606        return;
7607    }
7608    if(this.hidden){
7609        this.show();
7610    }
7611    if(this.firstFrame) {
7612        this.firstFrame = false;
7613    }
7614    this.renderLetters();
7615}
7616function SVGTintFilter(filter, filterManager){
7617    this.filterManager = filterManager;
7618    var feColorMatrix = document.createElementNS(svgNS,'feColorMatrix');
7619    feColorMatrix.setAttribute('type','matrix');
7620    feColorMatrix.setAttribute('color-interpolation-filters','linearRGB');
7621    feColorMatrix.setAttribute('values','0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0');
7622    feColorMatrix.setAttribute('result','f1');
7623    filter.appendChild(feColorMatrix);
7624    feColorMatrix = document.createElementNS(svgNS,'feColorMatrix');
7625    feColorMatrix.setAttribute('type','matrix');
7626    feColorMatrix.setAttribute('color-interpolation-filters','sRGB');
7627    feColorMatrix.setAttribute('values','1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0');
7628    feColorMatrix.setAttribute('result','f2');
7629    filter.appendChild(feColorMatrix);
7630    this.matrixFilter = feColorMatrix;
7631    if(filterManager.effectElements[2].p.v !== 100 || filterManager.effectElements[2].p.k){
7632        var feMerge = document.createElementNS(svgNS,'feMerge');
7633        filter.appendChild(feMerge);
7634        var feMergeNode;
7635        feMergeNode = document.createElementNS(svgNS,'feMergeNode');
7636        feMergeNode.setAttribute('in','SourceGraphic');
7637        feMerge.appendChild(feMergeNode);
7638        feMergeNode = document.createElementNS(svgNS,'feMergeNode');
7639        feMergeNode.setAttribute('in','f2');
7640        feMerge.appendChild(feMergeNode);
7641    }
7642}
7643
7644SVGTintFilter.prototype.renderFrame = function(forceRender){
7645    if(forceRender || this.filterManager.mdf){
7646        var colorBlack = this.filterManager.effectElements[0].p.v;
7647        var colorWhite = this.filterManager.effectElements[1].p.v;
7648        var opacity = this.filterManager.effectElements[2].p.v/100;
7649        this.matrixFilter.setAttribute('values',(colorWhite[0]- colorBlack[0])+' 0 0 0 '+ colorBlack[0] +' '+ (colorWhite[1]- colorBlack[1]) +' 0 0 0 '+ colorBlack[1] +' '+ (colorWhite[2]- colorBlack[2]) +' 0 0 0 '+ colorBlack[2] +' 0 0 0 ' + opacity + ' 0');
7650    }
7651};
7652function SVGFillFilter(filter, filterManager){
7653    this.filterManager = filterManager;
7654    var feColorMatrix = document.createElementNS(svgNS,'feColorMatrix');
7655    feColorMatrix.setAttribute('type','matrix');
7656    feColorMatrix.setAttribute('color-interpolation-filters','sRGB');
7657    feColorMatrix.setAttribute('values','1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0');
7658    filter.appendChild(feColorMatrix);
7659    this.matrixFilter = feColorMatrix;
7660}
7661SVGFillFilter.prototype.renderFrame = function(forceRender){
7662    if(forceRender || this.filterManager.mdf){
7663        var color = this.filterManager.effectElements[2].p.v;
7664        var opacity = this.filterManager.effectElements[6].p.v;
7665        this.matrixFilter.setAttribute('values','0 0 0 0 '+color[0]+' 0 0 0 0 '+color[1]+' 0 0 0 0 '+color[2]+' 0 0 0 '+opacity+' 0');
7666    }
7667};
7668function SVGStrokeEffect(elem, filterManager){
7669    this.initialized = false;
7670    this.filterManager = filterManager;
7671    this.elem = elem;
7672    this.paths = [];
7673}
7674
7675SVGStrokeEffect.prototype.initialize = function(){
7676
7677    var elemChildren = this.elem.layerElement.children || this.elem.layerElement.childNodes;
7678    var path,groupPath, i, len;
7679    if(this.filterManager.effectElements[1].p.v === 1){
7680        len = this.elem.maskManager.masksProperties.length;
7681        i = 0;
7682    } else {
7683        i = this.filterManager.effectElements[0].p.v - 1;
7684        len = i + 1;
7685    }
7686    groupPath = document.createElementNS(svgNS,'g'); 
7687    groupPath.setAttribute('fill','none');
7688    groupPath.setAttribute('stroke-linecap','round');
7689    groupPath.setAttribute('stroke-dashoffset',1);
7690    for(i;i<len;i+=1){
7691        path = document.createElementNS(svgNS,'path');
7692        groupPath.appendChild(path);
vendor: 10,396 bytes, lines 7693-7879
7693        this.paths.push({p:path,m:i});
7694    }
7695    if(this.filterManager.effectElements[10].p.v === 3){
7696        var mask = document.createElementNS(svgNS,'mask');
7697        var id = 'stms_' + randomString(10);
7698        mask.setAttribute('id',id);
7699        mask.setAttribute('mask-type','alpha');
7700        mask.appendChild(groupPath);
7701        this.elem.globalData.defs.appendChild(mask);
7702        var g = document.createElementNS(svgNS,'g');
7703        g.setAttribute('mask','url(' + locationHref + '#'+id+')');
7704        if(elemChildren[0]){
7705            g.appendChild(elemChildren[0]);
7706        }
7707        this.elem.layerElement.appendChild(g);
7708        this.masker = mask;
7709        groupPath.setAttribute('stroke','#fff');
7710    } else if(this.filterManager.effectElements[10].p.v === 1 || this.filterManager.effectElements[10].p.v === 2){
7711        if(this.filterManager.effectElements[10].p.v === 2){
7712            var elemChildren = this.elem.layerElement.children || this.elem.layerElement.childNodes;
7713            while(elemChildren.length){
7714                this.elem.layerElement.removeChild(elemChildren[0]);
7715            }
7716        }
7717        this.elem.layerElement.appendChild(groupPath);
7718        this.elem.layerElement.removeAttribute('mask');
7719        groupPath.setAttribute('stroke','#fff');
7720    }
7721    this.initialized = true;
7722    this.pathMasker = groupPath;
7723}
7724
7725SVGStrokeEffect.prototype.renderFrame = function(forceRender){
7726    if(!this.initialized){
7727        this.initialize();
7728    }
7729    var i, len = this.paths.length;
7730    var mask, path;
7731    for(i=0;i<len;i+=1){
7732        mask = this.elem.maskManager.viewData[this.paths[i].m];
7733        path = this.paths[i].p;
7734        if(forceRender || this.filterManager.mdf || mask.prop.mdf){
7735            path.setAttribute('d',mask.lastPath);
7736        }
7737        if(forceRender || this.filterManager.effectElements[9].p.mdf || this.filterManager.effectElements[4].p.mdf || this.filterManager.effectElements[7].p.mdf || this.filterManager.effectElements[8].p.mdf || mask.prop.mdf){
7738            var dasharrayValue;
7739            if(this.filterManager.effectElements[7].p.v !== 0 || this.filterManager.effectElements[8].p.v !== 100){
7740                var s = Math.min(this.filterManager.effectElements[7].p.v,this.filterManager.effectElements[8].p.v)/100;
7741                var e = Math.max(this.filterManager.effectElements[7].p.v,this.filterManager.effectElements[8].p.v)/100;
7742                var l = path.getTotalLength();
7743                dasharrayValue = '0 0 0 ' + l*s + ' ';
7744                var lineLength = l*(e-s);
7745                var segment = 1+this.filterManager.effectElements[4].p.v*2*this.filterManager.effectElements[9].p.v/100;
7746                var units = Math.floor(lineLength/segment);
7747                var j;
7748                for(j=0;j<units;j+=1){
7749                    dasharrayValue += '1 ' + this.filterManager.effectElements[4].p.v*2*this.filterManager.effectElements[9].p.v/100 + ' ';
7750                }
7751                dasharrayValue += '0 ' + l*10 + ' 0 0';
7752            } else {
7753                dasharrayValue = '1 ' + this.filterManager.effectElements[4].p.v*2*this.filterManager.effectElements[9].p.v/100;
7754            }
7755            path.setAttribute('stroke-dasharray',dasharrayValue);
7756        }
7757    }
7758    if(forceRender || this.filterManager.effectElements[4].p.mdf){
7759        this.pathMasker.setAttribute('stroke-width',this.filterManager.effectElements[4].p.v*2);
7760    }
7761    
7762    if(forceRender || this.filterManager.effectElements[6].p.mdf){
7763        this.pathMasker.setAttribute('opacity',this.filterManager.effectElements[6].p.v);
7764    }
7765    if(this.filterManager.effectElements[10].p.v === 1 || this.filterManager.effectElements[10].p.v === 2){
7766        if(forceRender || this.filterManager.effectElements[3].p.mdf){
7767            var color = this.filterManager.effectElements[3].p.v;
7768            this.pathMasker.setAttribute('stroke','rgb('+bm_floor(color[0]*255)+','+bm_floor(color[1]*255)+','+bm_floor(color[2]*255)+')');
7769        }
7770    }
7771};
7772function SVGTritoneFilter(filter, filterManager){
7773    this.filterManager = filterManager;
7774    var feColorMatrix = document.createElementNS(svgNS,'feColorMatrix');
7775    feColorMatrix.setAttribute('type','matrix');
7776    feColorMatrix.setAttribute('color-interpolation-filters','linearRGB');
7777    feColorMatrix.setAttribute('values','0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0');
7778    feColorMatrix.setAttribute('result','f1');
7779    filter.appendChild(feColorMatrix);
7780    var feComponentTransfer = document.createElementNS(svgNS,'feComponentTransfer');
7781    feComponentTransfer.setAttribute('color-interpolation-filters','sRGB');
7782    filter.appendChild(feComponentTransfer);
7783    this.matrixFilter = feComponentTransfer;
7784    var feFuncR = document.createElementNS(svgNS,'feFuncR');
7785    feFuncR.setAttribute('type','table');
7786    feComponentTransfer.appendChild(feFuncR);
7787    this.feFuncR = feFuncR;
7788    var feFuncG = document.createElementNS(svgNS,'feFuncG');
7789    feFuncG.setAttribute('type','table');
7790    feComponentTransfer.appendChild(feFuncG);
7791    this.feFuncG = feFuncG;
7792    var feFuncB = document.createElementNS(svgNS,'feFuncB');
7793    feFuncB.setAttribute('type','table');
7794    feComponentTransfer.appendChild(feFuncB);
7795    this.feFuncB = feFuncB;
7796}
7797
7798SVGTritoneFilter.prototype.renderFrame = function(forceRender){
7799    if(forceRender || this.filterManager.mdf){
7800        var color1 = this.filterManager.effectElements[0].p.v;
7801        var color2 = this.filterManager.effectElements[1].p.v;
7802        var color3 = this.filterManager.effectElements[2].p.v;
7803        var tableR = color3[0] + ' ' + color2[0] + ' ' + color1[0]
7804        var tableG = color3[1] + ' ' + color2[1] + ' ' + color1[1]
7805        var tableB = color3[2] + ' ' + color2[2] + ' ' + color1[2]
7806        this.feFuncR.setAttribute('tableValues', tableR);
7807        this.feFuncG.setAttribute('tableValues', tableG);
7808        this.feFuncB.setAttribute('tableValues', tableB);
7809        //var opacity = this.filterManager.effectElements[2].p.v/100;
7810        //this.matrixFilter.setAttribute('values',(colorWhite[0]- colorBlack[0])+' 0 0 0 '+ colorBlack[0] +' '+ (colorWhite[1]- colorBlack[1]) +' 0 0 0 '+ colorBlack[1] +' '+ (colorWhite[2]- colorBlack[2]) +' 0 0 0 '+ colorBlack[2] +' 0 0 0 ' + opacity + ' 0');
7811    }
7812};
7813function SVGProLevelsFilter(filter, filterManager){
7814    this.filterManager = filterManager;
7815    var effectElements = this.filterManager.effectElements;
7816    var feComponentTransfer = document.createElementNS(svgNS,'feComponentTransfer');
7817    var feFuncR, feFuncG, feFuncB;
7818    
7819    if(effectElements[9].p.k || effectElements[9].p.v !== 0 || effectElements[10].p.k || effectElements[10].p.v !== 1 || effectElements[11].p.k || effectElements[11].p.v !== 1 || effectElements[12].p.k || effectElements[12].p.v !== 0 || effectElements[13].p.k || effectElements[13].p.v !== 1){
7820        this.feFuncR = this.createFeFunc('feFuncR', feComponentTransfer);
7821    }
7822    if(effectElements[16].p.k || effectElements[16].p.v !== 0 || effectElements[17].p.k || effectElements[17].p.v !== 1 || effectElements[18].p.k || effectElements[18].p.v !== 1 || effectElements[19].p.k || effectElements[19].p.v !== 0 || effectElements[20].p.k || effectElements[20].p.v !== 1){
7823        this.feFuncG = this.createFeFunc('feFuncG', feComponentTransfer);
7824    }
7825    if(effectElements[23].p.k || effectElements[23].p.v !== 0 || effectElements[24].p.k || effectElements[24].p.v !== 1 || effectElements[25].p.k || effectElements[25].p.v !== 1 || effectElements[26].p.k || effectElements[26].p.v !== 0 || effectElements[27].p.k || effectElements[27].p.v !== 1){
7826        this.feFuncB = this.createFeFunc('feFuncB', feComponentTransfer);
7827    }
7828    if(effectElements[30].p.k || effectElements[30].p.v !== 0 || effectElements[31].p.k || effectElements[31].p.v !== 1 || effectElements[32].p.k || effectElements[32].p.v !== 1 || effectElements[33].p.k || effectElements[33].p.v !== 0 || effectElements[34].p.k || effectElements[34].p.v !== 1){
7829        this.feFuncA = this.createFeFunc('feFuncA', feComponentTransfer);
7830    }
7831    
7832    if(this.feFuncR || this.feFuncG || this.feFuncB || this.feFuncA){
7833        feComponentTransfer.setAttribute('color-interpolation-filters','sRGB');
7834        filter.appendChild(feComponentTransfer);
7835        feComponentTransfer = document.createElementNS(svgNS,'feComponentTransfer');
7836    }
7837
7838    if(effectElements[2].p.k || effectElements[2].p.v !== 0 || effectElements[3].p.k || effectElements[3].p.v !== 1 || effectElements[4].p.k || effectElements[4].p.v !== 1 || effectElements[5].p.k || effectElements[5].p.v !== 0 || effectElements[6].p.k || effectElements[6].p.v !== 1){
7839
7840        feComponentTransfer.setAttribute('color-interpolation-filters','sRGB');
7841        filter.appendChild(feComponentTransfer);
7842        this.feFuncRComposed = this.createFeFunc('feFuncR', feComponentTransfer);
7843        this.feFuncGComposed = this.createFeFunc('feFuncG', feComponentTransfer);
7844        this.feFuncBComposed = this.createFeFunc('feFuncB', feComponentTransfer);
7845    }
7846}
7847
7848SVGProLevelsFilter.prototype.createFeFunc = function(type, feComponentTransfer) {
7849    var feFunc = document.createElementNS(svgNS,type);
7850    feFunc.setAttribute('type','table');
7851    feComponentTransfer.appendChild(feFunc);
7852    return feFunc;
7853};
7854
7855SVGProLevelsFilter.prototype.getTableValue = function(inputBlack, inputWhite, gamma, outputBlack, outputWhite) {
7856    var cnt = 0;
7857    var segments = 256;
7858    var perc;
7859    var min = Math.min(inputBlack, inputWhite);
7860    var max = Math.max(inputBlack, inputWhite);
7861    var table = Array.call(null,{length:segments});
7862    var colorValue;
7863    var pos = 0;
7864    var outputDelta = outputWhite - outputBlack; 
7865    var inputDelta = inputWhite - inputBlack; 
7866    while(cnt <= 256) {
7867        perc = cnt/256;
7868        if(perc <= min){
7869            colorValue = inputDelta < 0 ? outputWhite : outputBlack;
7870        } else if(perc >= max){
7871            colorValue = inputDelta < 0 ? outputBlack : outputWhite;
7872        } else {
7873            colorValue = (outputBlack + outputDelta * Math.pow((perc - inputBlack) / inputDelta, 1 / gamma));
7874        }
7875        table[pos++] = colorValue;
7876        cnt += 256/(segments-1);
7877    }
7878    return table.join(' ');
7879};
7880
7881SVGProLevelsFilter.prototype.renderFrame = function(forceRender){
7882    if(forceRender || this.filterManager.mdf){
7883        var val, cnt, perc, bezier;
7884        var effectElements = this.filterManager.effectElements;
7885        if(this.feFuncRComposed && (forceRender || effectElements[2].p.mdf || effectElements[3].p.mdf || effectElements[4].p.mdf || effectElements[5].p.mdf || effectElements[6].p.mdf)){
7886            val = this.getTableValue(effectElements[2].p.v,effectElements[3].p.v,effectElements[4].p.v,effectElements[5].p.v,effectElements[6].p.v);
7887            this.feFuncRComposed.setAttribute('tableValues',val);
7888            this.feFuncGComposed.setAttribute('tableValues',val);
7889            this.feFuncBComposed.setAttribute('tableValues',val);
7890        }
7891
7892        if(this.feFuncR && (forceRender || effectElements[9].p.mdf || effectElements[10].p.mdf || effectElements[11].p.mdf || effectElements[12].p.mdf || effectElements[13].p.mdf)){
7893            val = this.getTableValue(effectElements[9].p.v,effectElements[10].p.v,effectElements[11].p.v,effectElements[12].p.v,effectElements[13].p.v);
7894            this.feFuncR.setAttribute('tableValues',val);
7895        }
7896
7897        if(this.feFuncG && (forceRender || effectElements[16].p.mdf || effectElements[17].p.mdf || effectElements[18].p.mdf || effectElements[19].p.mdf || effectElements[20].p.mdf)){
7898            val = this.getTableValue(effectElements[16].p.v,effectElements[17].p.v,effectElements[18].p.v,effectElements[19].p.v,effectElements[20].p.v);
7899            this.feFuncG.setAttribute('tableValues',val);
7900        }
7901
7902        if(this.feFuncB && (forceRender || effectElements[23].p.mdf || effectElements[24].p.mdf || effectElements[25].p.mdf || effectElements[26].p.mdf || effectElements[27].p.mdf)){
7903            val = this.getTableValue(effectElements[23].p.v,effectElements[24].p.v,effectElements[25].p.v,effectElements[26].p.v,effectElements[27].p.v);
7904            this.feFuncB.setAttribute('tableValues',val);
7905        }
7906
7907        if(this.feFuncA && (forceRender || effectElements[30].p.mdf || effectElements[31].p.mdf || effectElements[32].p.mdf || effectElements[33].p.mdf || effectElements[34].p.mdf)){
7908            val = this.getTableValue(effectElements[30].p.v,effectElements[31].p.v,effectElements[32].p.v,effectElements[33].p.v,effectElements[34].p.v);
7909            this.feFuncA.setAttribute('tableValues',val);
7910        }
7911        
7912    }
7913};
7914function SVGDropShadowEffect(filter, filterManager){
7915    /*<feGaussianBlur in="SourceAlpha" stdDeviation="3"/> <!-- stdDeviation is how much to blur -->
7916  <feOffset dx="2" dy="2" result="offsetblur"/> <!-- how much to offset -->
7917  <feMerge> 
7918    <feMergeNode/> <!-- this contains the offset blurred image -->
7919    <feMergeNode in="SourceGraphic"/> <!-- this contains the element that the filter is applied to -->
7920  </feMerge>*/
7921  /*<feFlood flood-color="#3D4574" flood-opacity="0.5" result="offsetColor"/>*/
7922    filter.setAttribute('x','-100%');
7923    filter.setAttribute('y','-100%');
7924    filter.setAttribute('width','400%');
7925    filter.setAttribute('height','400%');
7926    this.filterManager = filterManager;
7927
7928    var feGaussianBlur = document.createElementNS(svgNS,'feGaussianBlur');
7929    feGaussianBlur.setAttribute('in','SourceAlpha');
7930    feGaussianBlur.setAttribute('result','drop_shadow_1');
7931    feGaussianBlur.setAttribute('stdDeviation','0');
7932    this.feGaussianBlur = feGaussianBlur;
7933    filter.appendChild(feGaussianBlur);
7934
7935    var feOffset = document.createElementNS(svgNS,'feOffset');
7936    feOffset.setAttribute('dx','25');
7937    feOffset.setAttribute('dy','0');
7938    feOffset.setAttribute('in','drop_shadow_1');
7939    feOffset.setAttribute('result','drop_shadow_2');
7940    this.feOffset = feOffset;
7941    filter.appendChild(feOffset);
7942    var feFlood = document.createElementNS(svgNS,'feFlood');
7943    feFlood.setAttribute('flood-color','#00ff00');
7944    feFlood.setAttribute('flood-opacity','1');
7945    feFlood.setAttribute('result','drop_shadow_3');
7946    this.feFlood = feFlood;
7947    filter.appendChild(feFlood);
7948
7949    var feComposite = document.createElementNS(svgNS,'feComposite');
7950    feComposite.setAttribute('in','drop_shadow_3');
7951    feComposite.setAttribute('in2','drop_shadow_2');
7952    feComposite.setAttribute('operator','in');
7953    feComposite.setAttribute('result','drop_shadow_4');
7954    filter.appendChild(feComposite);
7955
7956
7957    var feMerge = document.createElementNS(svgNS,'feMerge');
7958    filter.appendChild(feMerge);
7959    var feMergeNode;
7960    feMergeNode = document.createElementNS(svgNS,'feMergeNode');
7961    feMerge.appendChild(feMergeNode);
7962    feMergeNode = document.createElementNS(svgNS,'feMergeNode');
7963    feMergeNode.setAttribute('in','SourceGraphic');
7964    this.feMergeNode = feMergeNode;
7965    this.feMerge = feMerge;
7966    this.originalNodeAdded = false;
7967    feMerge.appendChild(feMergeNode);
7968}
7969
7970SVGDropShadowEffect.prototype.renderFrame = function(forceRender){
7971    if(forceRender || this.filterManager.mdf){
7972        if(forceRender || this.filterManager.effectElements[4].p.mdf){
7973            this.feGaussianBlur.setAttribute('stdDeviation', this.filterManager.effectElements[4].p.v / 4);
7974        }
7975        if(forceRender || this.filterManager.effectElements[0].p.mdf){
7976            var col = this.filterManager.effectElements[0].p.v;
7977            this.feFlood.setAttribute('flood-color',rgbToHex(Math.round(col[0]*255),Math.round(col[1]*255),Math.round(col[2]*255)));
7978        }
7979        if(forceRender || this.filterManager.effectElements[1].p.mdf){
7980            this.feFlood.setAttribute('flood-opacity',this.filterManager.effectElements[1].p.v/255);
7981        }
7982        if(forceRender || this.filterManager.effectElements[2].p.mdf || this.filterManager.effectElements[3].p.mdf){
7983            var distance = this.filterManager.effectElements[3].p.v
7984            var angle = (this.filterManager.effectElements[2].p.v - 90) * degToRads
7985            var x = distance * Math.cos(angle)
7986            var y = distance * Math.sin(angle)
7987            this.feOffset.setAttribute('dx', x);
7988            this.feOffset.setAttribute('dy', y);
7989        }
7990        /*if(forceRender || this.filterManager.effectElements[5].p.mdf){
7991            if(this.filterManager.effectElements[5].p.v === 1 && this.originalNodeAdded) {
7992                this.feMerge.removeChild(this.feMergeNode);
7993                this.originalNodeAdded = false;
7994            } else if(this.filterManager.effectElements[5].p.v === 0 && !this.originalNodeAdded) {
7995                this.feMerge.appendChild(this.feMergeNode);
7996                this.originalNodeAdded = true;
7997            }
7998        }*/
7999    }
8000};
8001function SVGMatte3Effect(filterElem, filterManager, elem){
8002    this.initialized = false;
8003    this.filterManager = filterManager;
8004    this.filterElem = filterElem;
8005    this.elem = elem;
8006    elem.matteElement = document.createElementNS(svgNS,'g');
8007    elem.matteElement.appendChild(elem.layerElement);
8008    elem.matteElement.appendChild(elem.transformedElement);
8009    elem.baseElement = elem.matteElement;
8010}
8011
8012SVGMatte3Effect.prototype.setElementAsMask = function(elem, mask) {
8013    var masker = document.createElementNS(svgNS,'mask');
8014    masker.setAttribute('id',mask.layerId);
8015    masker.setAttribute('mask-type','alpha');
8016    masker.appendChild(mask.layerElement);
8017    elem.setMatte(mask.layerId);
8018    mask.data.hd = false;
8019    var defs = elem.globalData.defs;
8020    defs.appendChild(masker);
8021}
8022
8023SVGMatte3Effect.prototype.initialize = function() {
8024    var ind = this.filterManager.effectElements[0].p.v;
8025    var i = 0, len = this.elem.comp.elements.length;
8026    while(i < len) {
8027    	if(this.elem.comp.elements[i].data.ind === ind) {
8028    		this.setElementAsMask(this.elem, this.elem.comp.elements[i]);
8029    	}
8030    	i += 1;
8031    }
8032    this.initialized = true;
8033}
8034
8035SVGMatte3Effect.prototype.renderFrame = function() {
8036	if(!this.initialized) {
8037		this.initialize();
8038	}
8039}
8040function SVGEffects(elem){
8041    var i, len = elem.data.ef.length;
8042    var filId = randomString(10);
8043    var fil = filtersFactory.createFilter(filId);
8044    var count = 0;
8045    this.filters = [];
8046    var filterManager;
8047    for(i=0;i<len;i+=1){
8048        if(elem.data.ef[i].ty === 20){
8049            count += 1;
8050            filterManager = new SVGTintFilter(fil, elem.effects.effectElements[i]);
8051            this.filters.push(filterManager);
8052        }else if(elem.data.ef[i].ty === 21){
8053            count += 1;
8054            filterManager = new SVGFillFilter(fil, elem.effects.effectElements[i]);
8055            this.filters.push(filterManager);
8056        }else if(elem.data.ef[i].ty === 22){
8057            filterManager = new SVGStrokeEffect(elem, elem.effects.effectElements[i]);
8058            this.filters.push(filterManager);
8059        }else if(elem.data.ef[i].ty === 23){
8060            count += 1;
8061            filterManager = new SVGTritoneFilter(fil, elem.effects.effectElements[i]);
8062            this.filters.push(filterManager);
8063        }else if(elem.data.ef[i].ty === 24){
8064            count += 1;
8065            filterManager = new SVGProLevelsFilter(fil, elem.effects.effectElements[i]);
8066            this.filters.push(filterManager);
8067        }else if(elem.data.ef[i].ty === 25){
8068            count += 1;
8069            filterManager = new SVGDropShadowEffect(fil, elem.effects.effectElements[i]);
8070            this.filters.push(filterManager);
8071        }else if(elem.data.ef[i].ty === 28){
8072            //count += 1;
8073            filterManager = new SVGMatte3Effect(fil, elem.effects.effectElements[i], elem);
8074            this.filters.push(filterManager);
8075        }
8076    }
8077    if(count){
8078        elem.globalData.defs.appendChild(fil);
8079        elem.layerElement.setAttribute('filter','url(' + locationHref + '#'+filId+')');
8080    }
8081}
8082
8083SVGEffects.prototype.renderFrame = function(firstFrame){
8084    var i, len = this.filters.length;
8085    for(i=0;i<len;i+=1){
8086        this.filters[i].renderFrame(firstFrame);
8087    }
8088};
8089function ICompElement(data,parentContainer,globalData,comp, placeholder){
8090    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
8091    this.layers = data.layers;
8092    this.supports3d = true;
8093    this.completeLayers = false;
8094    this.pendingElements = [];
8095    this.elements = this.layers ? Array.apply(null,{length:this.layers.length}) : [];
8096    if(this.data.tm){
8097        this.tm = PropertyFactory.getProp(this,this.data.tm,0,globalData.frameRate,this.dynamicProperties);
8098    }
8099    if(this.data.xt){
8100        this.layerElement = document.createElementNS(svgNS,'g');
8101        this.buildAllItems();
8102    } else if(!globalData.progressiveLoad){
8103        this.buildAllItems();
8104    }
8105}
8106createElement(SVGBaseElement, ICompElement);
8107
8108ICompElement.prototype.hide = function(){
8109    if(!this.hidden){
8110        this._parent.hide.call(this);
8111        var i,len = this.elements.length;
8112        for( i = 0; i < len; i+=1 ){
8113            if(this.elements[i]){
8114                this.elements[i].hide();
8115            }
8116        }
8117    }
8118};
8119
8120ICompElement.prototype.prepareFrame = function(num){
8121    this._parent.prepareFrame.call(this,num);
8122    if(this.isVisible===false && !this.data.xt){
8123        return;
8124    }
8125
8126    if(this.tm){
8127        var timeRemapped = this.tm.v;
8128        if(timeRemapped === this.data.op){
8129            timeRemapped = this.data.op - 1;
8130        }
8131        this.renderedFrame = timeRemapped;
8132    } else {
8133        this.renderedFrame = num/this.data.sr;
8134    }
8135    var i,len = this.elements.length;
8136    if(!this.completeLayers){
8137        this.checkLayers(this.renderedFrame);
8138    }
8139    for( i = 0; i < len; i+=1 ){
8140        if(this.completeLayers || this.elements[i]){
8141            this.elements[i].prepareFrame(this.renderedFrame - this.layers[i].st);
8142        }
8143    }
8144};
8145
8146ICompElement.prototype.renderFrame = function(parentMatrix){
8147    var renderParent = this._parent.renderFrame.call(this,parentMatrix);
8148    var i,len = this.layers.length;
8149    if(renderParent===false){
8150        this.hide();
8151        return;
8152    }
8153
8154    if(this.hidden) {
8155        this.show();
8156    }
8157    for( i = 0; i < len; i+=1 ){
8158        if(this.completeLayers || this.elements[i]){
8159            this.elements[i].renderFrame();
8160        }
8161    }
8162    if(this.firstFrame){
8163        this.firstFrame = false;
8164    }
8165};
8166
8167ICompElement.prototype.setElements = function(elems){
8168    this.elements = elems;
8169};
8170
8171ICompElement.prototype.getElements = function(){
8172    return this.elements;
8173};
8174
8175ICompElement.prototype.destroy = function(){
8176    this._parent.destroy.call(this._parent);
8177    var i,len = this.layers.length;
8178    for( i = 0; i < len; i+=1 ){
8179        if(this.elements[i]){
8180            this.elements[i].destroy();
8181        }
8182    }
8183};
8184
8185ICompElement.prototype.checkLayers = SVGRenderer.prototype.checkLayers;
8186ICompElement.prototype.buildItem = SVGRenderer.prototype.buildItem;
8187ICompElement.prototype.buildAllItems = SVGRenderer.prototype.buildAllItems;
8188ICompElement.prototype.buildElementParenting = SVGRenderer.prototype.buildElementParenting;
8189ICompElement.prototype.createItem = SVGRenderer.prototype.createItem;
8190ICompElement.prototype.createImage = SVGRenderer.prototype.createImage;
8191ICompElement.prototype.createComp = SVGRenderer.prototype.createComp;
8192ICompElement.prototype.createSolid = SVGRenderer.prototype.createSolid;
8193ICompElement.prototype.createShape = SVGRenderer.prototype.createShape;
8194ICompElement.prototype.createText = SVGRenderer.prototype.createText;
8195ICompElement.prototype.createBase = SVGRenderer.prototype.createBase;
8196ICompElement.prototype.appendElementInPos = SVGRenderer.prototype.appendElementInPos;
8197ICompElement.prototype.checkPendingElements = SVGRenderer.prototype.checkPendingElements;
8198ICompElement.prototype.addPendingElement = SVGRenderer.prototype.addPendingElement;
8199function IImageElement(data,parentContainer,globalData,comp,placeholder){
8200    this.assetData = globalData.getAssetData(data.refId);
8201    this._parent.constructor.call(this,data,parentContainer,globalData,comp,placeholder);
8202}
8203createElement(SVGBaseElement, IImageElement);
8204
8205IImageElement.prototype.createElements = function(){
8206
8207    var assetPath = this.globalData.getAssetsPath(this.assetData);
8208
8209    this._parent.createElements.call(this);
8210
8211    this.innerElem = document.createElementNS(svgNS,'image');
8212    this.innerElem.setAttribute('width',this.assetData.w+"px");
8213    this.innerElem.setAttribute('height',this.assetData.h+"px");
8214    this.innerElem.setAttribute('preserveAspectRatio','xMidYMid slice');
8215    this.innerElem.setAttributeNS('http://www.w3.org/1999/xlink','href',assetPath);
8216    this.maskedElement = this.innerElem;
8217    this.layerElement.appendChild(this.innerElem);
8218    if(this.data.ln){
8219        this.layerElement.setAttribute('id',this.data.ln);
8220    }
8221    if(this.data.cl){
8222        this.layerElement.setAttribute('class',this.data.cl);
8223    }
8224
8225};
8226
8227IImageElement.prototype.renderFrame = function(parentMatrix){
8228    var renderParent = this._parent.renderFrame.call(this,parentMatrix);
8229    if(renderParent===false){
8230        this.hide();
8231        return;
8232    }
8233    if(this.hidden){
8234        this.show();
8235    }
8236    if(this.firstFrame){
8237        this.firstFrame = false;
8238    }
8239};
8240
8241IImageElement.prototype.destroy = function(){
8242    this._parent.destroy.call(this._parent);
8243    this.innerElem =  null;
8244};
8245function ISolidElement(data,parentContainer,globalData,comp, placeholder){
8246    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
8247}
8248createElement(SVGBaseElement, ISolidElement);
8249
8250ISolidElement.prototype.createElements = function(){
8251    this._parent.createElements.call(this);
8252
8253    var rect = document.createElementNS(svgNS,'rect');
8254    ////rect.style.width = this.data.sw;
8255    ////rect.style.height = this.data.sh;
8256    ////rect.style.fill = this.data.sc;
8257    rect.setAttribute('width',this.data.sw);
8258    rect.setAttribute('height',this.data.sh);
8259    rect.setAttribute('fill',this.data.sc);
8260    this.layerElement.appendChild(rect);
8261    this.innerElem = rect;
8262    if(this.data.ln){
8263        this.layerElement.setAttribute('id',this.data.ln);
8264    }
8265    if(this.data.cl){
8266        this.layerElement.setAttribute('class',this.data.cl);
8267    }
8268};
8269
8270ISolidElement.prototype.renderFrame = IImageElement.prototype.renderFrame;
8271ISolidElement.prototype.destroy = IImageElement.prototype.destroy;
8272
8273var animationManager = (function(){
8274    var moduleOb = {};
8275    var registeredAnimations = [];
8276    var initTime = 0;
8277    var len = 0;
8278    var idled = true;
8279    var playingAnimationsNum = 0;
8280
8281    function removeElement(ev){
8282        var i = 0;
8283        var animItem = ev.target;
8284        while(i<len) {
8285            if (registeredAnimations[i].animation === animItem) {
8286                registeredAnimations.splice(i, 1);
8287                i -= 1;
8288                len -= 1;
8289                if(!animItem.isPaused){
8290                    subtractPlayingCount();
8291                }
8292            }
8293            i += 1;
8294        }
8295    }
8296
8297    function registerAnimation(element, animationData){
8298        if(!element){
8299            return null;
8300        }
8301        var i=0;
8302        while(i<len){
8303            if(registeredAnimations[i].elem == element && registeredAnimations[i].elem !== null ){
8304                return registeredAnimations[i].animation;
8305            }
8306            i+=1;
8307        }
8308        var animItem = new AnimationItem();
8309        setupAnimation(animItem, element);
8310        animItem.setData(element, animationData);
8311        return animItem;
8312    }
8313
8314    function addPlayingCount(){
8315        playingAnimationsNum += 1;
8316        activate();
8317    }
8318
8319    function subtractPlayingCount(){
8320        playingAnimationsNum -= 1;
8321        if(playingAnimationsNum === 0){
8322            idled = true;
8323        }
8324    }
8325
8326    function setupAnimation(animItem, element){
8327        animItem.addEventListener('destroy',removeElement);
8328        animItem.addEventListener('_active',addPlayingCount);
8329        animItem.addEventListener('_idle',subtractPlayingCount);
8330        registeredAnimations.push({elem: element,animation:animItem});
8331        len += 1;
8332    }
8333
8334    function loadAnimation(params){
8335        var animItem = new AnimationItem();
8336        setupAnimation(animItem, null);
8337        animItem.setParams(params);
8338        return animItem;
8339    }
8340
8341
8342    function setSpeed(val,animation){
8343        var i;
8344        for(i=0;i<len;i+=1){
8345            registeredAnimations[i].animation.setSpeed(val, animation);
8346        }
8347    }
8348
8349    function setDirection(val, animation){
8350        var i;
8351        for(i=0;i<len;i+=1){
8352            registeredAnimations[i].animation.setDirection(val, animation);
8353        }
8354    }
8355
8356    function play(animation){
8357        var i;
8358        for(i=0;i<len;i+=1){
8359            registeredAnimations[i].animation.play(animation);
8360        }
8361    }
8362
8363    function moveFrame (value, animation) {
8364        initTime = Date.now();
8365        var i;
8366        for(i=0;i<len;i+=1){
8367            registeredAnimations[i].animation.moveFrame(value,animation);
8368        }
8369    }
8370
8371    function resume(nowTime) {
8372
8373        var elapsedTime = nowTime - initTime;
8374        var i;
8375        for(i=0;i<len;i+=1){
8376            registeredAnimations[i].animation.advanceTime(elapsedTime);
8377        }
8378        initTime = nowTime;
8379        if(!idled) {
8380            window.requestAnimationFrame(resume);
8381        }
8382    }
8383
8384    function first(nowTime){
8385        initTime = nowTime;
8386        window.requestAnimationFrame(resume);
8387    }
8388
8389    function pause(animation) {
8390        var i;
8391        for(i=0;i<len;i+=1){
8392            registeredAnimations[i].animation.pause(animation);
8393        }
8394    }
8395
8396    function goToAndStop(value,isFrame,animation) {
8397        var i;
8398        for(i=0;i<len;i+=1){
8399            registeredAnimations[i].animation.goToAndStop(value,isFrame,animation);
8400        }
8401    }
8402
8403    function stop(animation) {
8404        var i;
8405        for(i=0;i<len;i+=1){
8406            registeredAnimations[i].animation.stop(animation);
8407        }
8408    }
8409
8410    function togglePause(animation) {
8411        var i;
8412        for(i=0;i<len;i+=1){
8413            registeredAnimations[i].animation.togglePause(animation);
8414        }
8415    }
8416
8417    function destroy(animation) {
8418        var i;
8419        for(i=(len-1);i>=0;i-=1){
8420            registeredAnimations[i].animation.destroy(animation);
8421        }
8422    }
8423
8424    function searchAnimations(animationData, standalone, renderer){
8425        var animElements = document.getElementsByClassName('bodymovin');
8426        var i, len = animElements.length;
8427        for(i=0;i<len;i+=1){
8428            if(renderer){
8429                animElements[i].setAttribute('data-bm-type',renderer);
8430            }
8431            registerAnimation(animElements[i], animationData);
8432        }
8433        if(standalone && len === 0){
8434            if(!renderer){
8435                renderer = 'svg';
8436            }
8437            var body = document.getElementsByTagName('body')[0];
8438            body.innerHTML = '';
8439            var div = document.createElement('div');
8440            div.style.width = '100%';
8441            div.style.height = '100%';
8442            div.setAttribute('data-bm-type',renderer);
8443            body.appendChild(div);
8444            registerAnimation(div, animationData);
8445        }
8446    }
8447
8448    function resize(){
8449        var i;
8450        for(i=0;i<len;i+=1){
8451            registeredAnimations[i].animation.resize();
8452        }
8453    }
8454
8455    function start(){
8456        window.requestAnimationFrame(first);
8457    }
8458
8459    function activate(){
8460        if(idled){
8461            idled = false;
8462            window.requestAnimationFrame(first);
8463        }
8464    }
8465
8466    //start();
8467
8468    setTimeout(start,0);
8469
8470    moduleOb.registerAnimation = registerAnimation;
8471    moduleOb.loadAnimation = loadAnimation;
8472    moduleOb.setSpeed = setSpeed;
8473    moduleOb.setDirection = setDirection;
8474    moduleOb.play = play;
8475    moduleOb.moveFrame = moveFrame;
8476    moduleOb.pause = pause;
8477    moduleOb.stop = stop;
8478    moduleOb.togglePause = togglePause;
8479    moduleOb.searchAnimations = searchAnimations;
8480    moduleOb.resize = resize;
8481    moduleOb.start = start;
8482    moduleOb.goToAndStop = goToAndStop;
8483    moduleOb.destroy = destroy;
8484    return moduleOb;
8485}());
8486
8487var AnimationItem = function () {
8488    this._cbs = [];
8489    this.name = '';
8490    this.path = '';
8491    this.isLoaded = false;
8492    this.currentFrame = 0;
8493    this.currentRawFrame = 0;
8494    this.totalFrames = 0;
8495    this.frameRate = 0;
8496    this.frameMult = 0;
8497    this.playSpeed = 1;
8498    this.playDirection = 1;
8499    this.pendingElements = 0;
8500    this.playCount = 0;
8501    this.prerenderFramesFlag = true;
8502    this.animationData = {};
8503    this.layers = [];
8504    this.assets = [];
8505    this.isPaused = true;
8506    this.autoplay = false;
8507    this.loop = true;
8508    this.renderer = null;
8509    this.animationID = randomString(10);
8510    this.scaleMode = 'fit';
8511    this.assetsPath = '';
8512    this.timeCompleted = 0;
8513    this.segmentPos = 0;
8514    this.subframeEnabled = subframeEnabled;
8515    this.segments = [];
8516    this.pendingSegment = false;
8517    this._idle = true;
8518    this.projectInterface = ProjectInterface();
8519};
8520
8521AnimationItem.prototype.setParams = function(params) {
8522    var self = this;
8523    if(params.context){
8524        this.context = params.context;
8525    }
8526    if(params.wrapper || params.container){
8527        this.wrapper = params.wrapper || params.container;
8528    }
8529    var animType = params.animType ? params.animType : params.renderer ? params.renderer : 'svg';
8530    switch(animType){
8531        case 'canvas':
8532            this.renderer = new CanvasRenderer(this, params.rendererSettings);
8533            break;
8534        case 'svg':
8535            this.renderer = new SVGRenderer(this, params.rendererSettings);
8536            break;
8537        case 'hybrid':
8538        case 'html':
8539        default:
8540            this.renderer = new HybridRenderer(this, params.rendererSettings);
8541            break;
8542    }
8543    this.renderer.setProjectInterface(this.projectInterface);
8544    this.animType = animType;
8545
8546    if(params.loop === '' || params.loop === null){
8547    }else if(params.loop === false){
8548        this.loop = false;
8549    }else if(params.loop === true){
8550        this.loop = true;
8551    }else{
8552        this.loop = parseInt(params.loop);
8553    }
8554    this.autoplay = 'autoplay' in params ? params.autoplay : true;
8555    this.name = params.name ? params.name :  '';
8556    this.prerenderFramesFlag = 'prerender' in params ? params.prerender : true;
8557    this.autoloadSegments = params.hasOwnProperty('autoloadSegments') ? params.autoloadSegments :  true;
8558    if(params.animationData){
8559        self.configAnimation(params.animationData);
8560    }else if(params.path){
8561        if(params.path.substr(-4) != 'json'){
8562            if (params.path.substr(-1, 1) != '/') {
8563                params.path += '/';
8564            }
8565            params.path += 'data.json';
8566        }
8567
8568        var xhr = new XMLHttpRequest();
8569        if(params.path.lastIndexOf('\\') != -1){
8570            this.path = params.path.substr(0,params.path.lastIndexOf('\\')+1);
8571        }else{
8572            this.path = params.path.substr(0,params.path.lastIndexOf('/')+1);
8573        }
8574        this.assetsPath = params.assetsPath;
8575        this.fileName = params.path.substr(params.path.lastIndexOf('/')+1);
8576        this.fileName = this.fileName.substr(0,this.fileName.lastIndexOf('.json'));
8577        xhr.open('GET', params.path, true);
8578        xhr.send();
8579        xhr.onreadystatechange = function () {
8580            if (xhr.readyState == 4) {
8581                if(xhr.status == 200){
8582                    self.configAnimation(JSON.parse(xhr.responseText));
8583                }else{
8584                    try{
8585                        var response = JSON.parse(xhr.responseText);
8586                        self.configAnimation(response);
8587                    }catch(err){
8588                    }
8589                }
8590            }
8591        };
8592    }
8593};
8594
8595AnimationItem.prototype.setData = function (wrapper, animationData) {
8596    var params = {
8597        wrapper: wrapper,
8598        animationData: animationData ? (typeof animationData  === "object") ? animationData : JSON.parse(animationData) : null
8599    };
8600    var wrapperAttributes = wrapper.attributes;
8601
8602    params.path = wrapperAttributes.getNamedItem('data-animation-path') ? wrapperAttributes.getNamedItem('data-animation-path').value : wrapperAttributes.getNamedItem('data-bm-path') ? wrapperAttributes.getNamedItem('data-bm-path').value :  wrapperAttributes.getNamedItem('bm-path') ? wrapperAttributes.getNamedItem('bm-path').value : '';
8603    params.animType = wrapperAttributes.getNamedItem('data-anim-type') ? wrapperAttributes.getNamedItem('data-anim-type').value : wrapperAttributes.getNamedItem('data-bm-type') ? wrapperAttributes.getNamedItem('data-bm-type').value : wrapperAttributes.getNamedItem('bm-type') ? wrapperAttributes.getNamedItem('bm-type').value :  wrapperAttributes.getNamedItem('data-bm-renderer') ? wrapperAttributes.getNamedItem('data-bm-renderer').value : wrapperAttributes.getNamedItem('bm-renderer') ? wrapperAttributes.getNamedItem('bm-renderer').value : 'canvas';
8604
8605    var loop = wrapperAttributes.getNamedItem('data-anim-loop') ? wrapperAttributes.getNamedItem('data-anim-loop').value :  wrapperAttributes.getNamedItem('data-bm-loop') ? wrapperAttributes.getNamedItem('data-bm-loop').value :  wrapperAttributes.getNamedItem('bm-loop') ? wrapperAttributes.getNamedItem('bm-loop').value : '';
8606    if(loop === ''){
8607    }else if(loop === 'false'){
8608        params.loop = false;
8609    }else if(loop === 'true'){
8610        params.loop = true;
8611    }else{
8612        params.loop = parseInt(loop);
8613    }
8614    var autoplay = wrapperAttributes.getNamedItem('data-anim-autoplay') ? wrapperAttributes.getNamedItem('data-anim-autoplay').value :  wrapperAttributes.getNamedItem('data-bm-autoplay') ? wrapperAttributes.getNamedItem('data-bm-autoplay').value :  wrapperAttributes.getNamedItem('bm-autoplay') ? wrapperAttributes.getNamedItem('bm-autoplay').value : true;
8615    params.autoplay = autoplay !== "false";
8616
8617    params.name = wrapperAttributes.getNamedItem('data-name') ? wrapperAttributes.getNamedItem('data-name').value :  wrapperAttributes.getNamedItem('data-bm-name') ? wrapperAttributes.getNamedItem('data-bm-name').value : wrapperAttributes.getNamedItem('bm-name') ? wrapperAttributes.getNamedItem('bm-name').value :  '';
8618    var prerender = wrapperAttributes.getNamedItem('data-anim-prerender') ? wrapperAttributes.getNamedItem('data-anim-prerender').value :  wrapperAttributes.getNamedItem('data-bm-prerender') ? wrapperAttributes.getNamedItem('data-bm-prerender').value :  wrapperAttributes.getNamedItem('bm-prerender') ? wrapperAttributes.getNamedItem('bm-prerender').value : '';
8619
8620    if(prerender === 'false'){
8621        params.prerender = false;
8622    }
8623    this.setParams(params);
8624};
8625
8626AnimationItem.prototype.includeLayers = function(data) {
8627    if(data.op > this.animationData.op){
8628        this.animationData.op = data.op;
8629        this.totalFrames = Math.floor(data.op - this.animationData.ip);
8630        this.animationData.tf = this.totalFrames;
8631    }
8632    var layers = this.animationData.layers;
8633    var i, len = layers.length;
8634    var newLayers = data.layers;
8635    var j, jLen = newLayers.length;
8636    for(j=0;j<jLen;j+=1){
8637        i = 0;
8638        while(i<len){
8639            if(layers[i].id == newLayers[j].id){
8640                layers[i] = newLayers[j];
8641                break;
8642            }
8643            i += 1;
8644        }
8645    }
8646    if(data.chars || data.fonts){
8647        this.renderer.globalData.fontManager.addChars(data.chars);
8648        this.renderer.globalData.fontManager.addFonts(data.fonts, this.renderer.globalData.defs);
8649    }
8650    if(data.assets){
8651        len = data.assets.length;
8652        for(i = 0; i < len; i += 1){
8653            this.animationData.assets.push(data.assets[i]);
8654        }
8655    }
8656    //this.totalFrames = 50;
8657    //this.animationData.tf = 50;
8658    this.animationData.__complete = false;
8659    dataManager.completeData(this.animationData,this.renderer.globalData.fontManager);
8660    this.renderer.includeLayers(data.layers);
8661    if(expressionsPlugin){
8662        expressionsPlugin.initExpressions(this);
8663    }
8664    this.renderer.renderFrame(null);
8665    this.loadNextSegment();
8666};
8667
8668AnimationItem.prototype.loadNextSegment = function() {
8669    var segments = this.animationData.segments;
8670    if(!segments || segments.length === 0 || !this.autoloadSegments){
8671        this.trigger('data_ready');
8672        this.timeCompleted = this.animationData.tf;
8673        return;
8674    }
8675    var segment = segments.shift();
8676    this.timeCompleted = segment.time * this.frameRate;
8677    var xhr = new XMLHttpRequest();
8678    var self = this;
8679    var segmentPath = this.path+this.fileName+'_' + this.segmentPos + '.json';
8680    this.segmentPos += 1;
8681    xhr.open('GET', segmentPath, true);
8682    xhr.send();
8683    xhr.onreadystatechange = function () {
8684        if (xhr.readyState == 4) {
8685            if(xhr.status == 200){
8686                self.includeLayers(JSON.parse(xhr.responseText));
8687            }else{
8688                try{
8689                    var response = JSON.parse(xhr.responseText);
8690                    self.includeLayers(response);
8691                }catch(err){
8692                }
8693            }
8694        }
8695    };
8696};
8697
8698AnimationItem.prototype.loadSegments = function() {
8699    var segments = this.animationData.segments;
8700    if(!segments) {
8701        this.timeCompleted = this.animationData.tf;
8702    }
8703    this.loadNextSegment();
8704};
8705
8706AnimationItem.prototype.configAnimation = function (animData) {
8707    var _this = this;
8708    if(this.renderer && this.renderer.destroyed){
8709        return;
8710    }
8711    //console.log(JSON.parse(JSON.stringify(animData)));
8712    //animData.w = Math.round(animData.w/blitter);
8713    //animData.h = Math.round(animData.h/blitter);
8714    this.animationData = animData;
8715    this.totalFrames = Math.floor(this.animationData.op - this.animationData.ip);
8716    this.animationData.tf = this.totalFrames;
8717    this.renderer.configAnimation(animData);
8718    if(!animData.assets){
8719        animData.assets = [];
8720    }
8721    if(animData.comps) {
8722        animData.assets = animData.assets.concat(animData.comps);
8723        animData.comps = null;
8724    }
8725    this.renderer.searchExtraCompositions(animData.assets);
8726
8727    this.layers = this.animationData.layers;
8728    this.assets = this.animationData.assets;
8729    this.frameRate = this.animationData.fr;
8730    this.firstFrame = Math.round(this.animationData.ip);
8731    this.frameMult = this.animationData.fr / 1000;
8732    this.trigger('config_ready');
8733    this.imagePreloader = new ImagePreloader();
8734    this.imagePreloader.setAssetsPath(this.assetsPath);
8735    this.imagePreloader.setPath(this.path);
8736    this.imagePreloader.loadAssets(animData.assets, function(err) {
8737        if(!err) {
8738            _this.trigger('loaded_images');
8739        }
8740    });
8741    this.loadSegments();
8742    this.updaFrameModifier();
8743    if(this.renderer.globalData.fontManager){
8744        this.waitForFontsLoaded();
8745    }else{
8746        dataManager.completeData(this.animationData,this.renderer.globalData.fontManager);
8747        this.checkLoaded();
8748    }
8749};
8750
8751AnimationItem.prototype.waitForFontsLoaded = (function(){
8752    function checkFontsLoaded(){
8753        if(this.renderer.globalData.fontManager.loaded){
8754            dataManager.completeData(this.animationData,this.renderer.globalData.fontManager);
8755            //this.renderer.buildItems(this.animationData.layers);
8756            this.checkLoaded();
8757        }else{
8758            setTimeout(checkFontsLoaded.bind(this),20);
8759        }
8760    }
8761
8762    return function(){
8763        checkFontsLoaded.bind(this)();
8764    }
8765}());
8766
8767AnimationItem.prototype.addPendingElement = function () {
8768    this.pendingElements += 1;
8769}
8770
8771AnimationItem.prototype.elementLoaded = function () {
8772    this.pendingElements--;
8773    this.checkLoaded();
8774};
8775
8776AnimationItem.prototype.checkLoaded = function () {
8777    if (this.pendingElements === 0) {
8778        if(expressionsPlugin){
8779            expressionsPlugin.initExpressions(this);
8780        }
8781        this.renderer.initItems();
8782        setTimeout(function(){
8783            this.trigger('DOMLoaded');
8784        }.bind(this),0);
8785        this.isLoaded = true;
8786        this.gotoFrame();
8787        if(this.autoplay){
8788            this.play();
8789        }
8790    }
8791};
8792
8793AnimationItem.prototype.resize = function () {
8794    this.renderer.updateContainerSize();
8795};
8796
8797AnimationItem.prototype.setSubframe = function(flag){
8798    this.subframeEnabled = flag ? true : false;
8799}
8800
8801AnimationItem.prototype.gotoFrame = function () {
8802    if(this.subframeEnabled){
8803        this.currentFrame = this.currentRawFrame;
8804    }else{
8805        this.currentFrame = Math.floor(this.currentRawFrame);
8806    }
8807
8808    if(this.timeCompleted !== this.totalFrames && this.currentFrame > this.timeCompleted){
8809        this.currentFrame = this.timeCompleted;
8810    }
8811    this.trigger('enterFrame');
8812    this.renderFrame();
8813};
8814
8815AnimationItem.prototype.renderFrame = function () {
8816    if(this.isLoaded === false){
8817        return;
8818    }
8819    //console.log('this.currentFrame:',this.currentFrame + this.firstFrame);
8820    this.renderer.renderFrame(this.currentFrame + this.firstFrame);
8821};
8822
8823AnimationItem.prototype.play = function (name) {
8824    if(name && this.name != name){
8825        return;
8826    }
8827    if(this.isPaused === true){
8828        this.isPaused = false;
8829        if(this._idle){
8830            this._idle = false;
8831            this.trigger('_active');
8832        }
8833    }
8834};
8835
8836AnimationItem.prototype.pause = function (name) {
8837    if(name && this.name != name){
8838        return;
8839    }
8840    if(this.isPaused === false){
8841        this.isPaused = true;
8842        if(!this.pendingSegment){
8843            this._idle = true;
8844            this.trigger('_idle');
8845        }
8846    }
8847};
8848
8849AnimationItem.prototype.togglePause = function (name) {
8850    if(name && this.name != name){
8851        return;
8852    }
8853    if(this.isPaused === true){
8854        this.play();
8855    }else{
8856        this.pause();
8857    }
8858};
8859
8860AnimationItem.prototype.stop = function (name) {
8861    if(name && this.name != name){
8862        return;
8863    }
8864    this.pause();
8865    this.currentFrame = this.currentRawFrame = 0;
8866    this.playCount = 0;
8867    this.gotoFrame();
8868};
8869
8870AnimationItem.prototype.goToAndStop = function (value, isFrame, name) {
8871    if(name && this.name != name){
8872        return;
8873    }
8874    if(isFrame){
8875        this.setCurrentRawFrameValue(value);
8876    }else{
8877        this.setCurrentRawFrameValue(value * this.frameModifier);
8878    }
8879    this.pause();
8880};
8881
8882AnimationItem.prototype.goToAndPlay = function (value, isFrame, name) {
8883    this.goToAndStop(value, isFrame, name);
8884    this.play();
8885};
8886
8887AnimationItem.prototype.advanceTime = function (value) {
8888    if(this.pendingSegment){
8889        this.pendingSegment = false;
8890        this.adjustSegment(this.segments.shift());
8891        if(this.isPaused){
8892            this.play();
8893        }
8894        return;
8895    }
8896    if (this.isPaused === true || this.isLoaded === false) {
8897        return;
8898    }
8899    this.setCurrentRawFrameValue(this.currentRawFrame + value * this.frameModifier);
8900};
8901
8902AnimationItem.prototype.updateAnimation = function (perc) {
8903    this.setCurrentRawFrameValue(this.totalFrames * perc);
8904};
8905
8906AnimationItem.prototype.moveFrame = function (value, name) {
8907    if(name && this.name != name){
8908        return;
8909    }
8910    this.setCurrentRawFrameValue(this.currentRawFrame+value);
8911};
8912
8913AnimationItem.prototype.adjustSegment = function(arr){
8914    this.playCount = 0;
8915    if(arr[1] < arr[0]){
8916        if(this.frameModifier > 0){
8917            if(this.playSpeed < 0){
8918                this.setSpeed(-this.playSpeed);
8919            } else {
8920                this.setDirection(-1);
8921            }
8922        }
8923        this.totalFrames = arr[0] - arr[1];
8924        this.firstFrame = arr[1];
8925        this.setCurrentRawFrameValue(this.totalFrames - 0.01);
8926    } else if(arr[1] > arr[0]){
8927        if(this.frameModifier < 0){
8928            if(this.playSpeed < 0){
8929                this.setSpeed(-this.playSpeed);
8930            } else {
8931                this.setDirection(1);
8932            }
8933        }
8934        this.totalFrames = arr[1] - arr[0];
8935        this.firstFrame = arr[0];
8936        this.setCurrentRawFrameValue(0);
8937    }
8938    this.trigger('segmentStart');
8939};
8940AnimationItem.prototype.setSegment = function (init,end) {
8941    var pendingFrame = -1;
8942    if(this.isPaused) {
8943        if (this.currentRawFrame + this.firstFrame < init) {
8944            pendingFrame = init;
8945        } else if (this.currentRawFrame + this.firstFrame > end) {
8946            pendingFrame = end - init - 0.01;
8947        }
8948    }
8949
8950    this.firstFrame = init;
8951    this.totalFrames = end - init;
8952    if(pendingFrame !== -1) {
8953        this.goToAndStop(pendingFrame,true);
8954    }
8955}
8956
8957AnimationItem.prototype.playSegments = function (arr,forceFlag) {
8958    if(typeof arr[0] === 'object'){
8959        var i, len = arr.length;
8960        for(i=0;i<len;i+=1){
8961            this.segments.push(arr[i]);
8962        }
8963    }else{
8964        this.segments.push(arr);
8965    }
8966    if(forceFlag){
8967        this.adjustSegment(this.segments.shift());
8968    }
8969    if(this.isPaused){
8970        this.play();
8971    }
8972};
8973
8974AnimationItem.prototype.resetSegments = function (forceFlag) {
8975    this.segments.length = 0;
8976    this.segments.push([this.animationData.ip*this.frameRate,Math.floor(this.animationData.op - this.animationData.ip+this.animationData.ip*this.frameRate)]);
8977    if(forceFlag){
8978        this.adjustSegment(this.segments.shift());
8979    }
8980};
8981AnimationItem.prototype.checkSegments = function(){
8982    if(this.segments.length){
8983        this.pendingSegment = true;
8984    }
8985}
8986
8987AnimationItem.prototype.remove = function (name) {
8988    if(name && this.name != name){
8989        return;
8990    }
8991    this.renderer.destroy();
8992};
8993
8994AnimationItem.prototype.destroy = function (name) {
8995    if((name && this.name != name) || (this.renderer && this.renderer.destroyed)){
8996        return;
8997    }
8998    this.renderer.destroy();
8999    this.trigger('destroy');
9000    this._cbs = null;
9001    this.onEnterFrame = this.onLoopComplete = this.onComplete = this.onSegmentStart = this.onDestroy = null;
9002};
9003
9004AnimationItem.prototype.setCurrentRawFrameValue = function(value){
9005    this.currentRawFrame = value;
9006    //console.log(this.totalFrames);
9007    if (this.currentRawFrame >= this.totalFrames) {
9008        this.checkSegments();
9009        if(this.loop === false){
9010            this.currentRawFrame = this.totalFrames - 0.01;
9011            this.gotoFrame();
9012            this.pause();
9013            this.trigger('complete');
9014            return;
9015        }else{
9016            this.trigger('loopComplete');
9017            this.playCount += 1;
9018            if((this.loop !== true && this.playCount == this.loop) || this.pendingSegment){
9019                this.currentRawFrame = this.totalFrames - 0.01;
9020                this.gotoFrame();
9021                this.pause();
9022                this.trigger('complete');
9023                return;
9024            } else {
9025                this.currentRawFrame = this.currentRawFrame % this.totalFrames;
9026            }
9027        }
9028    } else if (this.currentRawFrame < 0) {
9029        this.checkSegments();
9030        this.playCount -= 1;
9031        if(this.playCount < 0){
9032            this.playCount = 0;
9033        }
9034        if(this.loop === false  || this.pendingSegment){
9035            this.currentRawFrame = 0;
9036            this.gotoFrame();
9037            this.pause();
9038            this.trigger('complete');
9039            return;
9040        }else{
9041            this.trigger('loopComplete');
9042            this.currentRawFrame = (this.totalFrames + this.currentRawFrame) % this.totalFrames;
9043            this.gotoFrame();
9044            return;
9045        }
9046    }
9047
9048    this.gotoFrame();
9049};
9050
9051AnimationItem.prototype.setSpeed = function (val) {
9052    this.playSpeed = val;
9053    this.updaFrameModifier();
9054};
9055
9056AnimationItem.prototype.setDirection = function (val) {
9057    this.playDirection = val < 0 ? -1 : 1;
9058    this.updaFrameModifier();
9059};
9060
9061AnimationItem.prototype.updaFrameModifier = function () {
9062    this.frameModifier = this.frameMult * this.playSpeed * this.playDirection;
9063};
9064
9065AnimationItem.prototype.getPath = function () {
9066    return this.path;
9067};
9068
9069AnimationItem.prototype.getAssetsPath = function (assetData) {
9070    var path = '';
9071    if(this.assetsPath){
9072        var imagePath = assetData.p;
9073        if(imagePath.indexOf('images/') !== -1){
9074            imagePath = imagePath.split('/')[1];
9075        }
9076        path = this.assetsPath + imagePath;
9077    } else {
9078        path = this.path;
9079        path += assetData.u ? assetData.u : '';
9080        path += assetData.p;
9081    }
9082    return path;
9083};
9084
9085AnimationItem.prototype.getAssetData = function (id) {
9086    var i = 0, len = this.assets.length;
9087    while (i < len) {
9088        if(id == this.assets[i].id){
9089            return this.assets[i];
9090        }
9091        i += 1;
9092    }
9093};
9094
9095AnimationItem.prototype.hide = function () {
9096    this.renderer.hide();
9097};
9098
9099AnimationItem.prototype.show = function () {
9100    this.renderer.show();
9101};
9102
9103AnimationItem.prototype.getAssets = function () {
9104    return this.assets;
9105};
9106
9107AnimationItem.prototype.trigger = function(name){
9108    if(this._cbs && this._cbs[name]){
9109        switch(name){
9110            case 'enterFrame':
9111                this.triggerEvent(name,new BMEnterFrameEvent(name,this.currentFrame,this.totalFrames,this.frameMult));
9112                break;
9113            case 'loopComplete':
9114                this.triggerEvent(name,new BMCompleteLoopEvent(name,this.loop,this.playCount,this.frameMult));
9115                break;
9116            case 'complete':
9117                this.triggerEvent(name,new BMCompleteEvent(name,this.frameMult));
9118                break;
9119            case 'segmentStart':
9120                this.triggerEvent(name,new BMSegmentStartEvent(name,this.firstFrame,this.totalFrames));
9121                break;
9122            case 'destroy':
9123                this.triggerEvent(name,new BMDestroyEvent(name,this));
9124                break;
9125            default:
9126                this.triggerEvent(name);
9127        }
9128    }
9129    if(name === 'enterFrame' && this.onEnterFrame){
9130        this.onEnterFrame.call(this,new BMEnterFrameEvent(name,this.currentFrame,this.totalFrames,this.frameMult));
9131    }
9132    if(name === 'loopComplete' && this.onLoopComplete){
9133        this.onLoopComplete.call(this,new BMCompleteLoopEvent(name,this.loop,this.playCount,this.frameMult));
9134    }
9135    if(name === 'complete' && this.onComplete){
9136        this.onComplete.call(this,new BMCompleteEvent(name,this.frameMult));
9137    }
9138    if(name === 'segmentStart' && this.onSegmentStart){
9139        this.onSegmentStart.call(this,new BMSegmentStartEvent(name,this.firstFrame,this.totalFrames));
9140    }
9141    if(name === 'destroy' && this.onDestroy){
9142        this.onDestroy.call(this,new BMDestroyEvent(name,this));
9143    }
9144};
9145
9146AnimationItem.prototype.addEventListener = _addEventListener;
9147AnimationItem.prototype.removeEventListener = _removeEventListener;
9148AnimationItem.prototype.triggerEvent = _triggerEvent;
9149
9150function CanvasRenderer(animationItem, config){
9151    this.animationItem = animationItem;
9152    this.renderConfig = {
9153        clearCanvas: (config && config.clearCanvas !== undefined) ? config.clearCanvas : true,
9154        context: (config && config.context) || null,
9155        progressiveLoad: (config && config.progressiveLoad) || false,
9156        preserveAspectRatio: (config && config.preserveAspectRatio) || 'xMidYMid meet',
9157        className: (config && config.className) || ''
9158    };
9159    this.renderConfig.dpr = (config && config.dpr) || 1;
9160    if (this.animationItem.wrapper) {
9161        this.renderConfig.dpr = (config && config.dpr) || window.devicePixelRatio || 1;
9162    }
9163    this.renderedFrame = -1;
9164    this.globalData = {
9165        frameNum: -1
9166    };
9167    this.contextData = {
9168        saved : Array.apply(null,{length:15}),
9169        savedOp: Array.apply(null,{length:15}),
9170        cArrPos : 0,
9171        cTr : new Matrix(),
9172        cO : 1
9173    };
9174    var i, len = 15;
9175    for(i=0;i<len;i+=1){
9176        this.contextData.saved[i] = Array.apply(null,{length:16});
9177    }
9178    this.elements = [];
9179    this.pendingElements = [];
9180    this.transformMat = new Matrix();
9181    this.completeLayers = false;
9182}
9183extendPrototype(BaseRenderer,CanvasRenderer);
9184
9185CanvasRenderer.prototype.createBase = function (data) {
9186    return new CVBaseElement(data, this, this.globalData);
9187};
9188
9189CanvasRenderer.prototype.createShape = function (data) {
9190    return new CVShapeElement(data, this, this.globalData);
9191};
9192
9193CanvasRenderer.prototype.createText = function (data) {
9194    return new CVTextElement(data, this, this.globalData);
9195};
9196
9197CanvasRenderer.prototype.createImage = function (data) {
9198    return new CVImageElement(data, this, this.globalData);
9199};
9200
9201CanvasRenderer.prototype.createComp = function (data) {
9202    return new CVCompElement(data, this, this.globalData);
9203};
9204
9205CanvasRenderer.prototype.createSolid = function (data) {
9206    return new CVSolidElement(data, this, this.globalData);
9207};
9208
9209CanvasRenderer.prototype.ctxTransform = function(props){
9210    if(props[0] === 1 && props[1] === 0 && props[4] === 0 && props[5] === 1 && props[12] === 0 && props[13] === 0){
9211        return;
9212    }
9213    if(!this.renderConfig.clearCanvas){
9214        this.canvasContext.transform(props[0],props[1],props[4],props[5],props[12],props[13]);
9215        return;
9216    }
9217    this.transformMat.cloneFromProps(props);
9218    this.transformMat.transform(this.contextData.cTr.props[0],this.contextData.cTr.props[1],this.contextData.cTr.props[2],this.contextData.cTr.props[3],this.contextData.cTr.props[4],this.contextData.cTr.props[5],this.contextData.cTr.props[6],this.contextData.cTr.props[7],this.contextData.cTr.props[8],this.contextData.cTr.props[9],this.contextData.cTr.props[10],this.contextData.cTr.props[11],this.contextData.cTr.props[12],this.contextData.cTr.props[13],this.contextData.cTr.props[14],this.contextData.cTr.props[15])
9219    //this.contextData.cTr.transform(props[0],props[1],props[2],props[3],props[4],props[5],props[6],props[7],props[8],props[9],props[10],props[11],props[12],props[13],props[14],props[15]);
9220    this.contextData.cTr.cloneFromProps(this.transformMat.props);
9221    var trProps = this.contextData.cTr.props;
9222    this.canvasContext.setTransform(trProps[0],trProps[1],trProps[4],trProps[5],trProps[12],trProps[13]);
9223};
9224
9225CanvasRenderer.prototype.ctxOpacity = function(op){
9226    if(op === 1){
9227        return;
9228    }
9229    if(!this.renderConfig.clearCanvas){
9230        this.canvasContext.globalAlpha *= op < 0 ? 0 : op;
9231        return;
9232    }
9233    this.contextData.cO *= op < 0 ? 0 : op;
9234    this.canvasContext.globalAlpha = this.contextData.cO;
9235};
9236
9237CanvasRenderer.prototype.reset = function(){
9238    if(!this.renderConfig.clearCanvas){
9239        this.canvasContext.restore();
9240        return;
9241    }
9242    this.contextData.cArrPos = 0;
9243    this.contextData.cTr.reset();
9244    this.contextData.cO = 1;
9245};
9246
9247CanvasRenderer.prototype.save = function(actionFlag){
9248    if(!this.renderConfig.clearCanvas){
9249        this.canvasContext.save();
9250        return;
9251    }
9252    if(actionFlag){
9253        this.canvasContext.save();
9254    }
9255    var props = this.contextData.cTr.props;
9256    if(this.contextData.saved[this.contextData.cArrPos] === null || this.contextData.saved[this.contextData.cArrPos] === undefined){
9257        this.contextData.saved[this.contextData.cArrPos] = new Array(16);
9258    }
9259    var i,arr = this.contextData.saved[this.contextData.cArrPos];
9260    for(i=0;i<16;i+=1){
9261        arr[i] = props[i];
9262    }
9263    this.contextData.savedOp[this.contextData.cArrPos] = this.contextData.cO;
9264    this.contextData.cArrPos += 1;
9265};
9266
9267CanvasRenderer.prototype.restore = function(actionFlag){
9268    if(!this.renderConfig.clearCanvas){
9269        this.canvasContext.restore();
9270        return;
9271    }
9272    if(actionFlag){
9273        this.canvasContext.restore();
9274    }
9275    this.contextData.cArrPos -= 1;
9276    var popped = this.contextData.saved[this.contextData.cArrPos];
9277    var i,arr = this.contextData.cTr.props;
9278    for(i=0;i<16;i+=1){
9279        arr[i] = popped[i];
9280    }
9281    this.canvasContext.setTransform(popped[0],popped[1],popped[4],popped[5],popped[12],popped[13]);
9282    popped = this.contextData.savedOp[this.contextData.cArrPos];
9283    this.contextData.cO = popped;
9284    this.canvasContext.globalAlpha = popped;
9285};
9286
9287CanvasRenderer.prototype.configAnimation = function(animData){
9288    if(this.animationItem.wrapper){
9289        this.animationItem.container = document.createElement('canvas');
9290        this.animationItem.container.style.width = '100%';
9291        this.animationItem.container.style.height = '100%';
9292        //this.animationItem.container.style.transform = 'translate3d(0,0,0)';
9293        //this.animationItem.container.style.webkitTransform = 'translate3d(0,0,0)';
9294        this.animationItem.container.style.transformOrigin = this.animationItem.container.style.mozTransformOrigin = this.animationItem.container.style.webkitTransformOrigin = this.animationItem.container.style['-webkit-transform'] = "0px 0px 0px";
9295        this.animationItem.wrapper.appendChild(this.animationItem.container);
9296        this.canvasContext = this.animationItem.container.getContext('2d');
9297        if(this.renderConfig.className) {
9298            this.animationItem.container.setAttribute('class', this.renderConfig.className);
9299        }
9300    }else{
9301        this.canvasContext = this.renderConfig.context;
9302    }
9303    this.data = animData;
9304    this.globalData.canvasContext = this.canvasContext;
9305    this.globalData.renderer = this;
9306    this.globalData.isDashed = false;
9307    this.globalData.totalFrames = Math.floor(animData.tf);
9308    this.globalData.compWidth = animData.w;
9309    this.globalData.compHeight = animData.h;
9310    this.globalData.frameRate = animData.fr;
9311    this.globalData.frameId = 0;
9312    this.globalData.compSize = {
9313        w: animData.w,
9314        h: animData.h
9315    };
9316    this.globalData.progressiveLoad = this.renderConfig.progressiveLoad;
9317    this.layers = animData.layers;
9318    this.transformCanvas = {};
9319    this.transformCanvas.w = animData.w;
9320    this.transformCanvas.h = animData.h;
9321    this.globalData.fontManager = new FontManager();
9322    this.globalData.fontManager.addChars(animData.chars);
9323    this.globalData.fontManager.addFonts(animData.fonts,document.body);
9324    this.globalData.getAssetData = this.animationItem.getAssetData.bind(this.animationItem);
9325    this.globalData.getAssetsPath = this.animationItem.getAssetsPath.bind(this.animationItem);
9326    this.globalData.elementLoaded = this.animationItem.elementLoaded.bind(this.animationItem);
9327    this.globalData.addPendingElement = this.animationItem.addPendingElement.bind(this.animationItem);
9328    this.globalData.transformCanvas = this.transformCanvas;
9329    this.elements = Array.apply(null,{length:animData.layers.length});
9330
9331    this.updateContainerSize();
9332};
9333
9334CanvasRenderer.prototype.updateContainerSize = function () {
9335    var elementWidth,elementHeight;
9336    if(this.animationItem.wrapper && this.animationItem.container){
9337        elementWidth = this.animationItem.wrapper.offsetWidth;
9338        elementHeight = this.animationItem.wrapper.offsetHeight;
9339        this.animationItem.container.setAttribute('width',elementWidth * this.renderConfig.dpr );
9340        this.animationItem.container.setAttribute('height',elementHeight * this.renderConfig.dpr);
9341    }else{
9342        elementWidth = this.canvasContext.canvas.width * this.renderConfig.dpr;
9343        elementHeight = this.canvasContext.canvas.height * this.renderConfig.dpr;
9344    }
9345    var elementRel,animationRel;
9346    if(this.renderConfig.preserveAspectRatio.indexOf('meet') !== -1 || this.renderConfig.preserveAspectRatio.indexOf('slice') !== -1){
9347        var par = this.renderConfig.preserveAspectRatio.split(' ');
9348        var fillType = par[1] || 'meet';
9349        var pos = par[0] || 'xMidYMid';
9350        var xPos = pos.substr(0,4);
9351        var yPos = pos.substr(4);
9352        elementRel = elementWidth/elementHeight;
9353        animationRel = this.transformCanvas.w/this.transformCanvas.h;
9354        if(animationRel>elementRel && fillType === 'meet' || animationRel<elementRel && fillType === 'slice'){
9355            this.transformCanvas.sx = elementWidth/(this.transformCanvas.w/this.renderConfig.dpr);
9356            this.transformCanvas.sy = elementWidth/(this.transformCanvas.w/this.renderConfig.dpr);
9357        }else{
9358            this.transformCanvas.sx = elementHeight/(this.transformCanvas.h / this.renderConfig.dpr);
9359            this.transformCanvas.sy = elementHeight/(this.transformCanvas.h / this.renderConfig.dpr);
9360        }
9361
9362        if(xPos === 'xMid' && ((animationRel<elementRel && fillType==='meet') || (animationRel>elementRel && fillType === 'slice'))){
9363            this.transformCanvas.tx = (elementWidth-this.transformCanvas.w*(elementHeight/this.transformCanvas.h))/2*this.renderConfig.dpr;
9364        } else if(xPos === 'xMax' && ((animationRel<elementRel && fillType==='meet') || (animationRel>elementRel && fillType === 'slice'))){
9365            this.transformCanvas.tx = (elementWidth-this.transformCanvas.w*(elementHeight/this.transformCanvas.h))*this.renderConfig.dpr;
9366        } else {
9367            this.transformCanvas.tx = 0;
9368        }
9369        if(yPos === 'YMid' && ((animationRel>elementRel && fillType==='meet') || (animationRel<elementRel && fillType === 'slice'))){
9370            this.transformCanvas.ty = ((elementHeight-this.transformCanvas.h*(elementWidth/this.transformCanvas.w))/2)*this.renderConfig.dpr;
9371        } else if(yPos === 'YMax' && ((animationRel>elementRel && fillType==='meet') || (animationRel<elementRel && fillType === 'slice'))){
9372            this.transformCanvas.ty = ((elementHeight-this.transformCanvas.h*(elementWidth/this.transformCanvas.w)))*this.renderConfig.dpr;
9373        } else {
9374            this.transformCanvas.ty = 0;
9375        }
9376
9377    }else if(this.renderConfig.preserveAspectRatio == 'none'){
9378        this.transformCanvas.sx = elementWidth/(this.transformCanvas.w/this.renderConfig.dpr);
9379        this.transformCanvas.sy = elementHeight/(this.transformCanvas.h/this.renderConfig.dpr);
9380        this.transformCanvas.tx = 0;
9381        this.transformCanvas.ty = 0;
9382    }else{
9383        this.transformCanvas.sx = this.renderConfig.dpr;
9384        this.transformCanvas.sy = this.renderConfig.dpr;
9385        this.transformCanvas.tx = 0;
9386        this.transformCanvas.ty = 0;
9387    }
9388    this.transformCanvas.props = [this.transformCanvas.sx,0,0,0,0,this.transformCanvas.sy,0,0,0,0,1,0,this.transformCanvas.tx,this.transformCanvas.ty,0,1];
9389    var i, len = this.elements.length;
9390    for(i=0;i<len;i+=1){
9391        if(this.elements[i] && this.elements[i].data.ty === 0){
9392            this.elements[i].resize(this.globalData.transformCanvas);
9393        }
9394    }
9395};
9396
9397CanvasRenderer.prototype.destroy = function () {
9398    if(this.renderConfig.clearCanvas) {
9399        this.animationItem.wrapper.innerHTML = '';
9400    }
9401    var i, len = this.layers ? this.layers.length : 0;
9402    for (i = len - 1; i >= 0; i-=1) {
9403        if(this.elements[i]) {
9404            this.elements[i].destroy();
9405        }
9406    }
9407    this.elements.length = 0;
9408    this.globalData.canvasContext = null;
9409    this.animationItem.container = null;
9410    this.destroyed = true;
9411};
9412
9413CanvasRenderer.prototype.renderFrame = function(num){
9414    if((this.renderedFrame == num && this.renderConfig.clearCanvas === true) || this.destroyed || num === null){
9415        return;
9416    }
9417    this.renderedFrame = num;
9418    this.globalData.frameNum = num - this.animationItem.firstFrame;
9419    this.globalData.frameId += 1;
9420    this.globalData.projectInterface.currentFrame = num;
9421    if(this.renderConfig.clearCanvas === true){
9422        this.reset();
9423        this.canvasContext.save();
9424        //this.canvasContext.canvas.width = this.canvasContext.canvas.width;
9425        this.canvasContext.clearRect(this.transformCanvas.tx, this.transformCanvas.ty, this.transformCanvas.w*this.transformCanvas.sx, this.transformCanvas.h*this.transformCanvas.sy);
9426    }else{
9427        this.save();
9428    }
9429    this.ctxTransform(this.transformCanvas.props);
9430    this.canvasContext.beginPath();
9431    this.canvasContext.rect(0,0,this.transformCanvas.w,this.transformCanvas.h);
9432    this.canvasContext.closePath();
9433    this.canvasContext.clip();
9434
9435    //console.log('--------');
9436    //console.log('NEW: ',num);
9437    var i, len = this.layers.length;
9438    if(!this.completeLayers){
9439        this.checkLayers(num);
9440    }
9441
9442    for (i = 0; i < len; i++) {
9443        if(this.completeLayers || this.elements[i]){
9444            this.elements[i].prepareFrame(num - this.layers[i].st);
9445        }
9446    }
9447    for (i = len - 1; i >= 0; i-=1) {
9448        if(this.completeLayers || this.elements[i]){
9449            this.elements[i].renderFrame();
9450        }
9451    }
9452    if(this.renderConfig.clearCanvas !== true){
9453        this.restore();
9454    } else {
9455        this.canvasContext.restore();
9456    }
9457};
9458
9459CanvasRenderer.prototype.buildItem = function(pos){
9460    var elements = this.elements;
9461    if(elements[pos] || this.layers[pos].ty == 99){
9462        return;
9463    }
9464    var element = this.createItem(this.layers[pos], this,this.globalData);
9465    elements[pos] = element;
9466    element.initExpressions();
9467    if(this.layers[pos].ty === 0){
9468        element.resize(this.globalData.transformCanvas);
9469    }
9470};
9471
9472CanvasRenderer.prototype.checkPendingElements  = function(){
9473    while(this.pendingElements.length){
9474        var element = this.pendingElements.pop();
9475        element.checkParenting();
9476    }
9477};
9478
9479CanvasRenderer.prototype.hide = function(){
9480    this.animationItem.container.style.display = 'none';
9481};
9482
9483CanvasRenderer.prototype.show = function(){
9484    this.animationItem.container.style.display = 'block';
9485};
9486
9487CanvasRenderer.prototype.searchExtraCompositions = function(assets){
9488    var i, len = assets.length;
9489    var floatingContainer = document.createElementNS(svgNS,'g');
9490    for(i=0;i<len;i+=1){
9491        if(assets[i].xt){
9492            var comp = this.createComp(assets[i],this.globalData.comp,this.globalData);
9493            comp.initExpressions();
9494            //comp.compInterface = CompExpressionInterface(comp);
9495            //Expressions.addLayersInterface(comp.elements, this.globalData.projectInterface);
9496            this.globalData.projectInterface.registerComposition(comp);
9497        }
9498    }
9499};
9500
9501function HybridRenderer(animationItem, config){
9502    this.animationItem = animationItem;
9503    this.layers = null;
9504    this.renderedFrame = -1;
9505    this.globalData = {
9506        frameNum: -1
9507    };
9508    this.renderConfig = {
9509        className: (config && config.className) || ''
9510    };
9511    this.pendingElements = [];
9512    this.elements = [];
9513    this.threeDElements = [];
9514    this.destroyed = false;
9515    this.camera = null;
9516    this.supports3d = true;
9517
9518}
9519
9520extendPrototype(BaseRenderer,HybridRenderer);
9521
9522HybridRenderer.prototype.buildItem = SVGRenderer.prototype.buildItem;
9523
9524HybridRenderer.prototype.checkPendingElements  = function(){
9525    while(this.pendingElements.length){
9526        var element = this.pendingElements.pop();
9527        element.checkParenting();
9528    }
9529};
9530
9531HybridRenderer.prototype.appendElementInPos = function(element, pos){
9532    var newDOMElement = element.getBaseElement();
9533    if(!newDOMElement){
9534        return;
9535    }
9536    var layer = this.layers[pos];
9537    if(!layer.ddd || !this.supports3d){
9538        var i = 0;
9539        var nextDOMElement, nextLayer;
9540        while(i<pos){
9541            if(this.elements[i] && this.elements[i]!== true && this.elements[i].getBaseElement){
9542                nextLayer = this.elements[i];
9543                nextDOMElement = this.layers[i].ddd ? this.getThreeDContainerByPos(i) : nextLayer.getBaseElement();
9544            }
9545            i += 1;
9546        }
9547        if(nextDOMElement){
9548            if(!layer.ddd || !this.supports3d){
9549                this.layerElement.insertBefore(newDOMElement, nextDOMElement);
9550            }
9551        } else {
9552            if(!layer.ddd || !this.supports3d){
9553                this.layerElement.appendChild(newDOMElement);
9554            }
9555        }
9556    } else {
9557        this.addTo3dContainer(newDOMElement,pos);
9558    }
9559};
9560
9561
9562HybridRenderer.prototype.createBase = function (data) {
9563    return new SVGBaseElement(data, this.layerElement,this.globalData,this);
9564};
9565
9566HybridRenderer.prototype.createShape = function (data) {
9567    if(!this.supports3d){
9568        return new IShapeElement(data, this.layerElement,this.globalData,this);
9569    }
9570    return new HShapeElement(data, this.layerElement,this.globalData,this);
9571};
9572
9573HybridRenderer.prototype.createText = function (data) {
9574    if(!this.supports3d){
9575        return new SVGTextElement(data, this.layerElement,this.globalData,this);
9576    }
9577    return new HTextElement(data, this.layerElement,this.globalData,this);
9578};
9579
9580HybridRenderer.prototype.createCamera = function (data) {
9581    this.camera = new HCameraElement(data, this.layerElement,this.globalData,this);
9582    return this.camera;
9583};
9584
9585HybridRenderer.prototype.createImage = function (data) {
9586    if(!this.supports3d){
9587        return new IImageElement(data, this.layerElement,this.globalData,this);
9588    }
9589    return new HImageElement(data, this.layerElement,this.globalData,this);
9590};
9591
9592HybridRenderer.prototype.createComp = function (data) {
9593    if(!this.supports3d){
9594        return new ICompElement(data, this.layerElement,this.globalData,this);
9595    }
9596    return new HCompElement(data, this.layerElement,this.globalData,this);
9597
9598};
9599
9600HybridRenderer.prototype.createSolid = function (data) {
9601    if(!this.supports3d){
9602        return new ISolidElement(data, this.layerElement,this.globalData,this);
9603    }
9604    return new HSolidElement(data, this.layerElement,this.globalData,this);
9605};
9606
9607HybridRenderer.prototype.getThreeDContainerByPos = function(pos){
9608    var i = 0, len = this.threeDElements.length;
9609    while(i<len) {
9610        if(this.threeDElements[i].startPos <= pos && this.threeDElements[i].endPos >= pos) {
9611            return this.threeDElements[i].perspectiveElem;
9612        }
9613        i += 1;
9614    }
9615}
9616
9617HybridRenderer.prototype.createThreeDContainer = function(pos){
9618    var perspectiveElem = document.createElement('div');
9619    styleDiv(perspectiveElem);
9620    perspectiveElem.style.width = this.globalData.compSize.w+'px';
9621    perspectiveElem.style.height = this.globalData.compSize.h+'px';
9622    perspectiveElem.style.transformOrigin = perspectiveElem.style.mozTransformOrigin = perspectiveElem.style.webkitTransformOrigin = "50% 50%";
9623    var container = document.createElement('div');
9624    styleDiv(container);
9625    container.style.transform = container.style.webkitTransform = 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)';
9626    perspectiveElem.appendChild(container);
9627    this.resizerElem.appendChild(perspectiveElem);
9628    var threeDContainerData = {
9629        container:container,
9630        perspectiveElem:perspectiveElem,
9631        startPos: pos,
9632        endPos: pos
9633    };
9634    this.threeDElements.push(threeDContainerData);
9635    return threeDContainerData;
9636};
9637
9638HybridRenderer.prototype.build3dContainers = function(){
9639    var i, len = this.layers.length;
9640    var lastThreeDContainerData;
9641    for(i=0;i<len;i+=1){
9642        if(this.layers[i].ddd){
9643            if(!lastThreeDContainerData){
9644                lastThreeDContainerData = this.createThreeDContainer(i);
9645            }
9646            lastThreeDContainerData.endPos = Math.max(lastThreeDContainerData.endPos,i);
9647        } else {
9648            lastThreeDContainerData = null;
9649        }
9650    }
9651};
9652
9653HybridRenderer.prototype.addTo3dContainer = function(elem,pos){
9654    var i = 0, len = this.threeDElements.length;
9655    while(i<len){
9656        if(pos <= this.threeDElements[i].endPos){
9657            var j = this.threeDElements[i].startPos;
9658            var nextElement;
9659            while(j<pos){
9660                if(this.elements[j] && this.elements[j].getBaseElement){
9661                    nextElement = this.elements[j].getBaseElement();
9662                }
9663                j += 1;
9664            }
9665            if(nextElement){
9666                this.threeDElements[i].container.insertBefore(elem, nextElement);
9667            } else {
9668                this.threeDElements[i].container.appendChild(elem);
9669            }
9670            break;
9671        }
9672        i += 1;
9673    }
9674};
9675
9676HybridRenderer.prototype.configAnimation = function(animData){
9677    var resizerElem = document.createElement('div');
9678    var wrapper = this.animationItem.wrapper;
9679    resizerElem.style.width = animData.w+'px';
9680    resizerElem.style.height = animData.h+'px';
9681    this.resizerElem = resizerElem;
9682    styleDiv(resizerElem);
9683    resizerElem.style.transformStyle = resizerElem.style.webkitTransformStyle = resizerElem.style.mozTransformStyle = "flat";
9684    if(this.renderConfig.className) {
9685      wrapper.setAttribute('class', this.renderConfig.className);
9686    }
9687    wrapper.appendChild(resizerElem);
9688
9689    resizerElem.style.overflow = 'hidden';
9690    var svg = document.createElementNS(svgNS,'svg');
9691    svg.setAttribute('width','1');
9692    svg.setAttribute('height','1');
9693    styleDiv(svg);
9694    this.resizerElem.appendChild(svg);
9695    var defs = document.createElementNS(svgNS,'defs');
9696    svg.appendChild(defs);
9697    this.globalData.defs = defs;
9698    this.data = animData;
9699    //Mask animation
9700    this.globalData.getAssetData = this.animationItem.getAssetData.bind(this.animationItem);
9701    this.globalData.getAssetsPath = this.animationItem.getAssetsPath.bind(this.animationItem);
9702    this.globalData.elementLoaded = this.animationItem.elementLoaded.bind(this.animationItem);
9703    this.globalData.frameId = 0;
9704    this.globalData.compSize = {
9705        w: animData.w,
9706        h: animData.h
9707    };
9708    this.globalData.frameRate = animData.fr;
9709    this.layers = animData.layers;
9710    this.globalData.fontManager = new FontManager();
9711    this.globalData.fontManager.addChars(animData.chars);
9712    this.globalData.fontManager.addFonts(animData.fonts,svg);
9713    this.layerElement = this.resizerElem;
9714    this.build3dContainers();
9715    this.updateContainerSize();
9716};
9717
9718HybridRenderer.prototype.destroy = function () {
9719    this.animationItem.wrapper.innerHTML = '';
9720    this.animationItem.container = null;
9721    this.globalData.defs = null;
9722    var i, len = this.layers ? this.layers.length : 0;
9723    for (i = 0; i < len; i++) {
9724        this.elements[i].destroy();
9725    }
9726    this.elements.length = 0;
9727    this.destroyed = true;
9728    this.animationItem = null;
9729};
9730
9731HybridRenderer.prototype.updateContainerSize = function () {
9732    var elementWidth = this.animationItem.wrapper.offsetWidth;
9733    var elementHeight = this.animationItem.wrapper.offsetHeight;
9734    var elementRel = elementWidth/elementHeight;
9735    var animationRel = this.globalData.compSize.w/this.globalData.compSize.h;
9736    var sx,sy,tx,ty;
9737    if(animationRel>elementRel){
9738        sx = elementWidth/(this.globalData.compSize.w);
9739        sy = elementWidth/(this.globalData.compSize.w);
9740        tx = 0;
9741        ty = ((elementHeight-this.globalData.compSize.h*(elementWidth/this.globalData.compSize.w))/2);
9742    }else{
9743        sx = elementHeight/(this.globalData.compSize.h);
9744        sy = elementHeight/(this.globalData.compSize.h);
9745        tx = (elementWidth-this.globalData.compSize.w*(elementHeight/this.globalData.compSize.h))/2;
9746        ty = 0;
9747    }
9748    this.resizerElem.style.transform = this.resizerElem.style.webkitTransform = 'matrix3d(' + sx + ',0,0,0,0,'+sy+',0,0,0,0,1,0,'+tx+','+ty+',0,1)';
9749};
9750
9751HybridRenderer.prototype.renderFrame = SVGRenderer.prototype.renderFrame;
9752
9753HybridRenderer.prototype.hide = function(){
9754    this.resizerElem.style.display = 'none';
9755};
9756
9757HybridRenderer.prototype.show = function(){
9758    this.resizerElem.style.display = 'block';
9759};
9760
9761HybridRenderer.prototype.initItems = function(){
9762    this.buildAllItems();
9763    if(this.camera){
9764        this.camera.setup();
9765    } else {
9766        var cWidth = this.globalData.compSize.w;
9767        var cHeight = this.globalData.compSize.h;
9768        var i, len = this.threeDElements.length;
9769        for(i=0;i<len;i+=1){
9770            this.threeDElements[i].perspectiveElem.style.perspective = this.threeDElements[i].perspectiveElem.style.webkitPerspective = Math.sqrt(Math.pow(cWidth,2) + Math.pow(cHeight,2)) + 'px';
9771        }
9772    }
9773};
9774
9775HybridRenderer.prototype.searchExtraCompositions = function(assets){
9776    var i, len = assets.length;
9777    var floatingContainer = document.createElement('div');
9778    for(i=0;i<len;i+=1){
9779        if(assets[i].xt){
9780            var comp = this.createComp(assets[i],floatingContainer,this.globalData.comp,null);
9781            comp.initExpressions();
9782            this.globalData.projectInterface.registerComposition(comp);
9783        }
9784    }
9785};
9786
9787function CVBaseElement(data, comp,globalData){
9788    this.globalData = globalData;
9789    this.data = data;
9790    this.comp = comp;
9791    this.canvasContext = globalData.canvasContext;
9792    this.init();
9793}
9794
9795createElement(BaseElement, CVBaseElement);
9796
9797CVBaseElement.prototype.createElements = function(){
9798    this.checkParenting();
9799};
9800
9801CVBaseElement.prototype.checkBlendMode = function(globalData){
9802    if(globalData.blendMode !== this.data.bm) {
9803        globalData.blendMode = this.data.bm;
9804
9805        var blendModeValue = '';
9806        switch (this.data.bm) {
9807            case 0:
9808                blendModeValue = 'normal';
9809                break;
9810            case 1:
9811                blendModeValue = 'multiply';
9812                break;
9813            case 2:
9814                blendModeValue = 'screen';
9815                break;
9816            case 3:
9817                blendModeValue = 'overlay';
9818                break;
9819            case 4:
9820                blendModeValue = 'darken';
9821                break;
9822            case 5:
9823                blendModeValue = 'lighten';
9824                break;
9825            case 6:
9826                blendModeValue = 'color-dodge';
9827                break;
9828            case 7:
9829                blendModeValue = 'color-burn';
9830                break;
9831            case 8:
9832                blendModeValue = 'hard-light';
9833                break;
9834            case 9:
9835                blendModeValue = 'soft-light';
9836                break;
9837            case 10:
9838                blendModeValue = 'difference';
9839                break;
9840            case 11:
9841                blendModeValue = 'exclusion';
9842                break;
9843            case 12:
9844                blendModeValue = 'hue';
9845                break;
9846            case 13:
9847                blendModeValue = 'saturation';
9848                break;
9849            case 14:
9850                blendModeValue = 'color';
9851                break;
9852            case 15:
9853                blendModeValue = 'luminosity';
9854                break;
9855        }
9856        globalData.canvasContext.globalCompositeOperation = blendModeValue;
9857    }
9858};
9859
9860
9861CVBaseElement.prototype.renderFrame = function(parentTransform){
9862    if(this.data.ty === 3){
9863        return false;
9864    }
9865        this.checkBlendMode(this.data.ty === 0?this.parentGlobalData:this.globalData);
9866
9867    if(!this.isVisible){
9868        return this.isVisible;
9869    }
9870    this.finalTransform.opMdf = this.finalTransform.op.mdf;
9871    this.finalTransform.matMdf = this.finalTransform.mProp.mdf;
9872    this.finalTransform.opacity = this.finalTransform.op.v;
9873
9874    var mat;
9875    var finalMat = this.finalTransform.mat;
9876
9877    if(this.hierarchy){
9878        var i, len = this.hierarchy.length;
9879        mat = this.finalTransform.mProp.v.props;
9880        finalMat.cloneFromProps(mat);
9881        for(i=0;i<len;i+=1){
9882            this.finalTransform.matMdf = this.hierarchy[i].finalTransform.mProp.mdf ? true : this.finalTransform.matMdf;
9883            mat = this.hierarchy[i].finalTransform.mProp.v.props;
9884            finalMat.transform(mat[0],mat[1],mat[2],mat[3],mat[4],mat[5],mat[6],mat[7],mat[8],mat[9],mat[10],mat[11],mat[12],mat[13],mat[14],mat[15]);
9885        }
9886    }else{
9887        if(!parentTransform){
9888            finalMat.cloneFromProps(this.finalTransform.mProp.v.props);
9889        }else{
9890            mat = this.finalTransform.mProp.v.props;
9891            finalMat.cloneFromProps(mat);
9892        }
9893    }
9894
9895    if(parentTransform){
9896        mat = parentTransform.mat.props;
9897        finalMat.transform(mat[0],mat[1],mat[2],mat[3],mat[4],mat[5],mat[6],mat[7],mat[8],mat[9],mat[10],mat[11],mat[12],mat[13],mat[14],mat[15]);
9898        this.finalTransform.opacity *= parentTransform.opacity;
9899        this.finalTransform.opMdf = parentTransform.opMdf ? true : this.finalTransform.opMdf;
9900        this.finalTransform.matMdf = parentTransform.matMdf ? true : this.finalTransform.matMdf
9901    }
9902
9903    if(this.data.hasMask){
9904        this.globalData.renderer.save(true);
9905        this.maskManager.renderFrame(this.data.ty === 0?null:finalMat);
9906    }
9907    if(this.data.hd){
9908        this.isVisible = false;
9909    }
9910    return this.isVisible;
9911
9912};
9913
9914CVBaseElement.prototype.addMasks = function(data){
9915    this.maskManager = new CVMaskElement(data,this,this.globalData);
9916};
9917
9918
9919CVBaseElement.prototype.destroy = function(){
9920    this.canvasContext = null;
9921    this.data = null;
9922    this.globalData = null;
9923    if(this.maskManager) {
9924        this.maskManager.destroy();
9925    }
9926};
9927
9928CVBaseElement.prototype.mHelper = new Matrix();
9929
9930function CVCompElement(data, comp,globalData){
9931    this._parent.constructor.call(this,data, comp,globalData);
9932    var compGlobalData = {};
9933    for(var s in globalData){
9934        if(globalData.hasOwnProperty(s)){
9935            compGlobalData[s] = globalData[s];
9936        }
9937    }
9938    compGlobalData.renderer = this;
9939    compGlobalData.compHeight = this.data.h;
9940    compGlobalData.compWidth = this.data.w;
9941    this.renderConfig = {
9942        clearCanvas: true
9943    };
9944    this.contextData = {
9945        saved : Array.apply(null,{length:15}),
9946        savedOp: Array.apply(null,{length:15}),
9947        cArrPos : 0,
9948        cTr : new Matrix(),
9949        cO : 1
9950    };
9951    this.completeLayers = false;
9952    var i, len = 15;
9953    for(i=0;i<len;i+=1){
9954        this.contextData.saved[i] = Array.apply(null,{length:16});
9955    }
9956    this.transformMat = new Matrix();
9957    this.parentGlobalData = this.globalData;
9958    var cv = document.createElement('canvas');
9959    //document.body.appendChild(cv);
9960    compGlobalData.canvasContext = cv.getContext('2d');
9961    this.canvasContext = compGlobalData.canvasContext;
9962    cv.width = this.data.w;
9963    cv.height = this.data.h;
9964    this.canvas = cv;
9965    this.globalData = compGlobalData;
9966    this.layers = data.layers;
9967    this.pendingElements = [];
9968    this.elements = Array.apply(null,{length:this.layers.length});
9969    if(this.data.tm){
9970        this.tm = PropertyFactory.getProp(this,this.data.tm,0,globalData.frameRate,this.dynamicProperties);
9971    }
9972    if(this.data.xt || !globalData.progressiveLoad){
9973        this.buildAllItems();
9974    }
9975}
9976createElement(CVBaseElement, CVCompElement);
9977
9978CVCompElement.prototype.ctxTransform = CanvasRenderer.prototype.ctxTransform;
9979CVCompElement.prototype.ctxOpacity = CanvasRenderer.prototype.ctxOpacity;
9980CVCompElement.prototype.save = CanvasRenderer.prototype.save;
9981CVCompElement.prototype.restore = CanvasRenderer.prototype.restore;
9982CVCompElement.prototype.reset =  function(){
9983    this.contextData.cArrPos = 0;
9984    this.contextData.cTr.reset();
9985    this.contextData.cO = 1;
9986};
9987CVCompElement.prototype.resize = function(transformCanvas){
9988    var maxScale = Math.max(transformCanvas.sx,transformCanvas.sy);
9989    this.canvas.width = this.data.w*maxScale;
9990    this.canvas.height = this.data.h*maxScale;
9991    this.transformCanvas = {
9992        sc:maxScale,
9993        w:this.data.w*maxScale,
9994        h:this.data.h*maxScale,
9995        props:[maxScale,0,0,0,0,maxScale,0,0,0,0,1,0,0,0,0,1]
9996    }
9997    var i,len = this.elements.length;
9998    for( i = 0; i < len; i+=1 ){
9999        if(this.elements[i] && this.elements[i].data.ty === 0){
10000            this.elements[i].resize(transformCanvas);
10001        }
10002    }
10003};
10004
10005CVCompElement.prototype.prepareFrame = function(num){
10006    this.globalData.frameId = this.parentGlobalData.frameId;
10007    this.globalData.mdf = false;
10008    this._parent.prepareFrame.call(this,num);
10009    if(this.isVisible===false && !this.data.xt){
10010        return;
10011    }
10012    var timeRemapped = num;
10013    if(this.tm){
10014        timeRemapped = this.tm.v;
10015        if(timeRemapped === this.data.op){
10016            timeRemapped = this.data.op - 1;
10017        }
10018    }
10019    this.renderedFrame = timeRemapped/this.data.sr;
10020    var i,len = this.elements.length;
10021
10022    if(!this.completeLayers){
10023        this.checkLayers(num);
10024    }
10025
10026    for( i = 0; i < len; i+=1 ){
10027        if(this.completeLayers || this.elements[i]){
10028            this.elements[i].prepareFrame(timeRemapped/this.data.sr - this.layers[i].st);
10029            if(this.elements[i].data.ty === 0 && this.elements[i].globalData.mdf){
10030                this.globalData.mdf = true;
10031            }
10032        }
10033    }
10034    if(this.globalData.mdf && !this.data.xt){
10035        this.canvasContext.clearRect(0, 0, this.data.w, this.data.h);
10036        this.ctxTransform(this.transformCanvas.props);
10037    }
10038};
10039
10040CVCompElement.prototype.renderFrame = function(parentMatrix){
10041    if(this._parent.renderFrame.call(this,parentMatrix)===false){
10042        return;
10043    }
10044    if(this.globalData.mdf){
10045        var i,len = this.layers.length;
10046        for( i = len - 1; i >= 0; i -= 1 ){
10047            if(this.completeLayers || this.elements[i]){
10048                this.elements[i].renderFrame();
10049            }
10050        }
10051    }
10052    if(this.data.hasMask){
10053        this.globalData.renderer.restore(true);
10054    }
10055    if(this.firstFrame){
10056        this.firstFrame = false;
10057    }
10058    this.parentGlobalData.renderer.save();
10059    this.parentGlobalData.renderer.ctxTransform(this.finalTransform.mat.props);
10060    this.parentGlobalData.renderer.ctxOpacity(this.finalTransform.opacity);
10061    this.parentGlobalData.renderer.canvasContext.drawImage(this.canvas,0,0,this.data.w,this.data.h);
10062    this.parentGlobalData.renderer.restore();
10063
10064    if(this.globalData.mdf){
10065        this.reset();
10066    }
10067};
10068
10069CVCompElement.prototype.setElements = function(elems){
10070    this.elements = elems;
10071};
10072
10073CVCompElement.prototype.getElements = function(){
10074    return this.elements;
10075};
10076
10077CVCompElement.prototype.destroy = function(){
10078    var i,len = this.layers.length;
10079    for( i = len - 1; i >= 0; i -= 1 ){
10080        this.elements[i].destroy();
10081    }
10082    this.layers = null;
10083    this.elements = null;
10084    this._parent.destroy.call(this._parent);
10085};
10086CVCompElement.prototype.checkLayers = CanvasRenderer.prototype.checkLayers;
10087CVCompElement.prototype.buildItem = CanvasRenderer.prototype.buildItem;
10088CVCompElement.prototype.checkPendingElements = CanvasRenderer.prototype.checkPendingElements;
10089CVCompElement.prototype.addPendingElement = CanvasRenderer.prototype.addPendingElement;
10090CVCompElement.prototype.buildAllItems = CanvasRenderer.prototype.buildAllItems;
10091CVCompElement.prototype.createItem = CanvasRenderer.prototype.createItem;
10092CVCompElement.prototype.createImage = CanvasRenderer.prototype.createImage;
10093CVCompElement.prototype.createComp = CanvasRenderer.prototype.createComp;
10094CVCompElement.prototype.createSolid = CanvasRenderer.prototype.createSolid;
10095CVCompElement.prototype.createShape = CanvasRenderer.prototype.createShape;
10096CVCompElement.prototype.createText = CanvasRenderer.prototype.createText;
10097CVCompElement.prototype.createBase = CanvasRenderer.prototype.createBase;
10098CVCompElement.prototype.buildElementParenting = CanvasRenderer.prototype.buildElementParenting;
10099function CVImageElement(data, comp,globalData){
10100    this.assetData = globalData.getAssetData(data.refId);
10101    this._parent.constructor.call(this,data, comp,globalData);
10102    this.globalData.addPendingElement();
10103}
10104createElement(CVBaseElement, CVImageElement);
10105
10106CVImageElement.prototype.createElements = function(){
10107    var imageLoaded = function(){
10108        this.globalData.elementLoaded();
10109        if(this.assetData.w !== this.img.width || this.assetData.h !== this.img.height){
10110            var canvas = document.createElement('canvas');
10111            canvas.width = this.assetData.w;
10112            canvas.height = this.assetData.h;
10113            var ctx = canvas.getContext('2d');
10114
10115            var imgW = this.img.width;
10116            var imgH = this.img.height;
10117            var imgRel = imgW / imgH;
10118            var canvasRel = this.assetData.w/this.assetData.h;
10119            var widthCrop, heightCrop;
10120            if(imgRel>canvasRel){
10121                heightCrop = imgH;
10122                widthCrop = heightCrop*canvasRel;
10123            } else {
10124                widthCrop = imgW;
10125                heightCrop = widthCrop/canvasRel;
10126            }
10127            ctx.drawImage(this.img,(imgW-widthCrop)/2,(imgH-heightCrop)/2,widthCrop,heightCrop,0,0,this.assetData.w,this.assetData.h);
10128            this.img = canvas;
10129        }
10130    }.bind(this);
10131    var imageFailed = function(){
10132        this.failed = true;
10133        this.globalData.elementLoaded();
10134    }.bind(this);
10135
10136    this.img = new Image();
10137    this.img.addEventListener('load', imageLoaded, false);
10138    this.img.addEventListener('error', imageFailed, false);
10139    var assetPath = this.globalData.getAssetsPath(this.assetData);
10140    this.img.src = assetPath;
10141
10142    this._parent.createElements.call(this);
10143
10144};
10145
10146CVImageElement.prototype.renderFrame = function(parentMatrix){
10147    if(this.failed){
10148        return;
10149    }
10150    if(this._parent.renderFrame.call(this,parentMatrix)===false){
10151        return;
10152    }
10153    var ctx = this.canvasContext;
10154    this.globalData.renderer.save();
10155    var finalMat = this.finalTransform.mat.props;
10156    this.globalData.renderer.ctxTransform(finalMat);
10157    this.globalData.renderer.ctxOpacity(this.finalTransform.opacity);
10158    ctx.drawImage(this.img,0,0);
10159    this.globalData.renderer.restore(this.data.hasMask);
10160    if(this.firstFrame){
10161        this.firstFrame = false;
10162    }
10163};
10164
10165CVImageElement.prototype.destroy = function(){
10166    this.img = null;
10167    this._parent.destroy.call(this._parent);
10168};
10169
10170function CVMaskElement(data,element){
10171    this.data = data;
10172    this.element = element;
10173    this.dynamicProperties = [];
10174    this.masksProperties = this.data.masksProperties;
10175    this.viewData = Array.apply(null,{length:this.masksProperties.length});
10176    var i, len = this.masksProperties.length;
10177    for (i = 0; i < len; i++) {
10178        this.viewData[i] = ShapePropertyFactory.getShapeProp(this.element,this.masksProperties[i],3,this.dynamicProperties,null);
10179    }
10180}
10181
10182CVMaskElement.prototype.prepareFrame = function(num){
10183    var i, len = this.dynamicProperties.length;
10184    for(i=0;i<len;i+=1){
10185        this.dynamicProperties[i].getValue(num);
10186        if(this.dynamicProperties[i].mdf){
10187            this.element.globalData.mdf = true;
10188        }
10189    }
10190};
10191
10192CVMaskElement.prototype.renderFrame = function (transform) {
10193    var ctx = this.element.canvasContext;
10194    var i, len = this.data.masksProperties.length;
10195    var pt,pt2,pt3,data, hasMasks = false;
10196    for (i = 0; i < len; i++) {
10197        if(this.masksProperties[i].mode === 'n'){
10198            continue;
10199        }
10200        if(hasMasks === false){
10201            ctx.beginPath();
10202            hasMasks = true;
10203        }
10204        if (this.masksProperties[i].inv) {
10205            ctx.moveTo(0, 0);
10206            ctx.lineTo(this.element.globalData.compWidth, 0);
10207            ctx.lineTo(this.element.globalData.compWidth, this.element.globalData.compHeight);
10208            ctx.lineTo(0, this.element.globalData.compHeight);
10209            ctx.lineTo(0, 0);
10210        }
10211        data = this.viewData[i].v;
10212        pt = transform ? transform.applyToPointArray(data.v[0][0],data.v[0][1],0):data.v[0];
10213        ctx.moveTo(pt[0], pt[1]);
10214        var j, jLen = data._length;
10215        for (j = 1; j < jLen; j++) {
10216            pt = transform ? transform.applyToPointArray(data.o[j - 1][0],data.o[j - 1][1],0) : data.o[j - 1];
10217            pt2 = transform ? transform.applyToPointArray(data.i[j][0],data.i[j][1],0) : data.i[j];
10218            pt3 = transform ? transform.applyToPointArray(data.v[j][0],data.v[j][1],0) : data.v[j];
10219            ctx.bezierCurveTo(pt[0], pt[1], pt2[0], pt2[1], pt3[0], pt3[1]);
10220        }
10221        pt = transform ? transform.applyToPointArray(data.o[j - 1][0],data.o[j - 1][1],0) : data.o[j - 1];
10222        pt2 = transform ? transform.applyToPointArray(data.i[0][0],data.i[0][1],0) : data.i[0];
10223        pt3 = transform ? transform.applyToPointArray(data.v[0][0],data.v[0][1],0) : data.v[0];
10224        ctx.bezierCurveTo(pt[0], pt[1], pt2[0], pt2[1], pt3[0], pt3[1]);
10225    }
10226    if(hasMasks){
10227        ctx.clip();
10228    }
10229};
10230
10231CVMaskElement.prototype.getMaskProperty = MaskElement.prototype.getMaskProperty;
10232
10233CVMaskElement.prototype.destroy = function(){
10234    this.element = null;
10235};
10236function CVShapeElement(data, comp,globalData){
10237    this.shapes = [];
10238    this.shapesData = data.shapes;
10239    this.stylesList = [];
10240    this.itemsData = [];
10241    this.prevViewData = [];
10242    this.shapeModifiers = [];
10243    this.processedElements = [];
10244    this._parent.constructor.call(this,data, comp,globalData);
10245}
10246createElement(CVBaseElement, CVShapeElement);
10247
10248CVShapeElement.prototype.transformHelper = {opacity:1,mat:new Matrix(),matMdf:false,opMdf:false};
10249
10250CVShapeElement.prototype.dashResetter = [];
10251
10252CVShapeElement.prototype.createElements = function(){
10253
10254    this._parent.createElements.call(this);
10255    this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,this.dynamicProperties, true);
10256};
10257
10258CVShapeElement.prototype.createStyleElement = function(data, dynamicProperties){
10259    var styleElem = {
10260        data: data,
10261        type: data.ty,
10262        elements: []
10263    };
10264    var elementData = {};
10265    if(data.ty == 'fl' || data.ty == 'st'){
10266        elementData.c = PropertyFactory.getProp(this,data.c,1,255,dynamicProperties);
10267        if(!elementData.c.k){
10268            styleElem.co = 'rgb('+bm_floor(elementData.c.v[0])+','+bm_floor(elementData.c.v[1])+','+bm_floor(elementData.c.v[2])+')';
10269        }
10270    }
10271    elementData.o = PropertyFactory.getProp(this,data.o,0,0.01,dynamicProperties);
10272    if(data.ty == 'st') {
10273        styleElem.lc = this.lcEnum[data.lc] || 'round';
10274        styleElem.lj = this.ljEnum[data.lj] || 'round';
10275        if(data.lj == 1) {
10276            styleElem.ml = data.ml;
10277        }
10278        elementData.w = PropertyFactory.getProp(this,data.w,0,null,dynamicProperties);
10279        if(!elementData.w.k){
10280            styleElem.wi = elementData.w.v;
10281        }
10282        if(data.d){
10283            var d = PropertyFactory.getDashProp(this,data.d,'canvas',dynamicProperties);
10284            elementData.d = d;
10285            if(!elementData.d.k){
10286                styleElem.da = elementData.d.dasharray;
10287                styleElem.do = elementData.d.dashoffset;
10288            }
10289        }
10290
10291    } else {
10292
10293        styleElem.r = data.r === 2 ? 'evenodd' : 'nonzero';
10294    }
10295    this.stylesList.push(styleElem);
10296    elementData.style = styleElem;
10297    return elementData;
10298}
10299
10300CVShapeElement.prototype.createGroupElement = function(data) {
10301    var elementData = {
10302        it: [],
10303        prevViewData: []
10304    };
10305    return elementData;
10306}
10307
10308CVShapeElement.prototype.createTransformElement = function(data, dynamicProperties) {
10309    var elementData = {
10310        transform : {
10311            mat: new Matrix(),
10312            opacity: 1,
10313            matMdf:false,
10314            opMdf:false,
10315            op: PropertyFactory.getProp(this,data.o,0,0.01,dynamicProperties),
10316            mProps: PropertyFactory.getProp(this,data,2,null,dynamicProperties)
10317        },
10318        elements: []
10319    };
10320    return elementData;
10321}
10322
10323CVShapeElement.prototype.createShapeElement = function(data, dynamicProperties) {
10324    var elementData = {
10325        nodes:[],
10326        trNodes:[],
10327        tr:[0,0,0,0,0,0]
10328    };
10329    var ty = 4;
10330    if(data.ty == 'rc'){
10331        ty = 5;
10332    }else if(data.ty == 'el'){
10333        ty = 6;
10334    }else if(data.ty == 'sr'){
10335        ty = 7;
10336    }
10337    elementData.sh = ShapePropertyFactory.getShapeProp(this,data,t
10337y,dynamicProperties);
10338    this.shapes.push(elementData.sh);
10339    this.addShapeToModifiers(elementData);
10340    jLen = this.stylesList.length;
10341    var hasStrokes = false, hasFills = false;
10342    for(j=0;j<jLen;j+=1){
10343        if(!this.stylesList[j].closed){
10344            this.stylesList[j].elements.push(elementData);
10345            if(this.stylesList[j].type === 'st'){
10346                hasStrokes = true;
10347            }else{
10348                hasFills = true;
10349            }
10350        }
10351    }
10352    elementData.st = hasStrokes;
10353    elementData.fl = hasFills;
10354    return elementData;
10355}
10356
10357CVShapeElement.prototype.reloadShapes = function(){
10358    this.firstFrame = true;
10359    var i, len = this.itemsData.length;
10360    for(i=0;i<len;i+=1){
10361        this.prevViewData[i] = this.itemsData[i];
10362    }
10363    this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,this.dynamicProperties, true);
10364    var i, len = this.dynamicProperties.length;
10365    for(i=0;i<len;i+=1){
10366        this.dynamicProperties[i].getValue();
10367    }
10368    this.renderModifiers();
10369}
10370
10371CVShapeElement.prototype.searchShapes = function(arr,itemsData, prevViewData,dynamicProperties, render){
10372    var i, len = arr.length - 1;
10373    var j, jLen;
10374    var ownArrays = [], ownModifiers = [], processedPos;
10375    for(i=len;i>=0;i-=1){
10376        processedPos = this.searchProcessedElement(arr[i]);
10377        if(!processedPos){
10378            arr[i]._render = render;
10379        } else {
10380            itemsData[i] = prevViewData[processedPos - 1];
10381        }
10382        if(arr[i].ty == 'fl' || arr[i].ty == 'st'){
10383            if(!processedPos){
10384                itemsData[i] = this.createStyleElement(arr[i], dynamicProperties);
10385            } else {
10386                itemsData[i].style.closed = false;
10387            }
10388            
10389            ownArrays.push(itemsData[i].style);
10390        }else if(arr[i].ty == 'gr'){
10391            if(!processedPos){
10392                itemsData[i] = this.createGroupElement(arr[i]);
10393            } else {
10394                jLen = itemsData[i].it.length;
10395                for(j=0;j<jLen;j+=1){
10396                    itemsData[i].prevViewData[j] = itemsData[i].it[j];
10397                }
10398            }
10399            this.searchShapes(arr[i].it,itemsData[i].it,itemsData[i].prevViewData,dynamicProperties, render);
10400        }else if(arr[i].ty == 'tr'){
10401            if(!processedPos){
10402                itemsData[i] = this.createTransformElement(arr[i], dynamicProperties);
10403            }
10404        }else if(arr[i].ty == 'sh' || arr[i].ty == 'rc' || arr[i].ty == 'el' || arr[i].ty == 'sr'){
10405            if(!processedPos){
10406                itemsData[i] = this.createShapeElement(arr[i], dynamicProperties);
10407            }
10408            
10409        }else if(arr[i].ty == 'tm' || arr[i].ty == 'rd'){
10410            if(!processedPos){
10411                var modifier = ShapeModifiers.getModifier(arr[i].ty);
10412                modifier.init(this,arr[i],dynamicProperties);
10413                itemsData[i] = modifier;
10414                this.shapeModifiers.push(modifier);
10415            } else {
10416                modifier = itemsData[i];
10417                modifier.closed = false;
10418            }
10419            ownModifiers.push(modifier);
10420        } else if(arr[i].ty == 'rp'){
10421            if(!processedPos){
10422                modifier = ShapeModifiers.getModifier(arr[i].ty);
10423                itemsData[i] = modifier;
10424                modifier.init(this,arr,i,itemsData,dynamicProperties);
10425                this.shapeModifiers.push(modifier);
10426                render = false;
10427            }else{
10428                modifier = itemsData[i];
10429                modifier.closed = true;
10430            }
10431            ownModifiers.push(modifier);
10432        }
10433        this.addProcessedElement(arr[i], i + 1);
10434    }
10435    len = ownArrays.length;
10436    for(i=0;i<len;i+=1){
10437        ownArrays[i].closed = true;
10438    }
10439    len = ownModifiers.length;
10440    for(i=0;i<len;i+=1){
10441        ownModifiers[i].closed = true;
10442    }
10443};
10444
10445CVShapeElement.prototype.addShapeToModifiers = IShapeElement.prototype.addShapeToModifiers;
10446CVShapeElement.prototype.renderModifiers = IShapeElement.prototype.renderModifiers;
10447CVShapeElement.prototype.lcEnum = IShapeElement.prototype.lcEnum;
10448CVShapeElement.prototype.ljEnum = IShapeElement.prototype.ljEnum;
10449CVShapeElement.prototype.searchProcessedElement = IShapeElement.prototype.searchProcessedElement;
10450CVShapeElement.prototype.addProcessedElement = IShapeElement.prototype.addProcessedElement;
10451
10452CVShapeElement.prototype.renderFrame = function(parentMatrix){
10453    if(this._parent.renderFrame.call(this, parentMatrix)===false){
10454        return;
10455    }
10456    this.transformHelper.mat.reset();
10457    this.transformHelper.opacity = this.finalTransform.opacity;
10458    this.transformHelper.matMdf = false;
10459    this.transformHelper.opMdf = this.finalTransform.opMdf;
10460    this.renderModifiers();
10461    this.renderShape(this.transformHelper,null,null,true);
10462    if(this.data.hasMask){
10463        this.globalData.renderer.restore(true);
10464    }
10465};
10466
10467CVShapeElement.prototype.renderShape = function(parentTransform,items,data,isMain){
10468    var i, len;
10469    if(!items){
10470        items = this.shapesData;
10471        len = this.stylesList.length;
10472        for(i=0;i<len;i+=1){
10473            this.stylesList[i].d = '';
10474            this.stylesList[i].mdf = false;
10475        }
10476    }
10477    if(!data){
10478        data = this.itemsData;
10479    }
10480    ///
10481    ///
10482    len = items.length - 1;
10483    var groupTransform,groupMatrix;
10484    groupTransform = parentTransform;
10485    for(i=len;i>=0;i-=1){
10486        if(items[i].ty == 'tr'){
10487            groupTransform = data[i].transform;
10488            var mtArr = data[i].transform.mProps.v.props;
10489            groupTransform.matMdf = groupTransform.mProps.mdf;
10490            groupTransform.opMdf = groupTransform.op.mdf;
10491            groupMatrix = groupTransform.mat;
10492            groupMatrix.cloneFromProps(mtArr);
10493            if(parentTransform){
10494                var props = parentTransform.mat.props;
10495                groupTransform.opacity = parentTransform.opacity;
10496                groupTransform.opacity *= data[i].transform.op.v;
10497                groupTransform.matMdf = parentTransform.matMdf ? true : groupTransform.matMdf;
10498                groupTransform.opMdf = parentTransform.opMdf ? true : groupTransform.opMdf;
10499                groupMatrix.transform(props[0],props[1],props[2],props[3],props[4],props[5],props[6],props[7],props[8],props[9],props[10],props[11],props[12],props[13],props[14],props[15]);
10500            }else{
10501                groupTransform.opacity = groupTransform.op.o;
10502            }
10503        }else if(items[i].ty == 'sh' || items[i].ty == 'el' || items[i].ty == 'rc' || items[i].ty == 'sr'){
10504            this.renderPath(items[i],data[i],groupTransform);
10505        }else if(items[i].ty == 'fl'){
10506            this.renderFill(items[i],data[i],groupTransform);
10507        }else if(items[i].ty == 'st'){
10508            this.renderStroke(items[i],data[i],groupTransform);
10509        }else if(items[i].ty == 'gr'){
10510            this.renderShape(groupTransform,items[i].it,data[i].it);
10511        }else if(items[i].ty == 'tm'){
10512            //
10513        }
10514    }
10515    if(!isMain){
10516        return;
10517    }
10518    len = this.stylesList.length;
10519    var j, jLen, k, kLen,elems,nodes, renderer = this.globalData.renderer, ctx = this.globalData.canvasContext, type;
10520    renderer.save();
10521    renderer.ctxTransform(this.finalTransform.mat.props);
10522    for(i=0;i<len;i+=1){
10523        type = this.stylesList[i].type;
10524        if((type === 'st' && this.stylesList[i].wi === 0) || !this.stylesList[i].data._render){
10525            continue;
10526        }
10527        renderer.save();
10528        elems = this.stylesList[i].elements;
10529        if(type === 'st'){
10530            ctx.strokeStyle = this.stylesList[i].co;
10531            ctx.lineWidth = this.stylesList[i].wi;
10532            ctx.lineCap = this.stylesList[i].lc;
10533            ctx.lineJoin = this.stylesList[i].lj;
10534            ctx.miterLimit = this.stylesList[i].ml || 0;
10535        }else{
10536            ctx.fillStyle = this.stylesList[i].co;
10537        }
10538        renderer.ctxOpacity(this.stylesList[i].coOp);
10539        if(type !== 'st'){
10540            ctx.beginPath();
10541        }
10542        jLen = elems.length;
10543        for(j=0;j<jLen;j+=1){
10544            if(type === 'st'){
10545                ctx.beginPath();
10546                if(this.stylesList[i].da){
10547                    ctx.setLineDash(this.stylesList[i].da);
10548                    ctx.lineDashOffset = this.stylesList[i].do;
10549                    this.globalData.isDashed = true;
10550                }else if(this.globalData.isDashed){
10551                    ctx.setLineDash(this.dashResetter);
10552                    this.globalData.isDashed = false;
10553                }
10554            }
10555            nodes = elems[j].trNodes;
10556            kLen = nodes.length;
10557
10558            for(k=0;k<kLen;k+=1){
10559                if(nodes[k].t == 'm'){
10560                    ctx.moveTo(nodes[k].p[0],nodes[k].p[1]);
10561                }else if(nodes[k].t == 'c'){
10562                    ctx.bezierCurveTo(nodes[k].p1[0],nodes[k].p1[1],nodes[k].p2[0],nodes[k].p2[1],nodes[k].p3[0],nodes[k].p3[1]);
10563                }else{
10564                    ctx.closePath();
10565                }
10566            }
10567            if(type === 'st'){
10568                ctx.stroke();
10569            }
10570        }
10571        if(type !== 'st'){
10572            ctx.fill(this.stylesList[i].r);
10573        }
10574        renderer.restore();
10575    }
10576    renderer.restore();
10577    if(this.firstFrame){
10578        this.firstFrame = false;
10579    }
10580};
10581CVShapeElement.prototype.renderPath = function(pathData,itemData,groupTransform){
10582    var len, i, j,jLen;
10583    var redraw = groupTransform.matMdf || itemData.sh.mdf || this.firstFrame;
10584    if(redraw) {
10585        var paths = itemData.sh.paths, groupTransformMat = groupTransform.mat;
10586        jLen = paths._length;
10587        var pathStringTransformed = itemData.trNodes;
10588        pathStringTransformed.length = 0;
10589        for(j=0;j<jLen;j+=1){
10590            var pathNodes = paths.shapes[j];
10591            if(pathNodes && pathNodes.v){
10592                len = pathNodes._length;
10593                for (i = 1; i < len; i += 1) {
10594                    if (i == 1) {
10595                        pathStringTransformed.push({
10596                            t: 'm',
10597                            p: groupTransformMat.applyToPointArray(pathNodes.v[0][0], pathNodes.v[0][1], 0)
10598                        });
10599                    }
10600                    pathStringTransformed.push({
10601                        t: 'c',
10602                        p1: groupTransformMat.applyToPointArray(pathNodes.o[i - 1][0], pathNodes.o[i - 1][1], 0),
10603                        p2: groupTransformMat.applyToPointArray(pathNodes.i[i][0], pathNodes.i[i][1], 0),
10604                        p3: groupTransformMat.applyToPointArray(pathNodes.v[i][0], pathNodes.v[i][1], 0)
10605                    });
10606                }
10607                if (len == 1) {
10608                    pathStringTransformed.push({
10609                        t: 'm',
10610                        p: groupTransformMat.applyToPointArray(pathNodes.v[0][0], pathNodes.v[0][1], 0)
10611                    });
10612                }
10613                if (pathNodes.c && len) {
10614                    pathStringTransformed.push({
10615                        t: 'c',
10616                        p1: groupTransformMat.applyToPointArray(pathNodes.o[i - 1][0], pathNodes.o[i - 1][1], 0),
10617                        p2: groupTransformMat.applyToPointArray(pathNodes.i[0][0], pathNodes.i[0][1], 0),
10618                        p3: groupTransformMat.applyToPointArray(pathNodes.v[0][0], pathNodes.v[0][1], 0)
10619                    });
10620                    pathStringTransformed.push({
10621                        t: 'z'
10622                    });
10623                }
10624                itemData.lStr = pathStringTransformed;
10625            }
10626
10627        }
10628
10629        if (itemData.st) {
10630            for (i = 0; i < 16; i += 1) {
10631                itemData.tr[i] = groupTransform.mat.props[i];
10632            }
10633        }
10634        itemData.trNodes = pathStringTransformed;
10635
10636    }
10637};
10638
10639
10640
10641CVShapeElement.prototype.renderFill = function(styleData,itemData, groupTransform){
10642    var styleElem = itemData.style;
10643
10644    if(itemData.c.mdf || this.firstFrame){
10645        styleElem.co = 'rgb('+bm_floor(itemData.c.v[0])+','+bm_floor(itemData.c.v[1])+','+bm_floor(itemData.c.v[2])+')';
10646    }
10647    if(itemData.o.mdf || groupTransform.opMdf || this.firstFrame){
10648        styleElem.coOp = itemData.o.v*groupTransform.opacity;
10649    }
10650};
10651
10652CVShapeElement.prototype.renderStroke = function(styleData,itemData, groupTransform){
10653    var styleElem = itemData.style;
10654    //TODO fix dashes
10655    var d = itemData.d;
10656    var dasharray,dashoffset;
10657    if(d && (d.mdf  || this.firstFrame)){
10658        styleElem.da = d.dasharray;
10659        styleElem.do = d.dashoffset;
10660    }
10661    if(itemData.c.mdf || this.firstFrame){
10662        styleElem.co = 'rgb('+bm_floor(itemData.c.v[0])+','+bm_floor(itemData.c.v[1])+','+bm_floor(itemData.c.v[2])+')';
10663    }
10664    if(itemData.o.mdf || groupTransform.opMdf || this.firstFrame){
10665        styleElem.coOp = itemData.o.v*groupTransform.opacity;
10666    }
10667    if(itemData.w.mdf || this.firstFrame){
10668        styleElem.wi = itemData.w.v;
10669    }
10670};
10671
10672
10673CVShapeElement.prototype.destroy = function(){
10674    this.shapesData = null;
10675    this.globalData = null;
10676    this.canvasContext = null;
10677    this.stylesList.length = 0;
10678    this.itemData.length = 0;
10679    this._parent.destroy.call(this._parent);
10680};
10681
10682
10683function CVSolidElement(data, comp,globalData){
10684    this._parent.constructor.call(this,data, comp,globalData);
10685}
10686createElement(CVBaseElement, CVSolidElement);
10687
10688CVSolidElement.prototype.renderFrame = function(parentMatrix){
10689    if(this._parent.renderFrame.call(this, parentMatrix)===false){
10690        return;
10691    }
10692    var ctx = this.canvasContext;
10693    this.globalData.renderer.save();
10694    this.globalData.renderer.ctxTransform(this.finalTransform.mat.props);
10695    this.globalData.renderer.ctxOpacity(this.finalTransform.opacity);
10696    ctx.fillStyle=this.data.sc;
10697    ctx.fillRect(0,0,this.data.sw,this.data.sh);
10698    this.globalData.renderer.restore(this.data.hasMask);
10699    if(this.firstFrame){
10700        this.firstFrame = false;
10701    }
10702};
10703function CVTextElement(data, comp, globalData){
10704    this.textSpans = [];
10705    this.yOffset = 0;
10706    this.fillColorAnim = false;
10707    this.strokeColorAnim = false;
10708    this.strokeWidthAnim = false;
10709    this.stroke = false;
10710    this.fill = false;
10711    this.justifyOffset = 0;
10712    this.currentRender = null;
10713    this.renderType = 'canvas';
10714    this.values = {
10715        fill: 'rgba(0,0,0,0)',
10716        stroke: 'rgba(0,0,0,0)',
10717        sWidth: 0,
10718        fValue: ''
10719    }
10720    this._parent.constructor.call(this,data,comp, globalData);
10721}
10722createElement(CVBaseElement, CVTextElement);
10723
10724extendPrototype(ITextElement, CVTextElement);
10725
10726CVTextElement.prototype.tHelper = document.createElement('canvas').getContext('2d');
10727
10728CVTextElement.prototype.createElements = function(){
10729
10730    this._parent.createElements.call(this);
10731    //console.log('this.data: ',this.data);
10732
10733};
10734
10735CVTextElement.prototype.buildNewText = function(){
10736    var documentData = this.textProperty.currentData;
10737    this.renderedLetters = Array.apply(null,{length:documentData.l ? documentData.l.length : 0});
10738
10739    var hasFill = false;
10740    if(documentData.fc) {
10741        hasFill = true;
10742        this.values.fill = this.buildColor(documentData.fc);
10743    }else{
10744        this.values.fill = 'rgba(0,0,0,0)';
10745    }
10746    this.fill = hasFill;
10747    var hasStroke = false;
10748    if(documentData.sc){
10749        hasStroke = true;
10750        this.values.stroke = this.buildColor(documentData.sc);
10751        this.values.sWidth = documentData.sw;
10752    }
10753    var fontData = this.globalData.fontManager.getFontByName(documentData.f);
10754    var i, len;
10755    var letters = documentData.l;
10756    var matrixHelper = this.mHelper;
10757    this.stroke = hasStroke;
10758    this.values.fValue = documentData.s + 'px '+ this.globalData.fontManager.getFontByName(documentData.f).fFamily;
10759    len = documentData.t.length;
10760    //this.tHelper.font = this.values.fValue;
10761    var charData, shapeData, k, kLen, shapes, j, jLen, pathNodes, commands, pathArr, singleShape = this.data.singleShape;
10762    var trackingOffset = documentData.tr/1000*documentData.s;
10763    var xPos = 0, yPos = 0, firstLine = true;
10764    var cnt = 0;
10765    for (i = 0; i < len; i += 1) {
10766        charData = this.globalData.fontManager.getCharData(documentData.t.charAt(i), fontData.fStyle, this.globalData.fontManager.getFontByName(
10766documentData.f).fFamily);
10767        shapeData = charData && charData.data || {};
10768        matrixHelper.reset();
10769        if(singleShape && letters[i].n) {
10770            xPos = -trackingOffset;
10771            yPos += documentData.yOffset;
10772            yPos += firstLine ? 1 : 0;
10773            firstLine = false;
10774        }
10775
10776        shapes = shapeData.shapes ? shapeData.shapes[0].it : [];
10777        jLen = shapes.length;
10778        matrixHelper.scale(documentData.s/100,documentData.s/100);
10779        if(singleShape){
10780            this.applyTextPropertiesToMatrix(documentData, matrixHelper, letters[i].line, xPos, yPos);
10781        }
10782        commands = Array.apply(null,{length:jLen})
10783        for(j=0;j<jLen;j+=1){
10784            kLen = shapes[j].ks.k.i.length;
10785            pathNodes = shapes[j].ks.k;
10786            pathArr = [];
10787            for(k=1;k<kLen;k+=1){
10788                if(k==1){
10789                    pathArr.push(matrixHelper.applyToX(pathNodes.v[0][0],pathNodes.v[0][1],0),matrixHelper.applyToY(pathNodes.v[0][0],pathNodes.v[0][1],0));
10790                }
10791                pathArr.push(matrixHelper.applyToX(pathNodes.o[k-1][0],pathNodes.o[k-1][1],0),matrixHelper.applyToY(pathNodes.o[k-1][0],pathNodes.o[k-1][1],0),matrixHelper.applyToX(pathNodes.i[k][0],pathNodes.i[k][1],0),matrixHelper.applyToY(pathNodes.i[k][0],pathNodes.i[k][1],0),matrixHelper.applyToX(pathNodes.v[k][0],pathNodes.v[k][1],0),matrixHelper.applyToY(pathNodes.v[k][0],pathNodes.v[k][1],0));
10792            }
10793            pathArr.push(matrixHelper.applyToX(pathNodes.o[k-1][0],pathNodes.o[k-1][1],0),matrixHelper.applyToY(pathNodes.o[k-1][0],pathNodes.o[k-1][1],0),matrixHelper.applyToX(pathNodes.i[0][0],pathNodes.i[0][1],0),matrixHelper.applyToY(pathNodes.i[0][0],pathNodes.i[0][1],0),matrixHelper.applyToX(pathNodes.v[0][0],pathNodes.v[0][1],0),matrixHelper.applyToY(pathNodes.v[0][0],pathNodes.v[0][1],0));
10794            commands[j] = pathArr;
10795        }
10796        if(singleShape){
10797            xPos += letters[i].l;
10798            xPos += trackingOffset;
10799        }
10800        if(this.textSpans[cnt]){
10801            this.textSpans[cnt].elem = commands;
10802        } else {
10803            this.textSpans[cnt] = {elem: commands};
10804        }
10805        cnt +=1;
10806    }
10807}
10808
10809CVTextElement.prototype.renderFrame = function(parentMatrix){
10810    if(this._parent.renderFrame.call(this, parentMatrix)===false){
10811        return;
10812    }
10813    var ctx = this.canvasContext;
10814    var finalMat = this.finalTransform.mat.props;
10815    this.globalData.renderer.save();
10816    this.globalData.renderer.ctxTransform(finalMat);
10817    this.globalData.renderer.ctxOpacity(this.finalTransform.opacity);
10818    ctx.font = this.values.fValue;
10819    ctx.lineCap = 'butt';
10820    ctx.lineJoin = 'miter';
10821    ctx.miterLimit = 4;
10822
10823    if(!this.data.singleShape){
10824        this.textAnimator.getMeasures(this.textProperty.currentData, this.lettersChangedFlag);
10825    }
10826
10827    var  i,len, j, jLen, k, kLen;
10828    var renderedLetters = this.textAnimator.renderedLetters;
10829
10830    var letters = this.textProperty.currentData.l;
10831
10832    len = letters.length;
10833    var renderedLetter;
10834    var lastFill = null, lastStroke = null, lastStrokeW = null, commands, pathArr;
10835    for(i=0;i<len;i+=1){
10836        if(letters[i].n){
10837            continue;
10838        }
10839        renderedLetter = renderedLetters[i];
10840        if(renderedLetter){
10841            this.globalData.renderer.save();
10842            this.globalData.renderer.ctxTransform(renderedLetter.p);
10843            this.globalData.renderer.ctxOpacity(renderedLetter.o);
10844        }
10845        if(this.fill){
10846            if(renderedLetter && renderedLetter.fc){
10847                if(lastFill !== renderedLetter.fc){
10848                    lastFill = renderedLetter.fc;
10849                    ctx.fillStyle = renderedLetter.fc;
10850                }
10851            }else if(lastFill !== this.values.fill){
10852                lastFill = this.values.fill;
10853                ctx.fillStyle = this.values.fill;
10854            }
10855            commands = this.textSpans[i].elem;
10856            jLen = commands.length;
10857            this.globalData.canvasContext.beginPath();
10858            for(j=0;j<jLen;j+=1) {
10859                pathArr = commands[j];
10860                kLen = pathArr.length;
10861                this.globalData.canvasContext.moveTo(pathArr[0], pathArr[1]);
10862                for (k = 2; k < kLen; k += 6) {
10863                    this.globalData.canvasContext.bezierCurveTo(pathArr[k], pathArr[k + 1], pathArr[k + 2], pathArr[k + 3], pathArr[k + 4], pathArr[k + 5]);
10864                }
10865            }
10866            this.globalData.canvasContext.closePath();
10867            this.globalData.canvasContext.fill();
10868            ///ctx.fillText(this.textSpans[i].val,0,0);
10869        }
10870        if(this.stroke){
10871            if(renderedLetter && renderedLetter.sw){
10872                if(lastStrokeW !== renderedLetter.sw){
10873                    lastStrokeW = renderedLetter.sw;
10874                    ctx.lineWidth = renderedLetter.sw;
10875                }
10876            }else if(lastStrokeW !== this.values.sWidth){
10877                lastStrokeW = this.values.sWidth;
10878                ctx.lineWidth = this.values.sWidth;
10879            }
10880            if(renderedLetter && renderedLetter.sc){
10881                if(lastStroke !== renderedLetter.sc){
10882                    lastStroke = renderedLetter.sc;
10883                    ctx.strokeStyle = renderedLetter.sc;
10884                }
10885            }else if(lastStroke !== this.values.stroke){
10886                lastStroke = this.values.stroke;
10887                ctx.strokeStyle = this.values.stroke;
10888            }
10889            commands = this.textSpans[i].elem;
10890            jLen = commands.length;
10891            this.globalData.canvasContext.beginPath();
10892            for(j=0;j<jLen;j+=1) {
10893                pathArr = commands[j];
10894                kLen = pathArr.length;
10895                this.globalData.canvasContext.moveTo(pathArr[0], pathArr[1]);
10896                for (k = 2; k < kLen; k += 6) {
10897                    this.globalData.canvasContext.bezierCurveTo(pathArr[k], pathArr[k + 1], pathArr[k + 2], pathArr[k + 3], pathArr[k + 4], pathArr[k + 5]);
10898                }
10899            }
10900            this.globalData.canvasContext.closePath();
10901            this.globalData.canvasContext.stroke();
10902            ///ctx.strokeText(letters[i].val,0,0);
10903        }
10904        if(renderedLetter) {
10905            this.globalData.renderer.restore();
10906        }
10907    }
10908    /*if(this.data.hasMask){
10909     this.globalData.renderer.restore(true);
10910     }*/
10911    this.globalData.renderer.restore(this.data.hasMask);
10912    if(this.firstFrame){
10913        this.firstFrame = false;
10914    }
10915};
10916function HBaseElement(data,parentContainer,globalData,comp, placeholder){
10917    this.globalData = globalData;
10918    this.comp = comp;
10919    this.data = data;
10920    this.matteElement = null;
10921    this.parentContainer = parentContainer;
10922    this.layerId = placeholder ? placeholder.layerId : 'ly_'+randomString(10);
10923    this.placeholder = placeholder;
10924    this.init();
10925};
10926
10927createElement(BaseElement, HBaseElement);
10928HBaseElement.prototype.checkBlendMode = function(){
10929
10930};
10931HBaseElement.prototype.setBlendMode = BaseElement.prototype.setBlendMode;
10932
10933/*HBaseElement.prototype.appendNodeToParent = function(node) {
10934    if(this.data.hd){
10935        return;
10936    }
10937    if(this.placeholder){
10938        var g = this.placeholder.phElement;
10939        g.parentNode.insertBefore(node, g);
10940        //g.parentNode.removeChild(g);
10941    }else{
10942        this.parentContainer.appendChild(node);
10943    }
10944};*/
10945
10946
10947HBaseElement.prototype.getBaseElement = function(){
10948    return this.baseElement;
10949};
10950
10951HBaseElement.prototype.createElements = function(){
10952    if(this.data.hasMask){
10953        this.layerElement = document.createElementNS(svgNS,'svg');
10954        styleDiv(this.layerElement);
10955        //this.appendNodeToParent(this.layerElement);
10956        this.baseElement = this.layerElement;
10957        this.maskedElement = this.layerElement;
10958    }else{
10959        this.layerElement = this.parentContainer;
10960    }
10961    this.transformedElement = this.layerElement;
10962    if(this.data.ln && (this.data.ty === 4 || this.data.ty === 0)){
10963        if(this.layerElement === this.parentContainer){
10964            this.layerElement = document.createElementNS(svgNS,'g');
10965            //this.appendNodeToParent(this.layerElement);
10966            this.baseElement = this.layerElement;
10967        }
10968        this.layerElement.setAttribute('id',this.data.ln);
10969    }
10970    this.setBlendMode();
10971    if(this.layerElement !== this.parentContainer){
10972        this.placeholder = null;
10973    }
10974    this.checkParenting();
10975};
10976
10977HBaseElement.prototype.renderFrame = function(parentTransform){
10978    if(this.data.ty === 3){
10979        return false;
10980    }
10981
10982    if(this.currentFrameNum === this.lastNum || !this.isVisible){
10983        return this.isVisible;
10984    }
10985    this.lastNum = this.currentFrameNum;
10986
10987    this.finalTransform.opMdf = this.finalTransform.op.mdf;
10988    this.finalTransform.matMdf = this.finalTransform.mProp.mdf;
10989    this.finalTransform.opacity = this.finalTransform.op.v;
10990    if(this.firstFrame){
10991        this.finalTransform.opMdf = true;
10992        this.finalTransform.matMdf = true;
10993    }
10994
10995    var mat;
10996    var finalMat = this.finalTransform.mat;
10997
10998    if(this.hierarchy){
10999        var i, len = this.hierarchy.length;
11000
11001        mat = this.finalTransform.mProp.v.props;
11002        finalMat.cloneFromProps(mat);
11003        for(i=0;i<len;i+=1){
11004            this.finalTransform.matMdf = this.hierarchy[i].finalTransform.mProp.mdf ? true : this.finalTransform.matMdf;
11005            mat = this.hierarchy[i].finalTransform.mProp.v.props;
11006            finalMat.transform(mat[0],mat[1],mat[2],mat[3],mat[4],mat[5],mat[6],mat[7],mat[8],mat[9],mat[10],mat[11],mat[12],mat[13],mat[14],mat[15]);
11007        }
11008    }else{
11009        if(this.isVisible && this.finalTransform.matMdf){
11010            if(!parentTransform){
11011                finalMat.cloneFromProps(this.finalTransform.mProp.v.props);
11012            }else{
11013                mat = this.finalTransform.mProp.v.props;
11014                finalMat.cloneFromProps(mat);
11015            }
11016        }
11017    }
11018    if(this.data.hasMask){
11019        this.maskManager.renderFrame(finalMat);
11020    }
11021
11022    if(parentTransform){
11023        mat = parentTransform.mat.props;
11024        finalMat.cloneFromProps(mat);
11025        this.finalTransform.opacity *= parentTransform.opacity;
11026        this.finalTransform.opMdf = parentTransform.opMdf ? true : this.finalTransform.opMdf;
11027        this.finalTransform.matMdf = parentTransform.matMdf ? true : this.finalTransform.matMdf
11028    }
11029
11030    if(this.finalTransform.matMdf){
11031        this.transformedElement.style.transform = this.transformedElement.style.webkitTransform = finalMat.toCSS();
11032        this.finalMat = finalMat;
11033    }
11034    if(this.finalTransform.opMdf){
11035        this.transformedElement.style.opacity = this.finalTransform.opacity;
11036    }
11037    return this.isVisible;
11038};
11039
11040HBaseElement.prototype.destroy = function(){
11041    this.layerElement = null;
11042    this.transformedElement = null;
11043    this.parentContainer = null;
11044    if(this.matteElement) {
11045        this.matteElement = null;
11046    }
11047    if(this.maskManager) {
11048        this.maskManager.destroy();
11049        this.maskManager = null;
11050    }
11051};
11052
11053HBaseElement.prototype.getDomElement = function(){
11054    return this.layerElement;
11055};
11056HBaseElement.prototype.addMasks = function(data){
11057    this.maskManager = new MaskElement(data,this,this.globalData);
11058};
11059
11060HBaseElement.prototype.hide = function(){
11061};
11062
11063HBaseElement.prototype.setMatte = function(){
11064
11065}
11066
11067HBaseElement.prototype.buildElementParenting = HybridRenderer.prototype.buildElementParenting;
11068function HSolidElement(data,parentContainer,globalData,comp, placeholder){
11069    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
11070}
11071createElement(HBaseElement, HSolidElement);
11072
11073HSolidElement.prototype.createElements = function(){
11074    var parent = document.createElement('div');
11075    styleDiv(parent);
11076    var cont = document.createElementNS(svgNS,'svg');
11077    styleDiv(cont);
11078    cont.setAttribute('width',this.data.sw);
11079    cont.setAttribute('height',this.data.sh);
11080    parent.appendChild(cont);
11081    this.layerElement = parent;
11082    this.transformedElement = parent;
11083    //this.appendNodeToParent(parent);
11084    this.baseElement = parent;
11085    this.innerElem = parent;
11086    if(this.data.ln){
11087        this.innerElem.setAttribute('id',this.data.ln);
11088    }
11089    if(this.data.bm !== 0){
11090        this.setBlendMode();
11091    }
11092    var rect = document.createElementNS(svgNS,'rect');
11093    rect.setAttribute('width',this.data.sw);
11094    rect.setAttribute('height',this.data.sh);
11095    rect.setAttribute('fill',this.data.sc);
11096    cont.appendChild(rect);
11097    if(this.data.hasMask){
11098        this.maskedElement = rect;
11099    }
11100    this.checkParenting();
11101};
11102
11103
11104
11105HSolidElement.prototype.hide = SVGBaseElement.prototype.hide;
11106HSolidElement.prototype.show = SVGBaseElement.prototype.show;
11107HSolidElement.prototype.renderFrame = IImageElement.prototype.renderFrame;
11108HSolidElement.prototype.destroy = IImageElement.prototype.destroy;
11109function HCompElement(data,parentContainer,globalData,comp, placeholder){
11110    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
11111    this.layers = data.layers;
11112    this.supports3d = true;
11113    this.completeLayers = false;
11114    this.pendingElements = [];
11115    this.elements = Array.apply(null,{length:this.layers.length});
11116    if(this.data.tm){
11117        this.tm = PropertyFactory.getProp(this,this.data.tm,0,globalData.frameRate,this.dynamicProperties);
11118    }
11119    if(this.data.hasMask) {
11120        this.supports3d = false;
11121    }
11122    if(this.data.xt){
11123        this.layerElement = document.createElement('div');
11124    }
11125    this.buildAllItems();
11126
11127}
11128createElement(HBaseElement, HCompElement);
11129
11130HCompElement.prototype.createElements = function(){
11131    var divElement = document.createElement('div');
11132    styleDiv(divElement);
11133    if(this.data.ln){
11134        divElement.setAttribute('id',this.data.ln);
11135    }
11136    divElement.style.clip = 'rect(0px, '+this.data.w+'px, '+this.data.h+'px, 0px)';
11137    if(this.data.hasMask){
11138        var compSvg = document.createElementNS(svgNS,'svg');
11139        styleDiv(compSvg);
11140        compSvg.setAttribute('width',this.data.w);
11141        compSvg.setAttribute('height',this.data.h);
11142        var g = document.createElementNS(svgNS,'g');
11143        compSvg.appendChild(g);
11144        divElement.appendChild(compSvg);
11145        this.maskedElement = g;
11146        this.baseElement = divElement;
11147        this.layerElement = g;
11148        this.transformedElement = divElement;
11149    }else{
11150        this.layerElement = divElement;
11151        this.baseElement = this.layerElement;
11152        this.transformedElement = divElement;
11153    }
11154    //this.appendNodeToParent(this.layerElement);
11155    this.checkParenting();
11156};
11157
11158HCompElement.prototype.hide = ICompElement.prototype.hide;
11159HCompElement.prototype.prepareFrame = ICompElement.prototype.prepareFrame;
11160HCompElement.prototype.setElements = ICompElement.prototype.setElements;
11161HCompElement.prototype.getElements = ICompElement.prototype.getElements;
11162HCompElement.prototype.destroy = ICompElement.prototype.destroy;
11163
11164HCompElement.prototype.renderFrame = function(parentMatrix){
11165    var renderParent = this._parent.renderFrame.call(this,parentMatrix);
11166    var i,len = this.layers.length;
11167    if(renderParent===false){
11168        this.hide();
11169        return;
11170    }
11171
11172    this.hidden = false;
11173
11174    for( i = 0; i < len; i+=1 ){
11175        if(this.completeLayers || this.elements[i]){
11176            this.elements[i].renderFrame();
11177        }
11178    }
11179    if(this.firstFrame){
11180        this.firstFrame = false;
11181    }
11182};
11183
11184HCompElement.prototype.checkLayers = BaseRenderer.prototype.checkLayers;
11185HCompElement.prototype.buildItem = HybridRenderer.prototype.buildItem;
11186HCompElement.prototype.checkPendingElements = HybridRenderer.prototype.checkPendingElements;
11187HCompElement.prototype.addPendingElement = HybridRenderer.prototype.addPendingElement;
11188HCompElement.prototype.buildAllItems = BaseRenderer.prototype.buildAllItems;
11189HCompElement.prototype.createItem = HybridRenderer.prototype.createItem;
11190HCompElement.prototype.buildElementParenting = HybridRenderer.prototype.buildElementParenting;
11191HCompElement.prototype.createImage = HybridRenderer.prototype.createImage;
11192HCompElement.prototype.createComp = HybridRenderer.prototype.createComp;
11193HCompElement.prototype.createSolid = HybridRenderer.prototype.createSolid;
11194HCompElement.prototype.createShape = HybridRenderer.prototype.createShape;
11195HCompElement.prototype.createText = HybridRenderer.prototype.createText;
11196HCompElement.prototype.createBase = HybridRenderer.prototype.createBase;
11197HCompElement.prototype.appendElementInPos = HybridRenderer.prototype.appendElementInPos;
11198function HShapeElement(data,parentContainer,globalData,comp, placeholder){
11199    this.shapes = [];
11200    this.shapesData = data.shapes;
11201    this.stylesList = [];
11202    this.itemsData = [];
11203    this.prevViewData = [];
11204    this.shapeModifiers = [];
11205    this.processedElements = [];
11206    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
11207    this.currentBBox = {
11208        x:999999,
11209        y: -999999,
11210        h: 0,
11211        w: 0
11212    };
11213}
11214createElement(HBaseElement, HShapeElement);
11215var parent = HShapeElement.prototype._parent;
11216extendPrototype(IShapeElement, HShapeElement);
11217HShapeElement.prototype._parent = parent;
11218HShapeElement.prototype._renderShapeFrame = HShapeElement.prototype.renderFrame;
11219
11220HShapeElement.prototype.createElements = function(){
11221    var parent = document.createElement('div');
11222    styleDiv(parent);
11223    var cont = document.createElementNS(svgNS,'svg');
11224    styleDiv(cont);
11225    var size = this.comp.data ? this.comp.data : this.globalData.compSize;
11226    cont.setAttribute('width',size.w);
11227    cont.setAttribute('height',size.h);
11228    if(this.data.hasMask){
11229        var g = document.createElementNS(svgNS,'g');
11230        parent.appendChild(cont);
11231        cont.appendChild(g);
11232        this.maskedElement = g;
11233        this.layerElement = g;
11234        this.shapesContainer = g;
11235    }else{
11236        parent.appendChild(cont);
11237        this.layerElement = cont;
11238        this.shapesContainer = document.createElementNS(svgNS,'g');
11239        this.layerElement.appendChild(this.shapesContainer);
11240    }
11241    if(!this.data.hd){
11242        //this.parentContainer.appendChild(parent);
11243        this.baseElement = parent;
11244    }
11245    this.innerElem = parent;
11246    if(this.data.ln){
11247        this.innerElem.setAttribute('id',this.data.ln);
11248    }
11249
11250    this.searchShapes(this.shapesData,this.itemsData,this.prevViewData,this.layerElement,this.dynamicProperties,0, [], true);
11251    this.buildExpressionInterface();
11252    this.layerElement = parent;
11253    this.transformedElement = parent;
11254    this.shapeCont = cont;
11255    if(this.data.bm !== 0){
11256        this.setBlendMode();
11257    }
11258    this.checkParenting();
11259};
11260
11261HShapeElement.prototype.renderFrame = function(parentMatrix){
11262    var firstFrame = this.firstFrame;
11263    this._renderShapeFrame();
11264
11265    if(this.isVisible && (this.elemMdf || firstFrame)){
11266        var boundingBox = this.shapeCont.getBBox();
11267        var changed = false;
11268        if(this.currentBBox.w !== boundingBox.width){
11269            this.currentBBox.w = boundingBox.width;
11270            this.shapeCont.setAttribute('width',boundingBox.width);
11271            changed = true;
11272        }
11273        if(this.currentBBox.h !== boundingBox.height){
11274            this.currentBBox.h = boundingBox.height;
11275            this.shapeCont.setAttribute('height',boundingBox.height);
11276            changed = true;
11277        }
11278        if(changed  || this.currentBBox.x !== boundingBox.x  || this.currentBBox.y !== boundingBox.y){
11279            this.currentBBox.w = boundingBox.width;
11280            this.currentBBox.h = boundingBox.height;
11281            this.currentBBox.x = boundingBox.x;
11282            this.currentBBox.y = boundingBox.y;
11283
11284            this.shapeCont.setAttribute('viewBox',this.currentBBox.x+' '+this.currentBBox.y+' '+this.currentBBox.w+' '+this.currentBBox.h);
11285            this.shapeCont.style.transform = this.shapeCont.style.webkitTransform = 'translate(' + this.currentBBox.x + 'px,' + this.currentBBox.y + 'px)';
11286        }
11287    }
11288
11289};
11290function HTextElement(data,parentContainer,globalData,comp, placeholder){
11291    this.textSpans = [];
11292    this.textPaths = [];
11293    this.currentBBox = {
11294        x:999999,
11295        y: -999999,
11296        h: 0,
11297        w: 0
11298    }
11299    this.renderType = 'svg';
11300    this.isMasked = false;
11301    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
11302
11303}
11304createElement(HBaseElement, HTextElement);
11305
11306extendPrototype(ITextElement, HTextElement);
11307
11308HTextElement.prototype.createElements = function(){
11309    this.isMasked = this.checkMasks();
11310    var parent = document.createElement('div');
11311    styleDiv(parent);
11312    this.layerElement = parent;
11313    this.transformedElement = parent;
11314    if(this.isMasked){
11315        this.renderType = 'svg';
11316        var cont = document.createElementNS(svgNS,'svg');
11317        styleDiv(cont);
11318        this.cont = cont;
11319        this.compW = this.comp.data.w;
11320        this.compH = this.comp.data.h;
11321        cont.setAttribute('width',this.compW);
11322        cont.setAttribute('height',this.compH);
11323        var g = document.createElementNS(svgNS,'g');
11324        cont.appendChild(g);
11325        parent.appendChild(cont);
11326        this.maskedElement = g;
11327        this.innerElem = g;
11328    } else {
11329        this.renderType = 'html';
11330        this.innerElem = parent;
11331    }
11332    this.baseElement = parent;
11333
11334    this.checkParenting();
11335
11336};
11337
11338HTextElement.prototype.buildNewText = function(){
11339    var documentData = this.textProperty.currentData;
11340    this.renderedLetters = Array.apply(null,{length:this.textProperty.currentData.l ? this.textProperty.currentData.l.length : 0});
11341    var innerElemStyle = this.innerElem.style;
11342    innerElemStyle.color = innerElemStyle.fill = documentData.fc ? this.buildColor(documentData.fc) : 'rgba(0,0,0,0)';
11343    if(documentData.sc){
11344        innerElemStyle.stroke = this.buildColor(documentData.sc);
11345        innerElemStyle.strokeWidth = documentData.sw+'px';
11346    }
11347    var fontData = this.globalData.fontManager.getFontByName(documentData.f);
11348    if(!this.globalData.fontManager.chars){
11349        innerElemStyle.fontSize = documentData.s+'px';
11350        innerElemStyle.lineHeight = documentData.s+'px';
11351        if(fontData.fClass){
11352            this.innerElem.className = fontData.fClass;
11353        } else {
11354            innerElemStyle.fontFamily = fontData.fFamily;
11355            var fWeight = documentData.fWeight, fStyle = documentData.fStyle;
11356            innerElemStyle.fontStyle = fStyle;
11357            innerElemStyle.fontWeight = fWeight;
11358        }
11359    }
11360    var i, len;
11361
11362    var letters = documentData.l;
11363    len = letters.length;
11364    var tSpan,tParent,tCont;
11365    var matrixHelper = this.mHelper;
11366    var shapes, shapeStr = '';
11367    var cnt = 0;
11368    for (i = 0;i < len ;i += 1) {
11369        if(this.globalData.fontManager.chars){
11370            if(!this.textPaths[cnt]){
11371                tSpan = document.createElementNS(svgNS,'path');
11372                tSpan.setAttribute('stroke-linecap', 'butt');
11373                tSpan.setAttribute('stroke-linejoin','round');
11374                tSpan.setAttribute('stroke-miterlimit','4');
11375            } else {
11376                tSpan = this.textPaths[cnt];
11377            }
11378            if(!this.isMasked){
11379                if(this.textSpans[cnt]){
11380                    tParent = this.textSpans[cnt];
11381                    tCont = tParent.children[0];
11382                } else {
11383
11384                    tParent = document.createElement('div');
11385                    tCont = document.createElementNS(svgNS,'svg');
11386                    tCont.appendChild(tSpan);
11387                    styleDiv(tParent);
11388                }
11389            }
11390        }else{
11391            if(!this.isMasked){
11392                if(this.textSpans[cnt]){
11393                    tParent = this.textSpans[cnt];
11394                    tSpan = this.textPaths[cnt];
11395                } else {
11396                    tParent = document.createElement('span');
11397                    styleDiv(tParent);
11398                    tSpan = document.createElement('span');
11399                    styleDiv(tSpan);
11400                    tParent.appendChild(tSpan);
11401                }
11402            } else {
11403                tSpan = this.textPaths[cnt] ? this.textPaths[cnt] : document.createElementNS(svgNS,'text');
11404            }
11405        }
11406        //tSpan.setAttribute('visibility', 'hidden');
11407        if(this.globalData.fontManager.chars){
11408            var charData = this.globalData.fontManager.getCharData(documentData.t.charAt(i), fontData.fStyle, this.globalData.fontManager.getFontByName(
11408documentData.f).fFamily);
11409            var shapeData;
11410            if(charData){
11411                shapeData = charData.data;
11412            } else {
11413                shapeData = null;
11414            }
11415            matrixHelper.reset();
11416            if(shapeData && shapeData.shapes){
11417                shapes = shapeData.shapes[0].it;
11418                matrixHelper.scale(documentData.s/100,documentData.s/100);
11419                shapeStr = this.createPathShape(matrixHelper,shapes);
11420                tSpan.setAttribute('d',shapeStr);
11421            }
11422            if(!this.isMasked){
11423                this.innerElem.appendChild(tParent);
11424                if(shapeData && shapeData.shapes){
11425                    document.body.appendChild(tCont);
11426
11427                    var boundingBox = tCont.getBBox();
11428                    tCont.setAttribute('width',boundingBox.width + 2);
11429                    tCont.setAttribute('height',boundingBox.height + 2);
11430                    tCont.setAttribute('viewBox',(boundingBox.x-1)+' '+ (boundingBox.y-1)+' '+ (boundingBox.width+2)+' '+ (boundingBox.height+2));
11431                    tCont.style.transform = tCont.style.webkitTransform = 'translate(' + (boundingBox.x-1) + 'px,' + (boundingBox.y-1) + 'px)';
11432
11433                    letters[i].yOffset = boundingBox.y-1;
11434                    tParent.appendChild(tCont);
11435
11436                } else{
11437                    tCont.setAttribute('width',1);
11438                    tCont.setAttribute('height',1);
11439                }
11440            }else{
11441                this.innerElem.appendChild(tSpan);
11442            }
11443        }else{
11444            tSpan.textContent = letters[i].val;
11445            tSpan.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space","preserve");
11446            if(!this.isMasked){
11447                this.innerElem.appendChild(tParent);
11448                //
11449                tSpan.style.transform = tSpan.style.webkitTransform = 'translate3d(0,'+ -documentData.s/1.2+'px,0)';
11450            } else {
11451                this.innerElem.appendChild(tSpan);
11452            }
11453        }
11454        //
11455        if(!this.isMasked){
11456            this.textSpans[cnt] = tParent;
11457        }else{
11458            this.textSpans[cnt] = tSpan;
11459        }
11460        this.textSpans[cnt].style.display = 'block';
11461        this.textPaths[cnt] = tSpan;
11462        cnt += 1;
11463    }
11464    while(cnt < this.textSpans.length){
11465        this.textSpans[cnt].style.display = 'none';
11466        cnt += 1;
11467    }
11468}
11469
11470HTextElement.prototype.hide = SVGTextElement.prototype.hide;
11471
11472HTextElement.prototype.renderFrame = function(parentMatrix){
11473
11474    var renderParent = this._parent.renderFrame.call(this,parentMatrix);
11475    if(renderParent===false){
11476        this.hide();
11477        return;
11478    }
11479    if(this.hidden){
11480        this.hidden = false;
11481        this.innerElem.style.display = 'block';
11482        this.layerElement.style.display = 'block';
11483    }
11484
11485    if(this.data.singleShape){
11486        if(!this.firstFrame && !this.lettersChangedFlag){
11487            return;
11488        } else {
11489            // Todo Benchmark if using this is better than getBBox
11490             if(this.isMasked && this.finalTransform.matMdf){
11491                 this.cont.setAttribute('viewBox',-this.finalTransform.mProp.p.v[0]+' '+ -this.finalTransform.mProp.p.v[1]+' '+this.compW+' '+this.compH);
11492                this.cont.style.transform = this.cont.style.webkitTransform = 'translate(' + -this.finalTransform.mProp.p.v[0] + 'px,' + -this.finalTransform.mProp.p.v[1] + 'px)';
11493             }
11494        }
11495    }
11496
11497    this.textAnimator.getMeasures(this.textProperty.currentData, this.lettersChangedFlag);
11498    if(!this.lettersChangedFlag && !this.textAnimator.lettersChangedFlag){
11499        return;
11500    }
11501    var  i,len, count = 0;
11502    var renderedLetters = this.textAnimator.renderedLetters;
11503
11504    var letters = this.textProperty.currentData.l;
11505
11506    len = letters.length;
11507    var renderedLetter, textSpan, textPath;
11508    for(i=0;i<len;i+=1){
11509        if(letters[i].n){
11510            count += 1;
11511            continue;
11512        }
11513        textSpan = this.textSpans[i];
11514        textPath = this.textPaths[i];
11515        renderedLetter = renderedLetters[count];
11516        count += 1;
11517        if(!this.isMasked){
11518            textSpan.style.transform = textSpan.style.webkitTransform = renderedLetter.m;
11519        }else{
11520            textSpan.setAttribute('transform',renderedLetter.m);
11521        }
11522        ////textSpan.setAttribute('opacity',renderedLetter.o);
11523        textSpan.style.opacity = renderedLetter.o;
11524        if(renderedLetter.sw){
11525            textPath.setAttribute('stroke-width',renderedLetter.sw);
11526        }
11527        if(renderedLetter.sc){
11528            textPath.setAttribute('stroke',renderedLetter.sc);
11529        }
11530        if(renderedLetter.fc){
11531            textPath.setAttribute('fill',renderedLetter.fc);
11532            textPath.style.color = renderedLetter.fc;
11533        }
11534    }
11535    if(this.isVisible && (this.elemMdf || this.firstFrame)){
11536        if(this.innerElem.getBBox){
11537            var boundingBox = this.innerElem.getBBox();
11538
11539            if(this.currentBBox.w !== boundingBox.width){
11540                this.currentBBox.w = boundingBox.width;
11541                this.cont.setAttribute('width',boundingBox.width);
11542            }
11543            if(this.currentBBox.h !== boundingBox.height){
11544                this.currentBBox.h = boundingBox.height;
11545                this.cont.setAttribute('height',boundingBox.height);
11546            }
11547
11548            var margin = 1;
11549            if(this.currentBBox.w !== (boundingBox.width + margin*2) || this.currentBBox.h !== (boundingBox.height + margin*2)  || this.currentBBox.x !== (boundingBox.x - margin)  || this.currentBBox.y !== (boundingBox.y - margin)){
11550                this.currentBBox.w = boundingBox.width + margin*2;
11551                this.currentBBox.h = boundingBox.height + margin*2;
11552                this.currentBBox.x = boundingBox.x - margin;
11553                this.currentBBox.y = boundingBox.y - margin;
11554
11555                this.cont.setAttribute('viewBox',this.currentBBox.x+' '+this.currentBBox.y+' '+this.currentBBox.w+' '+this.currentBBox.h);
11556                this.cont.style.transform = this.cont.style.webkitTransform = 'translate(' + this.currentBBox.x + 'px,' + this.currentBBox.y + 'px)';
11557            }
11558        }
11559    }
11560    if(this.firstFrame){
11561        this.firstFrame = false;
11562    }
11563}
11564function HImageElement(data,parentContainer,globalData,comp, placeholder){
11565    this.assetData = globalData.getAssetData(data.refId);
11566    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
11567}
11568createElement(HBaseElement, HImageElement);
11569
11570HImageElement.prototype.createElements = function(){
11571
11572    var assetPath = this.globalData.getAssetsPath(this.assetData);
11573    var img = new Image();
11574
11575    if(this.data.hasMask){
11576        var parent = document.createElement('div');
11577        styleDiv(parent);
11578        var cont = document.createElementNS(svgNS,'svg');
11579        styleDiv(cont);
11580        cont.setAttribute('width',this.assetData.w);
11581        cont.setAttribute('height',this.assetData.h);
11582        parent.appendChild(cont);
11583        this.imageElem = document.createElementNS(svgNS,'image');
11584        this.imageElem.setAttribute('width',this.assetData.w+"px");
11585        this.imageElem.setAttribute('height',this.assetData.h+"px");
11586        this.imageElem.setAttributeNS('http://www.w3.org/1999/xlink','href',assetPath);
11587        cont.appendChild(this.imageElem);
11588        this.layerElement = parent;
11589        this.transformedElement = parent;
11590        this.baseElement = parent;
11591        this.innerElem = parent;
11592        this.maskedElement = this.imageElem;
11593    } else {
11594        styleDiv(img);
11595        this.layerElement = img;
11596        this.baseElement = img;
11597        this.innerElem = img;
11598        this.transformedElement = img;
11599    }
11600    img.src = assetPath;
11601    if(this.data.ln){
11602        this.innerElem.setAttribute('id',this.data.ln);
11603    }
11604    this.checkParenting();
11605};
11606
11607HImageElement.prototype.show = HSolidElement.prototype.show;
11608HImageElement.prototype.hide = HSolidElement.prototype.hide;
11609HImageElement.prototype.renderFrame = HSolidElement.prototype.renderFrame;
11610HImageElement.prototype.destroy = HSolidElement.prototype.destroy;
11611function HCameraElement(data,parentContainer,globalData,comp, placeholder){
11612    this._parent.constructor.call(this,data,parentContainer,globalData,comp, placeholder);
11613    var getProp = PropertyFactory.getProp;
11614    this.pe = getProp(this,data.pe,0,0,this.dynamicProperties);
11615    if(data.ks.p.s){
11616        this.px = getProp(this,data.ks.p.x,1,0,this.dynamicProperties);
11617        this.py = getProp(this,data.ks.p.y,1,0,this.dynamicProperties);
11618        this.pz = getProp(this,data.ks.p.z,1,0,this.dynamicProperties);
11619    }else{
11620        this.p = getProp(this,data.ks.p,1,0,this.dynamicProperties);
11621    }
11622    if(data.ks.a){
11623        this.a = getProp(this,data.ks.a,1,0,this.dynamicProperties);
11624    }
11625    if(data.ks.or.k.length && data.ks.or.k[0].to){
11626        var i,len = data.ks.or.k.length;
11627        for(i=0;i<len;i+=1){
11628            data.ks.or.k[i].to = null;
11629            data.ks.or.k[i].ti = null;
11630        }
11631    }
11632    this.or = getProp(this,data.ks.or,1,degToRads,this.dynamicProperties);
11633    this.or.sh = true;
11634    this.rx = getProp(this,data.ks.rx,0,degToRads,this.dynamicProperties);
11635    this.ry = getProp(this,data.ks.ry,0,degToRads,this.dynamicProperties);
11636    this.rz = getProp(this,data.ks.rz,0,degToRads,this.dynamicProperties);
11637    this.mat = new Matrix();
11638}
11639createElement(HBaseElement, HCameraElement);
11640
11641HCameraElement.prototype.setup = function() {
11642    var i, len = this.comp.threeDElements.length, comp;
11643    for(i=0;i<len;i+=1){
11644        //[perspectiveElem,container]
11645        comp = this.comp.threeDElements[i];
11646        comp.perspectiveElem.style.perspective = comp.perspectiveElem.style.webkitPerspective = this.pe.v+'px';
11647        comp.container.style.transformOrigin = comp.container.style.mozTransformOrigin = comp.container.style.webkitTransformOrigin = "0px 0px 0px";
11648        comp.perspectiveElem.style.transform = comp.perspectiveElem.style.webkitTransform = 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)';
11649    }
11650};
11651
11652HCameraElement.prototype.createElements = function(){
11653};
11654
11655HCameraElement.prototype.hide = function(){
11656};
11657
11658HCameraElement.prototype.renderFrame = function(){
11659    var mdf = this.firstFrame;
11660    var i, len;
11661    if(this.hierarchy){
11662        len = this.hierarchy.length;
11663        for(i=0;i<len;i+=1){
11664            mdf = this.hierarchy[i].finalTransform.mProp.mdf ? true : mdf;
11665        }
11666    }
11667    if(mdf || (this.p && this.p.mdf) || (this.px && (this.px.mdf || this.py.mdf || this.pz.mdf)) || this.rx.mdf || this.ry.mdf || this.rz.mdf || this.or.mdf || (this.a && this.a.mdf)) {
11668        this.mat.reset();
11669
11670        if(this.p){
11671            this.mat.translate(-this.p.v[0],-this.p.v[1],this.p.v[2]);
11672        }else{
11673            this.mat.translate(-this.px.v,-this.py.v,this.pz.v);
11674        }
11675        if(this.a){
11676            var diffVector = [this.p.v[0]-this.a.v[0],this.p.v[1]-this.a.v[1],this.p.v[2]-this.a.v[2]];
11677            var mag = Math.sqrt(Math.pow(diffVector[0],2)+Math.pow(diffVector[1],2)+Math.pow(diffVector[2],2));
11678            //var lookDir = getNormalizedPoint(getDiffVector(this.a.v,this.p.v));
11679            var lookDir = [diffVector[0]/mag,diffVector[1]/mag,diffVector[2]/mag];
11680            var lookLengthOnXZ = Math.sqrt( lookDir[2]*lookDir[2] + lookDir[0]*lookDir[0] );
11681            var m_rotationX = (Math.atan2( lookDir[1], lookLengthOnXZ ));
11682            var m_rotationY = (Math.atan2( lookDir[0], -lookDir[2]));
11683            this.mat.rotateY(m_rotationY).rotateX(-m_rotationX);
11684
11685        }
11686        this.mat.rotateX(-this.rx.v).rotateY(-this.ry.v).rotateZ(this.rz.v);
11687        this.mat.rotateX(-this.or.v[0]).rotateY(-this.or.v[1]).rotateZ(this.or.v[2]);
11688        this.mat.translate(this.globalData.compSize.w/2,this.globalData.compSize.h/2,0);
11689        this.mat.translate(0,0,this.pe.v);
11690        if(this.hierarchy){
11691            var mat;
11692            len = this.hierarchy.length;
11693            for(i=0;i<len;i+=1){
11694                mat = this.hierarchy[i].finalTransform.mProp.iv.props;
11695                this.mat.transform(mat[0],mat[1],mat[2],mat[3],mat[4],mat[5],mat[6],mat[7],mat[8],mat[9],mat[10],mat[11],-mat[12],-mat[13],mat[14],mat[15]);
11696            }
11697        }
11698        len = this.comp.threeDElements.length;
11699        var comp;
11700        for(i=0;i<len;i+=1){
11701            comp = this.comp.threeDElements[i];
11702            comp.container.style.transform = comp.container.style.webkitTransform = this.mat.toCSS();
11703        }
11704    }
11705    this.firstFrame = false;
11706};
11707
11708HCameraElement.prototype.destroy = function(){
11709};
11710var Expressions = (function(){
11711    var ob = {};
11712    ob.initExpressions = initExpressions;
11713
11714
11715    function initExpressions(animation){
11716        animation.renderer.compInterface = CompExpressionInterface(animation.renderer);
11717        animation.renderer.globalData.projectInterface.registerComposition(animation.renderer);
11718    }
11719   return ob;
11720}());
11721
11722expressionsPlugin = Expressions;
11723
11724(function addPropertyDecorator() {
11725
11726    function getStaticValueAtTime() {
11727        return this.pv;
11728    }
11729
11730    function loopOut(type,duration,durationFlag){
11731        if(!this.k || !this.keyframes){
11732            return this.pv;
11733        }
11734        var currentFrame = this.comp.renderedFrame;
11735        var keyframes = this.keyframes;
11736        var lastKeyFrame = keyframes[keyframes.length - 1].t;
11737        if(currentFrame<=lastKeyFrame){
11738            return this.pv;
11739        }else{
11740            var cycleDuration, firstKeyFrame;
11741            if(!durationFlag){
11742                if(!duration || duration > keyframes.length - 1){
11743                    duration = keyframes.length - 1;
11744                }
11745                firstKeyFrame = keyframes[keyframes.length - 1 - duration].t;
11746                cycleDuration = lastKeyFrame - firstKeyFrame;
11747            } else {
11748                if(!duration){
11749                    cycleDuration = Math.max(0,lastKeyFrame - this.elem.data.ip);
11750                } else {
11751                    cycleDuration = Math.abs(lastKeyFrame - elem.comp.globalData.frameRate*duration);
11752                }
11753                firstKeyFrame = lastKeyFrame - cycleDuration;
11754            }
11755            var offsetTime = this.offsetTime || 0;
11756            var i, len, ret;
11757            if(type.toLowerCase() === 'pingpong') {
11758                var iterations = Math.floor((currentFrame - firstKeyFrame)/cycleDuration);
11759                if(iterations % 2 !== 0){
11760                    return this.getValueAtTime(((cycleDuration - (currentFrame - firstKeyFrame) % cycleDuration +  firstKeyFrame) - offsetTime) / this.comp.globalData.frameRate, 0);
11761                }
11762            } else if(type === 'offset'){
11763                var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0);
11764                var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0);
11765                var current = this.getValueAtTime(((currentFrame - firstKeyFrame) % cycleDuration +  firstKeyFrame) / this.comp.globalData.frameRate, 0);
11766                var repeats = Math.floor((currentFrame - firstKeyFrame)/cycleDuration);
11767                if(this.pv.length){
11768                    ret = new Array(initV.length);
11769                    len = ret.length;
11770                    for(i=0;i<len;i+=1){
11771                        ret[i] = (endV[i]-initV[i])*repeats + current[i];
11772                    }
11773                    return ret;
11774                }
11775                return (endV-initV)*repeats + current;
11776            } else if(type === 'continue'){
11777                var lastValue = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0);
11778                var nextLastValue = this.getValueAtTime((lastKeyFrame - 0.001) / this.comp.globalData.frameRate, 0);
11779                if(this.pv.length){
11780                    ret = new Array(lastValue.length);
11781                    len = ret.length;
11782                    for(i=0;i<len;i+=1){
11783                        ret[i] = lastValue[i] + (lastValue[i]-nextLastValue[i])*((currentFrame - lastKeyFrame)/ this.comp.globalData.frameRate)/0.0005;
11784                    }
11785                    return ret;
11786                }
11787                return lastValue + (lastValue-nextLastValue)*(((currentFrame - lastKeyFrame))/0.001);
11788            }
11789            return this.getValueAtTime((((currentFrame - firstKeyFrame) % cycleDuration +  firstKeyFrame) - offsetTime) / this.comp.globalData.frameRate, 0);
11790        }
11791    }
11792
11793    function loopIn(type,duration, durationFlag) {
11794        if(!this.k){
11795            return this.pv;
11796        }
11797        var currentFrame = time*elem.comp.globalData.frameRate;
11798        var keyframes = this.keyframes;
11799        var firstKeyFrame = keyframes[0].t;
11800        var offsetTime = this.offsetTime || 0;
11801        if(currentFrame>=firstKeyFrame){
11802            return this.pv;
11803        }else{
11804            var cycleDuration, lastKeyFrame;
11805            if(!durationFlag){
11806                if(!duration || duration > keyframes.length - 1){
11807                    duration = keyframes.length - 1;
11808                }
11809                lastKeyFrame = keyframes[duration].t;
11810                cycleDuration = lastKeyFrame - firstKeyFrame;
11811            } else {
11812                if(!duration){
11813                    cycleDuration = Math.max(0,this.elem.data.op - firstKeyFrame);
11814                } else {
11815                    cycleDuration = Math.abs(elem.comp.globalData.frameRate*duration);
11816                }
11817                lastKeyFrame = firstKeyFrame + cycleDuration;
11818            }
11819            var i, len, ret;
11820            if(type === 'pingpong') {
11821                var iterations = Math.floor((firstKeyFrame - currentFrame)/cycleDuration);
11822                if(iterations % 2 === 0){
11823                    return this.getValueAtTime((((firstKeyFrame - currentFrame)%cycleDuration +  firstKeyFrame) - offsetTime) / this.comp.globalData.frameRate, 0);
11824                }
11825            } else if(type === 'offset'){
11826                var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0);
11827                var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0);
11828                var current = this.getValueAtTime((cycleDuration - (firstKeyFrame - currentFrame)%cycleDuration +  firstKeyFrame) / this.comp.globalData.frameRate, 0);
11829                var repeats = Math.floor((firstKeyFrame - currentFrame)/cycleDuration)+1;
11830                if(this.pv.length){
11831                    ret = new Array(initV.length);
11832                    len = ret.length;
11833                    for(i=0;i<len;i+=1){
11834                        ret[i] = current[i]-(endV[i]-initV[i])*repeats;
11835                    }
11836                    return ret;
11837                }
11838                return current-(endV-initV)*repeats;
11839            } else if(type === 'continue'){
11840                var firstValue = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0);
11841                var nextFirstValue = this.getValueAtTime((firstKeyFrame + 0.001) / this.comp.globalData.frameRate, 0);
11842                if(this.pv.length){
11843                    ret = new Array(firstValue.length);
11844                    len = ret.length;
11845                    for(i=0;i<len;i+=1){
11846                        ret[i] = firstValue[i] + (firstValue[i]-nextFirstValue[i])*(firstKeyFrame - currentFrame)/0.001;
11847                    }
11848                    return ret;
11849                }
11850                return firstValue + (firstValue-nextFirstValue)*(firstKeyFrame - currentFrame)/0.001;
11851            }
11852
11853            return this.getValueAtTime(((cycleDuration - (firstKeyFrame - currentFrame) % cycleDuration +  firstKeyFrame) - offsetTime) / this.comp.globalData.frameRate, 0);
11854        }
11855    }
11856
11857    function getValueAtTime(frameNum) {
11858        if(!this._cachingAtTime) {
11859            this._cachingAtTime = {lastValue:-99999,lastIndex:0};
11860        }
11861        //console.log('this._cachingAtTime', JSON.parse(JSON.stringify(this._cachingAtTime)))
11862        if(frameNum !== this._cachingAtTime.lastFrame) {
11863            frameNum *= this.elem.globalData.frameRate;
11864            frameNum -= this.offsetTime;
11865            var i = this._caching.lastFrame < frameNum ? this._caching.lastIndex : 0;
11866            var interpolationResult = this.interpolateValue(frameNum, i, this.pv, this._cachingAtTime);
11867            this._cachingAtTime.lastIndex = interpolationResult.iterationIndex;
11868            this._cachingAtTime.value = interpolationResult.value;
11869            this._cachingAtTime.lastFrame = frameNum;
11870        }
11871        return this._cachingAtTime.value;
11872
11873    }
11874
11875    function getVelocityAtTime(frameNum) {
11876        if(this.vel !== undefined){
11877            return this.vel;
11878        }
11879        var delta = -0.01;
11880        //frameNum += this.elem.data.st;
11881        var v1 = this.getValueAtTime(frameNum);
11882        var v2 = this.getValueAtTime(frameNum + delta);
11883        var velocity;
11884        if(v1.length){
11885            velocity = Array.apply(null,{length:v1.length});
11886            var i;
11887            for(i=0;i<v1.length;i+=1){
11888                //removing frameRate
11889                //if needed, don't add it here
11890                //velocity[i] = this.elem.globalData.frameRate*((v2[i] - v1[i])/delta);
11891                velocity[i] = (v2[i] - v1[i])/delta;
11892            }
11893        } else {
11894            velocity = (v2 - v1)/delta;
11895        }
11896        return velocity;
11897    };
11898
11899    function setGroupProperty(propertyGroup){
11900        this.propertyGroup = propertyGroup;
11901    }
11902
11903    function searchExpressions(elem,data,prop){
11904        if(data.x){
11905            prop.k = true;
11906            prop.x = true;
11907            if(prop.getValue) {
11908                prop.getPreValue = prop.getValue;
11909            }
11910            prop.getValue = ExpressionManager.initiateExpression.bind(prop)(elem,data,prop);
11911        }
11912    }
11913
11914    function getTransformValueAtTime(time) {
11915        console.log('time:', time)
11916    }
11917
11918    function getTransformStaticValueAtTime(time) {
11919
11920    }
11921
11922    var TextExpressionSelectorProp = (function(){
11923
11924        function getValueProxy(index,total){
11925            this.textIndex = index+1;
11926            this.textTotal = total;
11927            this.getValue();
11928            return this.v;
11929        }
11930
11931        return function TextExpressionSelectorProp(elem,data){
11932            this.pv = 1;
11933            this.comp = elem.comp;
11934            this.elem = elem;
11935            this.mult = .01;
11936            this.type = 'textSelector';
11937            this.textTotal = data.totalChars;
11938            this.selectorValue = 100;
11939            this.lastValue = [1,1,1];
11940            searchExpressions.bind(this)(elem,data,this);
11941            this.getMult = getValueProxy;
11942            this.getVelocityAtTime = getVelocityAtTime;
11943            if(this.kf){
11944                this.getValueAtTime = getValueAtTime.bind(this);
11945            } else {
11946                this.getValueAtTime = getStaticValueAtTime.bind(this);
11947            }
11948            this.setGroupProperty = setGroupProperty;
11949        }
11950    }());
11951
11952
11953    var propertyGetProp = PropertyFactory.getProp;
11954    PropertyFactory.getProp = function(elem,data,type, mult, arr){
11955        var prop = propertyGetProp(elem,data,type, mult, arr);
11956        //prop.getVelocityAtTime = getVelocityAtTime;
11957        //prop.loopOut = loopOut;
11958        //prop.loopIn = loopIn;
11959        if(type === 2) {
11960            if(prop.dynamicProperties.length) {
11961                prop.getValueAtTime = getTransformValueAtTime.bind(prop);
11962            } else {
11963                prop.getValueAtTime = getTransformStaticValueAtTime.bind(prop);
11964            }
11965        } else {
11966            if(prop.kf){
11967                prop.getValueAtTime = getValueAtTime.bind(prop);
11968            } else {
11969                prop.getValueAtTime = getStaticValueAtTime.bind(prop);
11970            }
11971        }
11972        prop.setGroupProperty = setGroupProperty;
11973        prop.loopOut = loopOut;
11974        prop.loopIn = loopIn;
11975        prop.getVelocityAtTime = getVelocityAtTime;
11976        prop.numKeys = data.a === 1 ? data.k.length : 0;
11977        var isAdded = prop.k;
11978        if(data.ix !== undefined){
11979            Object.defineProperty(prop,'propertyIndex',{
11980                get: function(){
11981                    return data.ix;
11982                }
11983            })
11984        }
11985        searchExpressions(elem,data,prop);
11986        if(!isAdded && prop.x){
11987            arr.push(prop);
11988        }
11989
11990        return prop;
11991    }
11992
11993    function getShapeValueAtTime(frameNum) {
11994        if (!this._shapeValueAtTime) {
11995            this._lastIndexAtTime = 0;
11996            this._lastTimeAtTime = -999999;
11997            this._shapeValueAtTime = shape_pool.clone(this.pv);
11998        }
11999        if(frameNum !== this._lastTimeAtTime) {
12000            this._lastTimeAtTime = frameNum;
12001            frameNum *= this.elem.globalData.frameRate;
12002            var interpolationResult = this.interpolateShape(frameNum, this._lastIndexAtTime, this._shapeValueAtTime, false);
12003            this._lastIndexAtTime = interpolationResult.iterationIndex;
12004        }
12005        return this._shapeValueAtTime;
12006    }
12007
12008    var ShapePropertyConstructorFunction = ShapePropertyFactory.getConstructorFunction();
12009    var KeyframedShapePropertyConstructorFunction = ShapePropertyFactory.getKeyframedConstructorFunction();
12010
12011    ShapePropertyConstructorFunction.prototype.vertices = function(prop, time){
12012        var shapePath = this.v;
12013        if(time !== undefined) {
12014            shapePath = this.getValueAtTime(time, 0);
12015        }
12016        var i, len = shapePath._length;
12017        var vertices = shapePath[prop];
12018        var points = shapePath.v;
12019        var arr = Array.apply(null,{length:len})
12020        for(i = 0; i < len; i += 1) {
12021            if(prop === 'i' || prop === 'o') {
12022                arr[i] = [vertices[i][0] - points[i][0], vertices[i][1] - points[i][1]]
12023            } else {
12024                arr[i] = [vertices[i][0], vertices[i][1]]
12025            }
12026            
12027        }
12028        return arr;
12029    }
12030
12031    ShapePropertyConstructorFunction.prototype.points = function(time){
12032        return this.vertices('v', time);
12033    }
12034
12035    ShapePropertyConstructorFunction.prototype.inTangents = function(time){
12036        return this.vertices('i', time);
12037    }
12038
12039    ShapePropertyConstructorFunction.prototype.outTangents = function(time){
12040        return this.vertices('o', time);
12041    }
12042
12043    ShapePropertyConstructorFunction.prototype.isClosed = function(){
12044        return this.v.c;
12045    }
12046
12047    ShapePropertyConstructorFunction.prototype.pointOnPath = function(perc, time){
12048        var shapePath = this.v;
12049        if(time !== undefined) {
12050            shapePath = this.getValueAtTime(time, 0);
12051        }
12052        if(!this._segmentsLength) {
12053            this._segmentsLength = bez.getSegmentsLength(shapePath);
12054        }
12055
12056        var segmentsLength = this._segmentsLength;
12057        var lengths = segmentsLength.lengths;
12058        var lengthPos = segmentsLength.totalLength * perc;
12059        var i = 0, len = lengths.length;
12060        var j = 0, jLen;
12061        var accumulatedLength = 0;
12062        var segments;
12063        while(i < len) {
12064            if(accumulatedLength + lengths[i].addedLength > lengthPos) {
12065                segments = lengths[i].segments;
12066                var initIndex = i;
12067                var endIndex = (shapePath.c && i === len - 1) ? 0 : i + 1;
12068                var segmentPerc = (lengthPos - accumulatedLength)/lengths[i].addedLength;
12069                var pt = bez.getPointInSegment(shapePath.v[initIndex], shapePath.v[endIndex], shapePath.o[initIndex], shapePath.i[endIndex], segmentPerc, lengths[i])
12070                break;
12071            } else {
12072                accumulatedLength += lengths[i].addedLength;
12073            }
12074            i += 1;
12075        }
12076        if(!pt){
12077            pt = shapePath.c ? [shapePath.v[0][0],shapePath.v[0][1]]:[shapePath.v[shapePath._length-1][0],shapePath.v[shapePath._length-1][1]]
12078        }
12079        return pt;
12080    }
12081
12082    ShapePropertyConstructorFunction.prototype.vectorOnPath = function(perc, time, vectorType){
12083        //perc doesn't use triple equality because can be a Number object, not a primitive.
12084        perc = perc == 1 ? this.v.c ? 0 : 0.999 : perc;
12085        var pt1 = this.pointOnPath(perc, time);
12086        var pt2 = this.pointOnPath(perc + 0.001, time);
12087        var xLength = pt2[0] - pt1[0];
12088        var yLength = pt2[1] - pt1[1];
12089        var magnitude = Math.sqrt(Math.pow(xLength,2) + Math.pow(yLength,2));
12090        var unitVector = vectorType === 'tangent' ? [xLength/magnitude, yLength/magnitude] : [-yLength/magnitude, xLength/magnitude];
12091        return unitVector;
12092    }
12093
12094    ShapePropertyConstructorFunction.prototype.tangentOnPath = function(perc, time){
12095        return this.vectorOnPath(perc, time, 'tangent');
12096    }
12097
12098    ShapePropertyConstructorFunction.prototype.normalOnPath = function(perc, time){
12099        return this.vectorOnPath(perc, time, 'normal');
12100    }
12101
12102    ShapePropertyConstructorFunction.prototype.setGroupProperty = setGroupProperty;
12103    ShapePropertyConstructorFunction.prototype.getValueAtTime = getStaticValueAtTime;
12104
12105    KeyframedShapePropertyConstructorFunction.prototype.vertices = ShapePropertyConstructorFunction.prototype.vertices;
12106    KeyframedShapePropertyConstructorFunction.prototype.points = ShapePropertyConstructorFunction.prototype.points;
12107    KeyframedShapePropertyConstructorFunction.prototype.inTangents = ShapePropertyConstructorFunction.prototype.inTangents;
12108    KeyframedShapePropertyConstructorFunction.prototype.outTangents = ShapePropertyConstructorFunction.prototype.outTangents;
12109    KeyframedShapePropertyConstructorFunction.prototype.isClosed = ShapePropertyConstructorFunction.prototype.isClosed;
12110    KeyframedShapePropertyConstructorFunction.prototype.pointOnPath = ShapePropertyConstructorFunction.prototype.pointOnPath;
12111    KeyframedShapePropertyConstructorFunction.prototype.vectorOnPath = ShapePropertyConstructorFunction.prototype.vectorOnPath;
12112    KeyframedShapePropertyConstructorFunction.prototype.tangentOnPath = ShapePropertyConstructorFunction.prototype.tangentOnPath;
12113    KeyframedShapePropertyConstructorFunction.prototype.normalOnPath = ShapePropertyConstructorFunction.prototype.normalOnPath;
12114    KeyframedShapePropertyConstructorFunction.prototype.setGroupProperty = ShapePropertyConstructorFunction.prototype.setGroupProperty;
12115    KeyframedShapePropertyConstructorFunction.prototype.getValueAtTime = getShapeValueAtTime;
12116
12117    var propertyGetShapeProp = ShapePropertyFactory.getShapeProp;
12118    ShapePropertyFactory.getShapeProp = function(elem,data,type, arr, trims){
12119        var prop = propertyGetShapeProp(elem,data,type, arr, trims);
12120        var isAdded = prop.k;
12121        if(data.ix !== undefined){
12122            Object.defineProperty(prop,'propertyIndex',{
12123                get: function(){
12124                    return data.ix;
12125                }
12126            })
12127        }
12128        if(type === 3){
12129            searchExpressions(elem,data.pt,prop);
12130        } else if(type === 4){
12131            searchExpressions(elem,data.ks,prop);
12132        }
12133        if(!isAdded && prop.x){
12134            arr.push(prop);
12135        }
12136        return prop;
12137    }
12138
12139    var propertyGetTextProp = PropertyFactory.getTextSelectorProp;
12140    PropertyFactory.getTextSelectorProp = function(elem, data,arr){
12141        if(data.t === 1){
12142            return new TextExpressionSelectorProp(elem, data,arr);
12143        } else {
12144            return propertyGetTextProp(elem,data,arr);
12145        }
12146    }
12147}());
12148(function addTextPropertyDecorator() {
12149
12150    function searchExpressions(){
12151        if(this.data.d.x){
12152            this.comp = this.elem.comp;
12153            if(this.getValue) {
12154                this.getPreValue = this.getValue;
12155            }
12156            this.calculateExpression = ExpressionManager.initiateExpression.bind(this)(this.elem,this.data.d,this);
12157            this.getValue = this.getExpressionValue;
12158            return true;
12159        }
12160        return false;
12161    }
12162
12163    TextProperty.prototype.searchProperty = function(){
12164        this.kf = this.searchExpressions() || this.data.d.k.length > 1;
12165        return this.kf;
12166    }
12167
12168    TextProperty.prototype.getExpressionValue = function(num){
12169        this.calculateExpression();
12170        if(this.mdf) {
12171            this.currentData.t = this.v.toString();
12172            this.completeTextData(this.currentData);
12173        }
12174    }
12175
12176    TextProperty.prototype.searchExpressions = searchExpressions;
12177    
12178}());
12179var ExpressionManager = (function(){
12180    var ob = {};
12181    var Math = BMMath;
12182    var window = null;
12183    var document = null;
12184
12185    function duplicatePropertyValue(value, mult){
12186        mult = mult || 1;
12187
12188        if(typeof value === 'number'  || value instanceof Number){
12189            return value*mult;
12190        }else if(value.i){
12191            return JSON.parse(JSON.stringify(value));
12192        }else{
12193            var arr = Array.apply(null,{length:value.length});
12194            var i, len = value.length;
12195            for(i=0;i<len;i+=1){
12196                arr[i]=value[i]*mult;
12197            }
12198            return arr;
12199        }
12200    }
12201
12202    function shapesEqual(shape1, shape2) {
12203        if(shape1._length !== shape2._length || shape1.c !== shape2.c){
12204            return false;
12205        }
12206        var i, len = shape1._length;
12207        for(i = 0; i < len; i += 1) {
12208            if(shape1.v[i][0] !== shape2.v[i][0] || shape1.v[i][1] !== shape2.v[i][1]
12209                || shape1.o[i][0] !== shape2.o[i][0] || shape1.o[i][1] !== shape2.o[i][1]
12210                || shape1.i[i][0] !== shape2.i[i][0] || shape1.i[i][1] !== shape2.i[i][1]){
12211                return false;
12212            }
12213        }
12214        return true;
12215    }
12216
12217    function $bm_neg(a){
12218        var tOfA = typeof a;
12219        if(tOfA === 'number' || tOfA === 'boolean'  || a instanceof Number ){
12220            return -a;
12221        }
12222        if(a.constructor === Array){
12223            var i, lenA = a.length;
12224            var retArr = [];
12225            for(i=0;i<lenA;i+=1){
12226                retArr[i] = -a[i];
12227            }
12228            return retArr;
12229        }
12230    }
12231
12232    function sum(a,b) {
12233        var tOfA = typeof a;
12234        var tOfB = typeof b;
12235        if(tOfA === 'string' || tOfB === 'string'){
12236            return a + b;
12237        }
12238        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number) && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string'  || b instanceof Number)) {
12239            return a + b;
12240        }
12241        if(a.constructor === Array && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )){
12242            a[0] = a[0] + b;
12243            return a;
12244        }
12245        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && b.constructor === Array){
12246            b[0] = a + b[0];
12247            return b;
12248        }
12249        if(a.constructor === Array && b.constructor === Array){
12250            
12251            var i = 0, lenA = a.length, lenB = b.length;
12252            var retArr = [];
12253            while(i<lenA || i < lenB){
12254                if((typeof a[i] === 'number' || a[i] instanceof Number) && (typeof b[i] === 'number' || b[i] instanceof Number)){
12255                    retArr[i] = a[i] + b[i];
12256                }else{
12257                    retArr[i] = b[i] == undefined ? a[i] : a[i] || b[i];
12258                }
12259                i += 1;
12260            }
12261            return retArr;
12262        }
12263        return 0;
12264    }
12265    var add = sum;
12266
12267    function sub(a,b) {
12268        var tOfA = typeof a;
12269        var tOfB = typeof b;
12270        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )) {
12271            if(tOfA === 'string') {
12272                a = parseInt(a);
12273            }
12274            if(tOfB === 'string') {
12275                b = parseInt(b);
12276            }
12277            return a - b;
12278        }
12279        if( a.constructor === Array && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )){
12280            a[0] = a[0] - b;
12281            return a;
12282        }
12283        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) &&  b.constructor === Array){
12284            b[0] = a - b[0];
12285            return b;
12286        }
12287        if(a.constructor === Array && b.constructor === Array){
12288            var i = 0, lenA = a.length, lenB = b.length;
12289            var retArr = [];
12290            while(i<lenA || i < lenB){
12291                if((typeof a[i] === 'number' || a[i] instanceof Number) && typeof (typeof b[i] === 'number' || b[i] instanceof Number)){
12292                    retArr[i] = a[i] - b[i];
12293                }else{
12294                    retArr[i] = b[i] == undefined ? a[i] : a[i] || b[i];
12295                }
12296                i += 1;
12297            }
12298            return retArr;
12299        }
12300        return 0;
12301    }
12302
12303    function mul(a,b) {
12304        var tOfA = typeof a;
12305        var tOfB = typeof b;
12306        var arr;
12307        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )) {
12308            return a * b;
12309        }
12310
12311        var i, len;
12312        if(a.constructor === Array && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )){
12313            len = a.length;
12314            arr = Array.apply(null,{length:len});
12315            for(i=0;i<len;i+=1){
12316                arr[i] = a[i] * b;
12317            }
12318            return arr;
12319        }
12320        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && b.constructor === Array){
12321            len = b.length;
12322            arr = Array.apply(null,{length:len});
12323            for(i=0;i<len;i+=1){
12324                arr[i] = a * b[i];
12325            }
12326            return arr;
12327        }
12328        return 0;
12329    }
12330
12331    function div(a,b) {
12332        var tOfA = typeof a;
12333        var tOfB = typeof b;
12334        var arr;
12335        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number )) {
12336            return a / b;
12337        }
12338        var i, len;
12339        if(a.constructor === Array && (tOfB === 'number' || tOfB === 'boolean' || tOfB === 'string' || b instanceof Number  )){
12340            len = a.length;
12341            arr = Array.apply(null,{length:len});
12342            for(i=0;i<len;i+=1){
12343                arr[i] = a[i] / b;
12344            }
12345            return arr;
12346        }
12347        if((tOfA === 'number' || tOfA === 'boolean' || tOfA === 'string' || a instanceof Number ) && b.constructor === Array){
12348            len = b.length;
12349            arr = Array.apply(null,{length:len});
12350            for(i=0;i<len;i+=1){
12351                arr[i] = a / b[i];
12352            }
12353            return arr;
12354        }
12355        return 0;
12356    }
12357    function mod(a,b) {
12358        if(typeof a === 'string') {
12359            a = parseInt(a);
12360        }
12361        if(typeof b === 'string') {
12362            b = parseInt(b);
12363        }
12364        return a % b;
12365    }
12366
12367    function clamp(num, min, max) {
12368        if(min > max){
12369            var mm = max;
12370            max = min;
12371            min = mm;
12372        }
12373        return Math.min(Math.max(num, min), max);
12374    }
12375
12376    function radiansToDegrees(val) {
12377        return val/degToRads;
12378    }
12379    var radians_to_degrees = radiansToDegrees;
12380
12381    function degreesToRadians(val) {
12382        return val*degToRads;
12383    }
12384    var degrees_to_radians = radiansToDegrees;
12385
12386    var helperLengthArray = [0,0,0,0,0,0];
12387
12388    function length(arr1,arr2){
12389        if(typeof arr1 === 'number' || arr1 instanceof Number){
12390            arr2 = arr2 || 0;
12391            return Math.abs(arr1 - arr2);
12392        }
12393        if(!arr2){
12394            arr2 = helperLengthArray;
12395        }
12396        var i,len = Math.min(arr1.length,arr2.length);
12397        var addedLength = 0;
12398        for(i=0;i<len;i+=1){
12399            addedLength += Math.pow(arr2[i]-arr1[i],2);
12400        }
12401        return Math.sqrt(addedLength);
12402    }
12403
12404    function normalize(vec){
12405        return div(vec, length(vec));
12406    }
12407
12408    function rgbToHsl(val){
12409        var r = val[0]; var g = val[1]; var b = val[2];
12410        var max = Math.max(r, g, b), min = Math.min(r, g, b);
12411        var h, s, l = (max + min) / 2;
12412
12413        if(max == min){
12414            h = s = 0; // achromatic
12415        }else{
12416            var d = max - min;
12417            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
12418            switch(max){
12419                case r: h = (g - b) / d + (g < b ? 6 : 0); break;
12420                case g: h = (b - r) / d + 2; break;
12421                case b: h = (r - g) / d + 4; break;
12422            }
12423            h /= 6;
12424        }
12425
12426        return [h, s, l,val[3]];
12427    }
12428    function hslToRgb(val){
12429        var h = val[0];
12430        var s = val[1];
12431        var l = val[2];
12432
12433        var r, g, b;
12434
12435        if(s == 0){
12436            r = g = b = l; // achromatic
12437        }else{
12438            function hue2rgb(p, q, t){
12439                if(t < 0) t += 1;
12440                if(t > 1) t -= 1;
12441                if(t < 1/6) return p + (q - p) * 6 * t;
12442                if(t < 1/2) return q;
12443                if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
12444                return p;
12445            }
12446
12447            var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
12448            var p = 2 * l - q;
12449            r = hue2rgb(p, q, h + 1/3);
12450            g = hue2rgb(p, q, h);
12451            b = hue2rgb(p, q, h - 1/3);
12452        }
12453
12454        return [r, g , b, val[3]];
12455    }
12456
12457    function linear(t, tMin, tMax, value1, value2){
12458        if(value1 === undefined || value2 === undefined){
12459            return linear(t,0,1,tMin,tMax);
12460        }
12461        if(t <= tMin) {
12462            return value1;
12463        }else if(t >= tMax){
12464            return value2;
12465        }
12466        var perc = tMax === tMin ? 0 : (t-tMin)/(tMax-tMin);
12467        if(!value1.length){
12468            return value1 + (value2-value1)*perc;
12469        }
12470        var i, len = value1.length;
12471        var arr = Array.apply( null, { length: len } );
12472        for(i=0;i<len;i+=1){
12473            arr[i] = value1[i] + (value2[i]-value1[i])*perc;
12474        }
12475        return arr;
12476    }
12477    function random(min,max){
12478        if(max === undefined){
12479            if(min === undefined){
12480                min = 0;
12481                max = 1;
12482            } else {
12483                max = min;
12484                min = undefined;
12485            }
12486        }
12487        if(max.length){
12488            var i, len = max.length;
12489            if(!min){
12490                min = Array.apply(null,{length:len});
12491            }
12492            var arr = Array.apply(null,{length:len});
12493            var rnd = BMMath.random();
12494            for(i=0;i<len;i+=1){
12495                arr[i] = min[i] + rnd*(max[i]-min[i])
12496            }
12497            return arr;
12498        }
12499        if(min === undefined){
12500            min = 0;
12501        }
12502        var rndm = BMMath.random();
12503        return min + rndm*(max-min);
12504    }
12505
12506    function createPath(points, inTangents, outTangents, closed) {
12507        inTangents = inTangents && inTangents.length ? inTangents : points;
12508        outTangents = outTangents && outTangents.length ? outTangents : points;
12509        var path = shape_pool.newShape();
12510        var len = points.length;
12511        path.setPathData(closed, len);
12512        for(i = 0; i < len; i += 1) {
12513            path.setTripleAt(points[i][0],points[i][1],outTangents[i][0] + points[i][0],outTangents[i][1] + points[i][1],inTangents[i][0] + points[i][0],inTangents[i][1] + points[i][1],i,true)
12514        }
12515        return path
12516    }
12517
12518    function initiateExpression(elem,data,property){
12519        var val = data.x;
12520        var needsVelocity = /velocity(?![\w\d])/.test(val);
12521        var _needsRandom = val.indexOf('random') !== -1;
12522        var elemType = elem.data.ty;
12523        var transform,content,effect;
12524        var thisComp = elem.comp;
12525        var thisProperty = property;
12526        elem.comp.frameDuration = 1/elem.comp.globalData.frameRate;
12527        var inPoint = elem.data.ip/elem.comp.globalData.frameRate;
12528        var outPoint = elem.data.op/elem.comp.globalData.frameRate;
12529        var width = elem.data.sw ? elem.data.sw : 0;
12530        var height = elem.data.sh ? elem.data.sh : 0;
12531        var loopIn, loop_in, loopOut, loop_out;
12532        var toWorld,fromWorld,fromComp,fromCompToSurface,anchorPoint,thisLayer,thisComp,mask,valueAtTime,velocityAtTime;
12533        var fn = new Function();
12534        //var fnStr = 'var fn = function(){'+val+';this.v = $bm_rt;}';
12535        //eval(fnStr);
12536
12537        var fn = eval('[function(){' + val+';if($bm_rt.__shapeObject){this.v=shape_pool.clone($bm_rt.v);}else{this.v=$bm_rt;}}' + ']')[0];
12538        var bindedFn = fn.bind(this);
12539        var numKeys = property.kf ? data.k.length : 0;
12540
12541        var wiggle = function wiggle(freq,amp){
12542            var i,j, len = this.pv.length ? this.pv.length : 1;
12543            var addedAmps = Array.apply(null,{len:len});
12544            for(j=0;j<len;j+=1){
12545                addedAmps[j] = 0;
12546            }
12547            freq = 5;
12548            var iterations = Math.floor(time*freq);
12549            i = 0;
12550            j = 0;
12551            while(i<iterations){
12552                //var rnd = BMMath.random();
12553                for(j=0;j<len;j+=1){
12554                    addedAmps[j] += -amp + amp*2*BMMath.random();
12555                    //addedAmps[j] += -amp + amp*2*rnd;
12556                }
12557                i += 1;
12558            }
12559            //var rnd2 = BMMath.random();
12560            var periods = time*freq;
12561            var perc = periods - Math.floor(periods);
12562            var arr = Array.apply({length:len});
12563            if(len>1){
12564                for(j=0;j<len;j+=1){
12565                    arr[j] = this.pv[j] + addedAmps[j] + (-amp + amp*2*BMMath.random())*perc;
12566                    //arr[j] = this.pv[j] + addedAmps[j] + (-amp + amp*2*rnd)*perc;
12567                    //arr[i] = this.pv[i] + addedAmp + amp1*perc + amp2*(1-perc);
12568                }
12569                return arr;
12570            } else {
12571                return this.pv + addedAmps[0] + (-amp + amp*2*BMMath.random())*perc;
12572            }
12573        }.bind(this);
12574
12575        if(thisProperty.loopIn) {
12576            loopIn = thisProperty.loopIn.bind(thisProperty);
12577            loop_in = loopIn;
12578        }
12579
12580        if(thisProperty.loopOut) {
12581            loopOut = thisProperty.loopOut.bind(thisProperty);
12582            loop_out = loopOut;
12583        }
12584
12585        var loopInDuration = function loopInDuration(type,duration){
12586            return loopIn(type,duration,true);
12587        }.bind(this);
12588
12589        var loopOutDuration = function loopOutDuration(type,duration){
12590            return loopOut(type,duration,true);
12591        }.bind(this);
12592
12593        if(this.getValueAtTime) {
12594            valueAtTime = this.getValueAtTime.bind(this);
12595        }
12596
12597        if(this.getVelocityAtTime) {
12598            velocityAtTime = this.getVelocityAtTime.bind(this);
12599        }
12600
12601        var comp = elem.comp.globalData.projectInterface.bind(elem.comp.globalData.projectInterface);
12602
12603        function lookAt(elem1,elem2){
12604            var fVec = [elem2[0]-elem1[0],elem2[1]-elem1[1],elem2[2]-elem1[2]];
12605            var pitch = Math.atan2(fVec[0],Math.sqrt(fVec[1]*fVec[1]+fVec[2]*fVec[2]))/degToRads;
12606            var yaw = -Math.atan2(fVec[1],fVec[2])/degToRads;
12607            return [yaw,pitch,0];
12608        };
12609
12610        function easeOut(t, val1, val2){
12611            return -(val2-val1) * t*(t-2) + val1;
12612        };
12613
12614        function nearestKey(time){
12615            var i, len = data.k.length,index,keyTime;
12616            if(!data.k.length || typeof(data.k[0]) === 'number'){
12617                index = 0;
12618                keyTime = 0;
12619            } else {
12620                index = -1;
12621                time *= elem.comp.globalData.frameRate;
12622                if (time < data.k[0].t) {
12623                    index = 1;
12624                    keyTime = data.k[0].t;
12625                } else {
12626                    for(i=0;i<len-1;i+=1){
12627                        if(time === data.k[i].t){
12628                            index = i + 1;
12629                            keyTime = data.k[i].t;
12630                            break;
12631                        }else if(time>data.k[i].t && time<data.k[i+1].t){
12632                            if(time-data.k[i].t > data.k[i+1].t - time){
12633                                index = i + 2;
12634                                keyTime = data.k[i+1].t;
12635                            } else {
12636                                index = i + 1;
12637                                keyTime = data.k[i].t;
12638                            }
12639                            break;
12640                        }
12641                    }
12642                    if(index === -1){
12643                        index = i + 1;
12644                        keyTime = data.k[i].t;
12645                    }
12646                }
12647                
12648            }
12649            var ob = {};
12650            ob.index = index;
12651            ob.time = keyTime/elem.comp.globalData.frameRate;
12652            return ob;
12653        };
12654
12655        function key(ind){
12656            var ob, i, len;
12657            if(!data.k.length || typeof(data.k[0]) === 'number'){
12658                throw new Error('The property has no keyframe at index ' + ind);
12659            }
12660            ind -= 1;
12661            ob = {
12662                time: data.k[ind].t/elem.comp.globalData.frameRate
12663            };
12664            var arr;
12665            if(ind === data.k.length - 1 && !data.k[ind].h){
12666                arr = data.k[ind-1].e;
12667            }else{
12668                arr = data.k[ind].s;
12669            }
12670            len = arr.length;
12671            for(i=0;i<len;i+=1){
12672                ob[i] = arr[i];
12673            }
12674            return ob;
12675        };
12676
12677        function framesToTime(frames,fps){
12678            if(!fps){
12679                fps = elem.comp.globalData.frameRate;
12680            }
12681            return frames/fps;
12682        };
12683
12684        function timeToFrames(t,fps){
12685            if(!t && t !== 0){
12686                t = time;
12687            }
12688            if(!fps){
12689                fps = elem.comp.globalData.frameRate;
12690            }
12691            return t*fps;
12692        };
12693
12694        function seedRandom(seed){
12695            BMMath.seedrandom(randSeed + seed);
12696        };
12697
12698        function sourceRectAtTime() {
12699            return elem.sourceRectAtTime();
12700        }
12701
12702        var time,velocity, value,textIndex,textTotal,selectorValue;
12703        var index = elem.data.ind;
12704        var hasParent = !!(elem.hierarchy && elem.hierarchy.length);
12705        var parent;
12706        var randSeed = Math.floor(Math.random()*1000000);
12707        function executeExpression(){
12708            if(_needsRandom){
12709                seedRandom(randSeed);
12710            }
12711            if(this.frameExpressionId === elem.globalData.frameId && this.type !== 'textSelector'){
12712                return;
12713            }
12714            if(this.lock){
12715                this.v = duplicatePropertyValue(this.pv,this.mult);
12716                return true;
12717            }
12718            if(this.type === 'textSelector'){
12719                textIndex = this.textIndex;
12720                textTotal = this.textTotal;
12721                selectorValue = this.selectorValue;
12722            }
12723            if(!thisLayer){
12724                thisLayer = elem.layerInterface;
12725                thisComp = elem.comp.compInterface;
12726                toWorld = thisLayer.toWorld.bind(thisLayer);
12727                fromWorld = thisLayer.fromWorld.bind(thisLayer);
12728                fromComp = thisLayer.fromComp.bind(thisLayer);
12729                mask = thisLayer.mask ? thisLayer.mask.bind(thisLayer):null;
12730                fromCompToSurface = fromComp;
12731            }
12732            if(!transform){
12733                transform = elem.layerInterface("ADBE Transform Group");
12734                anchorPoint = transform.anchorPoint;
12735            }
12736            
12737            if(elemType === 4 && !content){
12738                content = thisLayer("ADBE Root Vectors Group");
12739            }
12740            if(!effect){
12741                effect = thisLayer(4);
12742            }
12743            hasParent = !!(elem.hierarchy && elem.hierarchy.length);
12744            if(hasParent && !parent){
12745                parent = elem.hierarchy[0].layerInterface;
12746            }
12747            this.lock = true;
12748            if(this.getPreValue){
12749                this.getPreValue();
12750            }
12751            value = this.pv;
12752            time = this.comp.renderedFrame/this.comp.globalData.frameRate;
12753            if(needsVelocity){
12754                velocity = velocityAtTime(time);
12755            }
12756            bindedFn();
12757            this.frameExpressionId = elem.globalData.frameId;
12758            var i,len;
12759            if(this.mult){
12760                if(typeof this.v === 'number' || this.v instanceof Number || this.v instanceof String || typeof this.v === 'string'){
12761                    this.v *= this.mult;
12762                }else if(this.v.length === 1){
12763                    this.v = this.v[0] * this.mult;
12764                }else{
12765                    len = this.v.length;
12766                    if(value === this.v){
12767                        this.v = len === 2 ? [value[0],value[1]] : [value[0],value[1],value[2]];
12768                    }
12769                    for(i = 0; i < len; i += 1){
12770                        this.v[i] *= this.mult;
12771                    }
12772                }
12773            }
12774            if(this.v.length === 1){
12775                this.v = this.v[0];
12776            }
12777            if(typeof this.v === 'number' || this.v instanceof Number || this.v instanceof String || typeof this.v === 'string'){
12778                if(this.lastValue !== this.v){
12779                    this.lastValue = this.v;
12780                    this.mdf = true;
12781                }
12782            }else if( this.v._length){
12783                if(!shapesEqual(this.v,this.localShapeCollection.shapes[0])){
12784                    this.mdf = true;
12785                    this.localShapeCollection.releaseShapes();
12786                    this.localShapeCollection.addShape(shape_pool.clone(this.v));
12787                }
12788            }else{
12789                len = this.v.length;
12790                for(i = 0; i < len; i += 1){
12791                    if(this.v[i] !== this.lastValue[i]){
12792                        this.lastValue[i] = this.v[i];
12793                        this.mdf = true;
12794                    }
12795                }
12796            }
12797            this.lock = false;
12798        }
12799        return executeExpression;
12800    };
12801
12802    ob.initiateExpression = initiateExpression;
12803    return ob;
12804}());
12805var ShapeExpressionInterface = (function(){
12806    var ob = {
12807        createShapeInterface:createShapeInterface,
12808        createGroupInterface:createGroupInterface,
12809        createTrimInterface:createTrimInterface,
12810        createStrokeInterface:createStrokeInterface,
12811        createTransformInterface:createTransformInterface,
12812        createEllipseInterface:createEllipseInterface,
12813        createStarInterface:createStarInterface,
12814        createRectInterface:createRectInterface,
12815        createRoundedInterface:createRoundedInterface,
12816        createRepatearInterface:createRepatearInterface,
12817        createPathInterface:createPathInterface,
12818        createFillInterface:createFillInterface
12819    };
12820    function createShapeInterface(shapes,view,propertyGroup){
12821        return shapeInterfaceFactory(shapes,view,propertyGroup);
12822    }
12823    function createGroupInterface(shapes,view,propertyGroup){
12824        return groupInterfaceFactory(shapes,view,propertyGroup);
12825    }
12826    function createFillInterface(shape,view,propertyGroup){
12827        return fillInterfaceFactory(shape,view,propertyGroup);
12828    }
12829    function createStrokeInterface(shape,view,propertyGroup){
12830        return strokeInterfaceFactory(shape,view,propertyGroup);
12831    }
12832    function createTrimInterface(shape,view,propertyGroup){
12833        return trimInterfaceFactory(shape,view,propertyGroup);
12834    }
12835    function createTransformInterface(shape,view,propertyGroup){
12836        return transformInterfaceFactory(shape,view,propertyGroup);
12837    }
12838    function createEllipseInterface(shape,view,propertyGroup){
12839        return ellipseInterfaceFactory(shape,view,propertyGroup);
12840    }
12841    function createStarInterface(shape,view,propertyGroup){
12842        return starInterfaceFactory(shape,view,propertyGroup);
12843    }
12844    function createRectInterface(shape,view,propertyGroup){
12845        return rectInterfaceFactory(shape,view,propertyGroup);
12846    }
12847    function createRoundedInterface(shape,view,propertyGroup){
12848        return roundedInterfaceFactory(shape,view,propertyGroup);
12849    }
12850    function createRepatearInterface(shape,view,propertyGroup){
12851        return repeaterInterfaceFactory(shape,view,propertyGroup);
12852    }
12853    function createPathInterface(shape,view,propertyGroup){
12854        return pathInterfaceFactory(shape,view,propertyGroup);
12855    }
12856
12857    function iterateElements(shapes,view, propertyGroup){
12858        var arr = [];
12859        var i, len = shapes ? shapes.length : 0;
12860        for(i=0;i<len;i+=1){
12861            if(shapes[i].ty == 'gr'){
12862                arr.push(ShapeExpressionInterface.createGroupInterface(shapes[i],view[i],propertyGroup));
12863            }else if(shapes[i].ty == 'fl'){
12864                arr.push(ShapeExpressionInterface.createFillInterface(shapes[i],view[i],propertyGroup));
12865            }else if(shapes[i].ty == 'st'){
12866                arr.push(ShapeExpressionInterface.createStrokeInterface(shapes[i],view[i],propertyGroup));
12867            }else if(shapes[i].ty == 'tm'){
12868                arr.push(ShapeExpressionInterface.createTrimInterface(shapes[i],view[i],propertyGroup));
12869            }else if(shapes[i].ty == 'tr'){
12870                //arr.push(ShapeExpressionInterface.createTransformInterface(shapes[i],view[i],propertyGroup));
12871            }else if(shapes[i].ty == 'el'){
12872                arr.push(ShapeExpressionInterface.createEllipseInterface(shapes[i],view[i],propertyGroup));
12873            }else if(shapes[i].ty == 'sr'){
12874                arr.push(ShapeExpressionInterface.createStarInterface(shapes[i],view[i],propertyGroup));
12875            } else if(shapes[i].ty == 'sh'){
12876                arr.push(ShapeExpressionInterface.createPathInterface(shapes[i],view[i],propertyGroup));
12877            } else if(shapes[i].ty == 'rc'){
12878                arr.push(ShapeExpressionInterface.createRectInterface(shapes[i],view[i],propertyGroup));
12879            } else if(shapes[i].ty == 'rd'){
12880                arr.push(ShapeExpressionInterface.createRoundedInterface(shapes[i],view[i],propertyGroup));
12881            } else if(shapes[i].ty == 'rp'){
12882                arr.push(ShapeExpressionInterface.createRepatearInterface(shapes[i],view[i],propertyGroup));
12883            } else{
12884                //console.log(shapes[i].ty);
12885            }
12886        }
12887        return arr;
12888    }
12889
12890    var shapeInterfaceFactory = (function(){
12891        return function(shapes,view,propertyGroup){
12892            var interfaces;
12893            function _interfaceFunction(value){
12894                if(typeof value === 'number'){
12895                    return interfaces[value-1];
12896                } else {
12897                    var i = 0, len = interfaces.length;
12898                    while(i<len){
12899                        if(interfaces[i]._name === value){
12900                            return interfaces[i];
12901                        }
12902                        i+=1;
12903                    }
12904                }
12905            }
12906            _interfaceFunction.propertyGroup = propertyGroup;
12907            interfaces = iterateElements(shapes, view, _interfaceFunction);
12908            return _interfaceFunction;
12909        }
12910    }());
12911
12912    var contentsInterfaceFactory = (function(){
12913       return function(shape,view, propertyGroup){
12914           var interfaces;
12915           var interfaceFunction = function _interfaceFunction(value){
12916               var i = 0, len = interfaces.length;
12917                while(i<len){
12918                    if(interfaces[i]._name === value || interfaces[i].mn === value || interfaces[i].propertyIndex === value || interfaces[i].ix === value || interfaces[i].ind === value){
12919                       return interfaces[i];
12920                    }
12921                    i+=1;
12922                }
12923                if(typeof value === 'number'){
12924                   return interfaces[value-1];
12925                }
12926           };
12927           interfaceFunction.propertyGroup = function(val){
12928               if(val === 1){
12929                   return interfaceFunction;
12930               } else{
12931                   return propertyGroup(val-1);
12932               }
12933           };
12934           interfaces = iterateElements(shape.it, view.it, interfaceFunction.propertyGroup);
12935           interfaceFunction.numProperties = interfaces.length;
12936           interfaceFunction.propertyIndex = shape.cix;
12937
12938           return interfaceFunction;
12939       }
12940    }());
12941
12942    var groupInterfaceFactory = (function(){
12943        return function(shape,view, propertyGroup){
12944            var interfaceFunction = function _interfaceFunction(value){
12945                switch(value){
12946                    case 'ADBE Vectors Group':
12947                    case 'Contents':
12948                    case 2:
12949                        return interfaceFunction.content;
12950                    case 'ADBE Vector Transform Group':
12951                    case 3:
12952                    default:
12953                        return interfaceFunction.transform;
12954                }
12955            }
12956            interfaceFunction.propertyGroup = function(val){
12957                if(val === 1){
12958                    return interfaceFunction;
12959                } else{
12960                    return propertyGroup(val-1);
12961                }
12962            };
12963            var content = contentsInterfaceFactory(shape,view,interfaceFunction.propertyGroup);
12964            var transformInterface = ShapeExpressionInterface.createTransformInterface(shape.it[shape.it.length - 1],view.it[view.it.length - 1],interfaceFunction.propertyGroup);
12965            interfaceFunction.content = content;
12966            interfaceFunction.transform = transformInterface;
12967            Object.defineProperty(interfaceFunction, '_name', {
12968                get: function(){
12969                    return shape.nm;
12970                }
12971            });
12972            //interfaceFunction.content = interfaceFunction;
12973            interfaceFunction.numProperties = shape.np;
12974            interfaceFunction.propertyIndex = shape.ix;
12975            interfaceFunction.nm = shape.nm;
12976            interfaceFunction.mn = shape.mn;
12977            return interfaceFunction;
12978        }
12979    }());
12980
12981    var fillInterfaceFactory = (function(){
12982        return function(shape,view,propertyGroup){
12983
12984            function interfaceFunction(val){
12985                if(val === 'Color' || val === 'color'){
12986                    return interfaceFunction.color;
12987                } else if(val === 'Opacity' || val === 'opacity'){
12988                    return interfaceFunction.opacity;
12989                }
12990            }
12991            Object.defineProperty(interfaceFunction, 'color', {
12992                get: function(){
12993                    return ExpressionValue(view.c, 1 / view.c.mult, 'color');
12994                }
12995            });
12996            Object.defineProperty(interfaceFunction, 'opacity', {
12997                get: function(){
12998                    return ExpressionValue(view.o, 100);
12999                }
13000            });
13001            Object.defineProperty(interfaceFunction, '_name', { value: shape.nm });
13002            Object.defineProperty(interfaceFunction, 'mn', { value: shape.mn });
13003
13004            view.c.setGroupProperty(propertyGroup);
13005            view.o.setGroupProperty(propertyGroup);
13006            return interfaceFunction;
13007        }
13008    }());
13009
13010    var strokeInterfaceFactory = (function(){
13011        return function(shape,view,propertyGroup){
13012            function _propertyGroup(val){
13013                if(val === 1){
13014                    return ob;
13015                } else{
13016                    return propertyGroup(val-1);
13017                }
13018            };
13019            function _dashPropertyGroup(val){
13020                if(val === 1){
13021                    return dashOb;
13022                } else{
13023                    return _propertyGroup(val-1);
13024                }
13025            };
13026            function addPropertyToDashOb(i) {
13027                Object.defineProperty(dashOb, shape.d[i].nm, {
13028                    get: function(){
13029                        return ExpressionValue(view.d.dataProps[i].p)
13030                    }
13031                });
13032            }
13033            var i, len = shape.d ? shape.d.length : 0;
13034            var dashOb = {}
13035            for (i = 0; i < len; i += 1) {
13036                addPropertyToDashOb(i);
13037                view.d.dataProps[i].p.setGroupProperty(_dashPropertyGroup);
13038            }
13039
13040            function interfaceFunction(val){
13041                if(val === 'Color' || val === 'color'){
13042                    return interfaceFunction.color;
13043                } else if(val === 'Opacity' || val === 'opacity'){
13044                    return interfaceFunction.opacity;
13045                } else if(val === 'Stroke Width' || val === 'stroke width'){
13046                    return interfaceFunction.strokeWidth;
13047                }
13048            }
13049            Object.defineProperty(interfaceFunction, 'color', {
13050                get: function(){
13051                    return ExpressionValue(view.c, 1 / view.c.mult, 'color');
13052                }
13053            });
13054            Object.defineProperty(interfaceFunction, 'opacity', {
13055                get: function(){
13056                    return ExpressionValue(view.o, 100);
13057                }
13058            });
13059            Object.defineProperty(interfaceFunction, 'strokeWidth', {
13060                get: function(){
13061                    return ExpressionValue(view.w);
13062                }
13063            });
13064            Object.defineProperty(interfaceFunction, 'dash', {
13065                get: function(){
13066                    return dashOb;
13067                }
13068            });
13069            Object.defineProperty(interfaceFunction, '_name', { value: shape.nm });
13070            Object.defineProperty(interfaceFunction, 'mn', { value: shape.mn });
13071
13072            view.c.setGroupProperty(_propertyGroup);
13073            view.o.setGroupProperty(_propertyGroup);
13074            view.w.setGroupProperty(_propertyGroup);
13075            return interfaceFunction;
13076        }
13077    }());
13078
13079    var trimInterfaceFactory = (function(){
13080        return function(shape,view,propertyGroup){
13081            function _propertyGroup(val){
13082                if(val == 1){
13083                    return interfaceFunction;
13084                } else {
13085                    return propertyGroup(--val);
13086                }
13087            }
13088            interfaceFunction.propertyIndex = shape.ix;
13089
13090            view.s.setGroupProperty(_propertyGroup);
13091            view.e.setGroupProperty(_propertyGroup);
13092            view.o.setGroupProperty(_propertyGroup);
13093
13094            function interfaceFunction(val){
13095                if(val === shape.e.ix || val === 'End' || val === 'end'){
13096                    return interfaceFunction.end;
13097                }
13098                if(val === shape.s.ix){
13099                    return interfaceFunction.start;
13100                }
13101                if(val === shape.
13101o.ix){
13102                    return interfaceFunction.offset;
13103                }
13104            }
13105            interfaceFunction.propertyIndex = shape.ix;
13106            Object.defineProperty(interfaceFunction, 'start', {
13107                get: function(){
13108                    return ExpressionValue(view.s, 1 / view.s.mult);
13109                }
13110            });
13111            Object.defineProperty(interfaceFunction, 'end', {
13112                get: function(){
13113                    return ExpressionValue(view.e, 1 / view.e.mult);
13114                }
13115            });
13116            Object.defineProperty(interfaceFunction, 'offset', {
13117                get: function(){
13118                    return ExpressionValue(view.o);
13119                }
13120            });
13121            Object.defineProperty(interfaceFunction, '_name', {
13122                get: function(){
13123                    return shape.nm;
13124                }
13125            });
13126            interfaceFunction.mn = shape.mn;
13127            return interfaceFunction;
13128        }
13129    }());
13130
13131    var transformInterfaceFactory = (function(){
13132        return function(shape,view,propertyGroup){
13133            function _propertyGroup(val){
13134                if(val == 1){
13135                    return interfaceFunction;
13136                } else {
13137                    return propertyGroup(--val);
13138                }
13139            }
13140            view.transform.mProps.o.setGroupProperty(_propertyGroup);
13141            view.transform.mProps.p.setGroupProperty(_propertyGroup);
13142            view.transform.mProps.a.setGroupProperty(_propertyGroup);
13143            view.transform.mProps.s.setGroupProperty(_propertyGroup);
13144            view.transform.mProps.r.setGroupProperty(_propertyGroup);
13145            if(view.transform.mProps.sk){
13146                view.transform.mProps.sk.setGroupProperty(_propertyGroup);
13147                view.transform.mProps.sa.setGroupProperty(_propertyGroup);
13148            }
13149            view.transform.op.setGroupProperty(_propertyGroup);
13150
13151            function interfaceFunction(value){
13152                if(shape.a.ix === value){
13153                    return interfaceFunction.anchorPoint;
13154                }
13155                if(shape.o.ix === value){
13156                    return interfaceFunction.opacity;
13157                }
13158                if(shape.p.ix === value){
13159                    return interfaceFunction.position;
13160                }
13161                if(shape.r.ix === value){
13162                    return interfaceFunction.rotation;
13163                }
13164                if(shape.s.ix === value){
13165                    return interfaceFunction.scale;
13166                }
13167                if(shape.sk && shape.sk.ix === value){
13168                    return interfaceFunction.skew;
13169                }
13170                if(shape.sa && shape.sa.ix === value){
13171                    return interfaceFunction.skewAxis;
13172                }
13173                if(value === 'Opacity') {
13174                    return interfaceFunction.opacity;
13175                }
13176                if(value === 'Position') {
13177                    return interfaceFunction.position;
13178                }
13179                if(value === 'Anchor Point') {
13180                    return interfaceFunction.anchorPoint;
13181                }
13182                if(value === 'Scale') {
13183                    return interfaceFunction.scale;
13184                }
13185                if(value === 'Rotation' || value === 'ADBE Vector Rotation') {
13186                    return interfaceFunction.rotation;
13187                }
13188                if(value === 'Skew') {
13189                    return interfaceFunction.skew;
13190                }
13191                if(value === 'Skew Axis') {
13192                    return interfaceFunction.skewAxis;
13193                }
13194
13195            }
13196            Object.defineProperty(interfaceFunction, 'opacity', {
13197                get: function(){
13198                    return ExpressionValue(view.transform.mProps.o, 1/view.transform.mProps.o.mult);
13199                }
13200            });
13201            Object.defineProperty(interfaceFunction, 'position', {
13202                get: function(){
13203                    return ExpressionValue(view.transform.mProps.p);
13204                }
13205            });
13206            Object.defineProperty(interfaceFunction, 'anchorPoint', {
13207                get: function(){
13208                    return ExpressionValue(view.transform.mProps.a);
13209                }
13210            });
13211            var scaleArray = [];
13212            Object.defineProperty(interfaceFunction, 'scale', {
13213                get: function(){
13214                    return ExpressionValue(view.transform.mProps.s, 1 / view.transform.mProps.s.mult);
13215                }
13216            });
13217            Object.defineProperty(interfaceFunction, 'rotation', {
13218                get: function(){
13219                    return ExpressionValue(view.transform.mProps.r, 1 / view.transform.mProps.r.mult);
13220                }
13221            });
13222            Object.defineProperty(interfaceFunction, 'skew', {
13223                get: function(){
13224                    return ExpressionValue(view.transform.mProps.sk);
13225                }
13226            });
13227            Object.defineProperty(interfaceFunction, 'skewAxis', {
13228                get: function(){
13229                    return ExpressionValue(view.transform.mProps.sa);
13230                }
13231            });
13232            Object.defineProperty(interfaceFunction, '_name', {
13233                get: function(){
13234                    return shape.nm;
13235                }
13236            });
13237            interfaceFunction.ty = 'tr';
13238            interfaceFunction.mn = shape.mn;
13239            return interfaceFunction;
13240        }
13241    }());
13242
13243    var ellipseInterfaceFactory = (function(){
13244        return function(shape,view,propertyGroup){
13245            function _propertyGroup(val){
13246                if(val == 1){
13247                    return interfaceFunction;
13248                } else {
13249                    return propertyGroup(--val);
13250                }
13251            }
13252            interfaceFunction.propertyIndex = shape.ix;
13253            var prop = view.sh.ty === 'tm' ? view.sh.prop : view.sh;
13254            prop.s.setGroupProperty(_propertyGroup);
13255            prop.p.setGroupProperty(_propertyGroup);
13256            function interfaceFunction(value){
13257                if(shape.p.ix === value){
13258                    return interfaceFunction.position;
13259                }
13260                if(shape.s.ix === value){
13261                    return interfaceFunction.size;
13262                }
13263            }
13264            Object.defineProperty(interfaceFunction, 'size', {
13265                get: function(){
13266                    return ExpressionValue(prop.s);
13267                }
13268            });
13269            Object.defineProperty(interfaceFunction, 'position', {
13270                get: function(){
13271                    return ExpressionValue(prop.p);
13272                }
13273            });
13274            Object.defineProperty(interfaceFunction, '_name', {
13275                get: function(){
13276                    return shape.nm;
13277                }
13278            });
13279            interfaceFunction.mn = shape.mn;
13280            return interfaceFunction;
13281        }
13282    }());
13283
13284    var starInterfaceFactory = (function(){
13285        return function(shape,view,propertyGroup){
13286            function _propertyGroup(val){
13287                if(val == 1){
13288                    return interfaceFunction;
13289                } else {
13290                    return propertyGroup(--val);
13291                }
13292            }
13293            var prop = view.sh.ty === 'tm' ? view.sh.prop : view.sh;
13294            interfaceFunction.propertyIndex = shape.ix;
13295            prop.or.setGroupProperty(_propertyGroup);
13296            prop.os.setGroupProperty(_propertyGroup);
13297            prop.pt.setGroupProperty(_propertyGroup);
13298            prop.p.setGroupProperty(_propertyGroup);
13299            prop.r.setGroupProperty(_propertyGroup);
13300            if(shape.ir){
13301                prop.ir.setGroupProperty(_propertyGroup);
13302                prop.is.setGroupProperty(_propertyGroup);
13303            }
13304
13305            function interfaceFunction(value){
13306                if(shape.p.ix === value){
13307                    return interfaceFunction.position;
13308                }
13309                if(shape.r.ix === value){
13310                    return interfaceFunction.rotation;
13311                }
13312                if(shape.pt.ix === value){
13313                    return interfaceFunction.points;
13314                }
13315                if(shape.or.ix === value || 'ADBE Vector Star Outer Radius' === value){
13316                    return interfaceFunction.outerRadius;
13317                }
13318                if(shape.os.ix === value){
13319                    return interfaceFunction.outerRoundness;
13320                }
13321                if(shape.ir && (shape.ir.ix === value || 'ADBE Vector Star Inner Radius' === value)){
13322                    return interfaceFunction.innerRadius;
13323                }
13324                if(shape.is && shape.is.ix === value){
13325                    return interfaceFunction.innerRoundness;
13326                }
13327
13328            }
13329            Object.defineProperty(interfaceFunction, 'position', {
13330                get: function(){
13331                    return ExpressionValue(prop.p);
13332                }
13333            });
13334            Object.defineProperty(interfaceFunction, 'rotation', {
13335                get: function(){
13336                    return ExpressionValue(prop.r, 1 / prop.r.mult);
13337                }
13338            });
13339            Object.defineProperty(interfaceFunction, 'points', {
13340                get: function(){
13341                    return ExpressionValue(prop.pt);
13342                }
13343            });
13344            Object.defineProperty(interfaceFunction, 'outerRadius', {
13345                get: function(){
13346                    return ExpressionValue(prop.or);
13347                }
13348            });
13349            Object.defineProperty(interfaceFunction, 'outerRoundness', {
13350                get: function(){
13351                    return ExpressionValue(prop.os);
13352                }
13353            });
13354            Object.defineProperty(interfaceFunction, 'innerRadius', {
13355                get: function(){
13356                    if(!prop.ir){
13357                        return 0;
13358                    }
13359                    return ExpressionValue(prop.ir);
13360                }
13361            });
13362            Object.defineProperty(interfaceFunction, 'innerRoundness', {
13363                get: function(){
13364                    if(!prop.is){
13365                        return 0;
13366                    }
13367                    return ExpressionValue(prop.is, 1 / prop.is.mult);
13368                }
13369            });
13370            Object.defineProperty(interfaceFunction, '_name', {
13371                get: function(){
13372                    return shape.nm;
13373                }
13374            });
13375            interfaceFunction.mn = shape.mn;
13376            return interfaceFunction;
13377        }
13378    }());
13379
13380    var rectInterfaceFactory = (function(){
13381        return function(shape,view,propertyGroup){
13382            function _propertyGroup(val){
13383                if(val == 1){
13384                    return interfaceFunction;
13385                } else {
13386                    return propertyGroup(--val);
13387                }
13388            }
13389            var prop = view.sh.ty === 'tm' ? view.sh.prop : view.sh;
13390            interfaceFunction.propertyIndex = shape.ix;
13391            prop.p.setGroupProperty(_propertyGroup);
13392            prop.s.setGroupProperty(_propertyGroup);
13393            prop.r.setGroupProperty(_propertyGroup);
13394
13395            function interfaceFunction(value){
13396                if(shape.p.ix === value){
13397                    return interfaceFunction.position;
13398                }
13399                if(shape.r.ix === value){
13400                    return interfaceFunction.roundness;
13401                }
13402                if(shape.s.ix === value || value === 'Size'){
13403                    return interfaceFunction.size;
13404                }
13405
13406            }
13407            Object.defineProperty(interfaceFunction, 'position', {
13408                get: function(){
13409                    return ExpressionValue(prop.p);
13410                }
13411            });
13412            Object.defineProperty(interfaceFunction, 'roundness', {
13413                get: function(){
13414                    return ExpressionValue(prop.r);
13415                }
13416            });
13417            Object.defineProperty(interfaceFunction, 'size', {
13418                get: function(){
13419                    return ExpressionValue(prop.s);
13420                }
13421            });
13422
13423            Object.defineProperty(interfaceFunction, '_name', {
13424                get: function(){
13425                    return shape.nm;
13426                }
13427            });
13428            interfaceFunction.mn = shape.mn;
13429            return interfaceFunction;
13430        }
13431    }());
13432
13433    var roundedInterfaceFactory = (function(){
13434        return function(shape,view,propertyGroup){
13435            function _propertyGroup(val){
13436                if(val == 1){
13437                    return interfaceFunction;
13438                } else {
13439                    return propertyGroup(--val);
13440                }
13441            }
13442            var prop = view;
13443            interfaceFunction.propertyIndex = shape.ix;
13444            prop.rd.setGroupProperty(_propertyGroup);
13445
13446            function interfaceFunction(value){
13447                if(shape.r.ix === value || 'Round Corners 1' === value){
13448                    return interfaceFunction.radius;
13449                }
13450
13451            }
13452            Object.defineProperty(interfaceFunction, 'radius', {
13453                get: function(){
13454                    return ExpressionValue(prop.rd);
13455                }
13456            });
13457
13458            Object.defineProperty(interfaceFunction, '_name', {
13459                get: function(){
13460                    return shape.nm;
13461                }
13462            });
13463            interfaceFunction.mn = shape.mn;
13464            return interfaceFunction;
13465        }
13466    }());
13467
13468    var repeaterInterfaceFactory = (function(){
13469        return function(shape,view,propertyGroup){
13470            function _propertyGroup(val){
13471                if(val == 1){
13472                    return interfaceFunction;
13473                } else {
13474                    return propertyGroup(--val);
13475                }
13476            }
13477            var prop = view;
13478            interfaceFunction.propertyIndex = shape.ix;
13479            prop.c.setGroupProperty(_propertyGroup);
13480            prop.o.setGroupProperty(_propertyGroup);
13481
13482            function interfaceFunction(value){
13483                if(shape.c.ix === value || 'Copies' === value){
13484                    return interfaceFunction.copies;
13485                } else if(shape.o.ix === value || 'Offset' === value){
13486                    return interfaceFunction.offset;
13487                }
13488
13489            }
13490            Object.defineProperty(interfaceFunction, 'copies', {
13491                get: function(){
13492                    return ExpressionValue(prop.c);
13493                }
13494            });
13495
13496            Object.defineProperty(interfaceFunction, 'offset', {
13497                get: function(){
13498                    return ExpressionValue(prop.o);
13499                }
13500            });
13501
13502            Object.defineProperty(interfaceFunction, '_name', {
13503                get: function(){
13504                    return shape.nm;
13505                }
13506            });
13507            interfaceFunction.mn = shape.mn;
13508            return interfaceFunction;
13509        }
13510    }());
13511
13512    var pathInterfaceFactory = (function(){
13513        return function(shape,view,propertyGroup){
13514            var prop = view.sh;
13515            function _propertyGroup(val){
13516                if(val == 1){
13517                    return interfaceFunction;
13518                } else {
13519                    return propertyGroup(--val);
13520                }
13521            }
13522            prop.setGroupProperty(_propertyGroup);
13523
13524            function interfaceFunction(val){
13525                if(val === 'Shape' || val === 'shape' || val === 'Path' || val === 'path' || val === 'ADBE Vector Shape' || val === 2){
13526                    return interfaceFunction.path;
13527                }
13528            }
13529
13530            Object.defineProperty(interfaceFunction, 'path', {
13531                get: function(){
13532                    if(prop.k){
13533                        prop.getValue();
13534                    }
13535                    return prop;
13536                    //return shape_pool.clone(prop.v);
13537                }
13538            });
13539            Object.defineProperty(interfaceFunction, 'shape', {
13540                get: function(){
13541                    if(prop.k){
13542                        prop.getValue();
13543                    }
13544                    return prop;
13545                    //return shape_pool.clone(prop.v);
13546                }
13547            });
13548            Object.defineProperty(interfaceFunction, '_name', { value: shape.nm });
13549            Object.defineProperty(interfaceFunction, 'ix', { value: shape.ix });
13550            Object.defineProperty(interfaceFunction, 'mn', { value: shape.mn });
13551            return interfaceFunction;
13552        }
13553    }());
13554
13555
13556    return ob;
13557}())
13558
13559var TextExpressionInterface = (function(){
13560	return function(elem){
13561        var _prevValue, _sourceText;
13562        function _thisLayerFunction(){
13563        }
13564        Object.defineProperty(_thisLayerFunction, "sourceText", {
13565            get: function(){
13566                var stringValue = elem.textProperty.currentData.t;
13567                if(elem.textProperty.currentData.t !== _prevValue) {
13568                    elem.textProperty.currentData.t = _prevValue;
13569                    _sourceText = new String(stringValue);
13570                    //If stringValue is an empty string, eval returns undefined, so it has to be returned as a String primitive
13571                    _sourceText.value = stringValue ? stringValue : new String(stringValue);
13572                }
13573                return _sourceText;
13574            }
13575        });
13576        return _thisLayerFunction;
13577    }
13578}())
13579var LayerExpressionInterface = (function (){
13580    function toWorld(arr, time){
13581        var toWorldMat = new Matrix();
13582        toWorldMat.reset();
13583        var transformMat;
13584        if(time) {
13585            //Todo implement value at time on transform properties
13586            //transformMat = this._elem.finalTransform.mProp.getValueAtTime(time);
13587            transformMat = this._elem.finalTransform.mProp;
13588        } else {
13589            transformMat = this._elem.finalTransform.mProp;
13590        }
13591        transformMat.applyToMatrix(toWorldMat);
13592        if(this._elem.hierarchy && this._elem.hierarchy.length){
13593            var i, len = this._elem.hierarchy.length;
13594            for(i=0;i<len;i+=1){
13595                this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat);
13596            }
13597            return toWorldMat.applyToPointArray(arr[0],arr[1],arr[2]||0);
13598        }
13599        return toWorldMat.applyToPointArray(arr[0],arr[1],arr[2]||0);
13600    }
13601    function fromWorld(arr, time){
13602        var toWorldMat = new Matrix();
13603        toWorldMat.reset();
13604        var transformMat;
13605        if(time) {
13606            //Todo implement value at time on transform properties
13607            //transformMat = this._elem.finalTransform.mProp.getValueAtTime(time);
13608            transformMat = this._elem.finalTransform.mProp;
13609        } else {
13610            transformMat = this._elem.finalTransform.mProp;
13611        }
13612        transformMat.applyToMatrix(toWorldMat);
13613        if(this._elem.hierarchy && this._elem.hierarchy.length){
13614            var i, len = this._elem.hierarchy.length;
13615            for(i=0;i<len;i+=1){
13616                this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat);
13617            }
13618            return toWorldMat.inversePoint(arr);
13619        }
13620        return toWorldMat.inversePoint(arr);
13621    }
13622    function fromComp(arr){
13623        var toWorldMat = new Matrix();
13624        toWorldMat.reset();
13625        this._elem.finalTransform.mProp.applyToMatrix(toWorldMat);
13626        if(this._elem.hierarchy && this._elem.hierarchy.length){
13627            var i, len = this._elem.hierarchy.length;
13628            for(i=0;i<len;i+=1){
13629                this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat);
13630            }
13631            return toWorldMat.inversePoint(arr);
13632        }
13633        return toWorldMat.inversePoint(arr);
13634    }
13635
13636
13637    return function(elem){
13638
13639        var transformInterface = TransformExpressionInterface(elem.transform);
13640
13641        function _registerMaskInterface(maskManager){
13642            _thisLayerFunction.mask = new MaskManagerInterface(maskManager, elem);
13643        }
13644        function _registerEffectsInterface(effects){
13645            _thisLayerFunction.effect = effects;
13646        }
13647
13648        function _thisLayerFunction(name){
13649            switch(name){
13650                case "ADBE Root Vectors Group":
13651                case "Contents":
13652                case 2:
13653                    return _thisLayerFunction.shapeInterface;
13654                case 1:
13655                case 6:
13656                case "Transform":
13657                case "transform":
13658                case "ADBE Transform Group":
13659                    return transformInterface;
13660                case 4:
13661                case "ADBE Effect Parade":
13662                    return _thisLayerFunction.effect;
13663            }
13664        }
13665        _thisLayerFunction.toWorld = toWorld;
13666        _thisLayerFunction.fromWorld = fromWorld;
13667        _thisLayerFunction.toComp = toWorld;
13668        _thisLayerFunction.fromComp = fromComp;
13669        _thisLayerFunction.sourceRectAtTime = elem.sourceRectAtTime.bind(elem);
13670        _thisLayerFunction._elem = elem;
13671        Object.defineProperty(_thisLayerFunction, 'hasParent', {
13672            get: function(){
13673                return !!elem.hierarchy;
13674            }
13675        });
13676        Object.defineProperty(_thisLayerFunction, 'parent', {
13677            get: function(){
13678                return elem.hierarchy[0].layerInterface;
13679            }
13680        });
13681        Object.defineProperty(_thisLayerFunction, "rotation", {
13682            get: function(){
13683                return transformInterface.rotation;
13684            }
13685        });
13686        Object.defineProperty(_thisLayerFunction, "scale", {
13687            get: function () {
13688                return transformInterface.scale;
13689            }
13690        });
13691
13692        Object.defineProperty(_thisLayerFunction, "position", {
13693            get: function () {
13694                return transformInterface.position;
13695            }
13696        });
13697
13698        Object.defineProperty(_thisLayerFunction, "anchorPoint", {
13699            get: function () {
13700                return transformInterface.anchorPoint;
13701            }
13702        });
13703
13704        Object.defineProperty(_thisLayerFunction, "transform", {
13705            get: function () {
13706                return transformInterface;
13707            }
13708        });
13709
13710        Object.defineProperty(_thisLayerFunction, "width", {
13711            get: function () {
13712                if(elem.data.ty === 0) {
13713                    return elem.data.w
13714                }
13715                return 100;
13716            }
13717        });
13718
13719        Object.defineProperty(_thisLayerFunction, "height", {
13720            get: function () {
13721                if(elem.data.ty === 0) {
13722                    return elem.data.h
13723                }
13724                return 100;
13725            }
13726        });
13727
13728        Object.defineProperty(_thisLayerFunction, "source", {
13729            get: function () {
13730                return elem.data.refId;
13731            }
13732        });
13733
13734        Object.defineProperty(_thisLayerFunction, "index", {
13735            get: function () {
13736                return elem.data.ind;
13737            }
13738        });
13739
13740        Object.defineProperty(_thisLayerFunction, "_name", { value:elem.data.nm });
13741        Object.defineProperty(_thisLayerFunction, "content", {
13742            get: function(){
13743                return _thisLayerFunction.shapeInterface;
13744            }
13745        });
13746
13747        Object.defineProperty(_thisLayerFunction, "active", {
13748            get: function(){
13749                return elem.isVisible;
13750            }
13751        });
13752
13753        Object.defineProperty(_thisLayerFunction, "text", {
13754            get: function(){
13755                return _thisLayerFunction.textInterface;
13756            }
13757        });
13758
13759        _thisLayerFunction.registerMaskInterface = _registerMaskInterface;
13760        _thisLayerFunction.registerEffectsInterface = _registerEffectsInterface;
13761        return _thisLayerFunction;
13762    }
13763}());
13764
13765var CompExpressionInterface = (function (){
13766    return function(comp){
13767        function _thisLayerFunction(name){
13768            var i=0, len = comp.layers.length;
13769            while(i<len){
13770                if(comp.layers[i].nm === name || comp.layers[i].ind === name){
13771                    return comp.elements[i].layerInterface;
13772                }
13773                i += 1;
13774            }
13775            return {active:false}
13776        }
13777        Object.defineProperty(_thisLayerFunction, "_name", { value:comp.data.nm });
13778        _thisLayerFunction.layer = _thisLayerFunction;
13779        _thisLayerFunction.pixelAspect = 1;
13780        _thisLayerFunction.height = comp.globalData.compSize.h;
13781        _thisLayerFunction.width = comp.globalData.compSize.w;
13782        _thisLayerFunction.pixelAspect = 1;
13783        _thisLayerFunction.frameDuration = 1/comp.globalData.frameRate;
13784        return _thisLayerFunction;
13785    }
13786}());
13787var TransformExpressionInterface = (function (){
13788    return function(transform){
13789        function _thisFunction(name){
13790            switch(name){
13791                case "scale":
13792                case "Scale":
13793                case "ADBE Scale":
13794                case 6:
13795                    return _thisFunction.scale;
13796                case "rotation":
13797                case "Rotation":
13798                case "ADBE Rotation":
13799                case "ADBE Rotate Z":
13800                case 10:
13801                    return _thisFunction.rotation;
13802                case "position":
13803                case "Position":
13804                case "ADBE Position":
13805                case 2:
13806                    return transform.position;
13807                case "anchorPoint":
13808                case "AnchorPoint":
13809                case "Anchor Point":
13810                case "ADBE AnchorPoint":
13811                case 1:
13812                    return _thisFunction.anchorPoint;
13813                case "opacity":
13814                case "Opacity":
13815                case 11:
13816                    return _thisFunction.opacity;
13817            }
13818        }
13819
13820        Object.defineProperty(_thisFunction, "rotation", {
13821            get: function(){
13822                return transform.rotation;
13823            }
13824        });
13825        Object.defineProperty(_thisFunction, "scale", {
13826            get: function () {
13827                return transform.scale;
13828            }
13829        });
13830
13831        Object.defineProperty(_thisFunction, "position", {
13832            get: function () {
13833                return transform.position;
13834            }
13835        });
13836
13837        Object.defineProperty(_thisFunction, "xPosition", {
13838            get: function () {
13839                return transform.xPosition;
13840            }
13841        });
13842
13843        Object.defineProperty(_thisFunction, "yPosition", {
13844            get: function () {
13845                return transform.yPosition;
13846            }
13847        });
13848
13849        Object.defineProperty(_thisFunction, "anchorPoint", {
13850            get: function () {
13851                return transform.anchorPoint;
13852            }
13853        });
13854
13855        Object.defineProperty(_thisFunction, "opacity", {
13856            get: function () {
13857                return transform.opacity;
13858            }
13859        });
13860
13861        Object.defineProperty(_thisFunction, "skew", {
13862            get: function () {
13863                return transform.skew;
13864            }
13865        });
13866
13867        Object.defineProperty(_thisFunction, "skewAxis", {
13868            get: function () {
13869                return transform.skewAxis;
13870            }
13871        });
13872
13873        return _thisFunction;
13874    }
13875}());
13876var ProjectInterface = (function (){
13877
13878    function registerComposition(comp){
13879        this.compositions.push(comp);
13880    }
13881
13882    return function(){
13883        function _thisProjectFunction(name){
13884            var i = 0, len = this.compositions.length;
13885            while(i<len){
13886                if(this.compositions[i].data && this.compositions[i].data.nm === name){
13887                    if(this.compositions[i].prepareFrame) {
13888                        this.compositions[i].prepareFrame(this.currentFrame);
13889                    }
13890                    return this.compositions[i].compInterface;
13891                }
13892                i+=1;
13893            }
13894        }
13895
13896        _thisProjectFunction.compositions = [];
13897        _thisProjectFunction.currentFrame = 0;
13898
13899        _thisProjectFunction.registerComposition = registerComposition;
13900
13901
13902
13903        return _thisProjectFunction;
13904    }
13905}());
13906var EffectsExpressionInterface = (function (){
13907    var ob = {
13908        createEffectsInterface: createEffectsInterface
13909    };
13910
13911    function createEffectsInterface(elem, propertyGroup){
13912        if(elem.effects){
13913
13914            var effectElements = [];
13915            var effectsData = elem.data.ef;
13916            var i, len = elem.effects.effectElements.length;
13917            for(i=0;i<len;i+=1){
13918                effectElements.push(createGroupInterface(effectsData[i],elem.effects.effectElements[i],propertyGroup,elem));
13919            }
13920
13921            return function(name){
13922                var effects = elem.data.ef, i = 0, len = effects.length;
13923                while(i<len) {
13924                    if(name === effects[i].nm || name === effects[i].mn || name === effects[i].ix){
13925                        return effectElements[i];
13926                    }
13927                    i += 1;
13928                }
13929            }
13930        }
13931    }
13932
13933    function createGroupInterface(data,elements, propertyGroup, elem){
13934        var effectElements = [];
13935        var i, len = data.ef.length;
13936        for(i=0;i<len;i+=1){
13937            if(data.ef[i].ty === 5){
13938                effectElements.push(createGroupInterface(data.ef[i],elements.effectElements[i],elements.effectElements[i].propertyGroup, elem));
13939            } else {
13940                effectElements.push(createValueInterface(elements.effectElements[i],data.ef[i].ty, elem, _propertyGroup));
13941            }
13942        }
13943
13944        function _propertyGroup(val) {
13945            if(val === 1){
13946               return groupInterface;
13947            } else{
13948               return propertyGroup(val-1);
13949            }
13950        }
13951
13952        var groupInterface = function(name){
13953            var effects = data.ef, i = 0, len = effects.length;
13954            while(i<len) {
13955                if(name === effects[i].nm || name === effects[i].mn || name === effects[i].ix){
13956                    if(effects[i].ty === 5){
13957                        return effectElements[i];
13958                    } else {
13959                        return effectElements[i]();
13960                    }
13961                }
13962                i += 1;
13963            }
13964            return effectElements[0]();
13965        }
13966
13967        groupInterface.propertyGroup = _propertyGroup;
13968
13969        if(data.mn === 'ADBE Color Control'){
13970            Object.defineProperty(groupInterface, 'color', {
13971                get: function(){
13972                    return effectElements[0]();
13973                }
13974            });
13975        }
13976        Object.defineProperty(groupInterface, 'numProperties', {
13977            get: function(){
13978                return data.np;
13979            }
13980        });
13981        groupInterface.active = data.en !== 0;
13982        return groupInterface
13983    }
13984
13985    function createValueInterface(element, type, elem, propertyGroup){
13986        function interfaceFunction(){
13987            if(type === 10){
13988                return elem.comp.compInterface(element.p.v);
13989            }
13990            return ExpressionValue(element.p);
13991        }
13992
13993        if(element.p.setGroupProperty) {
13994            element.p.setGroupProperty(propertyGroup);
13995        }
13996
13997        return interfaceFunction;
13998    }
13999
14000    return ob;
14001
14002}());
14003var MaskManagerInterface = (function(){
14004
14005	function MaskInterface(mask, data){
14006		this._mask = mask;
14007		this._data = data;
14008	}
14009	Object.defineProperty(MaskInterface.prototype, 'maskPath', {
14010        get: function(){
14011                if(this._mask.prop.k){
14012                    this._mask.prop.getValue();
14013                }
14014                return this._mask.prop;
14015            }
14016        });
14017
14018	var MaskManager = function(maskManager, elem){
14019		var _maskManager = maskManager;
14020		var _elem = elem;
14021		var _masksInterfaces = Array.apply(null,{length: maskManager.viewData.length});
14022		var i, len = maskManager.viewData.length;
14023		for(i = 0; i < len; i += 1) {
14024			_masksInterfaces[i] = new MaskInterface(maskManager.viewData[i], maskManager.masksProperties[i]);
14025		}
14026
14027		var maskFunction = function(name){
14028			i = 0;
14029		    while(i<len){
14030		        if(maskManager.masksProperties[i].nm === name){
14031		            return _masksInterfaces[i];
14032		        }
14033		        i += 1;
14034		    }
14035		}
14036		return maskFunction
14037	}
14038	return MaskManager
14039}())
14040
14041
14042var ExpressionValue = (function() {
14043	return function(elementProp, mult, type) {
14044        var expressionValue, arrayValue;
14045
14046		if (elementProp.k) {
14047            elementProp.getValue();
14048        }
14049        var i, len, arrValue;
14050        if (type) {
14051        	if(type === 'color') {
14052        		len = 4;
14053		        expressionValue = Array.apply(null, {length: len});
14054		        arrValue = Array.apply(null, {length: len});
14055		        for (i = 0; i < len; i += 1) {
14056		            expressionValue[i] = arrValue[i] = (mult && i < 3) ? elementProp.v[i] * mult : 1;
14057		        }
14058	        	expressionValue.value = arrValue;
14059        	}
14060        } else if (typeof elementProp.v === 'number' || elementProp.v instanceof Number){
14061            expressionValue = mult ? new Number(elementProp.v * mult) : new Number(elementProp.v);
14062            expressionValue.value = mult ? elementProp.v * mult : elementProp.v;
14063        } else {
14064        	len = elementProp.v.length;
14065	        expressionValue = Array.apply(null, {length: len});
14066	        arrValue = Array.apply(null, {length: len});
14067	        for (i = 0; i < len; i += 1) {
14068	            expressionValue[i] = arrValue[i] = mult ? elementProp.v[i] * mult : elementProp.v[i];
14069	        }
14070	        expressionValue.value = arrValue;
14071        }
14072        
14073        expressionValue.numKeys = elementProp.keyframes ? elementProp.keyframes.length : 0;
14074        expressionValue.key = function(pos) {
14075            if (!expressionValue.numKeys) {
14076                return 0;
14077            } else {
14078                return elementProp.keyframes[pos-1].t;
14079            }
14080        };
14081        expressionValue.valueAtTime = elementProp.getValueAtTime;
14082        expressionValue.propertyGroup = elementProp.propertyGroup;
14083        return expressionValue;
14084	}
14085}())
14086function SliderEffect(data,elem, dynamicProperties){
14087    this.p = PropertyFactory.getProp(elem,data.v,0,0,dynamicProperties);
14088}
14089function AngleEffect(data,elem, dynamicProperties){
14090    this.p = PropertyFactory.getProp(elem,data.v,0,0,dynamicProperties);
14091}
14092function ColorEffect(data,elem, dynamicProperties){
14093    this.p = PropertyFactory.getProp(elem,data.v,1,0,dynamicProperties);
14094}
14095function PointEffect(data,elem, dynamicProperties){
14096    this.p = PropertyFactory.getProp(elem,data.v,1,0,dynamicProperties);
14097}
14098function LayerIndexEffect(data,elem, dynamicProperties){
14099    this.p = PropertyFactory.getProp(elem,data.v,0,0,dynamicProperties);
14100}
14101function MaskIndexEffect(data,elem, dynamicProperties){
14102    this.p = PropertyFactory.getProp(elem,data.v,0,0,dynamicProperties);
14103}
14104function CheckboxEffect(data,elem, dynamicProperties){
14105    this.p = PropertyFactory.getProp(elem,data.v,0,0,dynamicProperties);
14106}
14107function NoValueEffect(){
14108    this.p = {};
14109}
14110function EffectsManager(data,element,dynamicProperties){
14111    var effects = data.ef;
14112    this.effectElements = [];
14113    var i,len = effects.length;
14114    var effectItem;
14115    for(i=0;i<len;i++) {
14116        effectItem = new GroupEffect(effects[i],element,dynamicProperties);
14117        this.effectElements.push(effectItem);
14118    }
14119}
14120
14121function GroupEffect(data,element,dynamicProperties){
14122    this.dynamicProperties = [];
14123    this.init(data,element,this.dynamicProperties);
14124    if(this.dynamicProperties.length){
14125        dynamicProperties.push(this);
14126    }
14127}
14128
14129GroupEffect.prototype.getValue = function(){
14130    this.mdf = false;
14131    var i, len = this.dynamicProperties.length;
14132    for(i=0;i<len;i+=1){
14133        this.dynamicProperties[i].getValue();
14134        this.mdf = this.dynamicProperties[i].mdf ? true : this.mdf;
14135    }
14136};
14137
14138GroupEffect.prototype.init = function(data,element,dynamicProperties){
14139    this.data = data;
14140    this.mdf = false;
14141    this.effectElements = [];
14142    var i, len = this.data.ef.length;
14143    var eff, effects = this.data.ef;
14144    for(i=0;i<len;i+=1){
14145        switch(effects[i].ty){
14146            case 0:
14147                eff = new SliderEffect(effects[i],element,dynamicProperties);
14148                this.effectElements.push(eff);
14149                break;
14150            case 1:
14151                eff = new AngleEffect(effects[i],element,dynamicProperties);
14152                this.effectElements.push(eff);
14153                break;
14154            case 2:
14155                eff = new ColorEffect(effects[i],element,dynamicProperties);
14156                this.effectElements.push(eff);
14157                break;
14158            case 3:
14159                eff = new PointEffect(effects[i],element,dynamicProperties);
14160                this.effectElements.push(eff);
14161                break;
14162            case 4:
14163            case 7:
14164                eff = new CheckboxEffect(effects[i],element,dynamicProperties);
14165                this.effectElements.push(eff);
14166                break;
14167            case 10:
14168                eff = new LayerIndexEffect(effects[i],element,dynamicProperties);
14169                this.effectElements.push(eff);
14170                break;
14171            case 11:
14172                eff = new MaskIndexEffect(effects[i],element,dynamicProperties);
14173                this.effectElements.push(eff);
14174                break;
14175            case 5:
14176                eff = new EffectsManager(effects[i],element,dynamicProperties);
14177                this.effectElements.push(eff);
14178                break;
14179            case 6:
14180                eff = new NoValueEffect(effects[i],element,dynamicProperties);
14181                this.effectElements.push(eff);
14182                break;
14183        }
14184    }
14185};
14186    var bodymovinjs = {};
14187
14188    function setLocationHref (href) {
14189        locationHref = href;
14190    }
14191    function play(animation){
14192        animationManager.play(animation);
14193    }
14194
14195    function pause(animation) {
14196        animationManager.pause(animation);
14197    }
14198
14199    function togglePause(animation) {
14200        animationManager.togglePause(animation);
14201    }
14202
14203    function setSpeed(value, animation) {
14204        animationManager.setSpeed(value, animation);
14205    }
14206
14207    function setDirection(value, animation) {
14208        animationManager.setDirection(value, animation);
14209    }
14210
14211    function stop(animation) {
14212        animationManager.stop(animation);
14213    }
14214
14215    function moveFrame(value) {
14216        animationManager.moveFrame(value);
14217    }
14218
14219    function searchAnimations() {
14220        if (standalone === true) {
14221            animationManager.searchAnimations(animationData, standalone, renderer);
14222        } else {
14223            animationManager.searchAnimations();
14224        }
14225    }
14226
14227    function registerAnimation(elem) {
14228        return animationManager.registerAnimation(elem);
14229    }
14230
14231    function resize() {
14232        animationManager.resize();
14233    }
14234
14235    function start() {
14236        animationManager.start();
14237    }
14238
14239    function goToAndStop(val, isFrame, animation) {
14240        animationManager.goToAndStop(val, isFrame, animation);
14241    }
14242
14243    function setSubframeRendering(flag) {
14244        subframeEnabled = flag;
14245    }
14246
14247    function loadAnimation(params) {
14248        if (standalone === true) {
14249            params.animationData = JSON.parse(animationData);
14250        }
14251        return animationManager.loadAnimation(params);
14252    }
14253
14254    function destroy(animation) {
14255        return animationManager.destroy(animation);
14256    }
14257
14258    function setQuality(value) {
14259        if (typeof value === 'string') {
14260            switch (value) {
14261                case 'high':
14262                    defaultCurveSegments = 200;
14263                    break;
14264                case 'medium':
14265                    defaultCurveSegments = 50;
14266                    break;
14267                case 'low':
14268                    defaultCurveSegments = 10;
14269                    break;
14270            }
14271        } else if (!isNaN(value) && value > 1) {
14272            defaultCurveSegments = value;
14273        }
14274        if (defaultCurveSegments >= 50) {
14275            roundValues(false);
14276        } else {
14277            roundValues(true);
14278        }
14279    }
14280
14281    function inBrowser() {
14282        return typeof navigator !== 'undefined';
14283    }
14284
14285    function installPlugin(type, plugin) {
14286        if (type === 'expressions') {
14287            expressionsPlugin = plugin;
14288        }
14289    }
14290
14291    function getFactory(name) {
14292        switch (name) {
14293            case "propertyFactory":
14294                return PropertyFactory;
14295            case "shapePropertyFactory":
14296                return ShapePropertyFactory;
14297            case "matrix":
14298                return Matrix;
14299        }
14300    }
14301    bodymovinjs.play = play;
14302    bodymovinjs.pause = pause;
14303    bodymovinjs.setLocationHref = setLocationHref;
14304    bodymovinjs.togglePause = togglePause;
14305    bodymovinjs.setSpeed = setSpeed;
14306    bodymovinjs.setDirection = setDirection;
14307    bodymovinjs.stop = stop;
14308    bodymovinjs.moveFrame = moveFrame;
14309    bodymovinjs.searchAnimations = searchAnimations;
14310    bodymovinjs.registerAnimation = registerAnimation;
14311    bodymovinjs.loadAnimation = loadAnimation;
14312    bodymovinjs.setSubframeRendering = setSubframeRendering;
14313    bodymovinjs.resize = resize;
14314    bodymovinjs.start = start;
14315    bodymovinjs.goToAndStop = goToAndStop;
14316    bodymovinjs.destroy = destroy;
14317    bodymovinjs.setQuality = setQuality;
14318    bodymovinjs.inBrowser = inBrowser;
14319    bodymovinjs.installPlugin = installPlugin;
14320    bodymovinjs.__getFactory = getFactory;
14321    bodymovinjs.version = '4.13.0';
14322
14323    function checkReady() {
14324        if (document.readyState === "complete") {
14325            clearInterval(readyStateCheckInterval);
14326            searchAnimations();
14327        }
14328    }
14329
14330    function getQueryVariable(variable) {
14331        var vars = queryString.split('&');
14332        for (var i = 0; i < vars.length; i++) {
14333            var pair = vars[i].split('=');
14334            if (decodeURIComponent(pair[0]) == variable) {
14335                return decodeURIComponent(pair[1]);
14336            }
14337        }
14338    }
14339    var standalone = '__[STANDALONE]__';
14340    var animationData = '__[ANIMATIONDATA]__';
14341    var renderer = '';
14342    if (standalone) {
14343        var scripts = document.getElementsByTagName('script');
14344        var index = scripts.length - 1;
14345        var myScript = scripts[index] || {
14346            src: ''
14347        };
14348        var queryString = myScript.src.replace(/^[^\?]+\??/, '');
14349        renderer = getQueryVariable('renderer');
14350    }
14351    var readyStateCheckInterval = setInterval(checkReady, 100);
14352    return bodymovinjs;
14353}));

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.