whole_func_string: function sendAsset (res,assetDocument,options) {
          var data,
              id;
  
          if (assetDocument.metadata && assetDocument.metadata['content-type']) {
              res.setHeader('Content-Type', assetDocument.metadata['content-type']);
          } else {
              res.setHeader('Content-Type', 'text/plain');
          }
  
          data = assetDocument.data;
            id = assetDocument.id;
  
  
          /*
           *	Performs transformations on an image
           *	TODO: Think about a more generic way to perform other transformations.
           *	TODO: Implement filters
           */
          if (options && options.transform)  {
              var aspectRatio       = assetDocument.metadata.aspectRatio.value,
                  width             = parseInt (options.transform.width,10) || assetDocument.metadata.width,  //Use the original values, since the transformation uses the lower value, aspect ratio gets corrected
                  height            = parseInt (options.transform.height,10) || assetDocument.metadata.height,
                  scale_mode        = options.transform.scale_mode==='fit'?'':'!', //gm accepts an third parameter "options" which forces a resize when set to '!'
                  transformData     = {},  // contains the data, applied to their respectice transform function from gm
                  transformOrderDef = ["resize","crop"], //The default transformorder
                  transformOrder    = options.transform.transform, //Weakly match length to filter all falsy values, if no transform order was specified, use the default one.
                  cropCoords        = options.transform.cropCoords,
                  cleanedCoords  = [], // [width,height,x,y]
                  cropSize,
                  parsedCoords, //JSON parsed cropCoords
                  gmInstance,
                  tmpCond, //used to temporarily assign test conditions
                  query,
                  max;
  
              //Parse the transformorder
              if (transformOrder) {
                  try {
                      transformOrder = JSON.parse (transformOrder); //Should be assigned to its own variable
                  } catch (e) {
                      transformOrder = transformOrderDef;
                  }
              } else {
                  transformOrder = transformOrderDef;
              }
  
              /*
               *  preserve the right values for width and height, to match the aspect ratio if scale mode is fit
               *	We need to normalize the data to e.g. get the same cached version for w: 50 h: 7889 and w:50 h: 123
               */
  
              if (scale_mode !== '!') { //'' == false.
                  max = Math.max (width,height);
                  if (width === max) {
                      width  = Math.round (height * aspectRatio);	//Round it if the aspect ratio * height is not an int
                  } else if (height === max) {
                      height = Math.round (width / aspectRatio);
                  }
              }
  
  
  
              //If the aspect ratio matches the original, scale_mode:fill should be corrected, to make sure the cached assets are the same
              if ((width / height).toPrecision (5) === aspectRatio.toPrecision (5)) {
                  scale_mode = '';
              }
  
              // reformat the cropcoords vlaue to be able to directly apply it on the crop function of gm
              if (typeof cropCoords !== 'undefined') {
                  try {
                      parsedCoords = JSON.parse (cropCoords);
  
                      //The sum of the cropcoords, only a value > 0 makes sense...
                      tmpCond = parsedCoords.reduce (function sum (a,b) {
                          return a + (Array.isArray (b)?b.reduce (sum,0):b);
                      },0);
  
                      if (transformOrder.indexOf ("crop") > transformOrder.indexOf ("resize")) {
                          cropSize = [width,height];   //If the cropping should happen after the resizing, we should use the resized images width and height for reference
                      } else {
                          cropSize = [assetDocument.metadata.width,assetDocument.metadata.height]; //otherwise we use the original image size as reference for the cropping
                      }
  
                      //TODO: Handle negative new width and rheight values
                      if (tmpCond > 0) {
                          cleanedCoords [0] = cropSize [0] - parsedCoords [1][0];	//new width
                          cleanedCoords [1] = cropSize [1] - parsedCoords [1][1];	//new height
                          cleanedCoords [2] = parsedCoords [0][0];	//x
                          cleanedCoords [3] = parsedCoords [0][1];	//y
                      }
  
                      tmpCond = null;
                  } catch (e) {
                      //don't crop the image if false values have been passed
                  }
              }
  
              //If the recaalculated width and height either match the original size or are larger, use the original image.
              if (width >= assetDocument.metadata.width && height >= assetDocument.metadata.height && cleanedCoords.length === 0) {
                  res.writeHead(200);
                  return  res.end(data);
              }
  
  
              query = {
                  parentId: id,
                  'transforms.width':width,
                  'transforms.height':height,
                   'transforms.scale_mode':scale_mode,
                   'transforms.cropCoords': cleanedCoords,
                   'transforms.transformOrder': transformOrder
               };	//The query to find the cached version, if existent
  
  
              Asset.findOne (query,'parentId transforms data', function (err, cachedAssetDocument) {
                  if (!cachedAssetDocument) {	//If no transformed asset exists with the given parameters
                      cachedAssetDocument = new Asset ();	//we create a new one, and save it in the mongodb
  
                      //Define the data that should be passed to the different transformation methods
                      transformData.resize = [width, height, scale_mode];
                      transformData.crop = cleanedCoords;
  
                      gmInstance = gm (data);
  
                      /*	Iterate over the transformations that shopuld be performed, in their (optionally) defined order.
                       *	check if we have a defined dataset that can be applied to the transformation
                       *	and if the data exists
                       */
                      for (var i = 0,transformation,currentData; i < transformOrder.length; i++) {
                          transformation = transformOrder [i];
                          currentData = transformData [transformation];
                          if (currentData && currentData.length > 0) {
                              gmInstance [transformation].apply (gmInstance, currentData);
                          }
                      }
  
  
                      //When the transformations were applied, save the resulting image and return its buffer
                      gmInstance.toBuffer (function (err,buffer) {
                          if (err) { next(err); }
  
                          cachedAssetDocument.data       = buffer;
                          cachedAssetDocument.parentId   = id;
                          cachedAssetDocument.transforms = {
                              width: width,
                              height: height,
                              cropCoords: cleanedCoords,
                              transformOrder: transformOrder,
                              scale_mode: scale_mode
                          };
  
                          cachedAssetDocument.save ( function (err) {
                              if (err) { next(err); }
                              res.send (buffer);
                          });
                      });
                  } else {  //Otherwise send back the cached version
                      res.send (cachedAssetDocument.data);
                  }
              });
          } else {
              res.writeHead(200);
              return  res.end(data);
          }
      }
func_code_string: function sendAsset (res,assetDocument,options) {
          var data,
              id;
  
          if (assetDocument.metadata && assetDocument.metadata['content-type']) {
              res.setHeader('Content-Type', assetDocument.metadata['content-type']);
          } else {
              res.setHeader('Content-Type', 'text/plain');
          }
  
          data = assetDocument.data;
            id = assetDocument.id;
  
  
          /*
           *	Performs transformations on an image
           *	TODO: Think about a more generic way to perform other transformations.
           *	TODO: Implement filters
           */
          if (options && options.transform)  {
              var aspectRatio       = assetDocument.metadata.aspectRatio.value,
                  width             = parseInt (options.transform.width,10) || assetDocument.metadata.width,  //Use the original values, since the transformation uses the lower value, aspect ratio gets corrected
                  height            = parseInt (options.transform.height,10) || assetDocument.metadata.height,
                  scale_mode        = options.transform.scale_mode==='fit'?'':'!', //gm accepts an third parameter "options" which forces a resize when set to '!'
                  transformData     = {},  // contains the data, applied to their respectice transform function from gm
                  transformOrderDef = ["resize","crop"], //The default transformorder
                  transformOrder    = options.transform.transform, //Weakly match length to filter all falsy values, if no transform order was specified, use the default one.
                  cropCoords        = options.transform.cropCoords,
                  cleanedCoords  = [], // [width,height,x,y]
                  cropSize,
                  parsedCoords, //JSON parsed cropCoords
                  gmInstance,
                  tmpCond, //used to temporarily assign test conditions
                  query,
                  max;
  
              //Parse the transformorder
              if (transformOrder) {
                  try {
                      transformOrder = JSON.parse (transformOrder); //Should be assigned to its own variable
                  } catch (e) {
                      transformOrder = transformOrderDef;
                  }
              } else {
                  transformOrder = transformOrderDef;
              }
  
              /*
               *  preserve the right values for width and height, to match the aspect ratio if scale mode is fit
               *	We need to normalize the data to e.g. get the same cached version for w: 50 h: 7889 and w:50 h: 123
               */
  
              if (scale_mode !== '!') { //'' == false.
                  max = Math.max (width,height);
                  if (width === max) {
                      width  = Math.round (height * aspectRatio);	//Round it if the aspect ratio * height is not an int
                  } else if (height === max) {
                      height = Math.round (width / aspectRatio);
                  }
              }
  
  
  
              //If the aspect ratio matches the original, scale_mode:fill should be corrected, to make sure the cached assets are the same
              if ((width / height).toPrecision (5) === aspectRatio.toPrecision (5)) {
                  scale_mode = '';
              }
  
              // reformat the cropcoords vlaue to be able to directly apply it on the crop function of gm
              if (typeof cropCoords !== 'undefined') {
                  try {
                      parsedCoords = JSON.parse (cropCoords);
  
                      //The sum of the cropcoords, only a value > 0 makes sense...
                      tmpCond = parsedCoords.reduce (function sum (a,b) {
                          return a + (Array.isArray (b)?b.reduce (sum,0):b);
                      },0);
  
                      if (transformOrder.indexOf ("crop") > transformOrder.indexOf ("resize")) {
                          cropSize = [width,height];   //If the cropping should happen after the resizing, we should use the resized images width and height for reference
                      } else {
                          cropSize = [assetDocument.metadata.width,assetDocument.metadata.height]; //otherwise we use the original image size as reference for the cropping
                      }
  
                      //TODO: Handle negative new width and rheight values
                      if (tmpCond > 0) {
                          cleanedCoords [0] = cropSize [0] - parsedCoords [1][0];	//new width
                          cleanedCoords [1] = cropSize [1] - parsedCoords [1][1];	//new height
                          cleanedCoords [2] = parsedCoords [0][0];	//x
                          cleanedCoords [3] = parsedCoords [0][1];	//y
                      }
  
                      tmpCond = null;
                  } catch (e) {
                      //don't crop the image if false values have been passed
                  }
              }
  
              //If the recaalculated width and height either match the original size or are larger, use the original image.
              if (width >= assetDocument.metadata.width && height >= assetDocument.metadata.height && cleanedCoords.length === 0) {
                  res.writeHead(200);
                  return  res.end(data);
              }
  
  
              query = {
                  parentId: id,
                  'transforms.width':width,
                  'transforms.height':height,
                   'transforms.scale_mode':scale_mode,
                   'transforms.cropCoords': cleanedCoords,
                   'transforms.transformOrder': transformOrder
               };	//The query to find the cached version, if existent
  
  
              Asset.findOne (query,'parentId transforms data', function (err, cachedAssetDocument) {
                  if (!cachedAssetDocument) {	//If no transformed asset exists with the given parameters
                      cachedAssetDocument = new Asset ();	//we create a new one, and save it in the mongodb
  
                      //Define the data that should be passed to the different transformation methods
                      transformData.resize = [width, height, scale_mode];
                      transformData.crop = cleanedCoords;
  
                      gmInstance = gm (data);
  
                      /*	Iterate over the transformations that shopuld be performed, in their (optionally) defined order.
                       *	check if we have a defined dataset that can be applied to the transformation
                       *	and if the data exists
                       */
                      for (var i = 0,transformation,currentData; i < transformOrder.length; i++) {
                          transformation = transformOrder [i];
                          currentData = transformData [transformation];
                          if (currentData && currentData.length > 0) {
                              gmInstance [transformation].apply (gmInstance, currentData);
                          }
                      }
  
  
                      //When the transformations were applied, save the resulting image and return its buffer
                      gmInstance.toBuffer (function (err,buffer) {
                          if (err) { next(err); }
  
                          cachedAssetDocument.data       = buffer;
                          cachedAssetDocument.parentId   = id;
                          cachedAssetDocument.transforms = {
                              width: width,
                              height: height,
                              cropCoords: cleanedCoords,
                              transformOrder: transformOrder,
                              scale_mode: scale_mode
                          };
  
                          cachedAssetDocument.save ( function (err) {
                              if (err) { next(err); }
                              res.send (buffer);
                          });
                      });
                  } else {  //Otherwise send back the cached version
                      res.send (cachedAssetDocument.data);
                  }
              });
          } else {
              res.writeHead(200);
              return  res.end(data);
          }
      }
func_documentation_string: /*
  Sends the buffer of the asset to the client.
  Accepts options to perform transformations on the asset.