code: func NewAppFromString(app string) (*App, error) {
  	var (
  		name   string
  		labels map[types.ACIdentifier]string
  	)
  
  	preparedApp, err := prepareAppString(app)
  	if err != nil {
  		return nil, err
  	}
  	v, err := url.ParseQuery(preparedApp)
  	if err != nil {
  		return nil, err
  	}
  	labels = make(map[types.ACIdentifier]string, 0)
  	for key, val := range v {
  		if len(val) > 1 {
  			return nil, fmt.Errorf("label %s with multiple values %q", key, val)
  		}
  		if key == "name" {
  			name = val[0]
  			continue
  		}
  		labelName, err := types.NewACIdentifier(key)
  		if err != nil {
  			return nil, err
  		}
  		labels[*labelName] = val[0]
  	}
  	a, err := NewApp(name, labels)
  	if err != nil {
  		return nil, err
  	}
  	return a, nil
  }
docs: // NewAppFromString takes a command line app parameter and returns a map of labels.
  //
  // Example app parameters:
  // 	example.com/reduce-worker:1.0.0
  // 	example.com/reduce-worker,channel=alpha,label=value
  // 	example.com/reduce-worker:1.0.0,label=value
  //
  // As can be seen in above examples - colon, comma and equal sign have
  // special meaning. If any of them has to be a part of a label's value
  // then consider writing your own string to App parser.