/*//////////////////////////////////////
CSSmu.js - CSS Timeline handling library
version 1.0.1 - last edited 2015.10.14
----------------------------------------
by auer404 - http://www.auer404.com
----------------------------------------
(jQuery required)
//////////////////////////////////////*/

function CSSmu() {
    if (arguments.length == 0) {return false}
    
    var base_group = false;
    var add_groups = new Array();
    var target_Timelines = new Array();
    var prop_Objects = new Array();
 
 for (var i = 0; i < arguments.length; i++) {
    var arg = arguments[i];
    
    if (typeof arg == "string") {
        
        var new_TL = CSSmu.create_Timeline(arg);
        target_Timelines.push(new_TL);
        
    } else if (typeof arg == "object") {
        
        if (typeof arg.type == "undefined") {

        if (typeof arg.name != "undefined") {
            
        var new_TL = CSSmu.create_Timeline(arg.name);
        new_TL.updateSettings(arg, true);
        target_Timelines.push(new_TL);
        
        } else {
                
        if (typeof arg.duplicate != "undefined") {
            
            var to_duplicate = arg.duplicate;
            if (to_duplicate.type == "timeline") {
                
                var new_TL = to_duplicate.duplicate();
                new_TL.updateSettings(arg, true);
                target_Timelines.push(new_TL);
        
            } else if (to_duplicate.type == "group") {
               
               var new_TL = to_duplicate.duplicate();
               new_TL.updateSettings(arg, true);
               
               if (base_group == false) {
               base_group = new_TL;
               } else {
               add_groups.push(new_TL);
               }
               
                
            }
            
        } else {
            
            prop_Objects.push(arg);
            
        }
        
        }
        
        } else {
            
            if (arg.type == "timeline" && typeof arg.name != "undefined") {
                
                target_Timelines.push(arg);

            } else if (arg.type == "group") {
                
              if (base_group == false) {
               base_group = arg;
               } else {
               add_groups.push(arg);
               }  
                
            }
            
        }
       
    }
    
    }
    
    if (base_group != false && add_groups.length > 0) {
        for (var i = 0; i < add_groups.length; i++) {
                base_group.addGroup(add_groups[i]);
            }
    }
    
    if (target_Timelines.length >= 2) {
        
        var tTL_names = new Array();
        for (var i = 0; i < target_Timelines.length; i++) {
            var this_tTL = target_Timelines[i];
            if (tTL_names.indexOf(this_tTL.name) == -1) {
                tTL_names.push(this_tTL.name);
            } else {
                this_tTL.TODELETE = true;
            }
        }
        
        var ok_tTL = new Array();
        for (var i = 0; i < target_Timelines.length; i++) {
            var this_tTL = target_Timelines[i];
            if (typeof this_tTL.TODELETE == "undefined") {
                ok_tTL.push(this_tTL);
            }
        }
        
        if (base_group != false) {
            for (var i = 0; i < ok_tTL.length; i++) {
                base_group.addSubTimeline(ok_tTL[i]);
            }
            for (var pOi = 0; pOi < prop_Objects.length; pOi++) {
        base_group.updateSettings(prop_Objects[pOi], true);
        }
        return base_group;
        }
        var new_G = CSSmu.create_Group(ok_tTL);
        for (var pOi = 0; pOi < prop_Objects.length; pOi++) {
        new_G.updateSettings(prop_Objects[pOi], true);
        }
        return new_G;
        
    } else {
        if (target_Timelines.length > 0) {
            
           if (base_group != false) {
            base_group.addSubTimeline(target_Timelines[0]);
            for (var pOi = 0; pOi < prop_Objects.length; pOi++) {
        base_group.updateSettings(prop_Objects[pOi], true);
        }
        return base_group;
            }
            
        for (var pOi = 0; pOi < prop_Objects.length; pOi++) {
        target_Timelines[0].updateSettings(prop_Objects[pOi], true);
        }
        return target_Timelines[0];    
        }
        
        if (base_group != false) {

            for (var pOi = 0; pOi < prop_Objects.length; pOi++) {
        base_group.updateSettings(prop_Objects[pOi], true);
        }
        return base_group;
            }
        
        return false;
    }
    
    return false;
    
}

CSSmu.defaultRate = 25;
CSSmu.defaultMode = "loop";
CSSmu.frameMarker = "_f";
CSSmu.rootSelector = "body";

CSSmu.harmonize_arguments = function(value) {
    
    var args = new Array();
    if (value.length == 1 && $.isArray(value[0])) {
        args = value[0];
    } else {
        args = value;
    }
    
    return args;

}

CSSmu.getSelectors = function(timeline_name) {
        
        var sList = new Array();
        var all_rules = new Array();
        var root_required = false;
        
        for (var ssn = 0; ssn < document.styleSheets.length; ssn++) {
    var rules = document.styleSheets[ssn].rules || document.styleSheets[ssn].cssRules;

    for (var i = 0 ; i < rules.length; i++) {
        if (typeof rules[i].selectorText != "undefined") {
        all_rules.push(rules[i]);

        } else {

            if (typeof rules[i].cssRules != "undefined") {
                var these_rules = rules[i].cssRules;
                for (var j = 0; j < these_rules.length; j++) {
                    if (typeof these_rules[j].selectorText != "undefined") {
                        all_rules.push(these_rules[j]);
                    }
                }
            }
        }
    }
    
    for (var i = 0; i < all_rules.length; i++) {

    var sel = all_rules[i].selectorText;

    var sorted_sel = sel.split(",");
    for (var j = 0; j < sorted_sel.length; j++) {
        var ok_sel = $.trim(sorted_sel[j]);
        
    if (ok_sel.indexOf(timeline_name + CSSmu.frameMarker) != -1) {
        var theclassName = new RegExp("." + timeline_name + CSSmu.frameMarker , 'g');
        ok_sel = ok_sel.replace(theclassName , "__CSSMU_FLAG__" + "." + timeline_name + CSSmu.frameMarker);
        var splitted_sel = ok_sel.split("." + timeline_name);
        
       for (var k = 0; k < splitted_sel.length; k++) {
            var sel_sub = splitted_sel[k];

            if (sel_sub.substring(0,CSSmu.frameMarker.length) == CSSmu.frameMarker) {
                sel_sub = sel_sub.substring(CSSmu.frameMarker.length);

                var ss_end = sel_sub.search(/[^0-9]/);
                if (ss_end == -1 || sel_sub.indexOf("__CSSMU_FLAG__") == -1) {
                    sel_sub = "";
                } else {
                    sel_sub = sel_sub.substring(ss_end);
                }
            }
            if (sel_sub == "__CSSMU_FLAG__") {
                root_required = true;
            }
            
            sel_sub = sel_sub.replace(/(\[.+\])/g , ""); 
            sel_sub = sel_sub.replace(/\s+\./g , "__SEP__."); 
            sel_sub = sel_sub.replace(/\s+#/g , "__SEP__#"); 
            sel_sub = sel_sub.replace(/\s+/g , " ");
            sel_sub = sel_sub.replace(/[^A-Za-z0-9_\-\.#]/g , "__SEP__");
            sel_sub = sel_sub.replace(/\./g , "__SEP2__.");
            sel_sub = sel_sub.replace(/#/g , "__SEP2__#");
            
            sel_sub2 = sel_sub.split("__SEP__");
            for (var l = 0; l < sel_sub2.length; l++) {
              var splitted2 = sel_sub2[l];

              if (splitted2.indexOf("__CSSMU_FLAG__") == -1) {
                splitted2 = "";
              } else {
                splitted2 = splitted2.replace(/__CSSMU_FLAG__/g , "");
              }
              
              var sel_sub3 = splitted2.split("__SEP2__");
              for (var m = 0; m < sel_sub3.length; m++) {
                var splitted3 = sel_sub3[m];
                
                if (sList.indexOf(splitted3) == -1 && splitted3 != "") {
                sList.push(splitted3);
                }
                
              }
              
            }  
    }
    
    }
    
    }
    
    }
    
    if (root_required && CSSmu.rootSelector != false) {
        sList.push(CSSmu.rootSelector);
    }
    
    }
    return sList;
}
    
CSSmu.getFrameCount = function(timeline_name) {

    var all_rules = new Array();
    
        var fc = 0;
        for (var ssn = 0; ssn < document.styleSheets.length; ssn++) {
    var rules = document.styleSheets[ssn].rules || document.styleSheets[ssn].cssRules;
    
        for (var i = 0 ; i < rules.length; i++) {
        if (typeof rules[i].selectorText != "undefined") {
        all_rules.push(rules[i]);
        } else {

            if (typeof rules[i].cssRules != "undefined") {
                var these_rules = rules[i].cssRules;
                for (var j = 0; j < these_rules.length; j++) {
                    if (typeof these_rules[j].selectorText != "undefined") {
                        all_rules.push(these_rules[j]);
                    }
                }
            }
        }
    }

    for (var i = 0 ; i < all_rules.length; i++) {

    var sel = all_rules[i].selectorText;

    if (sel.indexOf(timeline_name + CSSmu.frameMarker) != -1) {
        var splitted_sel = sel.split(timeline_name);

        for (var j = 0; j < splitted_sel.length; j++) {
            var sel_sub = splitted_sel[j];
            if (sel_sub.substring(0,CSSmu.frameMarker.length) == CSSmu.frameMarker) {
                sel_sub = sel_sub.substring(CSSmu.frameMarker.length);
                var ss_end = sel_sub.search(/[^0-9]/);
                if (ss_end != -1) {
                    sel_sub = sel_sub.substring(0,ss_end);
                }
                sel_sub = parseInt(sel_sub);
                if (sel_sub > fc) {
                    fc = sel_sub;
                }
            }
        }
    }
    
    }
    }
    return fc;   
}

CSSmu.create_Timeline = function(name) {
    
    var A = new Object;
    
    A.type = "timeline";
    A.name = name;
    A.frameCount = 0;
    A.frameRate = CSSmu.defaultRate;
    A.frameInterval = Math.round(1000 / A.frameRate);
    A.currentFrame = 0;
    A.mode = CSSmu.defaultMode;
    A.selectors = new Array();
    A.restrictedTargets = new Array();
    A.excludedTargets = new Array();
    A.parentTimeline = false;
    A.isMainSubTimeline = false;
    A.frameCallbacks = new Array();
    A.tmp_frameCallback = false;
    A.onStartCallback = false;
    A.onEndCallback = false;
    A.onPlayCallback = false;
    A.onPauseCallback = false;
    A.onStopCallback = false;
    A.onEachFrameCallback = false;
    A.isPlaying = false;
    A.timer = false;
    
    A.subTimelines = new Array();
    A.mainSubTimeline = A;
    A.mainSubTimelineName = A.name;
    
    A.become = function(res) { CSSmu.transferProperties(this, res); return this}
    
    A.selectors = CSSmu.getSelectors(A.name).slice(0);
    
    A.frameCount = CSSmu.getFrameCount(A.name);
    
    A.setRate = function(new_rate) {
        this.frameRate = new_rate;
        this.frameInterval = Math.round(1000 / new_rate);
        if (this.isPlaying) {this.pause(true); this.play(true)}
        return this;
        }
    
    A.setCurrentFrame = function(new_cf) {
    if (new_cf > this.frameCount || new_cf < 0) {return this}
    this.currentFrame = new_cf;
    return this;
    }
    
    A.setMode = function(new_mode) {this.mode = new_mode; return this}
    
    A.addSelector = function() {
        
        var args = CSSmu.harmonize_arguments(arguments);
        
    for (var i = 0; i < args.length; i++) {
        if (args[i] && args[i] != "" && args[i] != null) {
        this.selectors.push(args[i]);
        }
        }
        return this;
    }
    A.addSelectors = A.addSelector;
    
    A.removeSelector = function() {
        
        var args = CSSmu.harmonize_arguments(arguments);
        
    for (var i = 0; i < args.length; i++) {
            if (this.selectors.indexOf(args[i]) != -1) {
        this.selectors.splice(this.selectors.indexOf(args[i]), 1);
            }
        }
        return this;
    }
    A.removeSelectors = A.removeSelector;
    
    A.clearSelectors = function() {this.selectors.length = 0; return this}
    
    A.resetSelectors = function() {
        this.clearSelectors();
        this.selectors = CSSmu.getSelectors(this.name).slice(0);
        return this;
        }
    
    A.restrictTo = function() {
        
        this.restrictedTargets.length = 0;
        
        if (arguments[0] == false) {return this}
        
        var args = CSSmu.harmonize_arguments(arguments);

        for (var i = 0; i < args.length; i++) {
            if (args[i] && args[i] != "" && args[i] != null) {
        this.restrictedTargets.push(args[i]);
            }
        }
        return this;
    }
    
    A.exclude = function() {
        
        this.excludedTargets.length = 0;
        
        if (arguments[0] == false) {return this}
        
        var args = CSSmu.harmonize_arguments(arguments);
        
        for (var i = 0; i < args.length; i++) {
            if (args[i] && args[i] != "" && args[i] != null) {
        this.excludedTargets.push(args[i]);
            }
        }
        return this;
    }
    
    A.onFrame = function(f, fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.frameCallbacks[f] = fct;
            return this;
            }
    
    A.onStart = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onStartCallback = fct;
            return this;
            }
            
    A.onEnd = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onEndCallback = fct;
            return this;
            }
            
    A.onPlay = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onPlayCallback = fct;
            return this;
            }
            
    A.onPause = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onPauseCallback = fct;
            return this;
            }
            
    A.onStop = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onStopCallback = fct;
            return this;
            }
            
    A.onEachFrame = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onEachFrameCallback = fct;
            return this;
            }
            
    A.each_onFrame = A.onFrame;
    A.each_onStart = A.onStart;
    A.each_onEnd = A.onEnd;
    A.each_onPlay = A.onPlay;
    A.each_onPause = A.onPause;
    A.each_onStop = A.onStop;
    A.each_onEachFrame = A.onEachFrame;
    
    A.displayFrame = function(f) {
        
        var ov_elems = this.restrictedTargets;
        var ex_elems = this.excludedTargets;
        
        this.setCurrentFrame(f);
        var curr_cn = this.name + CSSmu.frameMarker + this.currentFrame;
        var prev_cn = this.name + CSSmu.frameMarker + (this.currentFrame - 1);
        var next_cn = this.name + CSSmu.frameMarker + (this.currentFrame + 1);
        var first_cn = this.name + CSSmu.frameMarker + 1;
        var last_cn = this.name + CSSmu.frameMarker + this.frameCount;
        
        if (ov_elems.length == 0) {
            var the_targets = this.selectors;
        } else {
            var the_targets = ov_elems;
            
        }
        
        for (var i = 0; i < the_targets.length; i++) {

                   var A_target = $(the_targets[i]);
             
             if (ov_elems.length > 0) {
                
                var ov_filter_exp = "";
                for (var j = 0; j < this.selectors.length; j++) {
                ov_filter_exp += this.selectors[j];
                if (j < this.selectors.length - 1) {
                    ov_filter_exp += ",";
                }
             }
                A_target = A_target.filter(ov_filter_exp);
             }
             
             for (var j = 0; j < ex_elems.length; j++) {
                A_target = A_target.not($(ex_elems[j]));
             }
            
            A_target.removeClass(prev_cn);
            A_target.removeClass(next_cn);
            A_target.addClass(curr_cn);
            
            if (this.currentFrame != 1) {
             A_target.removeClass(first_cn);   
            }
            
            if (this.currentFrame != this.frameCount) {
             A_target.removeClass(last_cn);   
            }
             
        }
        
        if (typeof this.frameCallbacks[this.currentFrame] == "function") {
            this.tmp_frameCallback = this.frameCallbacks[this.currentFrame];
            this.tmp_frameCallback();
        }
        
        if (typeof this.onEachFrameCallback == "function") {
            this.onEachFrameCallback();
        }
        
        if (typeof this.onStartCallback == "function" && this.currentFrame == 1) {
            this.onStartCallback();
        }
        
        if (typeof this.onEndCallback == "function" && this.currentFrame == this.frameCount) {
            this.onEndCallback();
        }
        
        if (this.isMainSubTimeline && typeof this.parentTimeline.frameCallbacks[this.currentFrame] == "function") {
            this.parentTimeline.tmp_frameCallback = this.parentTimeline.frameCallbacks[this.currentFrame];
            this.parentTimeline.tmp_frameCallback();
        }
        
        if (this.isMainSubTimeline && typeof this.parentTimeline.onEachFrameCallback == "function") {
            this.parentTimeline.onEachFrameCallback();
        }
        
        if (this.isMainSubTimeline && typeof this.parentTimeline.onStartCallback == "function" && this.currentFrame == 1) {
            this.parentTimeline.onStartCallback();
        }
        
        if (this.isMainSubTimeline && typeof this.parentTimeline.onEndCallback == "function" && this.currentFrame == this.frameCount) {
            this.parentTimeline.onEndCallback();
        }
       return this; 
    }
        
    A.play = function(ignore_callback) {
        if (this.isPlaying) {return false}
        ignore_callback = typeof ignore_callback != "undefined" ? ignore_callback : false;
        
        if (typeof this.onPlayCallback == "function" && !ignore_callback) {
            this.onPlayCallback();
        }
        
        clearInterval(this.timer);
        this.isPlaying = true;
        if (this.isMainSubTimeline) {
            this.parentTimeline.isPlaying = true;
           }
           
           var revert_when_done = A.mode;
        
        if (A.mode == "wave") {
           A.setMode("w_forth"); 
        }
        
        if (A.mode == "once wave" || A.mode == "wave once") {
            A.setMode("w_forth_1");
        }
        
        if (A.mode.indexOf("backwards") != -1 && A.mode.indexOf("wave") != -1) {
            A.setMode("w_back");
        }
        
        if (A.mode.indexOf("once") != -1 && A.mode.indexOf("backwards") != -1 && A.mode.indexOf("wave") != -1) {
            A.setMode("w_back_1");
        }
        
        if (A.mode == "once wave stay" || A.mode == "wave once stay") {
            A.setMode("w_forth_1 stay");
        }
        
        if (A.mode.indexOf("once") != -1 && A.mode.indexOf("backwards") != -1 && A.mode.indexOf("wave") != -1 && A.mode.indexOf("stay") != -1) {
            A.setMode("w_back_1 stay");
        }
        
        var must_clean = false;
        
        if (this.currentFrame == 0) {
            if (this.mode.indexOf("back") == -1) {
            this.displayFrame(1);
            } else {
            this.displayFrame(this.frameCount);    
            }
        }
        
        this.timer = setInterval(function(){
           
           if (A.mode == "loop") {
            
           A.currentFrame++;
           if (A.currentFrame > A.frameCount) {A.setCurrentFrame(1)}
           
           } else if (A.mode == "once") {
            
           A.currentFrame++;
           if (A.currentFrame > A.frameCount) {A.pause(); A.mode = revert_when_done; must_clean = true}
           
           } else if (A.mode == "once stay") {
            
           A.currentFrame++;
           if (A.currentFrame >= A.frameCount) {A.pause(); A.mode = revert_when_done}
           
           } else if (A.mode == "once backwards" || A.mode == "backwards once") {
            
            A.currentFrame--;
           if (A.currentFrame < 1) {A.pause(); A.mode = revert_when_done; must_clean = true}
           
           } else if (A.mode == "once backwards stay" || A.mode == "backwards once stay") {
            
            A.currentFrame--;
           if (A.currentFrame <= 1) {A.pause(); A.mode = revert_when_done} 
           
           } else if (A.mode == "loop backwards" || A.mode == "backwards loop" || A.mode == "backwards") {
            
            A.currentFrame--;
           if (A.currentFrame < 1) {A.setCurrentFrame(A.frameCount)}
            
           } else if (A.mode == "w_forth") {
            
            A.currentFrame++;
           if (A.currentFrame >= A.frameCount) {A.setMode("w_back")}
            
           } else if (A.mode == "w_back") {
            
            A.currentFrame--;
           if (A.currentFrame <= 1) {A.setMode("w_forth")}
            
           } else if (A.mode == "w_back_1") {
            
            A.currentFrame--;
           if (A.currentFrame <= 1) {A.setMode("once")}
            
           } else if (A.mode == "w_back_1 stay") {
            
            A.currentFrame--;
           if (A.currentFrame <= 1) {A.setMode("once stay")}
            
           } else if (A.mode == "w_forth_1") {
            
            A.currentFrame++;
           if (A.currentFrame >= A.frameCount) {A.setMode("backwards once")}
            
           } else if (A.mode == "w_forth_1 stay") {
            
            A.currentFrame++;
           if (A.currentFrame >= A.frameCount) {A.setMode("backwards once stay")}
            
           }
           
           if (A.isMainSubTimeline) {
            A.parentTimeline.currentFrame = A.currentFrame;
           }
           
           A.displayFrame(A.currentFrame);
           
           if (must_clean) {
            A.clean();
           }
           
        },this.frameInterval);
        return this;
    }
        
    A.pause = function(ignore_callback) {
        if (!this.isPlaying) {return this}
       ignore_callback = typeof ignore_callback != "undefined" ? ignore_callback : false;
       
       if (typeof this.onPauseCallback == "function" && !ignore_callback) {
            this.onPauseCallback();
        }
       
       clearInterval(this.timer);
       this.isPlaying = false;
       if (this.isMainSubTimeline) {
            this.parentTimeline.isPlaying = false;
           }
      return this;  
    }
    
    A.toggle = function() {
        if (this.isPlaying) {this.pause()}
        else {this.play()}
        return this;
    }
    
    A.stop = function() {
        
        if (typeof this.onStopCallback == "function") {
            this.onStopCallback();
        }
        
        this.pause();
        this.clean();
        this.setCurrentFrame(0);
        return this;
    }
    
    A.clean = function() {
        var ov_elems = this.restrictedTargets;
        var ex_elems = this.excludedTargets;
        
        if (ov_elems.length == 0) {
            var the_targets = this.selectors;
        } else {
            var the_targets = ov_elems;
        }
        
        for (var i = 0; i < the_targets.length; i++) {

                   var A_target = $(the_targets[i]);
                   
                 if (ov_elems.length > 0) {
                
                var ov_filter_exp = "";
                for (var j = 0; j < this.selectors.length; j++) {
                ov_filter_exp += this.selectors[j];
                if (j < this.selectors.length - 1) {
                    ov_filter_exp += ",";
                }
             }
                A_target = A_target.filter(ov_filter_exp);
             }
                   
                   for (var j = 0; j < ex_elems.length; j++) {
                A_target = A_target.not($(ex_elems[j]));
             }
                   
            for (var j = 0; j <= this.frameCount + 1; j++) {
            A_target.removeClass(this.name + CSSmu.frameMarker + j);
            }
             
        }
        return this;
    }
    
    A.duplicate = function() {
        
        var new_A = CSSmu.create_Timeline(this.name);
        new_A.selectors = this.selectors.slice(0);
        new_A.restrictedTargets = this.restrictedTargets.slice(0);
        new_A.excludedTargets = this.excludedTargets.slice(0);
        new_A.frameCallbacks = this.frameCallbacks.slice(0);
        new_A.onStartCallback = this.onStartCallback;
        new_A.onEndCallback = this.onEndCallback;
        new_A.onPlayCallback = this.onPlayCallback;
        new_A.onPauseCallback = this.onPauseCallback;
        new_A.onStopCallback = this.onStopCallback;
        new_A.onEachFrameCallback = this.onEachFrameCallback;
        new_A.setRate(this.frameRate);
        new_A.setMode(this.mode);
        new_A.setCurrentFrame(this.currentFrame);
        
        return new_A;
        
    }
    
    A.siblingTimeline = function(tl_name) {
        if (!this.parentTimeline) {return this}
        
        if (typeof tl_name == "number") {
            if (typeof this.parentTimeline.subTimelines[tl_name] != "undefined") {
                return this.parentTimeline.subTimelines[tl_name];
            }
            return false;
        }
        
       for (var i = 0; i < this.parentTimeline.subTimelines.length; i++) {
           if (this.parentTimeline.subTimelines[i].name == tl_name) {return this.parentTimeline.subTimelines[i];}
        }
        return false;
    }
    
    A.updateSettings = function(props, ignore_namechange, from_group) {
       ignore_namechange = typeof ignore_namechange != "undefined" ? ignore_namechange : true;
       from_group = typeof from_group != "undefined" ? from_group : false;
       if (typeof props != "object") {return this}
    
    if (typeof props.name == "string" && !ignore_namechange) {this.name = props.name}
    if (typeof props.rate == "number") {this.setRate(props.rate)}
    if (typeof props.mode == "string") {this.setMode(props.mode)}
    if (typeof props.currentFrame == "number") {this.setCurrentFrame(props.currentFrame)}
    if (typeof props.defaultFrame == "number") {this.setCurrentFrame(props.defaultFrame)}
    
    if (typeof props.selectors != "undefined") {
        var new_selectors = new Array();
        if (typeof props.selectors == "string") {
        new_selectors = props.selectors.split(",");
        for (var i = 0; i < new_selectors.length; i++) {
            new_selectors[i] = $.trim(new_selectors[i]);
        }
        } else if (typeof props.selectors == "object" && typeof props.selectors.length != "undefined") {
        new_selectors = props.selectors.slice(0);   
        }
        this.selectors.length = 0;
        if(new_selectors.length > 0) {
        this.addSelectors(new_selectors);
        } else {
        this.resetSelectors();
        }
    }
    
    if (typeof props.restrictTo != "undefined") {
        var new_restricted = new Array();
        if (typeof props.restrictTo == "string") {
        new_restricted = props.restrictTo.split(",");
        for (var i = 0; i < new_restricted.length; i++) {
            new_restricted[i] = $.trim(new_restricted[i]);
        }
        } else if (typeof props.restrictTo == "object" && typeof props.restrictTo.length != "undefined") {
        new_restricted = props.restrictTo.slice(0);   
        } else if (typeof props.restrictTo == "object" && typeof props.restrictTo.length == "undefined") {
        new_restricted.push(props.restrictTo);   
        }
        this.restrictTo(new_restricted);
    }
    
    if (typeof props.exclude != "undefined") {
        var new_excluded = new Array();
        if (typeof props.exclude == "string") {
        new_excluded = props.exclude.split(",");
        for (var i = 0; i < new_excluded.length; i++) {
            new_excluded[i] = $.trim(new_excluded[i]);
        }
        } else if (typeof props.exclude == "object" && typeof props.exclude.length != "undefined") {
        new_excluded = props.exclude.slice(0);   
        } else if (typeof props.exclude == "object" && typeof props.exclude.length == "undefined") {
        new_excluded.push(props.exclude);   
        }
        this.exclude(new_excluded);
    }
    
    if (from_group) {
    var cb_target = this.parentTimeline;
    } else {
    var cb_target = this;
    }
    
    if (typeof props.onFrame == "object" && typeof props.onFrame.length != "undefined") {
        var cb = props.onFrame;
        for (var i = 0; i < cb.length; i++) {
            cb_target.onFrame(cb[i][0],cb[i][1]);
        }
    }
    
    if (typeof props.onEachFrame == "function" || props.onEachFrame === false) {
            cb_target.onEachFrame(props.onEachFrame);
    }
    
    if (typeof props.onStart == "function" || props.onStart === false) {
            cb_target.onStart(props.onStart);
    }
    
    if (typeof props.onEnd == "function" || props.onEnd === false) {
            cb_target.onEnd(props.onEnd);
    }
    
    if (typeof props.onPlay == "function" || props.onPlay === false) {
            cb_target.onPlay(props.onPlay);
    }
    
    if (typeof props.onPause == "function" || props.onPause === false) {
            cb_target.onPause(props.onPause);
    }
    
    if (typeof props.onStop == "function" || props.onStop === false) {
            cb_target.onStop(props.onStop);
    }
    
    if (typeof props.each_onFrame == "object" && typeof props.each_onFrame.length != "undefined") {
        var cb = props.each_onFrame;
        for (var i = 0; i < cb.length; i++) {
            this.onFrame(cb[i][0],cb[i][1]);
        }
    }
    
    if (typeof props.each_onEachFrame == "function" || props.each_onEachFrame === false) {
            this.onEachFrame(props.each_onEachFrame);
    }
    
    if (typeof props.each_onStart == "function" || props.each_onStart === false) {
            this.onStart(props.each_onStart);
    }
    
    if (typeof props.each_onEnd == "function" || props.each_onEnd === false) {
            this.onEnd(props.each_onEnd);
    }
    
    if (typeof props.each_onPlay == "function" || props.each_onPlay === false) {
            this.onPlay(props.each_onPlay);
    }
    
    if (typeof props.each_onPause == "function" || props.each_onPause === false) {
            this.onPause(props.each_onPause);
    }
    
    if (typeof props.each_onStop == "function" || props.each_onStop === false) {
            this.onStop(props.each_onStop);
    }
    return this;
    }
    
    A.addGroup = function(other_Group) {
        
        if (typeof other_Group.type == "undefined") {return this}
        
        if (other_Group.type == "group") {
            var res = other_Group.addSubTimeline(this.duplicate());
            this.become(res);
        } else if (other_Group.type == "timeline") {
            var res = CSSmu(this.duplicate(), other_Group);
            this.become(res);
        }
        
        return this;
        
    }
    
    A.addSubTimeline = function(){return this}
    A.setMainSubTimeline = function(){return this}
    A.subTimeline = function(){return this}
    
    return A;
    
}

CSSmu.create_Group = function() {
    
    var G = new Object;
    
    G.type = "group";
    G.name = false;
    G.frameCount = 0;
    G.frameRate = 0;
    G.frameInterval = 0;
    G.currentFrame = false;
    G.mode = false;
    G.selectors = new Array();
    G.restrictedTargets = new Array();
    G.excludedTargets = new Array();
    G.parentTimeline = G;
    G.isMainSubTimeline = false;
    G.frameCallbacks = new Array();
    G.tmp_frameCallback = false;
    G.onStartCallback = false;
    G.onEndCallback = false;
    G.onPlayCallback = false;
    G.onPauseCallback = false;
    G.onStopCallback = false;
    G.onEachFrameCallback = false;
    G.isPlaying = false;
    G.timer = false;
    
    G.subTimelines = new Array();
    G.mainSubTimeline = false;
    G.mainSubTimelineName = false;
    
    G.become = function(res) { CSSmu.transferProperties(this, res); return this}
    
    G.subTimeline = function(tl_name) {
        
        if (typeof tl_name == "number") {
            if (typeof this.subTimelines[tl_name] != "undefined") {
                return this.subTimelines[tl_name];
            }
            return false;
        }
        
       for (var i = 0; i < this.subTimelines.length; i++) {
           if (this.subTimelines[i].name == tl_name) {return this.subTimelines[i];}
        }
        return false;
    }
    
    G.addSubTimeline = function(new_tl) {
        var tl_name = new_tl.name;
        if (this.subTimeline(tl_name)) {return this}
        
       this.subTimelines.push(new_tl);
       new_tl.parentTimeline = this;
       if (new_tl.frameCount > this.frameCount) {
        this.setMainSubTimeline(new_tl);
       }
       
       return this;
    }
    
    G.setMainSubTimeline = function(tl) {
        if (typeof tl == "string") {tl = this.subTimeline(tl)}
        
        if (this.subTimelines.indexOf(tl) == -1) {
            alert('not found');
            return this;
        }
        
        this.frameCount = tl.frameCount;
        for (var i = 0; i < this.subTimelines.length; i++) {
            this.subTimelines[i].isMainSubTimeline = false;
        }
        tl.isMainSubTimeline = true;
        this.mainSubTimeline = tl;
        this.mainSubTimelineName = tl.name;
        if (tl.isPlaying) {this.isPlaying = true} else {this.isPlaying = false}
        return this;
    }
    
    var args = CSSmu.harmonize_arguments(arguments);
    
    for (var i = 0; i < args.length; i++) {
        G.addSubTimeline(args[i]);
    }
    
    G.setRate = function(new_rate) {
        for (var i = 0; i < this.subTimelines.length; i++) {
        this.subTimelines[i].setRate(new_rate);
        }
        return this;
        }
        
    G.setCurrentFrame = function(new_cf) {
        for (var i = 0; i < this.subTimelines.length; i++) {
            if (this.subTimelines[i].frameCount >= new_cf) {
        this.subTimelines[i].setCurrentFrame(new_cf);
            }
        }
        return this;
    }
        
    G.setMode = function(new_mode) {
        for (var i = 0; i < this.subTimelines.length; i++) {
        this.subTimelines[i].setMode(new_mode);
        }
        return this;
        }

    G.addSelector = function() {
        
        var args = CSSmu.harmonize_arguments(arguments);
        
        for (var i = 0; i < this.subTimelines.length; i++) {
    for (var j = 0; j < args.length; j++) {
        if (args[j] && args[j] != "" && args[j] != null) {
            this.subTimelines[i].selectors.push(args[j]);
        }
        }
        }
        return this;
    }
    G.addSelectors = G.addSelector;
        
    G.removeSelector = function() {
        
        var args = CSSmu.harmonize_arguments(arguments);
        
        for (var i = 0; i < this.subTimelines.length; i++) {
        for (var j = 0; j < args.length; j++) {
            if (this.subTimelines[i].selectors.indexOf(args[j]) != -1) {
            this.subTimelines[i].selectors.splice(this.subTimelines[i].selectors.indexOf(args[j]),1);
            }
        }
        }
        return this;
    }
    G.removeSelectors = G.removeSelector;
    
    G.clearSelectors = function() {
        for (var i = 0; i < this.subTimelines.length; i++) {
            this.subTimelines[i].selectors.length = 0;
        }
        return this;
    }
    
    G.resetSelectors = function() {
        for (var i = 0; i < this.subTimelines.length; i++) {
            this.subTimelines[i].resetSelectors();
        }
        return this;
    }
        
    G.restrictTo = function() {
        
        var args = CSSmu.harmonize_arguments(arguments);
        
        for (var i = 0; i < this.subTimelines.length; i++) {
        this.subTimelines[i].restrictedTargets.length = 0;
        if (arguments[0] !== false && arguments.length > 0) {
        for (var j = 0; j < args.length; j++) {
            if (args[j] && args[j] != "" && args[j] != null) {
            this.subTimelines[i].restrictedTargets.push(args[j]);
            }
        }
        }
        }
        return this;
    }
        
    G.exclude = function() {
        
        var args = CSSmu.harmonize_arguments(arguments);
        
        for (var i = 0; i < this.subTimelines.length; i++) {
        this.subTimelines[i].excludedTargets.length = 0;
        if (arguments[0] !== false && arguments.length > 0) {
        for (var j = 0; j < args.length; j++) {
            if (args[j] && args[j] != "" && args[j] != null) {
            this.subTimelines[i].excludedTargets.push(args[j]);
            }
        }
        }
        }
        return this;
    }
    
    G.onFrame = function(f, fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.frameCallbacks[f] = fct;
            return this;
            }
    
    G.onStart = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onStartCallback = fct;
            return this;
            }
            
    G.onEnd = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onEndCallback = fct;
            return this;
            }
            
    G.onPlay = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onPlayCallback = fct;
            return this;
            }
            
    G.onPause = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onPauseCallback = fct;
            return this;
            }
            
    G.onStop = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onStopCallback = fct;
            return this;
            }
            
    G.onEachFrame = function(fct) {
        if (typeof fct == "undefined" || !fct) {fct = false}
            this.onEachFrameCallback = fct;
            return this;
            }
            
    G.each_onFrame = function(f, fct) {
        for (var i = 0; i < this.subTimelines.length; i++) {
            this.subTimelines[i].onFrame(f,fct);
            }
            return this;
        }
    
    G.each_onStart = function(fct) {
        for (var i = 0; i < this.subTimelines.length; i++) {
            this.subTimelines[i].onStart(fct);
                }
            }
            
    G.each_onEnd = function(fct) {
        for (var i = 0; i < this.subTimelines.length; i++) {
            this.subTimelines[i].onEnd(fct);
                }
                return this;
            }
            
    G.each_onPlay = function(fct) {
        for (var i = 0; i < this.subTimelines.length; i++) {
            this.subTimelines[i].onPlay(fct);
                }
                return this;
            }
            
    G.each_onPause = function(fct) {
        for (var i = 0; i < this.subTimelines.length; i++) {
            this.subTimelines[i].onPause(fct);
                }
                return this;
            }
            
    G.each_onStop = function(fct) {
        for (var i = 0; i < this.subTimelines.length; i++) {
            this.subTimelines[i].onStop(fct);
                }
                return this;
            }
            
    G.each_onEachFrame = function(fct) {
        for (var i = 0; i < this.subTimelines.length; i++) {
            this.subTimelines[i].onEachFrame(fct);
                }
                return this;
            }
    
    G.displayFrame = function(f) {
       for (var i = 0; i < this.subTimelines.length; i++) {
            if (this.subTimelines[i].frameCount >= f) {
        this.subTimelines[i].displayFrame(f);
            }
        }
        return this;
    }
        
    G.play = function(ignore_callback) {
        ignore_callback = typeof ignore_callback != "undefined" ? ignore_callback : false;
        
        if (typeof this.onPlayCallback == "function" && !ignore_callback) {
            this.onPlayCallback();
        }
        
        for (var i = 0; i < this.subTimelines.length; i++) {
           this.subTimelines[i].play(ignore_callback); 
        }
        return this;
    }
    
    G.pause = function(ignore_callback) {
        if (!this.isPlaying) {return this}
        ignore_callback = typeof ignore_callback != "undefined" ? ignore_callback : false;
        
        if (typeof this.onPauseCallback == "function" && !ignore_callback) {
            this.onPauseCallback();
        }
        
        for (var i = 0; i < this.subTimelines.length; i++) {
           this.subTimelines[i].pause(ignore_callback); 
        }
        return this;
    }
    
    G.toggle = function() {
        if (this.isPlaying) {this.pause()}
        else {this.play()}
        return this;
    }
    
    G.stop = function() {

        if (typeof this.onStopCallback == "function") {
            this.onStopCallback();
        }
        
       for (var i = 0; i < this.subTimelines.length; i++) {
           this.subTimelines[i].stop(); 
        }
        return this;
    }
    
    G.clean = function() {
       for (var i = 0; i < this.subTimelines.length; i++) {
           this.subTimelines[i].clean(); 
        }
        return this;
    }
    
    G.duplicate = function() {
       var new_G = CSSmu.create_Group();
       
       for (var i = 0; i < this.subTimelines.length; i++) {
           var new_A = this.subTimelines[i].duplicate();
           new_G.addSubTimeline(new_A);
        }
        
        new_G.setMainSubTimeline(new_G.subTimeline(G.mainSubTimeline.name));
        
        new_G.frameCallbacks = this.frameCallbacks.slice(0);
        new_G.onStartCallback = this.onStartCallback;
        new_G.onEndCallback = this.onEndCallback;
        new_G.onPlayCallback = this.onPlayCallback;
        new_G.onPauseCallback = this.onPauseCallback;
        new_G.onStopCallback = this.onStopCallback;
        new_G.onEachFrameCallback = this.onEachFrameCallback;
       
       return new_G;
    }
    
    G.updateSettings = function(props, ignore_namechange) {
        ignore_namechange = typeof ignore_namechange != "undefined" ? ignore_namechange : true;
       for (var i = 0; i < this.subTimelines.length; i++) {
           this.subTimelines[i].updateSettings(props, ignore_namechange, true); 
        }
        return this;
    }
    
    G.addGroup = function(other_Group) {
        
        if (typeof other_Group.type == "undefined") {return this}
        
        if (other_Group.type == "group") {
        for (var i = 0; i < other_Group.subTimelines.length; i++) {
            var new_TL = other_Group.subTimelines[i];
            this.addSubTimeline(new_TL);
        }
        } else if (other_Group.type == "timeline") {
            this.addSubTimeline(other_Group);
        }
        
        return this;
    }
    
    G.siblingTimeline = function(){return this}
    
    return G;
    
}

CSSmu.transferProperties = function(target, source) {
    
    var src_propnames = Object.keys(source);
    for (var i = 0; i < src_propnames.length; i++) {
    target[src_propnames[i]] = source[src_propnames[i]];
    }
    return target;
}