docs: function(rawAttributeString, rawText, apool){
      var extractedText = "";
      var hasLineAttributes = false;
      var lineAttributes = [];
      var inlineAttributeString;
      var listLevel = 0;
      var listTypeName;
      
      
      function _analyzeLists () {
          // identify list
          listLevel = 0;
          if (rawAttributeString) {
              var opIter = Changeset.opIterator(rawAttributeString);
              if (opIter.hasNext()) {
                  var listType = Changeset.opAttributeValue(opIter.next(), 'list', apool);
  
                  if (listType) {
                      var listTypeParts = /([a-z]+)([12345678])/.exec(listType);
                      if (listTypeParts) {
                          listTypeName = listTypeParts[1];
                          listLevel = Number(listTypeParts[2]);
                      }
                  }
              }
          }
      }
      
      function _analyzeLineAttributes () {
          var lineMarkerFound = false;
  
          // start lineMarker (lmkr) check
          var firstCharacterOfLineOpIterator = Changeset.opIterator(Changeset.subattribution(rawAttributeString, 0, 1));
  
          if (firstCharacterOfLineOpIterator.hasNext()) {
              var singleOperation = firstCharacterOfLineOpIterator.next();
  
              // iterate through attributes
              Changeset.eachAttribNumber(singleOperation.attribs, function (a) {
                  lineAttributes.push([apool.numToAttrib[a][0], apool.numToAttrib[a][1]]);
  
                  if (apool.numToAttrib[a][0] === "lmkr") {
                      lineMarkerFound = true;
                  }
              });
          }
          
          hasLineAttributes = lineMarkerFound;
          
          if (hasLineAttributes) {
              // line text without linemarker ("*")
              extractedText = rawText.substring(1);
              inlineAttributeString = Changeset.subattribution(rawAttributeString, 1);
          } else {
              extractedText = rawText;
              inlineAttributeString = rawAttributeString;
          }
      }
      
      _analyzeLists();
      _analyzeLineAttributes();
      
      var _attributeStringWithoutListAttributes = function(attributeString) {
          var opIterator = Changeset.opIterator(attributeString);
          var filteredAttributeString = "";
          
          while (opIterator.hasNext()) {
              var nextOperation = opIterator.next();
              var filteredAttributes = Changeset.filterAttribNumbers(nextOperation.attribs, function (a) {
                  return !_isListAttribute(apool.numToAttrib[a][0]);
              });
              nextOperation.attribs = filteredAttributes;
              filteredAttributeString += Changeset.opString(nextOperation);
          }
          return filteredAttributeString;
      };
      
      
      var hasList = function(){
          return listLevel > 0;
      };
      
      var _withoutListAttributes = function(attributes) {
          return attributes.filter(function(item) {
              return !_isListAttribute(item[0]);
          });
      };
      
      var _withoutLmkrAttributes = function(attributes) {
          return attributes.filter(function(item) {
              return !_isLinemarkerAttribute(item[0]);
          });
      };
      
      var _hasNonlistLineAttributes = function() {
          return _withoutListAttributes(_withoutLmkrAttributes(lineAttributes)).length > 0;
      };
      
      /**
       * splits the line into line attributes and the remaining plain text and inline attributes
       * depending on the given parameters 
       * @param {Boolean} listsEnabled if the client sent the parameter lists=true
       * @param {Boolean} lineAttributesEnabled if the client sent the parameter lineattribs=true
       * @return {lineAttributes: Array, inlineAttributeString: String, inlinePlaintext: String}
       */
      var extractLineAttributes = function(listsEnabled, lineAttributesEnabled) {
          if ((!hasList() && !hasLineAttributes) || (!listsEnabled && !lineAttributesEnabled)) {
                  return {
                      lineAttributes: [],
                      inlineAttributeString: rawAttributeString,
                      inlinePlaintext: rawText
                  };
              }
              
              if (listsEnabled && !lineAttributesEnabled) {
                  if (hasList() && _hasNonlistLineAttributes()) {
                      return {
                          lineAttributes: [],
                          inlineAttributeString: _attributeStringWithoutListAttributes(rawAttributeString),
                          inlinePlaintext: rawText
                      };
                  } else if (hasList() && !_hasNonlistLineAttributes()){
                      return {
                          lineAttributes: [],
                          inlineAttributeString: inlineAttributeString,
                          inlinePlaintext: extractedText
                      };
                  } else if (!hasList() && hasLineAttributes){
                      return {
                          lineAttributes: [],
                          inlineAttributeString: rawAttributeString,
                          inlinePlaintext: rawText
                      };
                  } else {
                      console.error("Plugin error: it seems the developer missed a case here.");
                  }
              } else if (listsEnabled && lineAttributesEnabled) {
                  if (_hasNonlistLineAttributes()) {
                      return {
                          lineAttributes: _withoutListAttributes(lineAttributes),
                          inlineAttributeString: inlineAttributeString,
                          inlinePlaintext: extractedText
                      };
                  } else {
                      return {
                          lineAttributes: [],
                          inlineAttributeString: inlineAttributeString,
                          inlinePlaintext: extractedText
                      };
                  }
              } else if (!listsEnabled && lineAttributesEnabled) {
                  return {
                      lineAttributes: lineAttributes,
                      inlineAttributeString: inlineAttributeString,
                      inlinePlaintext: extractedText
                  };
              } else {
                  console.error("Plugin error: it seems the developer missed a case here.");
              }
      };
      
      
      return {
          getPlaintext: function(removeLinemarker){
              return removeLinemarker ? extractedText : rawText;
          },
          getAttributeString: function(removeLineAttributes){
              return removeLineAttributes ? inlineAttributeString : rawAttributeString;
          },
          hasLineAttributes: function(){
              return hasLineAttributes;
          },
          getLineAttributes: function() {
              return lineAttributes;
          },
          extractLineAttributes: extractLineAttributes,
          hasList: hasList,
          getListLevel: function(){
              return listLevel;
          },
          getListType: function(){
              return listTypeName;
          }
          
      };
  }