kameleoon-client-ruby 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/lib/kameleoon/client_readiness.rb +40 -0
 - data/lib/kameleoon/configuration/data_file.rb +41 -0
 - data/lib/kameleoon/configuration/feature_flag.rb +3 -2
 - data/lib/kameleoon/configuration/rule.rb +18 -3
 - data/lib/kameleoon/configuration/settings.rb +3 -1
 - data/lib/kameleoon/configuration/variable.rb +0 -2
 - data/lib/kameleoon/configuration/variation_exposition.rb +0 -2
 - data/lib/kameleoon/data/browser.rb +1 -1
 - data/lib/kameleoon/data/conversion.rb +1 -1
 - data/lib/kameleoon/data/custom_data.rb +10 -14
 - data/lib/kameleoon/data/data.rb +22 -3
 - data/lib/kameleoon/data/device.rb +2 -1
 - data/lib/kameleoon/data/manager/assigned_variation.rb +38 -0
 - data/lib/kameleoon/data/manager/data_array_storage.rb +43 -0
 - data/lib/kameleoon/data/manager/data_map_storage.rb +43 -0
 - data/lib/kameleoon/data/manager/page_view_visit.rb +19 -0
 - data/lib/kameleoon/data/manager/visitor.rb +142 -0
 - data/lib/kameleoon/data/manager/visitor_manager.rb +71 -0
 - data/lib/kameleoon/data/page_view.rb +2 -1
 - data/lib/kameleoon/exceptions.rb +30 -35
 - data/lib/kameleoon/hybrid/manager.rb +13 -31
 - data/lib/kameleoon/{client.rb → kameleoon_client.rb} +164 -336
 - data/lib/kameleoon/kameleoon_client_config.rb +91 -0
 - data/lib/kameleoon/kameleoon_client_factory.rb +42 -0
 - data/lib/kameleoon/network/activity_event.rb +6 -3
 - data/lib/kameleoon/network/cookie/cookie_manager.rb +84 -0
 - data/lib/kameleoon/network/net_provider.rb +5 -37
 - data/lib/kameleoon/network/network_manager.rb +8 -7
 - data/lib/kameleoon/network/request.rb +3 -2
 - data/lib/kameleoon/network/response.rb +0 -8
 - data/lib/kameleoon/network/url_provider.rb +5 -3
 - data/lib/kameleoon/targeting/conditions/browser_condition.rb +2 -3
 - data/lib/kameleoon/targeting/conditions/conversion_condition.rb +12 -4
 - data/lib/kameleoon/targeting/conditions/custom_datum.rb +19 -13
 - data/lib/kameleoon/targeting/conditions/device_condition.rb +3 -4
 - data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +2 -1
 - data/lib/kameleoon/targeting/conditions/page_title_condition.rb +11 -4
 - data/lib/kameleoon/targeting/conditions/page_url_condition.rb +18 -4
 - data/lib/kameleoon/targeting/conditions/string_value_condition.rb +2 -0
 - data/lib/kameleoon/targeting/conditions/target_experiment.rb +11 -6
 - data/lib/kameleoon/utils.rb +41 -4
 - data/lib/kameleoon/version.rb +1 -1
 - data/lib/kameleoon.rb +4 -2
 - metadata +14 -10
 - data/lib/kameleoon/client_config.rb +0 -44
 - data/lib/kameleoon/configuration/experiment.rb +0 -42
 - data/lib/kameleoon/cookie.rb +0 -88
 - data/lib/kameleoon/factory.rb +0 -43
 - data/lib/kameleoon/network/experiment_event.rb +0 -35
 - data/lib/kameleoon/storage/variation_storage.rb +0 -42
 - data/lib/kameleoon/storage/visitor_variation.rb +0 -20
 
| 
         @@ -0,0 +1,91 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Kameleoon
         
     | 
| 
      
 4 
     | 
    
         
            +
              # KameleoonClient configuration which can be used instead of an external configuration file
         
     | 
| 
      
 5 
     | 
    
         
            +
              class KameleoonClientConfig
         
     | 
| 
      
 6 
     | 
    
         
            +
                DEFAULT_REFRESH_INTERVAL_MINUTES = 60
         
     | 
| 
      
 7 
     | 
    
         
            +
                DEFAULT_SESSION_DURATION_MINUTES = 30
         
     | 
| 
      
 8 
     | 
    
         
            +
                DEFAULT_TIMEOUT_MILLISECONDS = 10_000
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                attr_reader :client_id, :client_secret, :refresh_interval_second, :session_duration_second,
         
     | 
| 
      
 11 
     | 
    
         
            +
                            :default_timeout_millisecond, :environment, :top_level_domain, :verbose_mode
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def initialize(
         
     | 
| 
      
 14 
     | 
    
         
            +
                  client_id,
         
     | 
| 
      
 15 
     | 
    
         
            +
                  client_secret,
         
     | 
| 
      
 16 
     | 
    
         
            +
                  refresh_interval_minute: DEFAULT_REFRESH_INTERVAL_MINUTES,
         
     | 
| 
      
 17 
     | 
    
         
            +
                  session_duration_minute: DEFAULT_SESSION_DURATION_MINUTES,
         
     | 
| 
      
 18 
     | 
    
         
            +
                  default_timeout_millisecond: DEFAULT_TIMEOUT_MILLISECONDS,
         
     | 
| 
      
 19 
     | 
    
         
            +
                  environment: nil,
         
     | 
| 
      
 20 
     | 
    
         
            +
                  top_level_domain: nil,
         
     | 
| 
      
 21 
     | 
    
         
            +
                  verbose_mode: false
         
     | 
| 
      
 22 
     | 
    
         
            +
                )
         
     | 
| 
      
 23 
     | 
    
         
            +
                  raise Exception::ConfigCredentialsInvalid, 'Client ID is not specified' if client_id&.empty? != false
         
     | 
| 
      
 24 
     | 
    
         
            +
                  raise Exception::ConfigCredentialsInvalid, 'Client secret is not specified' if client_secret&.empty? != false
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  @verbose_mode = verbose_mode || false
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  @client_id = client_id
         
     | 
| 
      
 29 
     | 
    
         
            +
                  @client_secret = client_secret
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  if refresh_interval_minute.nil?
         
     | 
| 
      
 32 
     | 
    
         
            +
                    refresh_interval_minute = DEFAULT_REFRESH_INTERVAL_MINUTES
         
     | 
| 
      
 33 
     | 
    
         
            +
                  elsif refresh_interval_minute <= 0
         
     | 
| 
      
 34 
     | 
    
         
            +
                    log('Configuration refresh interval must have positive value. ' \
         
     | 
| 
      
 35 
     | 
    
         
            +
                      "Default refresh interval (#{DEFAULT_REFRESH_INTERVAL_MINUTES} minutes) is applied.")
         
     | 
| 
      
 36 
     | 
    
         
            +
                    refresh_interval_minute = DEFAULT_REFRESH_INTERVAL_MINUTES
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @refresh_interval_second = refresh_interval_minute * 60
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  if session_duration_minute.nil?
         
     | 
| 
      
 41 
     | 
    
         
            +
                    session_duration_minute = DEFAULT_SESSION_DURATION_MINUTES
         
     | 
| 
      
 42 
     | 
    
         
            +
                  elsif session_duration_minute <= 0
         
     | 
| 
      
 43 
     | 
    
         
            +
                    log('Session duration must have positive value. ' \
         
     | 
| 
      
 44 
     | 
    
         
            +
                      "Default session duration (#{DEFAULT_SESSION_DURATION_MINUTES} minutes) is applied.")
         
     | 
| 
      
 45 
     | 
    
         
            +
                    session_duration_minute = DEFAULT_SESSION_DURATION_MINUTES
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @session_duration_second = session_duration_minute * 60
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  if default_timeout_millisecond.nil?
         
     | 
| 
      
 50 
     | 
    
         
            +
                    @default_timeout_millisecond = DEFAULT_TIMEOUT_MILLISECONDS
         
     | 
| 
      
 51 
     | 
    
         
            +
                  elsif default_timeout_millisecond <= 0
         
     | 
| 
      
 52 
     | 
    
         
            +
                    log('Default timeout must have positive value. ' \
         
     | 
| 
      
 53 
     | 
    
         
            +
                      "Default timeout (#{DEFAULT_TIMEOUT_MILLISECONDS} ms) is applied.")
         
     | 
| 
      
 54 
     | 
    
         
            +
                    @default_timeout_millisecond = DEFAULT_TIMEOUT_MILLISECONDS
         
     | 
| 
      
 55 
     | 
    
         
            +
                  else
         
     | 
| 
      
 56 
     | 
    
         
            +
                    @default_timeout_millisecond = default_timeout_millisecond
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  @environment = environment
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  if top_level_domain.nil?
         
     | 
| 
      
 62 
     | 
    
         
            +
                    log('Setting top level domain is strictly recommended, otherwise you may have problems when using subdomains.')
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                  @top_level_domain = top_level_domain
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def self.read_from_yaml(path)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  yaml = YAML.load_file(path) if File.exist?(path)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  if yaml.nil?
         
     | 
| 
      
 70 
     | 
    
         
            +
                    warn "Kameleoon SDK: Configuration file with path #{path} does not exist"
         
     | 
| 
      
 71 
     | 
    
         
            +
                    yaml = {}
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  KameleoonClientConfig.new(
         
     | 
| 
      
 74 
     | 
    
         
            +
                    yaml['client_id'],
         
     | 
| 
      
 75 
     | 
    
         
            +
                    yaml['client_secret'],
         
     | 
| 
      
 76 
     | 
    
         
            +
                    refresh_interval_minute: yaml['refresh_interval_minute'],
         
     | 
| 
      
 77 
     | 
    
         
            +
                    session_duration_minute: yaml['session_duration_minute'],
         
     | 
| 
      
 78 
     | 
    
         
            +
                    default_timeout_millisecond: yaml['default_timeout_millisecond'],
         
     | 
| 
      
 79 
     | 
    
         
            +
                    environment: yaml['environment'],
         
     | 
| 
      
 80 
     | 
    
         
            +
                    top_level_domain: yaml['top_level_domain'],
         
     | 
| 
      
 81 
     | 
    
         
            +
                    verbose_mode: yaml['verbose_mode']
         
     | 
| 
      
 82 
     | 
    
         
            +
                  )
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                private
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                def log(text)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  print "Kameleoon SDK Log: #{text}\n" if @verbose_mode
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'concurrent'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kameleoon/kameleoon_client'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'kameleoon/kameleoon_client_config'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module Kameleoon
         
     | 
| 
      
 8 
     | 
    
         
            +
              # A Factory class for creating kameleoon clients
         
     | 
| 
      
 9 
     | 
    
         
            +
              module KameleoonClientFactory
         
     | 
| 
      
 10 
     | 
    
         
            +
                CONFIG_PATH = '/etc/kameleoon/client-ruby.yaml'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                @clients = Concurrent::Map.new
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def self.create(site_code, config: nil, config_path: CONFIG_PATH)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  unless config.is_a?(KameleoonClientConfig)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    config_path = CONFIG_PATH unless config_path.is_a?(String)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    config = KameleoonClientConfig.read_from_yaml(config_path)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  key = get_client_key(site_code, config.environment)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @clients.compute_if_absent(key) do
         
     | 
| 
      
 21 
     | 
    
         
            +
                    client = KameleoonClient.new(site_code, config)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    client.send(:log, "Client created with site code: #{site_code}")
         
     | 
| 
      
 23 
     | 
    
         
            +
                    client.send(:fetch_configuration_initially)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    client
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def self.forget(site_code, environment = nil)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  key = get_client_key(site_code, environment)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @clients.compute_if_present(key) do |client|
         
     | 
| 
      
 31 
     | 
    
         
            +
                    client.send(:dispose)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                private_class_method
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def self.get_client_key(site_code, environment)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  environment.nil? ? site_code : "#{site_code}/#{environment}"
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -12,20 +12,23 @@ module Kameleoon 
     | 
|
| 
       12 
12 
     | 
    
         
             
                class ActivityEvent
         
     | 
| 
       13 
13 
     | 
    
         
             
                  EVENT_TYPE = 'activity'
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
                   
     | 
| 
      
 15 
     | 
    
         
            +
                  attr_reader :sent
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
                  def initialize
         
     | 
| 
       18 
18 
     | 
    
         
             
                    @sent = false
         
     | 
| 
       19 
     | 
    
         
            -
                    @nonce = Kameleoon::Utils.generate_random_string(Kameleoon::NONCE_LENGTH)
         
     | 
| 
       20 
19 
     | 
    
         
             
                  end
         
     | 
| 
       21 
20 
     | 
    
         | 
| 
       22 
21 
     | 
    
         
             
                  def obtain_full_post_text_line
         
     | 
| 
       23 
22 
     | 
    
         
             
                    params = {
         
     | 
| 
       24 
23 
     | 
    
         
             
                      eventType: EVENT_TYPE,
         
     | 
| 
       25 
     | 
    
         
            -
                      nonce:  
     | 
| 
      
 24 
     | 
    
         
            +
                      nonce: Kameleoon::Utils.generate_random_string(Kameleoon::NONCE_LENGTH)
         
     | 
| 
       26 
25 
     | 
    
         
             
                    }
         
     | 
| 
       27 
26 
     | 
    
         
             
                    UriHelper.encode_query(params)
         
     | 
| 
       28 
27 
     | 
    
         
             
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def mark_as_sent
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @sent = true
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
       29 
32 
     | 
    
         
             
                end
         
     | 
| 
       30 
33 
     | 
    
         
             
              end
         
     | 
| 
       31 
34 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,84 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kameleoon/utils'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Kameleoon
         
     | 
| 
      
 6 
     | 
    
         
            +
              module Network
         
     | 
| 
      
 7 
     | 
    
         
            +
                module Cookie
         
     | 
| 
      
 8 
     | 
    
         
            +
                  COOKIE_KEY_JS = '_js_'
         
     | 
| 
      
 9 
     | 
    
         
            +
                  VISITOR_CODE_COOKIE = 'kameleoonVisitorCode'
         
     | 
| 
      
 10 
     | 
    
         
            +
                  COOKIE_TTL_SECONDS = 380 * 86_400 # 380 days in seconds
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  class CookieManager
         
     | 
| 
      
 13 
     | 
    
         
            +
                    attr_accessor :consent_required
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    def initialize(top_level_domain)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      @consent_required = false
         
     | 
| 
      
 17 
     | 
    
         
            +
                      @top_level_domain = top_level_domain
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    def get_or_add(cookies, default_visitor_code = nil)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      return if cookies.nil?
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                      visitor_code = get_visitor_code_from_cookies(cookies)
         
     | 
| 
      
 24 
     | 
    
         
            +
                      unless visitor_code.nil?
         
     | 
| 
      
 25 
     | 
    
         
            +
                        Utils::VisitorCode.validate(visitor_code)
         
     | 
| 
      
 26 
     | 
    
         
            +
                        # Remove adding cookies when we will be sure that it doesn't break anything
         
     | 
| 
      
 27 
     | 
    
         
            +
                        add(visitor_code, cookies) unless @consent_required
         
     | 
| 
      
 28 
     | 
    
         
            +
                        return visitor_code
         
     | 
| 
      
 29 
     | 
    
         
            +
                      end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                      if default_visitor_code.nil?
         
     | 
| 
      
 32 
     | 
    
         
            +
                        visitor_code = Utils::VisitorCode.generate
         
     | 
| 
      
 33 
     | 
    
         
            +
                        add(visitor_code, cookies) unless @consent_required
         
     | 
| 
      
 34 
     | 
    
         
            +
                        return visitor_code
         
     | 
| 
      
 35 
     | 
    
         
            +
                      end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                      visitor_code = default_visitor_code
         
     | 
| 
      
 38 
     | 
    
         
            +
                      Utils::VisitorCode.validate(visitor_code)
         
     | 
| 
      
 39 
     | 
    
         
            +
                      add(visitor_code, cookies)
         
     | 
| 
      
 40 
     | 
    
         
            +
                      visitor_code
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    def update(visitor_code, consent, cookies)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      return if cookies.nil?
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                      if consent
         
     | 
| 
      
 47 
     | 
    
         
            +
                        add(visitor_code, cookies)
         
     | 
| 
      
 48 
     | 
    
         
            +
                      else
         
     | 
| 
      
 49 
     | 
    
         
            +
                        remove(cookies)
         
     | 
| 
      
 50 
     | 
    
         
            +
                      end
         
     | 
| 
      
 51 
     | 
    
         
            +
                    end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                    private
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    def add(visitor_code, cookies)
         
     | 
| 
      
 56 
     | 
    
         
            +
                      cookie = {
         
     | 
| 
      
 57 
     | 
    
         
            +
                        value: visitor_code,
         
     | 
| 
      
 58 
     | 
    
         
            +
                        expires: Time.now + COOKIE_TTL_SECONDS,
         
     | 
| 
      
 59 
     | 
    
         
            +
                        path: '/',
         
     | 
| 
      
 60 
     | 
    
         
            +
                        domain: @top_level_domain
         
     | 
| 
      
 61 
     | 
    
         
            +
                      }
         
     | 
| 
      
 62 
     | 
    
         
            +
                      cookies[VISITOR_CODE_COOKIE] = cookie
         
     | 
| 
      
 63 
     | 
    
         
            +
                    end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                    def remove(cookies)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      cookies[VISITOR_CODE_COOKIE] = nil if @consent_required
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                    def get_visitor_code_from_cookies(cookies)
         
     | 
| 
      
 70 
     | 
    
         
            +
                      cookie = cookies[VISITOR_CODE_COOKIE]
         
     | 
| 
      
 71 
     | 
    
         
            +
                      case cookie
         
     | 
| 
      
 72 
     | 
    
         
            +
                      when String
         
     | 
| 
      
 73 
     | 
    
         
            +
                        visitor_code = cookie
         
     | 
| 
      
 74 
     | 
    
         
            +
                      when Hash
         
     | 
| 
      
 75 
     | 
    
         
            +
                        visitor_code = cookie[:value]
         
     | 
| 
      
 76 
     | 
    
         
            +
                      end
         
     | 
| 
      
 77 
     | 
    
         
            +
                      visitor_code = visitor_code[COOKIE_KEY_JS.size..] if visitor_code&.start_with?(COOKIE_KEY_JS)
         
     | 
| 
      
 78 
     | 
    
         
            +
                      visitor_code = nil if visitor_code&.empty?
         
     | 
| 
      
 79 
     | 
    
         
            +
                      visitor_code
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,6 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require 'em-synchrony/em-http'
         
     | 
| 
       4 
3 
     | 
    
         
             
            require 'net/http'
         
     | 
| 
       5 
4 
     | 
    
         
             
            require 'kameleoon/version'
         
     | 
| 
       6 
5 
     | 
    
         
             
            require 'kameleoon/network/response'
         
     | 
| 
         @@ -16,7 +15,8 @@ module Kameleoon 
     | 
|
| 
       16 
15 
     | 
    
         
             
                  private
         
     | 
| 
       17 
16 
     | 
    
         | 
| 
       18 
17 
     | 
    
         
             
                  def collect_headers(request)
         
     | 
| 
       19 
     | 
    
         
            -
                    headers =  
     | 
| 
      
 18 
     | 
    
         
            +
                    headers = request.extra_headers || {}
         
     | 
| 
      
 19 
     | 
    
         
            +
                    headers['Content-Type'] = request.content_type
         
     | 
| 
       20 
20 
     | 
    
         
             
                    headers['User-Agent'] = request.user_agent unless request.user_agent.nil?
         
     | 
| 
       21 
21 
     | 
    
         
             
                    headers
         
     | 
| 
       22 
22 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -26,40 +26,6 @@ module Kameleoon 
     | 
|
| 
       26 
26 
     | 
    
         
             
                  end
         
     | 
| 
       27 
27 
     | 
    
         
             
                end
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                class EMNetProvider < NetProvider
         
     | 
| 
       30 
     | 
    
         
            -
                  def make_request(request)
         
     | 
| 
       31 
     | 
    
         
            -
                    connetion_options = {
         
     | 
| 
       32 
     | 
    
         
            -
                      tls: { verify_peer: false },
         
     | 
| 
       33 
     | 
    
         
            -
                      connect_timeout: request.timeout,
         
     | 
| 
       34 
     | 
    
         
            -
                      inactivity_timeout: request.timeout
         
     | 
| 
       35 
     | 
    
         
            -
                    }
         
     | 
| 
       36 
     | 
    
         
            -
                    headers = collect_headers(request)
         
     | 
| 
       37 
     | 
    
         
            -
                    request_options = { head: headers, body: request.data }
         
     | 
| 
       38 
     | 
    
         
            -
                    begin
         
     | 
| 
       39 
     | 
    
         
            -
                      case request.method
         
     | 
| 
       40 
     | 
    
         
            -
                      when Method::POST
         
     | 
| 
       41 
     | 
    
         
            -
                        EventMachine::HttpRequest.new(request.url, connetion_options).apost(request_options)
         
     | 
| 
       42 
     | 
    
         
            -
                      when Method::GET
         
     | 
| 
       43 
     | 
    
         
            -
                        EventMachine::HttpRequest.new(request.url, connetion_options).aget(request_options)
         
     | 
| 
       44 
     | 
    
         
            -
                      else
         
     | 
| 
       45 
     | 
    
         
            -
                        dfr = DeferrableResponse.new
         
     | 
| 
       46 
     | 
    
         
            -
                        dfr.response = unknown_method_response(request.method, request)
         
     | 
| 
       47 
     | 
    
         
            -
                        dfr
         
     | 
| 
       48 
     | 
    
         
            -
                      end
         
     | 
| 
       49 
     | 
    
         
            -
                    rescue => e
         
     | 
| 
       50 
     | 
    
         
            -
                      dfr = DeferrableResponse.new
         
     | 
| 
       51 
     | 
    
         
            -
                      dfr.response = Response.new(e, nil, nil, request)
         
     | 
| 
       52 
     | 
    
         
            -
                      dfr
         
     | 
| 
       53 
     | 
    
         
            -
                    end
         
     | 
| 
       54 
     | 
    
         
            -
                  end
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
                  def self.em_resp_to_response(request, resp)
         
     | 
| 
       57 
     | 
    
         
            -
                    return resp if resp.is_a?(Response)
         
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
                    Response.new(nil, resp.response_header.status, resp.response, request)
         
     | 
| 
       60 
     | 
    
         
            -
                  end
         
     | 
| 
       61 
     | 
    
         
            -
                end
         
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
29 
     | 
    
         
             
                class SyncNetProvider < NetProvider
         
     | 
| 
       64 
30 
     | 
    
         
             
                  def make_request(request)
         
     | 
| 
       65 
31 
     | 
    
         
             
                    resp = nil
         
     | 
| 
         @@ -84,7 +50,9 @@ module Kameleoon 
     | 
|
| 
       84 
50 
     | 
    
         
             
                    rescue => e
         
     | 
| 
       85 
51 
     | 
    
         
             
                      return Response.new(e, nil, nil, request)
         
     | 
| 
       86 
52 
     | 
    
         
             
                    end
         
     | 
| 
       87 
     | 
    
         
            -
                     
     | 
| 
      
 53 
     | 
    
         
            +
                    body = resp.body
         
     | 
| 
      
 54 
     | 
    
         
            +
                    body = nil if body&.empty?
         
     | 
| 
      
 55 
     | 
    
         
            +
                    Response.new(nil, resp.code.to_i, body, request)
         
     | 
| 
       88 
56 
     | 
    
         
             
                  end
         
     | 
| 
       89 
57 
     | 
    
         
             
                end
         
     | 
| 
       90 
58 
     | 
    
         
             
              end
         
     | 
| 
         @@ -1,10 +1,10 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require 'em-synchrony'
         
     | 
| 
       4 
3 
     | 
    
         
             
            require 'kameleoon/network/content_type'
         
     | 
| 
       5 
4 
     | 
    
         
             
            require 'kameleoon/network/method'
         
     | 
| 
       6 
5 
     | 
    
         
             
            require 'kameleoon/network/request'
         
     | 
| 
       7 
6 
     | 
    
         
             
            require 'kameleoon/network/net_provider'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'kameleoon/version'
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
            module Kameleoon
         
     | 
| 
       10 
10 
     | 
    
         
             
              module Network
         
     | 
| 
         @@ -14,6 +14,8 @@ module Kameleoon 
     | 
|
| 
       14 
14 
     | 
    
         
             
                  FETCH_CONFIGURATION_ATTEMPT_NUMBER = 4
         
     | 
| 
       15 
15 
     | 
    
         
             
                  TRACKING_CALL_ATTEMPT_NUMBER = 4
         
     | 
| 
       16 
16 
     | 
    
         
             
                  TRACKING_CALL_RETRY_DELAY = 5.0 # in seconds
         
     | 
| 
      
 17 
     | 
    
         
            +
                  SDK_TYPE_HEADER = 'X-Kameleoon-SDK-Type'
         
     | 
| 
      
 18 
     | 
    
         
            +
                  SDK_VERSION_HEADER = 'X-Kameleoon-SDK-Version'
         
     | 
| 
       17 
19 
     | 
    
         | 
| 
       18 
20 
     | 
    
         
             
                  attr_reader :environment, :default_timeout, :url_provider
         
     | 
| 
       19 
21 
     | 
    
         | 
| 
         @@ -21,7 +23,6 @@ module Kameleoon 
     | 
|
| 
       21 
23 
     | 
    
         
             
                    @environment = environment
         
     | 
| 
       22 
24 
     | 
    
         
             
                    @default_timeout = default_timeout
         
     | 
| 
       23 
25 
     | 
    
         
             
                    @url_provider = url_provider
         
     | 
| 
       24 
     | 
    
         
            -
                    @em_net_provider = EMNetProvider.new
         
     | 
| 
       25 
26 
     | 
    
         
             
                    @sync_net_provider = SyncNetProvider.new
         
     | 
| 
       26 
27 
     | 
    
         
             
                    @log_func = log_func
         
     | 
| 
       27 
28 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -29,11 +30,11 @@ module Kameleoon 
     | 
|
| 
       29 
30 
     | 
    
         
             
                  def fetch_configuration(timestamp = nil, timeout = nil)
         
     | 
| 
       30 
31 
     | 
    
         
             
                    url = @url_provider.make_configuration_url(@environment, timestamp)
         
     | 
| 
       31 
32 
     | 
    
         
             
                    timeout = ensure_timeout(timeout)
         
     | 
| 
       32 
     | 
    
         
            -
                     
     | 
| 
      
 33 
     | 
    
         
            +
                    sdk_headers = { SDK_TYPE_HEADER => SDK_NAME, SDK_VERSION_HEADER => SDK_VERSION }
         
     | 
| 
      
 34 
     | 
    
         
            +
                    request = Request.new(Method::GET, url, ContentType::JSON, timeout, extra_headers: sdk_headers)
         
     | 
| 
       33 
35 
     | 
    
         
             
                    attempts_left = FETCH_CONFIGURATION_ATTEMPT_NUMBER
         
     | 
| 
       34 
36 
     | 
    
         
             
                    while attempts_left.positive?
         
     | 
| 
       35 
     | 
    
         
            -
                       
     | 
| 
       36 
     | 
    
         
            -
                      response = EMNetProvider.em_resp_to_response(request, em_resp)
         
     | 
| 
      
 37 
     | 
    
         
            +
                      response = @sync_net_provider.make_request(request)
         
     | 
| 
       37 
38 
     | 
    
         
             
                      result = handle_response(response)
         
     | 
| 
       38 
39 
     | 
    
         
             
                      return result if result
         
     | 
| 
       39 
40 
     | 
    
         | 
| 
         @@ -64,13 +65,13 @@ module Kameleoon 
     | 
|
| 
       64 
65 
     | 
    
         
             
                    url = @url_provider.make_tracking_url(visitor_code)
         
     | 
| 
       65 
66 
     | 
    
         
             
                    timeout = ensure_timeout(timeout)
         
     | 
| 
       66 
67 
     | 
    
         
             
                    data = (lines.map(&:obtain_full_post_text_line).join("\n") || '').encode('UTF-8')
         
     | 
| 
       67 
     | 
    
         
            -
                    request = Request.new(Method::POST, url, ContentType::TEXT, timeout, user_agent, data)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    request = Request.new(Method::POST, url, ContentType::TEXT, timeout, user_agent: user_agent, data: data)
         
     | 
| 
       68 
69 
     | 
    
         
             
                    Thread.new do
         
     | 
| 
       69 
70 
     | 
    
         
             
                      attempts_left = TRACKING_CALL_ATTEMPT_NUMBER
         
     | 
| 
       70 
71 
     | 
    
         
             
                      loop do
         
     | 
| 
       71 
72 
     | 
    
         
             
                        response = @sync_net_provider.make_request(request)
         
     | 
| 
       72 
73 
     | 
    
         
             
                        if handle_response(response) != false
         
     | 
| 
       73 
     | 
    
         
            -
                          lines.each 
     | 
| 
      
 74 
     | 
    
         
            +
                          lines.each(&:mark_as_sent)
         
     | 
| 
       74 
75 
     | 
    
         
             
                          break
         
     | 
| 
       75 
76 
     | 
    
         
             
                        end
         
     | 
| 
       76 
77 
     | 
    
         
             
                        attempts_left -= 1
         
     | 
| 
         @@ -5,14 +5,15 @@ module Kameleoon 
     | 
|
| 
       5 
5 
     | 
    
         
             
                ##
         
     | 
| 
       6 
6 
     | 
    
         
             
                # Request represents HTTP request.
         
     | 
| 
       7 
7 
     | 
    
         
             
                class Request
         
     | 
| 
       8 
     | 
    
         
            -
                  attr_reader :method, :url, :content_type, :timeout, :user_agent, :data
         
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :method, :url, :content_type, :timeout, :user_agent, :extra_headers, :data
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                  def initialize(method, url, content_type, timeout, user_agent  
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(method, url, content_type, timeout, user_agent: nil, extra_headers: nil, data: nil)
         
     | 
| 
       11 
11 
     | 
    
         
             
                    @method = method
         
     | 
| 
       12 
12 
     | 
    
         
             
                    @url = url
         
     | 
| 
       13 
13 
     | 
    
         
             
                    @content_type = content_type
         
     | 
| 
       14 
14 
     | 
    
         
             
                    @timeout = timeout
         
     | 
| 
       15 
15 
     | 
    
         
             
                    @user_agent = user_agent
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @extra_headers = extra_headers
         
     | 
| 
       16 
17 
     | 
    
         
             
                    @data = !data.nil? && data.is_a?(String) ? data.encode('UTF-8') : data
         
     | 
| 
       17 
18 
     | 
    
         
             
                  end
         
     | 
| 
       18 
19 
     | 
    
         
             
                end
         
     | 
| 
         @@ -12,7 +12,7 @@ module Kameleoon 
     | 
|
| 
       12 
12 
     | 
    
         
             
                  VISITOR_DATA_PATH = '/visit/visitor'
         
     | 
| 
       13 
13 
     | 
    
         
             
                  GET_DATA_PATH = '/map/map'
         
     | 
| 
       14 
14 
     | 
    
         
             
                  POST_DATA_PATH = '/map/maps'
         
     | 
| 
       15 
     | 
    
         
            -
                   
     | 
| 
      
 15 
     | 
    
         
            +
                  CONFIGURATION_API_URL_FORMAT = 'https://sdk-config.kameleoon.eu/%s'
         
     | 
| 
       16 
16 
     | 
    
         
             
                  RT_CONFIGURATION_URL = 'https://events.kameleoon.com:8110/sse'
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                  DEFAULT_DATA_API_URL = 'https://data.kameleoon.io'
         
     | 
| 
         @@ -56,10 +56,12 @@ module Kameleoon 
     | 
|
| 
       56 
56 
     | 
    
         
             
                  end
         
     | 
| 
       57 
57 
     | 
    
         | 
| 
       58 
58 
     | 
    
         
             
                  def make_configuration_url(environment = nil, timestamp = nil)
         
     | 
| 
       59 
     | 
    
         
            -
                     
     | 
| 
      
 59 
     | 
    
         
            +
                    url = format(CONFIGURATION_API_URL_FORMAT, @site_code)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    params = {}
         
     | 
| 
       60 
61 
     | 
    
         
             
                    params[:environment] = environment unless environment.nil?
         
     | 
| 
       61 
62 
     | 
    
         
             
                    params[:ts] = timestamp unless timestamp.nil?
         
     | 
| 
       62 
     | 
    
         
            -
                    "#{ 
     | 
| 
      
 63 
     | 
    
         
            +
                    url = "#{url}?#{UriHelper.encode_query(params)}" unless params.empty?
         
     | 
| 
      
 64 
     | 
    
         
            +
                    url
         
     | 
| 
       63 
65 
     | 
    
         
             
                  end
         
     | 
| 
       64 
66 
     | 
    
         | 
| 
       65 
67 
     | 
    
         
             
                  def make_real_time_url
         
     | 
| 
         @@ -22,9 +22,8 @@ module Kameleoon 
     | 
|
| 
       22 
22 
     | 
    
         
             
                    @version_match_type = json_condition['versionMatchType']
         
     | 
| 
       23 
23 
     | 
    
         
             
                  end
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                  def check( 
     | 
| 
       26 
     | 
    
         
            -
                    browser 
     | 
| 
       27 
     | 
    
         
            -
                    browser && check_targeting(browser)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def check(browser)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    browser.is_a?(Kameleoon::Browser) && check_targeting(browser)
         
     | 
| 
       28 
27 
     | 
    
         
             
                  end
         
     | 
| 
       29 
28 
     | 
    
         | 
| 
       30 
29 
     | 
    
         
             
                  private
         
     | 
| 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require 'kameleoon/data/ 
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kameleoon/data/conversion'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kameleoon/data/manager/data_array_storage'
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            module Kameleoon
         
     | 
| 
       6 
7 
     | 
    
         
             
              # @api private
         
     | 
| 
         @@ -12,9 +13,16 @@ module Kameleoon 
     | 
|
| 
       12 
13 
     | 
    
         
             
                    @goal_id = json_condition['goalId']
         
     | 
| 
       13 
14 
     | 
    
         
             
                  end
         
     | 
| 
       14 
15 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
                  def check( 
     | 
| 
       16 
     | 
    
         
            -
                     
     | 
| 
       17 
     | 
    
         
            -
                     
     | 
| 
      
 16 
     | 
    
         
            +
                  def check(conversion_storage)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return false unless conversion_storage.is_a?(Kameleoon::DataManager::DataArrayStorage)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    return true if @goal_id.nil?
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    is_targeted = false
         
     | 
| 
      
 21 
     | 
    
         
            +
                    conversion_storage.enumerate do |conversion|
         
     | 
| 
      
 22 
     | 
    
         
            +
                      is_targeted = conversion.is_a?(Kameleoon::Conversion) && (@goal_id == conversion.goal_id)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      break if is_targeted
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                    is_targeted
         
     | 
| 
       18 
26 
     | 
    
         
             
                  end
         
     | 
| 
       19 
27 
     | 
    
         
             
                end
         
     | 
| 
       20 
28 
     | 
    
         
             
              end
         
     | 
| 
         @@ -12,6 +12,10 @@ module Kameleoon 
     | 
|
| 
       12 
12 
     | 
    
         
             
                  include Kameleoon::Exception
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
                  class << self
         
     | 
| 
      
 15 
     | 
    
         
            +
                    def op_undefined(values, value)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      false
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
       15 
19 
     | 
    
         
             
                    def op_match(values, value)
         
     | 
| 
       16 
20 
     | 
    
         
             
                      re = Regexp.new(value.to_s)
         
     | 
| 
       17 
21 
     | 
    
         
             
                      values.any? { |v| re.match(v) }
         
     | 
| 
         @@ -26,7 +30,8 @@ module Kameleoon 
     | 
|
| 
       26 
30 
     | 
    
         
             
                    end
         
     | 
| 
       27 
31 
     | 
    
         | 
| 
       28 
32 
     | 
    
         
             
                    def op_equal(values, value)
         
     | 
| 
       29 
     | 
    
         
            -
                       
     | 
| 
      
 33 
     | 
    
         
            +
                      epsilon = 1e-9
         
     | 
| 
      
 34 
     | 
    
         
            +
                      values.any? { |v| (v.to_f - value.to_f).abs < epsilon }
         
     | 
| 
       30 
35 
     | 
    
         
             
                    end
         
     | 
| 
       31 
36 
     | 
    
         | 
| 
       32 
37 
     | 
    
         
             
                    def op_greater(values, value)
         
     | 
| 
         @@ -52,6 +57,7 @@ module Kameleoon 
     | 
|
| 
       52 
57 
     | 
    
         
             
                  end
         
     | 
| 
       53 
58 
     | 
    
         | 
| 
       54 
59 
     | 
    
         
             
                  @@op = {
         
     | 
| 
      
 60 
     | 
    
         
            +
                    Operator::UNDEFINED => method(:op_undefined),
         
     | 
| 
       55 
61 
     | 
    
         
             
                    Operator::REGULAR_EXPRESSION => method(:op_match),
         
     | 
| 
       56 
62 
     | 
    
         
             
                    Operator::CONTAINS => method(:op_contains),
         
     | 
| 
       57 
63 
     | 
    
         
             
                    Operator::EXACT => method(:op_exact),
         
     | 
| 
         @@ -71,24 +77,24 @@ module Kameleoon 
     | 
|
| 
       71 
77 
     | 
    
         
             
                    end
         
     | 
| 
       72 
78 
     | 
    
         | 
| 
       73 
79 
     | 
    
         
             
                    @type = ConditionType::CUSTOM_DATUM
         
     | 
| 
       74 
     | 
    
         
            -
                    @index = json_condition['customDataIndex']
         
     | 
| 
      
 80 
     | 
    
         
            +
                    @index = json_condition['customDataIndex'].to_i
         
     | 
| 
       75 
81 
     | 
    
         
             
                    @operator = json_condition['valueMatchType']
         
     | 
| 
      
 82 
     | 
    
         
            +
                    @operation = @@op[@operator]
         
     | 
| 
       76 
83 
     | 
    
         
             
                    @value = json_condition['value']
         
     | 
| 
       77 
84 
     | 
    
         
             
                  end
         
     | 
| 
       78 
85 
     | 
    
         | 
| 
       79 
     | 
    
         
            -
                  def check( 
     | 
| 
       80 
     | 
    
         
            -
                    is_targeted =  
     | 
| 
       81 
     | 
    
         
            -
                     
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                       
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
                         
     | 
| 
      
 86 
     | 
    
         
            +
                  def check(custom_data_storage)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    is_targeted = nil
         
     | 
| 
      
 88 
     | 
    
         
            +
                    if custom_data_storage.is_a?(Kameleoon::DataManager::DataMapStorage)
         
     | 
| 
      
 89 
     | 
    
         
            +
                      custom_data = custom_data_storage.get(@index)
         
     | 
| 
      
 90 
     | 
    
         
            +
                      if custom_data.is_a?(Kameleoon::CustomData)
         
     | 
| 
      
 91 
     | 
    
         
            +
                        unless @operation
         
     | 
| 
      
 92 
     | 
    
         
            +
                          raise KameleoonError.new("Undefined operator #{@operator}"), "Undefined operator #{@operator}"
         
     | 
| 
      
 93 
     | 
    
         
            +
                        end
         
     | 
| 
      
 94 
     | 
    
         
            +
                        is_targeted = @operation.call(custom_data.values, @value)
         
     | 
| 
       88 
95 
     | 
    
         
             
                      end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
                      is_targeted = @operation.call(custom_data.values, @value)
         
     | 
| 
       91 
96 
     | 
    
         
             
                    end
         
     | 
| 
      
 97 
     | 
    
         
            +
                    is_targeted = (@operator == Operator::UNDEFINED.to_s) if is_targeted.nil?
         
     | 
| 
       92 
98 
     | 
    
         
             
                    is_targeted
         
     | 
| 
       93 
99 
     | 
    
         
             
                  end
         
     | 
| 
       94 
100 
     | 
    
         
             
                end
         
     | 
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require 'kameleoon/data/ 
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kameleoon/data/device'
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module Kameleoon
         
     | 
| 
       6 
6 
     | 
    
         
             
              # @api private
         
     | 
| 
         @@ -12,9 +12,8 @@ module Kameleoon 
     | 
|
| 
       12 
12 
     | 
    
         
             
                    @device_type = json_condition['device']
         
     | 
| 
       13 
13 
     | 
    
         
             
                  end
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
                  def check( 
     | 
| 
       16 
     | 
    
         
            -
                    device 
     | 
| 
       17 
     | 
    
         
            -
                    device && @device_type == device.device_type
         
     | 
| 
      
 15 
     | 
    
         
            +
                  def check(device)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    device.is_a?(Kameleoon::Device) && @device_type == device.device_type
         
     | 
| 
       18 
17 
     | 
    
         
             
                  end
         
     | 
| 
       19 
18 
     | 
    
         
             
                end
         
     | 
| 
       20 
19 
     | 
    
         
             
              end
         
     | 
| 
         @@ -10,7 +10,8 @@ module Kameleoon 
     | 
|
| 
       10 
10 
     | 
    
         
             
                  def check(data)
         
     | 
| 
       11 
11 
     | 
    
         
             
                    experiment_id = data.experiment_id
         
     | 
| 
       12 
12 
     | 
    
         
             
                    storage = data.storage
         
     | 
| 
       13 
     | 
    
         
            -
                    storage. 
     | 
| 
      
 13 
     | 
    
         
            +
                    storage.is_a?(Kameleoon::DataManager::DataMapStorage) &&
         
     | 
| 
      
 14 
     | 
    
         
            +
                      (storage.size.zero? || ((storage.size == 1) && !storage.get(experiment_id).nil?))
         
     | 
| 
       14 
15 
     | 
    
         
             
                  end
         
     | 
| 
       15 
16 
     | 
    
         
             
                end
         
     | 
| 
       16 
17 
     | 
    
         
             
              end
         
     | 
| 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require 'kameleoon/data/ 
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kameleoon/data/manager/data_map_storage'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kameleoon/data/manager/page_view_visit'
         
     | 
| 
       4 
5 
     | 
    
         
             
            require_relative 'string_value_condition'
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
       6 
7 
     | 
    
         
             
            module Kameleoon
         
     | 
| 
         @@ -12,9 +13,15 @@ module Kameleoon 
     | 
|
| 
       12 
13 
     | 
    
         
             
                    super(json_condition, json_condition['title'])
         
     | 
| 
       13 
14 
     | 
    
         
             
                  end
         
     | 
| 
       14 
15 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
                  def check( 
     | 
| 
       16 
     | 
    
         
            -
                     
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def check(page_view_visit_storage)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return false unless page_view_visit_storage.is_a?(Kameleoon::DataManager::DataMapStorage)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    is_targeted = false
         
     | 
| 
      
 20 
     | 
    
         
            +
                    page_view_visit_storage.enumerate do |visit|
         
     | 
| 
      
 21 
     | 
    
         
            +
                      is_targeted = visit.is_a?(Kameleoon::DataManager::PageViewVisit) && check_targeting(visit.page_view.title)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      break if is_targeted
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
                    is_targeted
         
     | 
| 
       18 
25 
     | 
    
         
             
                  end
         
     | 
| 
       19 
26 
     | 
    
         
             
                end
         
     | 
| 
       20 
27 
     | 
    
         
             
              end
         
     | 
| 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require 'kameleoon/data/ 
     | 
| 
      
 3 
     | 
    
         
            +
            require 'kameleoon/data/manager/data_map_storage'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kameleoon/data/manager/page_view_visit'
         
     | 
| 
       4 
5 
     | 
    
         
             
            require_relative 'string_value_condition'
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
       6 
7 
     | 
    
         
             
            module Kameleoon
         
     | 
| 
         @@ -12,9 +13,22 @@ module Kameleoon 
     | 
|
| 
       12 
13 
     | 
    
         
             
                    super(json_condition, json_condition['url'])
         
     | 
| 
       13 
14 
     | 
    
         
             
                  end
         
     | 
| 
       14 
15 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
                  def check( 
     | 
| 
       16 
     | 
    
         
            -
                     
     | 
| 
       17 
     | 
    
         
            -
                     
     | 
| 
      
 16 
     | 
    
         
            +
                  def check(page_view_visit_storage)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return false unless page_view_visit_storage.is_a?(Kameleoon::DataManager::DataMapStorage)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    return !page_view_visit_storage.get(condition_value).nil? if operator == Operator::EXACT
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    is_targeted = false
         
     | 
| 
      
 21 
     | 
    
         
            +
                    page_view_visit_storage.enumerate do |visit|
         
     | 
| 
      
 22 
     | 
    
         
            +
                      is_targeted = check_page_view_visit(visit)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      break if is_targeted
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                    is_targeted
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  private
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  def check_page_view_visit(visit)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    visit.is_a?(Kameleoon::DataManager::PageViewVisit) && check_targeting(visit.page_view.url)
         
     | 
| 
       18 
32 
     | 
    
         
             
                  end
         
     | 
| 
       19 
33 
     | 
    
         
             
                end
         
     | 
| 
       20 
34 
     | 
    
         
             
              end
         
     | 
| 
         @@ -24,16 +24,21 @@ module Kameleoon 
     | 
|
| 
       24 
24 
     | 
    
         
             
                  end
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
                  def check(variation_storage)
         
     | 
| 
       27 
     | 
    
         
            -
                     
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 27 
     | 
    
         
            +
                    return false unless variation_storage.is_a?(Kameleoon::DataManager::DataMapStorage) &&
         
     | 
| 
      
 28 
     | 
    
         
            +
                                        variation_storage.size.positive?
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    variation = variation_storage.get(@experiment)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    return false unless variation.is_a?(Kameleoon::DataManager::AssignedVariation)
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
       30 
33 
     | 
    
         
             
                    case @operator
         
     | 
| 
       31 
34 
     | 
    
         
             
                    when Operator::EXACT
         
     | 
| 
       32 
     | 
    
         
            -
                       
     | 
| 
      
 35 
     | 
    
         
            +
                      variation = variation_storage.get(@experiment)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      variation.variation_id == @variation
         
     | 
| 
       33 
37 
     | 
    
         
             
                    when Operator::ANY
         
     | 
| 
       34 
     | 
    
         
            -
                       
     | 
| 
      
 38 
     | 
    
         
            +
                      true
         
     | 
| 
      
 39 
     | 
    
         
            +
                    else
         
     | 
| 
      
 40 
     | 
    
         
            +
                      false
         
     | 
| 
       35 
41 
     | 
    
         
             
                    end
         
     | 
| 
       36 
     | 
    
         
            -
                    is_targeted
         
     | 
| 
       37 
42 
     | 
    
         
             
                  end
         
     | 
| 
       38 
43 
     | 
    
         
             
                end
         
     | 
| 
       39 
44 
     | 
    
         
             
              end
         
     |