hunk.code_window: import React from 'react';
   import * as AsyncClient from 'utils/async_client.jsx';
   import ReactionStore from 'stores/reaction_store.jsx';
   import ReactionListView from './reaction_list_view.jsx';
  
hunk.labels: keep keep add keep keep keep
hunk.after_edit: import EmojiStore from 'stores/emoji_store.jsx';
  
hunk.file_path: webapp/components/post_view/components/reaction_list_container.jsx
hunk.type: add
file: package minio
  
  import (
  	"encoding/base64"
  	"fmt"
  	"strings"
  	"time"
  )
  
  // expirationDateFormat date format for expiration key in json policy.
  const expirationDateFormat = "2006-01-02T15:04:05.999Z"
  
  // policyCondition explanation:
  // http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
  //
  // Example:
  //
  //   policyCondition {
  //       matchType: "$eq",
  //       key: "$Content-Type",
  //       value: "image/png",
  //   }
  //
  type policyCondition struct {
  	matchType string
  	condition string
  	value     string
  }
  
  // PostPolicy - Provides strict static type conversion and validation
  // for Amazon S3's POST policy JSON string.
  type PostPolicy struct {
  	// Expiration date and time of the POST policy.
  	expiration time.Time
  	// Collection of different policy conditions.
  	conditions []policyCondition
  	// ContentLengthRange minimum and maximum allowable size for the
  	// uploaded content.
  	contentLengthRange struct {
  		min int64
  		max int64
  	}
  
  	// Post form data.
  	formData map[string]string
  }
  
  // NewPostPolicy - Instantiate new post policy.
  func NewPostPolicy() *PostPolicy {
  	p := &PostPolicy{}
  	p.conditions = make([]policyCondition, 0)
  	p.formData = make(map[string]string)
  	return p
  }
  
  // SetExpires - Sets expiration time for the new policy.
  func (p *PostPolicy) SetExpires(t time.Time) error {
  	if t.IsZero() {
  		return ErrInvalidArgument("No expiry time set.")
  	}
  	p.expiration = t
  	return nil
  }
  
  // SetKey - Sets an object name for the policy based upload.
  func (p *PostPolicy) SetKey(key string) error {
  	if strings.TrimSpace(key) == "" || key == "" {
  		return ErrInvalidArgument("Object name is empty.")
  	}
  	policyCond := policyCondition{
  		matchType: "eq",
  		condition: "$key",
  		value:     key,
  	}
  	if err := p.addNewPolicy(policyCond); err != nil {
  		return err
  	}
  	p.formData["key"] = key
  	return nil
  }
  
  // SetKeyStartsWith - Sets an object name that an policy based upload
  // can start with.
  func (p *PostPolicy) SetKeyStartsWith(keyStartsWith string) error {
  	if strings.TrimSpace(keyStartsWith) == "" || keyStartsWith == "" {
  		return ErrInvalidArgument("Object prefix is empty.")
  	}
  	policyCond := policyCondition{
  		matchType: "starts-with",
  		condition: "$key",
  		value:     keyStartsWith,
  	}
  	if err := p.addNewPolicy(policyCond); err != nil {
  		return err
  	}
  	p.formData["key"] = keyStartsWith
  	return nil
  }
  
  // SetBucket - Sets bucket at which objects will be uploaded to.
  func (p *PostPolicy) SetBucket(bucketName string) error {
  	if strings.TrimSpace(bucketName) == "" || bucketName == "" {
  		return ErrInvalidArgument("Bucket name is empty.")
  	}
  	policyCond := policyCondition{
  		matchType: "eq",
  		condition: "$bucket",
  		value:     bucketName,
  	}
  	if err := p.addNewPolicy(policyCond); err != nil {
  		return err
  	}
  	p.formData["bucket"] = bucketName
  	return nil
  }
  
  // SetContentType - Sets content-type of the object for this policy
  // based upload.
  func (p *PostPolicy) SetContentType(contentType string) error {
  	if strings.TrimSpace(contentType) == "" || contentType == "" {
  		return ErrInvalidArgument("No content type specified.")
  	}
  	policyCond := policyCondition{
  		matchType: "eq",
  		condition: "$Content-Type",
  		value:     contentType,
  	}
  	if err := p.addNewPolicy(policyCond); err != nil {
  		return err
  	}
  	p.formData["Content-Type"] = contentType
  	return nil
  }
  
  // SetContentLengthRange - Set new min and max content length
  // condition for all incoming uploads.
  func (p *PostPolicy) SetContentLengthRange(min, max int64) error {
  	if min > max {
  		return ErrInvalidArgument("Minimum limit is larger than maximum limit.")
  	}
  	if min < 0 {
  		return ErrInvalidArgument("Minimum limit cannot be negative.")
  	}
  	if max < 0 {
  		return ErrInvalidArgument("Maximum limit cannot be negative.")
  	}
  	p.contentLengthRange.min = min
  	p.contentLengthRange.max = max
  	return nil
  }
  
  // SetSuccessStatusAction - Sets the status success code of the object for this policy
  // based upload.
  func (p *PostPolicy) SetSuccessStatusAction(status string) error {
  	if strings.TrimSpace(status) == "" || status == "" {
  		return ErrInvalidArgument("Status is empty")
  	}
  	policyCond := policyCondition{
  		matchType: "eq",
  		condition: "$success_action_status",
  		value:     status,
  	}
  	if err := p.addNewPolicy(policyCond); err != nil {
  		return err
  	}
  	p.formData["success_action_status"] = status
  	return nil
  }
  
  // addNewPolicy - internal helper to validate adding new policies.
  func (p *PostPolicy) addNewPolicy(policyCond policyCondition) error {
  	if policyCond.matchType == "" || policyCond.condition == "" || policyCond.value == "" {
  		return ErrInvalidArgument("Policy fields are empty.")
  	}
  	p.conditions = append(p.conditions, policyCond)
  	return nil
  }
  
  // Stringer interface for printing policy in json formatted string.
  func (p PostPolicy) String() string {
  	return string(p.marshalJSON())
  }
  
  // marshalJSON - Provides Marshalled JSON in bytes.
  func (p PostPolicy) marshalJSON() []byte {
  	expirationStr := `"expiration":"` + p.expiration.Format(expirationDateFormat) + `"`
  	var conditionsStr string
  	conditions := []string{}
  	for _, po := range p.conditions {
  		conditions = append(conditions, fmt.Sprintf("[\"%s\",\"%s\",\"%s\"]", po.matchType, po.condition, po.value))
  	}
  	if p.contentLengthRange.min != 0 || p.contentLengthRange.max != 0 {
  		conditions = append(conditions, fmt.Sprintf("[\"content-length-range\", %d, %d]",
  			p.contentLengthRange.min, p.contentLengthRange.max))
  	}
  	if len(conditions) > 0 {
  		conditionsStr = `"conditions":[` + strings.Join(conditions, ",") + "]"
  	}
  	retStr := "{"
  	retStr = retStr + expirationStr + ","
  	retStr = retStr + conditionsStr
  	retStr = retStr + "}"
  	return []byte(retStr)
  }
  
  // base64 - Produces base64 of PostPolicy's Marshalled json.
  func (p PostPolicy) base64() string {
  	return base64.StdEncoding.EncodeToString(p.marshalJSON())
  }
  