Show:
                        import Ember from "ember";
                        import EmberObjectUtils from "ember-object-utils";
                        import EmberTimerUtils from "ember-timer-utils";
                        import binaryInsert from "./binaryInsert";
                        import ArrayModifierTypes from "./array-modifier-types/index";
                        import ArrayModifierGroups from "./array-modifier-groups/index";
                        
                        /**
                         * ArrayModifierMixin modifies array in "content" and puts it in "arrangedContent".
                         *
                         * @class ArrayModifier.ArrayModifierMixin
                         */
                        //TODO : revisit the observers addition and deletion
                        export default Ember.Mixin.create(EmberObjectUtils.ObjectWithArrayMixin, {
                          init : function() {
                            this._super();
                            //add a sort on _originalIndex with least priority to maintain the original order at the end
                            this.get("arrayModifierGrps").pushObject(ArrayModifierGroups.ArrayModifierGroupsMap.sort.create({
                              arrayModifiers : Ember.A([
                                ArrayModifierTypes.ArrayModifiersMap.sort.create({
                                  property : "_originalIndex",
                                  priority : 10,
                                }),
                              ]),
                            }));
                          },
                        
                          unique_id : Ember.computed(function() {
                            return EmberObjectUtils.getEmberId(this);
                          }),
                        
                          /**
                           * Array mods added to the controller.
                           *
                           * @property arrayModifiers
                           * @type Array
                           */
                          arrayModifiers : EmberObjectUtils.hasMany(ArrayModifierTypes.ArrayModifiersMap, "type"),
                          //arrayModifiers : null,
                        
                          /**
                           * Array mods groups formed by arrayModifiers.
                           *
                           * @property arrayModifierGrps
                           * @type Array
                           * @readOnly
                           */
                          arrayModifierGrps : EmberObjectUtils.hasMany(ArrayModifierGroups.ArrayModifierGroupsMap, "type"),
                          //arrayModifierGrps : null,
                        
                          arrayProps : ["arrayModifiers", "arrayModifierGrps"],
                          //not firing on adding new objects!
                          isModified : Ember.computed("arrayModifierGrps.@each", function() {
                            var arrayModifierGrps = this.get("arrayModifierGrps");
                            return !!arrayModifierGrps && arrayModifierGrps.length > 0;
                          }),
                        
                          addArrayModifierToGroup : function(arrayModifier) {
                            var arrayModifierGrps = this.get("arrayModifierGrps"), arrayModifierGrp = arrayModifierGrps.findBy("type", arrayModifier.get("groupType")),
                                arrayModifiers = this.get("arrayModifiers");
                            if(arrayModifierGrp) {
                              binaryInsert(arrayModifierGrp.get("arrayModifiers"), arrayModifier, function(a, b) {
                                var priority = ArrayModifierGroups.compare(a.get("priority"), b.get("priority"));
                                if(priority === 0) {
                                  return ArrayModifierGroups.compare(arrayModifiers.indexOf(a), arrayModifiers.indexOf(b));
                                }
                                return priority;
                              });
                            }
                            else {
                              arrayModifierGrp = ArrayModifierGroups.ArrayModifierGroupsMap[arrayModifier.get("groupType")].create({
                                arrayModifiers : Ember.A([arrayModifier]),
                              });
                              binaryInsert(arrayModifierGrps, arrayModifierGrp, function(a, b) {
                                return ArrayModifierGroups.compare(a.get("priority"), b.get("priority"));
                              });
                            }
                          },
                        
                          removeArrayModifierFromGroup : function(arrayModifier) {
                            var arrayModifierGrps = this.get("arrayModifierGrps"), arrayModifierGrp = arrayModifierGrps.findBy("type", arrayModifier.get("groupType")),
                                arrayModifiers = arrayModifierGrp.get("arrayModifiers");
                            if(arrayModifierGrp) {
                              arrayModifiers.removeObject(arrayModifier);
                              if(arrayModifiers.length === 0) {
                                arrayModifierGrps.removeObject(arrayModifierGrp);
                              }
                            }
                          },
                        
                          arrayModifiersWillBeDeleted : function(deletedArrayModifiers/*, idx*/) {
                            var content = this.get("content") || Ember.A([]), arrangedContent = this.get("arrangedContent"),
                                that = this;
                            deletedArrayModifiers.forEach(function(arrayModifier) {
                              arrayModifier.removeModifierObservers(this, "arrayModifiersDidChange");
                              content.forEach(function(item) {
                                if(arrayModifier.get("addObserverToAll") || arrangedContent.contains(item)) {
                                  Ember.addObserver(item, arrayModifier.get("property"), this, "contentItemPropertyDidChange");
                                }
                              }, this);
                              this.removeArrayModifierFromGroup(arrayModifier);
                            }, this);
                            EmberTimerUtils.addToQue(this.get("unique_id")+"__ArrayModifierChanged", 250).then(function() {
                              that.notifyPropertyChange("arrangedContent");
                            });
                          },
                        
                          arrayModifiersWasAdded : function(addedArrayModifiers/*, idx*/) {
                            var content = this.get("content") || Ember.A([]), arrangedContent = this.get("arrangedContent"),
                                that = this;
                            addedArrayModifiers.forEach(function(arrayModifier) {
                              arrayModifier.addModifierObservers(this, "arrayModifiersDidChange");
                              content.forEach(function(item) {
                                if(arrayModifier.get("addObserverToAll") || arrangedContent.contains(item)) {
                                  Ember.removeObserver(item, arrayModifier.get("property"), this, "contentItemPropertyDidChange");
                                }
                              }, this);
                              this.addArrayModifierToGroup(arrayModifier);
                            }, this);
                            EmberTimerUtils.addToQue(this.get("unique_id")+"__ArrayModifierChanged", 250).then(function() {
                              that.notifyPropertyChange("arrangedContent");
                            });
                          },
                        
                          addObserversToItemsPerModifier : function(override, arranged, propKey) {
                            var arrayModifiers = this.get("arrayModifiers");
                            arrayModifiers.forEach(function(arrayModifier) {
                              this.addObserversToItems(arrayModifier, override, arranged, propKey);
                            }, this);
                          },
                        
                          addObserversToItems : function(arrayModifier, override, arranged, propKey) {
                            var content = override || this.get("content") || Ember.A([]), arrangedContent = arranged || this.get("arrangedContent"),
                                _propKey = propKey || "property";
                            content.forEach(function(item) {
                              if(arrayModifier.get("addObserverToAll") || arrangedContent.contains(item)) {
                                Ember.addObserver(item, arrayModifier.get(_propKey), this, "contentItemPropertyDidChange");
                              }
                            }, this);
                          },
                        
                          removeObserversFromItemsPerModifier : function(override, arranged, propKey) {
                            var arrayModifiers = this.get("arrayModifiers");
                            arrayModifiers.forEach(function(arrayModifier) {
                              this.removeObserversFromItems(arrayModifier, override, arranged, propKey);
                            }, this);
                          },
                        
                          removeObserversFromItems : function(arrayModifier, override, arranged, propKey) {
                            var content = override || this.get("content") || Ember.A([]), arrangedContent = arranged || this.get("arrangedContent"),
                                _propKey = propKey || "property";
                            content.forEach(function(item) {
                              if(arrayModifier.get("addObserverToAll") || arrangedContent.contains(item)) {
                                Ember.removeObserver(item, arrayModifier.get(_propKey), this, "contentItemPropertyDidChange");
                              }
                            }, this);
                          },
                        
                          arrayModifiersDidChange : function(obj, key) {
                            var that = this, lastVal = obj.get("_" + key);
                            if(key === "property" && lastVal) {
                              this.removeObserversFromItems(obj, null, null, "_" + key); 
                            }
                            EmberTimerUtils.addToQue(this.get("unique_id")+"__ArrayModifierChanged", 250).then(function() {
                              that.notifyPropertyChange("arrangedContent");
                            });
                          },
                        
                          arrayModifiersDidChange_each : function(/*obj, key*/) {
                            var that = this;
                            EmberTimerUtils.addToQue(this.get("unique_id")+"__ArrayModifierChanged_Each", 500).then(function() {
                              var content = that.get("content"), arrangedContent = that.get("arrangedContent"),
                                  arrayModifierGrps = that.get("arrayModifierGrps");
                              //enclose the operation in a run loop to decrease the view render overhead
                              Ember.run(function() {
                                content.forEach(function(item) {
                                  var inArrangedContent = arrangedContent.contains(item),
                                      canAdd = true;
                                  arrayModifierGrps.forEach(function(arrayModifierGrp) {
                                    if(!arrayModifierGrp.canAdd(item)) {
                                      canAdd = false;
                                    }
                                  }, this);
                                  if(inArrangedContent && !canAdd) {
                                    arrangedContent.removeObject(item);
                                  }
                                  else if(!inArrangedContent && canAdd) {
                                    //need break functionality, so using for
                                    for(var j = 0; j < arrayModifierGrps.length; j++) {
                                      if(!arrayModifierGrps[j].modifySingle(arrangedContent, item, arrangedContent.indexOf(item))) {
                                        break;
                                      }
                                    }
                                  }
                                }, this);
                              });
                            });
                          },
                        
                          destroy : function() {
                            this.removeObserversFromItemsPerModifier();
                            return this._super();
                          },
                        
                          arrangedContent : Ember.computed("content", function() {
                            var content = this.get("content"), arrangedContent,
                                arrayModifierGrps = this.get("arrayModifierGrps"),
                                isModified = !!arrayModifierGrps && arrayModifierGrps.length > 0,
                                hasContent = content && (content.length > 0 || (content.get && content.get("length") > 0));
                        
                            if(hasContent) {
                              content.forEach(function(item, idx) {
                                item.set("_originalIndex", idx);
                              });
                              arrangedContent = Ember.A(content.slice());
                              if(isModified) {
                                arrayModifierGrps.forEach(function(arrayModifierGrp) {
                                  if(arrangedContent.length > 0) {
                                    arrangedContent = arrayModifierGrp.modify(arrangedContent);
                                  }
                                }, this);
                                this.addObserversToItemsPerModifier(content, arrangedContent);
                              }
                              return Ember.A(arrangedContent);
                            }
                        
                            return Ember.A([]);
                          }),
                        
                          _contentWillChange : Ember.beforeObserver("content", function() {
                            this.removeObserversFromItemsPerModifier();
                            this._super();
                          }),
                        
                          contentArrayWillChange : function(array, idx, removedCount/*, addedCount*/) {
                            var isModified = this.get("isModified");
                            if(isModified) {
                              var arrangedContent = this.get("arrangedContent"),
                                  removedObjects = array.slice(idx, idx+removedCount);
                              this.removeObserversFromItemsPerModifier(removedObjects);
                              removedObjects.forEach(function(item) {
                                item.set("_originalIndex", -1);
                                arrangedContent.removeObject(item);
                              });
                            }
                          },
                        
                          contentArrayDidChange : function(array, idx, removedCount, addedCount) {
                            var isModified = this.get("isModified");
                            if(isModified) {
                              var arrangedContent = this.get("arrangedContent"),
                                  addedObjects = array.slice(idx, idx+addedCount),
                                  arrayModifierGrps = this.get("arrayModifierGrps");
                              this.addObserversToItemsPerModifier(addedObjects);
                              //TODO : handle this in a better way than looping through the whole array
                              for(var i = idx + 1; i < array.length; i++) {
                                array[i].set("_originalIndex", i);
                              }
                              addedObjects.forEach(function(item, i) {
                                item.set("_originalIndex", i + idx);
                                for(var j = 0; j < arrayModifierGrps.length; j++) {
                                  if(!arrayModifierGrps[j].modifySingle(arrangedContent, item, arrangedContent.indexOf(item))) {
                                    break;
                                  }
                                }
                              });
                            }
                          },
                        
                          contentItemPropertyDidChange : function(item) {
                            var arrayModifierGrps = this.get("arrayModifierGrps"),
                                arrangedContent = this.get("arrangedContent");
                            for(var i = 0; i < arrayModifierGrps.length; i++) {
                              if(!arrayModifierGrps[i].modifySingle(arrangedContent, item, arrangedContent.indexOf(item))) {
                                break;
                              }
                            }
                          },
                        });