def effective_properties(category_name, event_name, additional_properties = { })
      event = version_object.fetch_event(category_name, event_name)

      explicit = { }
      self.class.merge_properties(explicit, additional_properties, property_separator)
      properties = @implicit_properties.merge(explicit)

      event.validate!(properties)
      # We need to do this instead of just using || so that you can override a present distinct_id with nil.
      net_distinct_id = if properties.has_key?('distinct_id') then properties.delete('distinct_id') else self.distinct_id end

      event_external_name = event.external_name || external_name.call(event)
      raise TypeError, "The external name of an event must be a String" unless event_external_name.kind_of?(String)

      {
        :distinct_id   => net_distinct_id,
        :event_name    => event.full_name,
        :external_name => event_external_name,
        :properties    => properties
      }
    end
def effective_properties(category_name, event_name, additional_properties = { })
      event = version_object.fetch_event(category_name, event_name)

      explicit = { }
      self.class.merge_properties(explicit, additional_properties, property_separator)
      properties = @implicit_properties.merge(explicit)

      event.validate!(properties)
      # We need to do this instead of just using || so that you can override a present distinct_id with nil.
      net_distinct_id = if properties.has_key?('distinct_id') then properties.delete('distinct_id') else self.distinct_id end

      event_external_name = event.external_name || external_name.call(event)
      raise TypeError, "The external name of an event must be a String" unless event_external_name.kind_of?(String)

      {
        :distinct_id   => net_distinct_id,
        :event_name    => event.full_name,
        :external_name => event_external_name,
        :properties    => properties
      }
    end
Given a category, an event, and (optionally) additional properties, performs all of the expansion and validation
 of #event!, but does not actually fire the event -- rather, returns a Hash containing:

 [:distinct_id]   The +distinct_id+ that should be passed with the event; this can be +nil+ if there is no distinct
                  ID being passed.
 [:event_name]    The fully-qualified event name, including +global_events_prefix+ and version number.
 [:external_name] The event name for use in an events backend.
                  By default this is +:event_name+ but can be overridden.
 [:properties]    The full set of properties, expanded (so values will only be scalars, never Hashes or objects),
                  with String keys, exactly as they should be passed to an events system.

 This method can be used for many things, but its primary purpose is to support front-end (Javascript-fired)
 events: you can have it compute exactly the set of properties that should be attached to such events, embed
 them into the page (using HTML +data+ attributes, JavaScript literals, or any other storage mechanism you want),
 and then have the front-end fire them. This allows consistency between front-end and back-end events, and is
 another big advantage of MetaEvents.