gradient fills finnished
diff --git a/extension/jsx/utils/ProjectParser.jsx b/extension/jsx/utils/ProjectParser.jsx
index 8b108b6..11ae643 100644
--- a/extension/jsx/utils/ProjectParser.jsx
+++ b/extension/jsx/utils/ProjectParser.jsx
@@ -54,15 +54,17 @@
             //bm_eventDispatcher.log(XML_Ob['prop.list'][0]['prop.pair'][0]['prop.list'][0]['prop.pair'][0]['prop.list'][0]['prop.pair'][0]['prop.list'][0]['prop.pair'].length());
             var stops = XML_Ob['prop.list'][0]['prop.pair'][0]['prop.list'][0]['prop.pair'][0]['prop.list'][0]['prop.pair'][0]['prop.list'][0]['prop.pair'];
             var colors = XML_Ob['prop.list'][0]['prop.pair'][0]['prop.list'][0]['prop.pair'][1]['prop.list'][0]['prop.pair'][0]['prop.list'][0]['prop.pair'];
-            bm_eventDispatcher.log(colors.toString());
             i = 0;
             len = stops.length();
-            var opacitiesArr = [],op, floats, nextFloats, midPoint, midPosition;
+            var opacitiesArr = [],op, floats, nextFloats, midPoint, midPosition, hasOpacity = false;
             while(i<len){
                 floats = stops[i]['prop.list'][0]['prop.pair'][0]['array'][0].float;
                 op = [];
                 op.push(bm_generalUtils.roundNumber(Number(floats[0].toString()),3));
                 op.push(bm_generalUtils.roundNumber(Number(floats[2].toString()),3));
+                if(op[1] !== 1){
+                    hasOpacity = true;
+                }
                 opacitiesArr.push(op);
                 midPosition = bm_generalUtils.roundNumber(Number(floats[1].toString()),3);
                 if(i<len-1 && midPosition !== 0.5){
@@ -76,6 +78,9 @@
                 }
                 i += 1;
             }
+            if(!hasOpacity){
+                opacitiesArr.length = 0;
+            }
             i = 0;
             len = colors.length();
             var colorsArr = [];
@@ -103,8 +108,6 @@
                 }
                 i += 1;
             }
-            bm_eventDispatcher.log(opacitiesArr);
-            bm_eventDispatcher.log(colorsArr);
             gradientData.c = colorsArr;
             gradientData.o = opacitiesArr;
             //var jsonData = bm_xml2json(XML_Ob);
diff --git a/extension/jsx/utils/shapeHelper.jsx b/extension/jsx/utils/shapeHelper.jsx
index fc7e4c9..cdd3b37 100644
--- a/extension/jsx/utils/shapeHelper.jsx
+++ b/extension/jsx/utils/shapeHelper.jsx
@@ -9,6 +9,7 @@
         star: 'sr',
         fill: 'fl',
         gfill: 'gf',
+        gStroke: 'sf',
         stroke: 'st',
         merge: 'mm',
         trim: 'tm',
@@ -43,6 +44,8 @@
             return shapeItemTypes.group;
         case 'ADBE Vector Graphic - G-Fill':
             return shapeItemTypes.gfill;
+        case 'ADBE Vector Graphic - G-Stroke':
+            return shapeItemTypes.gStroke;
         default:
             bm_eventDispatcher.log(matchName);
             return '';
@@ -154,6 +157,28 @@
                     ob.e = bm_keyframeHelper.exportKeyframes(prop.property('End Point'), frameRate);
                     ob.o = bm_keyframeHelper.exportKeyframes(prop.property('Opacity'), frameRate);
                     ob.t = prop.property('Type').value;
+                    if(ob.t === 2){
+                        ob.h = bm_keyframeHelper.exportKeyframes(prop.property('Highlight Length'), frameRate);
+                        ob.a = bm_keyframeHelper.exportKeyframes(prop.property('Highlight Angle'), frameRate);
+                    }
+
+                } else if (itemType === shapeItemTypes.gStroke) {
+                    ob = {};
+                    ob.ty = itemType;
+                    var gradientData = bm_ProjectHelper.getGradientData(navigationShapeTree);
+                    ob.c = gradientData.c;
+                    ob.y = gradientData.o;
+                    ob.s = bm_keyframeHelper.exportKeyframes(prop.property('Start Point'), frameRate);
+                    ob.e = bm_keyframeHelper.exportKeyframes(prop.property('End Point'), frameRate);
+                    ob.o = bm_keyframeHelper.exportKeyframes(prop.property('Opacity'), frameRate);
+                    ob.w = bm_keyframeHelper.exportKeyframes(prop.property('Stroke Width'), frameRate);
+                    ob.lc = prop.property('Line Cap').value;
+                    ob.lj = prop.property('Line Join').value;
+                    ob.t = prop.property('Type').value;
+                    if(ob.t === 2){
+                        ob.h = bm_keyframeHelper.exportKeyframes(prop.property('Highlight Length'), frameRate);
+                        ob.a = bm_keyframeHelper.exportKeyframes(prop.property('Highlight Angle'), frameRate);
+                    }
 
                 } else if (itemType === shapeItemTypes.stroke) {
                     ob = {};
diff --git a/player/index.html b/player/index.html
index 2d7b9d9..336da80 100644
--- a/player/index.html
+++ b/player/index.html
@@ -10,8 +10,8 @@
         }
         #bodymovin{
             background-color:#ddd;
-            width:900px;
-            height:600px;
+            width:1000px;
+            height:400px;
             /*width:800px;
             height:500px;*/
             display:block;
diff --git a/player/js/elements/ShapeElement.js b/player/js/elements/ShapeElement.js
index 7b785b7..cc01bcd 100644
--- a/player/js/elements/ShapeElement.js
+++ b/player/js/elements/ShapeElement.js
@@ -87,15 +87,15 @@
 
             }else if(arr[i].ty == 'gf'){
                 pathElement = document.createElementNS(svgNS, "path");
-                var mask = document.createElementNS(svgNS,"mask");
-                var maskElement = document.createElementNS(svgNS, "path");
-                mask.appendChild(maskElement);
                 var gradientId = 'gr_'+randomString(10);
-                var opacityId = 'op_'+randomString(10);
-                var maskId = 'mk_'+randomString(10);
-                mask.setAttribute('id',maskId);
-                pathElement.setAttribute('mask','url(#'+maskId+')');
-                var gfill = document.createElementNS(svgNS,'linearGradient');
+                var gfill,opFill;
+                if(arr[i].t === 1){
+                    gfill = document.createElementNS(svgNS,'linearGradient');
+                } else {
+                    gfill = document.createElementNS(svgNS,'radialGradient');
+                    data[i].h = PropertyFactory.getProp(this,arr[i].h,1,0.01,dynamicProperties);
+                    data[i].a = PropertyFactory.getProp(this,arr[i].a,1,degToRads,dynamicProperties);
+                }
                 gfill.setAttribute('id',gradientId);
                 gfill.setAttribute('spreadMethod','pad');
                 gfill.setAttribute('gradientUnits','userSpaceOnUse');
@@ -107,26 +107,39 @@
                     stop.setAttribute('style','stop-color:rgb('+Math.round(arr[i].c[j][1]*255)+','+Math.round(arr[i].c[j][2]*255)+','+Math.round(arr[i].c[j][3]*255)+')');
                     gfill.appendChild(stop);
                 }
-                var opFill = document.createElementNS(svgNS,'linearGradient');
-                opFill.setAttribute('id',opacityId);
-                opFill.setAttribute('spreadMethod','pad');
-                opFill.setAttribute('gradientUnits','userSpaceOnUse');
-                jLen = arr[i].y.length;
-                for(j=0;j<jLen;j+=1){
-                    stop = document.createElementNS(svgNS,'stop');
-                    stop.setAttribute('offset',Math.round(arr[i].y[j][0]*100)+'%');
-                    stop.setAttribute('style','stop-color:rgb(255,255,255);stop-opacity:'+arr[i].y[j][1]);
-                    opFill.appendChild(stop);
-                }
                 pathElement.setAttribute('fill','url(#'+gradientId+')');
-                maskElement.setAttribute('fill','url(#'+opacityId+')');
                 this.globalData.defs.appendChild(gfill);
-                this.globalData.defs.appendChild(opFill);
-                this.globalData.defs.appendChild(mask);
-                data[i].s = PropertyFactory.getProp(this,arr[i].s,0,null,dynamicProperties);
-                data[i].e = PropertyFactory.getProp(this,arr[i].e,0,null,dynamicProperties);
+                if(arr[i].y.length){
+                    var mask = document.createElementNS(svgNS,"mask");
+                    var maskElement = document.createElementNS(svgNS, "path");
+                    mask.appendChild(maskElement);
+                    var opacityId = 'op_'+randomString(10);
+                    var maskId = 'mk_'+randomString(10);
+                    mask.setAttribute('id',maskId);
+                    pathElement.setAttribute('mask','url(#'+maskId+')');
+                    if(arr[i].t === 1){
+                        opFill = document.createElementNS(svgNS,'linearGradient');
+                    } else {
+                        opFill = document.createElementNS(svgNS,'radialGradient');
+                    }
+                    opFill.setAttribute('id',opacityId);
+                    opFill.setAttribute('spreadMethod','pad');
+                    opFill.setAttribute('gradientUnits','userSpaceOnUse');
+                    jLen = arr[i].y.length;
+                    for(j=0;j<jLen;j+=1){
+                        stop = document.createElementNS(svgNS,'stop');
+                        stop.setAttribute('offset',Math.round(arr[i].y[j][0]*100)+'%');
+                        stop.setAttribute('style','stop-color:rgb(255,255,255);stop-opacity:'+arr[i].y[j][1]);
+                        opFill.appendChild(stop);
+                    }
+                    maskElement.setAttribute('fill','url(#'+opacityId+')');
+                    this.globalData.defs.appendChild(opFill);
+                    this.globalData.defs.appendChild(mask);
+                    data[i].of = opFill;
+                }
+                data[i].s = PropertyFactory.getProp(this,arr[i].s,1,null,dynamicProperties);
+                data[i].e = PropertyFactory.getProp(this,arr[i].e,1,null,dynamicProperties);
                 data[i].gf = gfill;
-                data[i].of = opFill;
             }else{
                 pathElement = document.createElementNS(svgNS, "path");
                 if(!data[i].c.k) {
@@ -435,17 +448,58 @@
     }
     var gfill = viewData.gf;
     var opFill = viewData.of;
-    if(viewData.s.mdf || this.firstFrame){
-        gfill.setAttribute('x1',viewData.s.v[0]);
-        gfill.setAttribute('y1',viewData.s.v[1]);
-        opFill.setAttribute('x1',viewData.s.v[0]);
-        opFill.setAttribute('y1',viewData.s.v[1]);
-    }
-    if(viewData.e.mdf || this.firstFrame){
-        gfill.setAttribute('x2',viewData.e.v[0]);
-        gfill.setAttribute('y2',viewData.e.v[1]);
-        opFill.setAttribute('x2',viewData.e.v[0]);
-        opFill.setAttribute('y2',viewData.e.v[1]);
+    if(styleData.t === 1){
+        if(viewData.s.mdf || this.firstFrame){
+            gfill.setAttribute('x1',viewData.s.v[0]);
+            gfill.setAttribute('y1',viewData.s.v[1]);
+            if(opFill){
+                opFill.setAttribute('x1',viewData.s.v[0]);
+                opFill.setAttribute('y1',viewData.s.v[1]);
+            }
+        }
+        if(viewData.e.mdf || this.firstFrame){
+            gfill.setAttribute('x2',viewData.e.v[0]);
+            gfill.setAttribute('y2',viewData.e.v[1]);
+            if(opFill){
+                opFill.setAttribute('x2',viewData.e.v[0]);
+                opFill.setAttribute('y2',viewData.e.v[1]);
+            }
+        }
+    } else {
+        if(viewData.s.mdf || this.firstFrame){
+            gfill.setAttribute('cx',viewData.s.v[0]);
+            gfill.setAttribute('cy',viewData.s.v[1]);
+            if(opFill){
+                opFill.setAttribute('cx',viewData.s.v[0]);
+                opFill.setAttribute('cy',viewData.s.v[1]);
+            }
+        }
+        var rad;
+        if(viewData.s.mdf || viewData.e.mdf || this.firstFrame){
+            rad = Math.sqrt(Math.pow(viewData.s.v[0]-viewData.e.v[0],2)+Math.pow(viewData.s.v[1]-viewData.e.v[1],2));
+            gfill.setAttribute('r',rad);
+            if(opFill){
+                opFill.setAttribute('r',rad);
+            }
+        }
+        if(viewData.e.mdf || viewData.h.mdf || viewData.a.mdf || this.firstFrame){
+            if(!rad){
+                rad = Math.sqrt(Math.pow(viewData.s.v[0]-viewData.e.v[0],2)+Math.pow(viewData.s.v[1]-viewData.e.v[1],2));
+            }
+            var ang = Math.atan2(viewData.e.v[1]-viewData.s.v[1], viewData.e.v[0]-viewData.s.v[0]);
+
+            var percent = viewData.h.v >= 1 ? 0.99 : viewData.h.v;
+            var dist = rad*percent;
+            var x = Math.cos(ang + viewData.a.v)*dist + viewData.s.v[0];
+            var y = Math.sin(ang + viewData.a.v)*dist + viewData.s.v[1];
+            gfill.setAttribute('fx',x);
+            gfill.setAttribute('fy',y);
+            if(opFill){
+                opFill.setAttribute('fx',x);
+                opFill.setAttribute('fy',y);
+            }
+        }
+        //gfill.setAttribute('fy','200');
     }
 };
 
diff --git a/player/js/elements/canvasElements/CVShapeElement.js b/player/js/elements/canvasElements/CVShapeElement.js
index f141134..14de064 100644
--- a/player/js/elements/canvasElements/CVShapeElement.js
+++ b/player/js/elements/canvasElements/CVShapeElement.js
@@ -34,15 +34,17 @@
     var j, jLen;
     var ownArrays = [], ownModifiers = [], styleElem;
     for(i=len;i>=0;i-=1){
-        if(arr[i].ty == 'fl' || arr[i].ty == 'st'){
+        if(arr[i].ty == 'fl' || arr[i].ty == 'st' || arr[i].ty == 'gf'){
             styleElem = {
                 type: arr[i].ty,
                 elements: []
             };
             data[i] = {};
-            data[i].c = PropertyFactory.getProp(this,arr[i].c,1,255,dynamicProperties);
-            if(!data[i].c.k){
-                styleElem.co = 'rgb('+bm_floor(data[i].c.v[0])+','+bm_floor(data[i].c.v[1])+','+bm_floor(data[i].c.v[2])+')';
+            if(arr[i].ty == 'fl' || arr[i].ty == 'st'){
+                data[i].c = PropertyFactory.getProp(this,arr[i].c,1,255,dynamicProperties);
+                if(!data[i].c.k){
+                    styleElem.co = 'rgb('+bm_floor(data[i].c.v[0])+','+bm_floor(data[i].c.v[1])+','+bm_floor(data[i].c.v[2])+')';
+                }
             }
             data[i].o = PropertyFactory.getProp(this,arr[i].o,0,0.01,dynamicProperties);
             if(arr[i].ty == 'st') {
@@ -64,6 +66,15 @@
                     }
                 }
 
+            } else if(arr[i].ty == 'gf') {
+                data[i].s = PropertyFactory.getProp(this,arr[i].s,1,null,dynamicProperties);
+                data[i].e = PropertyFactory.getProp(this,arr[i].e,1,null,dynamicProperties);
+                if(arr[i].t === 2){
+                    data[i].h = PropertyFactory.getProp(this,arr[i].h,1,0.01,dynamicProperties);
+                    data[i].a = PropertyFactory.getProp(this,arr[i].a,1,degToRads,dynamicProperties);
+                }
+                styleElem.c = arr[i].c;
+
             }
             this.stylesList.push(styleElem);
             data[i].style = styleElem;
@@ -213,6 +224,8 @@
             this.renderPath(items[i],data[i],groupTransform);
         }else if(items[i].ty == 'fl'){
             this.renderFill(items[i],data[i],groupTransform);
+        }else if(items[i].ty == 'gf'){
+            this.renderGFill(items[i],data[i],groupTransform);
         }else if(items[i].ty == 'st'){
             this.renderStroke(items[i],data[i],groupTransform);
         }else if(items[i].ty == 'gr'){
@@ -230,18 +243,30 @@
     renderer.ctxTransform(this.finalTransform.mat.props);
     for(i=0;i<len;i+=1){
         type = this.stylesList[i].type;
+        if(type === 'gf'){
+            ctx.save();
+
+        }
         if(type === 'st' && this.stylesList[i].wi === 0){
             continue;
         }
         renderer.save();
         elems = this.stylesList[i].elements;
-        jLen = elems.length;
         if(type === 'st'){
             ctx.strokeStyle = this.stylesList[i].co;
             ctx.lineWidth = this.stylesList[i].wi;
             ctx.lineCap = this.stylesList[i].lc;
             ctx.lineJoin = this.stylesList[i].lj;
             ctx.miterLimit = this.stylesList[i].ml || 0;
+        }else if(type === 'gf'){
+            var grad = ctx.createLinearGradient(this.stylesList[i].x1,this.stylesList[i].y1,this.stylesList[i].x2,this.stylesList[i].y2);
+            jLen = this.stylesList[i].c.length;
+            j = 0;
+            while(j<jLen){
+                grad.addColorStop(this.stylesList[i].c[j][0],"rgb("+Math.round(this.stylesList[i].c[j][1]*255)+","+Math.round(this.stylesList[i].c[j][2]*255)+","+Math.round(this.stylesList[i].c[j][3]*255)+")");
+                j += 1;
+            }
+            ctx.fillStyle = grad;
         }else{
             ctx.fillStyle = this.stylesList[i].co;
         }
@@ -249,6 +274,7 @@
         if(type !== 'st'){
             ctx.beginPath();
         }
+        jLen = elems.length;
         for(j=0;j<jLen;j+=1){
             if(type === 'st'){
                 ctx.beginPath();
@@ -280,6 +306,29 @@
         if(type !== 'st'){
             ctx.fill();
         }
+        if(type === 'gf'){
+            ctx.globalCompositeOperation = 'destination-in';
+            jLen = elems.length;
+            for(j=0;j<jLen;j+=1){
+                nodes = elems[j].trNodes;
+                kLen = nodes.length;
+
+                for(k=0;k<kLen;k+=1){
+                    if(nodes[k].t == 'm'){
+                        ctx.moveTo(nodes[k].p[0],nodes[k].p[1]);
+                    }else if(nodes[k].t == 'c'){
+                        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]);
+                    }else{
+                        ctx.closePath();
+                    }
+                }
+                if(type === 'st'){
+                    ctx.stroke();
+                }
+            }
+            ctx.restore();
+
+        }
         renderer.restore();
     }
     renderer.restore();
@@ -358,6 +407,17 @@
     }
 };
 
+CVShapeElement.prototype.renderGFill = function(styleData,viewData, groupTransform){
+    var styleElem = viewData.style;
+    if(viewData.s.mdf || viewData.e.mdf || this.firstFrame){
+        styleElem.x1 = viewData.s.v[0];
+        styleElem.y1 = viewData.s.v[1];
+        styleElem.x2 = viewData.e.v[0];
+        styleElem.y2 = viewData.e.v[1];
+    }
+
+};
+
 CVShapeElement.prototype.renderStroke = function(styleData,viewData, groupTransform){
     var styleElem = viewData.style;
     //TODO fix dashes