code: func (s *Scheduler) createTemplate(ctx context.Context, app *twelvefactor.Manifest, stackTags []*cloudformation.Tag) (*cloudformationTemplate, error) {
  	data := &TemplateData{
  		Manifest:  app,
  		StackTags: stackTags,
  	}
  
  	buf := new(bytes.Buffer)
  	if err := s.Template.Execute(buf, data); err != nil {
  		return nil, err
  	}
  
  	key := fmt.Sprintf("%s/%s/%x", app.Name, app.AppID, sha1.Sum(buf.Bytes()))
  	url := fmt.Sprintf("https://%s.s3.amazonaws.com/%s", s.Bucket, key)
  
  	if _, err := s.s3.PutObject(&s3.PutObjectInput{
  		Bucket:      aws.String(s.Bucket),
  		Key:         aws.String(fmt.Sprintf("/%s", key)),
  		Body:        bytes.NewReader(buf.Bytes()),
  		ContentType: aws.String("application/json"),
  	}); err != nil {
  		return nil, fmt.Errorf("error uploading stack template to s3: %v", err)
  	}
  
  	t := &cloudformationTemplate{
  		URL:  aws.String(url),
  		Size: buf.Len(),
  	}
  
  	resp, err := s.cloudformation.ValidateTemplate(&cloudformation.ValidateTemplateInput{
  		TemplateURL: aws.String(url),
  	})
  	if err != nil {
  		return t, &templateValidationError{template: t, err: err}
  	}
  
  	t.Parameters = resp.Parameters
  
  	return t, nil
  }
docs: // createTemplate takes a scheduler.App, and returns a validated cloudformation
  // template.