anchor.diff:  
   TIP: You can look at the source code for the https://github.com/technipelago/grails-crm-content/tree/master/test/integration/grails/plugins/crm/content[integration tests^] to find more code examples.
   
  +=== Save photos to Amazon S3
  +
  +The bean `crmContentRouter` is responsible for routing content from/to a `CrmContentProvider` when reading and writing content.
  +The following example replaces the default content router with an implementation that looks at the content type and size.
  +All large images attached to contacts (`CrmContact`) are stored in Amazon S3 and all other content are stored by the default content provider (the local file system).
  +The `awsContentProvider` bean is provided by `crm-content-aws` plugin.
  +
  +[source,groovy]
  +.grails-app/conf/spring/resources.groovy
  +----
  +import grails.plugins.crm.contact.CrmContact
  +
  +beans = {
  +    crmContentRouter(grails.plugins.crm.content.PatternContentRouter, ref("crmCoreService")) { bean ->
  +        bean.autowire = 'byName'
  +
  +        pattern = /.*\.(jpg|jpeg|png)$/
  +        minLength = 131072
  +        referenceClass = CrmContact
  +        defaultProvider = ref("crmFileContentProvider")
  +        provider = ref("awsContentProvider")
  +    }
  +}
  +----
  +
   == Tag Library
   
   === render
  
positive.code: ----
  
  === Create a file
  [source.groovy]
  .CreateFile.groovy
  ----
  def bytes = "Hello World".getBytes()
  
negative.code: 
  == Changes
  
  2.4.6:: Content-Disposition filename is now URL encoded. Content router can be replaced with custom impl to store content in other locations.
  2.4.5:: Make it easier to use multiple storage providers in the same application
  2.4.4:: withInputStream now returns what the closure returns (was void).
  2.4.3:: Fix for threading issues when loading FreeMarker templates from different tenants.
  