def validate_target(target, allow_selector)
      choices = ":agent_id OR " + (allow_selector ? ":selector, " : "") + ":tags and/or :scope"
      if target.is_a?(Hash)
        t = SerializationHelper.symbolize_keys(target)

        if (agent_id = t[:agent_id])
          raise ArgumentError, "Invalid target: #{target.inspect}" if t.size > 1
        end

        if (selector = t[:selector])
          if allow_selector
            selector = selector.to_sym
            unless [:any, :all].include?(selector)
              raise ArgumentError, "Invalid target selector (#{t[:selector].inspect}), choices are :any and :all"
            end
            t[:selector] = selector
          else
            raise ArgumentError, "Invalid target hash (#{target.inspect}), choices are #{choices}"
          end
        end

        if (scope = t[:scope])
          if scope.is_a?(Hash)
            scope = SerializationHelper.symbolize_keys(scope)
            unless (scope[:account] || scope[:shard]) && (scope.keys - [:account, :shard]).empty?
              raise ArgumentError, "Invalid target scope (#{t[:scope].inspect}), choices are :account and :shard"
            end
            t[:scope] = scope
          else
            raise ArgumentError, "Invalid target scope (#{t[:scope].inspect}), must be a hash of :account and/or :shard"
          end
        end

        if (tags = t[:tags]) && !tags.is_a?(Array)
          raise ArgumentError, "Invalid target tags (#{t[:tags].inspect}), must be an array"
        end

        unless (agent_id || selector || scope || tags) && (t.keys - [:agent_id, :selector, :scope, :tags]).empty?
          raise ArgumentError, "Invalid target hash (#{target.inspect}), choices are #{choices}"
        end
        target = t
      elsif !target.nil? && !target.is_a?(String)
        raise ArgumentError, "Invalid target (#{target.inspect}), choices are specific target name or a hash of #{choices}"
      end
      true
    end
def validate_target(target, allow_selector)
      choices = ":agent_id OR " + (allow_selector ? ":selector, " : "") + ":tags and/or :scope"
      if target.is_a?(Hash)
        t = SerializationHelper.symbolize_keys(target)

        if (agent_id = t[:agent_id])
          raise ArgumentError, "Invalid target: #{target.inspect}" if t.size > 1
        end

        if (selector = t[:selector])
          if allow_selector
            selector = selector.to_sym
            unless [:any, :all].include?(selector)
              raise ArgumentError, "Invalid target selector (#{t[:selector].inspect}), choices are :any and :all"
            end
            t[:selector] = selector
          else
            raise ArgumentError, "Invalid target hash (#{target.inspect}), choices are #{choices}"
          end
        end

        if (scope = t[:scope])
          if scope.is_a?(Hash)
            scope = SerializationHelper.symbolize_keys(scope)
            unless (scope[:account] || scope[:shard]) && (scope.keys - [:account, :shard]).empty?
              raise ArgumentError, "Invalid target scope (#{t[:scope].inspect}), choices are :account and :shard"
            end
            t[:scope] = scope
          else
            raise ArgumentError, "Invalid target scope (#{t[:scope].inspect}), must be a hash of :account and/or :shard"
          end
        end

        if (tags = t[:tags]) && !tags.is_a?(Array)
          raise ArgumentError, "Invalid target tags (#{t[:tags].inspect}), must be an array"
        end

        unless (agent_id || selector || scope || tags) && (t.keys - [:agent_id, :selector, :scope, :tags]).empty?
          raise ArgumentError, "Invalid target hash (#{target.inspect}), choices are #{choices}"
        end
        target = t
      elsif !target.nil? && !target.is_a?(String)
        raise ArgumentError, "Invalid target (#{target.inspect}), choices are specific target name or a hash of #{choices}"
      end
      true
    end
Validate target argument of send per the semantics of each kind of send:
   - The target is either a specific target name, a non-empty hash, or nil
   - A specific target name must be a string (or use :agent_id key)
   - A non-empty hash target
     - may have keys in symbol or string format
     - may contain an :agent_id to select a specific target, but then cannot
       have any other keys
     - may be allowed to contain a :selector key with value :any or :all,
       depending on the kind of send
     - may contain a :scope key with a hash value with keys :account and/or :shard
     - may contain a :tags key with an array value

 === Parameters
 target(String|Hash):: Identity of specific target, or hash for selecting targets;
   returned with all hash keys converted to symbols
 allow_selector(Boolean):: Whether to allow :selector

 === Return
 true:: Always return true

 === Raise
 ArgumentError:: If target is invalid