whole_func_string: function(lineNum){
          var Changeset = require('ep_etherpad-lite/static/js/Changeset');
          var ChangesetUtils = require('ep_etherpad-lite/static/js/ChangesetUtils');
          var _ = require('ep_etherpad-lite/static/js/underscore');
  
          var aline = Cristo.rep.alines[lineNum];
          if(aline){
              var entry = Cristo.rep.lines.atIndex(lineNum);
              var text = entry.text;
              var opIter = Changeset.opIterator(aline);
              var ci = -1;
              var bci = -1;
              var attributes = [];
              while (opIter.hasNext()) {
                  var op = opIter.next();
                  bci = ci + 1;
                  ci += op.chars;
                  Changeset.eachAttribNumber(op.attribs, function (n) {
                      if(bci > text.length){ return; }
                      attributes.push({
                          name: Cristo.rep.apool.getAttribKey(n),
                          value: Cristo.rep.apool.getAttribValue(n),
                          offset: bci,
                          limit: ci - bci + 1,
                          charStart: text[bci],
                          charEnd: text[Math.min(ci, text.length - 1)],
                          remove: function(withChar, limit){
                              limit = Math.min(this.offset + ( limit>0? limit:this.limit ), entry.width);
                              var builder = Changeset.builder(Cristo.rep.lines.totalWidth());
                              if(withChar){
                                  ChangesetUtils.buildKeepToStartOfRange(Cristo.rep, builder, [lineNum, this.offset]);
                                  ChangesetUtils.buildRemoveRange(Cristo.rep, builder, [lineNum, this.offset], [lineNum, limit]);
                              } else{
                                  var attribs = _replaceAttrib(this);
                                  //console.log('rm', attribs, this.name, this.value, 'ch: '+this.char, 'l', lineNum, this.offset, limit);
                                  ChangesetUtils.buildKeepToStartOfRange(Cristo.rep, builder, [lineNum, this.offset]);
                                  ChangesetUtils.buildKeepRange(Cristo.rep, builder, [lineNum, this.offset], [lineNum, limit], attribs, Cristo.rep.apool);
                              }
                              return Cristo.documentAttributeManager.applyChangeset(builder);
                          },
                          changeValue:function(newValue, limit){
                              limit = Math.min(this.offset + ( limit>0? limit:this.limit ), entry.width);
                              var builder = Changeset.builder(Cristo.rep.lines.totalWidth());
                              var attribs = _replaceAttrib(this, newValue);
                              ChangesetUtils.buildKeepToStartOfRange(Cristo.rep, builder, [lineNum, this.offset]);
                              ChangesetUtils.buildKeepRange(Cristo.rep, builder, [lineNum, this.offset], [lineNum, limit], attribs, Cristo.rep.apool);
                              return Cristo.documentAttributeManager.applyChangeset(builder);
                          }
                      });
                  });
              }
  
              var _replaceAttrib = function(cont, value){
                  value = value || '';
                  return _.chain(attributes).map(function(a){
                      if(a.offset === cont.offset && a.char === cont.char){
                          if(a.name === cont.name && a.value === cont.value){
                              return [a.name, value];
                          }
                      }
                  }).filter(function(v){return v;}).value();
              };
  
              return attributes;
          }
          return [];
      }
func_code_string: function(lineNum){
          var Changeset = require('ep_etherpad-lite/static/js/Changeset');
          var ChangesetUtils = require('ep_etherpad-lite/static/js/ChangesetUtils');
          var _ = require('ep_etherpad-lite/static/js/underscore');
  
          var aline = Cristo.rep.alines[lineNum];
          if(aline){
              var entry = Cristo.rep.lines.atIndex(lineNum);
              var text = entry.text;
              var opIter = Changeset.opIterator(aline);
              var ci = -1;
              var bci = -1;
              var attributes = [];
              while (opIter.hasNext()) {
                  var op = opIter.next();
                  bci = ci + 1;
                  ci += op.chars;
                  Changeset.eachAttribNumber(op.attribs, function (n) {
                      if(bci > text.length){ return; }
                      attributes.push({
                          name: Cristo.rep.apool.getAttribKey(n),
                          value: Cristo.rep.apool.getAttribValue(n),
                          offset: bci,
                          limit: ci - bci + 1,
                          charStart: text[bci],
                          charEnd: text[Math.min(ci, text.length - 1)],
                          remove: function(withChar, limit){
                              limit = Math.min(this.offset + ( limit>0? limit:this.limit ), entry.width);
                              var builder = Changeset.builder(Cristo.rep.lines.totalWidth());
                              if(withChar){
                                  ChangesetUtils.buildKeepToStartOfRange(Cristo.rep, builder, [lineNum, this.offset]);
                                  ChangesetUtils.buildRemoveRange(Cristo.rep, builder, [lineNum, this.offset], [lineNum, limit]);
                              } else{
                                  var attribs = _replaceAttrib(this);
                                  //console.log('rm', attribs, this.name, this.value, 'ch: '+this.char, 'l', lineNum, this.offset, limit);
                                  ChangesetUtils.buildKeepToStartOfRange(Cristo.rep, builder, [lineNum, this.offset]);
                                  ChangesetUtils.buildKeepRange(Cristo.rep, builder, [lineNum, this.offset], [lineNum, limit], attribs, Cristo.rep.apool);
                              }
                              return Cristo.documentAttributeManager.applyChangeset(builder);
                          },
                          changeValue:function(newValue, limit){
                              limit = Math.min(this.offset + ( limit>0? limit:this.limit ), entry.width);
                              var builder = Changeset.builder(Cristo.rep.lines.totalWidth());
                              var attribs = _replaceAttrib(this, newValue);
                              ChangesetUtils.buildKeepToStartOfRange(Cristo.rep, builder, [lineNum, this.offset]);
                              ChangesetUtils.buildKeepRange(Cristo.rep, builder, [lineNum, this.offset], [lineNum, limit], attribs, Cristo.rep.apool);
                              return Cristo.documentAttributeManager.applyChangeset(builder);
                          }
                      });
                  });
              }
  
              var _replaceAttrib = function(cont, value){
                  value = value || '';
                  return _.chain(attributes).map(function(a){
                      if(a.offset === cont.offset && a.char === cont.char){
                          if(a.name === cont.name && a.value === cont.value){
                              return [a.name, value];
                          }
                      }
                  }).filter(function(v){return v;}).value();
              };
  
              return attributes;
          }
          return [];
      }
func_documentation_string: Gets all attributes on line. Any attribute is nice described, and provides functions such remove, or changeValue.
  attribute.remove(withChar, limit) - remove attribute to the limit, if withChar == true then characters will be removed too.
  attribute.changeValue(newValue, limit) - replace current value on new to the limit
  - default limit is a count of following chars, which have the same attribute.
  TIP: It should be called from stack callWithAce (inside)
  @example: You can use Cristo.callWithAce(function(ace){Cristo.getAllAttributesOnLine()},'myCall')
  @param lineNum {Number}
  @returns {Array} of objects like this one {name, value, offset, limit, charStart, charEnd, remove(), changeValue()}