/// <summary>
        ///     Advances to a particular state in your application. The string can be
        ///     any value of your choosing, and will show up in the dashboard.
        ///     A state is a section of your app that the user is currently in.
        /// </summary>
        public override void AdvanceTo(string state, string info,
                                       IDictionary <string, object> parameters)
        {
            if (Constants.isNoop)
            {
                return;
            }
            if (!calledStart)
            {
                CompatibilityLayer.LogError("You cannot call AdvanceTo before calling Start.");
                return;
            }

            IDictionary <string, string> requestParams = new Dictionary <string, string>();

            requestParams[Constants.Params.INFO] = info;
            if (state != null)
            {
                requestParams[Constants.Params.STATE] = state;
            }
            if (parameters != null)
            {
                requestParams[Constants.Params.PARAMS] = Json.Serialize(parameters);
            }
            LeanplumRequest.Post(Constants.Methods.ADVANCE, requestParams).Send();
        }
        /// <summary>
        ///     Logs a particular event in your application. The string can be
        ///     any value of your choosing, and will show up in the dashboard.
        ///     To track purchases, use Leanplum.PURCHASE_EVENT_NAME as the event name.
        /// </summary>
        public void Track(string eventName, double value, string info,
                          IDictionary <string, object> parameters, IDictionary <string, string> arguments)
        {
            if (Constants.isNoop)
            {
                return;
            }
            if (!calledStart)
            {
                CompatibilityLayer.LogError("You cannot call Track before calling Start.");
                return;
            }
            IDictionary <string, string> requestParams = new Dictionary <string, string>();

            requestParams[Constants.Params.EVENT] = eventName;
            requestParams[Constants.Params.VALUE] = value.ToString();
            if (info != null)
            {
                requestParams [Constants.Params.INFO] = info;
            }
            if (parameters != null)
            {
                requestParams[Constants.Params.PARAMS] = Json.Serialize(parameters);
            }
            if (arguments != null)
            {
                foreach (string argName in arguments.Keys)
                {
                    requestParams[argName] = arguments[argName];
                }
            }
            LeanplumRequest.Post(Constants.Methods.TRACK, requestParams).Send();
        }
Beispiel #3
0
        /// <summary>
        ///     Set location manually. Calls SetDeviceLocationWithLatitude with cell type. Best if
        ///     used in after calling DisableLocationCollection.
        /// </summary>
        /// <param name="latitude"> Device location latitude. </param>
        /// <param name="longitude"> Device location longitude. </param>
        public override void SetDeviceLocation(double latitude, double longitude)
        {
            var parameters = new Dictionary <string, string>();

            parameters[Constants.Keys.LOCATION] = string.Format("{0},{1}", latitude, longitude);
            LeanplumRequest.Post(Constants.Methods.SET_USER_ATTRIBUTES, parameters);
        }
 /// <summary>
 ///     Call this when your application pauses.
 /// </summary>
 internal static void Pause()
 {
     if (Constants.isNoop)
     {
         return;
     }
     if (!calledStart)
     {
         CompatibilityLayer.LogError("You cannot call Pause before calling start.");
         return;
     }
     if (!isPaused)
     {
         isPaused = true;
         LeanplumRequest request =
             LeanplumRequest.Post(Constants.Methods.PAUSE_SESSION, null);
         request.Response += (object obj) =>
         {
             CompatibilityLayer.FlushSavedSettings();
         };
         request.Error += (Exception obj) =>
         {
             CompatibilityLayer.FlushSavedSettings();
         };
         request.SendIfConnected();
     }
 }
Beispiel #5
0
        internal static void CheckVarsUpdate(Action callback)
        {
            IDictionary <string, string> updateVarsParams = new Dictionary <string, string>();

            updateVarsParams[Constants.Params.INCLUDE_DEFAULTS] = false.ToString();

            LeanplumRequest updateVarsReq = LeanplumRequest.Post(Constants.Methods.GET_VARS, updateVarsParams);

            updateVarsReq.Response += delegate(object varsUpdate)
            {
                var getVariablesResponse = Util.GetLastResponse(varsUpdate) as IDictionary <string, object>;
                var newVarValues         = Util.GetValueOrDefault(getVariablesResponse, Constants.Keys.VARS) as IDictionary <string, object>;
                var newVarFileAttributes = Util.GetValueOrDefault(getVariablesResponse, Constants.Keys.FILE_ATTRIBUTES) as IDictionary <string, object>;
                var newVariants          = Util.GetValueOrDefault(getVariablesResponse, Constants.Keys.VARIANTS) as List <object> ?? new List <object>();

                ApplyVariableDiffs(newVarValues, newVarFileAttributes, newVariants);

                if (callback != null)
                {
                    callback();
                }
            };
            updateVarsReq.Error += delegate
            {
                if (callback != null)
                {
                    callback();
                }
            };
            updateVarsReq.SendNow();
            VarsNeedUpdate = false;
        }
Beispiel #6
0
        /// <summary>
        ///     Set location manually. Calls SetDeviceLocationWithLatitude with cell type. Best if
        ///     used in after calling DisableLocationCollection.
        /// </summary>
        /// <param name="latitude"> Device location latitude. </param>
        /// <param name="longitude"> Device location longitude. </param>
        /// <param name="city"> Location city. </param>
        /// <param name="region"> Location region. </param>
        /// <param name="country"> Country ISO code. </param>
        /// <param name="type"> Location accuracy type. </param>
        public override void SetDeviceLocation(double latitude, double longitude, string city, string region, string country, LPLocationAccuracyType type)
        {
            var parameters = new Dictionary <string, string>();

            parameters[Constants.Keys.LOCATION] = string.Format("{0},{1}", latitude, longitude);
            parameters[Constants.Keys.LOCATION_ACCURACY_TYPE] = LocationAccuracyTypeToString(type);
            parameters[Constants.Keys.COUNTRY] = city;
            parameters[Constants.Keys.REGION]  = region;
            parameters[Constants.Keys.CITY]    = country;
            LeanplumRequest.Post(Constants.Methods.SET_USER_ATTRIBUTES, parameters);
        }
Beispiel #7
0
 internal static bool SendVariablesIfChanged()
 {
     if (devModeValuesFromServer != null && valuesFromClient != devModeValuesFromServer)
     {
         var parameters = new Dictionary <string, string>();
         parameters[Constants.Params.VARIABLES] = Json.Serialize(valuesFromClient);
         parameters[Constants.Params.KINDS]     = Json.Serialize(defaultKinds);
         LeanplumUnityHelper.QueueOnMainThread(() => LeanplumRequest.Post(Constants.Methods.SET_VARS, parameters).SendNow());
         return(true);
     }
     return(false);
 }
 /// <summary>
 ///     Resumes the current state.
 /// </summary>
 public override void ResumeState()
 {
     if (Constants.isNoop)
     {
         return;
     }
     if (!calledStart)
     {
         CompatibilityLayer.LogError("You cannot call ResumeState before calling start.");
         return;
     }
     LeanplumRequest.Post(Constants.Methods.RESUME_STATE,
                          new Dictionary <string, string>()).Send();
 }
Beispiel #9
0
        public override void Remove(string messageId)
        {
            if (messageId != null)
            {
                var msgs = _messages.FindAll(msg => msg.Id != messageId).ToList();

                UpdateMessages(msgs);

                var param = new Dictionary <string, string>
                {
                    [Constants.Params.INBOX_MESSAGE_ID] = messageId
                };

                LeanplumRequest request = LeanplumRequest.Post(Constants.Methods.DELETE_INBOX_MESSAGE, param);
                request.SendIfConnected();
            }
        }
        /// <summary>
        ///     Allows start to be called again.
        /// </summary>
        internal static void Reset()
        {
            if (calledStart)
            {
                Stop();
            }

            calledStart = false;
            _hasStarted = false;
            _HasStartedAndRegisteredAsDeveloper = false;
            startSuccessful = false;

            variablesChanged = null;
            variablesChangedAndNoDownloadsPending = null;
            started = null;
            LeanplumRequest.ClearNoPendingDownloads();
        }
 /// <summary>
 ///     Call this when your application resumes.
 /// </summary>
 internal static void Resume()
 {
     if (Constants.isNoop)
     {
         return;
     }
     if (!calledStart)
     {
         CompatibilityLayer.LogError("You cannot call Resume before calling start.");
         return;
     }
     if (isPaused)
     {
         isPaused = false;
         LeanplumRequest.Post(Constants.Methods.RESUME_SESSION, null).SendIfConnected();
     }
 }
 /// <summary>
 ///     Call this when your application stops.
 /// </summary>
 internal static void Stop()
 {
     if (Constants.isNoop)
     {
         return;
     }
     if (!calledStart)
     {
         CompatibilityLayer.LogError("You cannot call Stop before calling start.");
         return;
     }
     if (leanplumSocket != null)
     {
         leanplumSocket.Close();
     }
     LeanplumRequest.Post(Constants.Methods.STOP, null).SendIfConnected();
 }
        /// <summary>
        ///     Sets the traffic source info for the current user.
        ///     Keys in info must be one of: publisherId, publisherName, publisherSubPublisher,
        ///     publisherSubSite, publisherSubCampaign, publisherSubAdGroup, publisherSubAd.
        /// </summary>
        public override void SetTrafficSourceInfo(IDictionary <string, string> info)
        {
            if (Constants.isNoop)
            {
                return;
            }
            if (!calledStart)
            {
                CompatibilityLayer.LogError("You cannot call SetTrafficSourceInfo before calling " +
                                            "Start.");
                return;
            }
            IDictionary <string, string> requestParams = new Dictionary <string, string>();

            requestParams[Constants.Params.TRAFFIC_SOURCE] = Json.Serialize(info);
            LeanplumRequest.Post(Constants.Methods.SET_TRAFFIC_SOURCE_INFO, requestParams).Send();
        }
Beispiel #14
0
        public override void Read(string messageId)
        {
            if (messageId != null)
            {
                var msg = _messages.Find(message => message.Id == messageId);

                if (msg != null)
                {
                    msg.IsRead = true;

                    var param = new Dictionary <string, string>
                    {
                        [Constants.Params.INBOX_MESSAGE_ID] = messageId
                    };

                    LeanplumRequest request = LeanplumRequest.Post(Constants.Methods.MARK_INBOX_MESSAGE_AS_READ, param);
                    request.SendIfConnected();
                }
            }
        }
Beispiel #15
0
        internal static void ForceSendVariables(Leanplum.SyncVariablesCompleted completedHandler)
        {
            var parameters = new Dictionary <string, string>();

            parameters[Constants.Params.VARIABLES] = Json.Serialize(valuesFromClient);
            parameters[Constants.Params.KINDS]     = Json.Serialize(defaultKinds);
            LeanplumUnityHelper.QueueOnMainThread(() => {
                LeanplumRequest setVarsReq = LeanplumRequest.Post(Constants.Methods.SET_VARS, parameters);
                setVarsReq.Response       += delegate(object response)
                {
                    completedHandler?.Invoke(true);
                };
                setVarsReq.Error += delegate(Exception ex)
                {
                    LeanplumNative.CompatibilityLayer.LogError("Leanplum Error: ForceSyncVariables", ex);
                    completedHandler?.Invoke(false);
                };
                setVarsReq.SendNow();
            });
        }
        /// <summary>
        ///     Updates the user ID and adds or modifies user attributes.
        /// </summary>
        /// <param name="newUserId">New user identifier.</param>
        /// <param name="value">User attributes.</param>
        public override void SetUserAttributes(string newUserId, IDictionary <string, object> value)
        {
            if (!calledStart)
            {
                CompatibilityLayer.LogWarning("Start was not called. Set user ID and attributes " +
                                              "as the arguments when calling Start.");
                return;
            }
            if (Constants.isNoop)
            {
                return;
            }

            var parameters = new Dictionary <string, string>();

            if (value != null)
            {
                ValidateAttributes(value);
                parameters[Constants.Params.USER_ATTRIBUTES] = Json.Serialize(value);
            }
            if (!String.IsNullOrEmpty(newUserId))
            {
                parameters[Constants.Params.NEW_USER_ID] = newUserId;
                VarCache.SaveDiffs();
            }
            LeanplumRequest.Post(Constants.Methods.SET_USER_ATTRIBUTES, parameters).Send();

            if (!String.IsNullOrEmpty(newUserId))
            {
                LeanplumRequest.UserId = newUserId;
                if (_hasStarted)
                {
                    VarCache.SaveDiffs();
                }
            }
        }
        /// <summary>
        ///     Call this when your application starts.
        ///     This will initiate a call to Leanplum's servers to get the values
        ///     of the variables used in your app.
        /// </summary>
        public override void Start(string userId, IDictionary <string, object> attributes,
                                   Leanplum.StartHandler startResponseAction)
        {
            if (calledStart)
            {
                CompatibilityLayer.Log("Already called start");
                return;
            }
            if (String.IsNullOrEmpty(LeanplumRequest.AppId))
            {
                CompatibilityLayer.LogError("You cannot call Start without setting your app's " +
                                            "API keys.");
                return;
            }

            if (CompatibilityLayer.GetPlatformName() == "Standalone")
            {
                // TODO: Fix this.
                // This is a workaround for SSL issues when running on
                // standalone when connecting with the production server.
                // No issue on staging.
                Constants.API_SSL = false;
            }

            if (startResponseAction != null)
            {
                Started += startResponseAction;
            }
            if (Constants.isNoop)
            {
                _hasStarted     = true;
                startSuccessful = true;
                OnVariablesChanged();
                OnVariablesChangedAndNoDownloadsPending();
                OnStarted(true);
                VarCache.ApplyVariableDiffs(null, null);
                return;
            }

            ValidateAttributes(attributes);
            calledStart = true;

            // Load the variables that were stored on the device from the last session.
            VarCache.IsSilent = true;
            VarCache.LoadDiffs();
            VarCache.IsSilent = false;

            // Setup class members.
            VarCache.Update += delegate
            {
                OnVariablesChanged();
                if (LeanplumRequest.PendingDownloads == 0)
                {
                    OnVariablesChangedAndNoDownloadsPending();
                }
            };

            LeanplumRequest.NoPendingDownloads += delegate
            {
                OnVariablesChangedAndNoDownloadsPending();
            };

            string deviceId;

            if (customDeviceId != null)
            {
                deviceId = customDeviceId;
            }
            else
            {
                deviceId = CompatibilityLayer.GetDeviceId();
            }
            LeanplumRequest.DeviceId = deviceId;

            // Don't overwrite UserID if it was set previously if Start()
            // was called without a new UserID.
            if (!String.IsNullOrEmpty(userId))
            {
                LeanplumRequest.UserId = userId;
            }
            if (String.IsNullOrEmpty(LeanplumRequest.UserId))
            {
                LeanplumRequest.UserId = deviceId;
            }

            // Setup parameters.
            var parameters = new Dictionary <string, string>();

            parameters[Constants.Params.INCLUDE_DEFAULTS]      = false.ToString();
            parameters[Constants.Params.VERSION_NAME]          = CompatibilityLayer.VersionName ?? "";
            parameters[Constants.Params.DEVICE_NAME]           = CompatibilityLayer.GetDeviceName();
            parameters[Constants.Params.DEVICE_MODEL]          = CompatibilityLayer.GetDeviceModel();
            parameters[Constants.Params.DEVICE_SYSTEM_NAME]    = CompatibilityLayer.GetSystemName();
            parameters[Constants.Params.DEVICE_SYSTEM_VERSION] =
                CompatibilityLayer.GetSystemVersion();
            TimeZone timezone = System.TimeZone.CurrentTimeZone;

            if (timezone.IsDaylightSavingTime(DateTime.UtcNow))
            {
                parameters[Constants.Keys.TIMEZONE] = timezone.DaylightName;
            }
            else
            {
                parameters[Constants.Keys.TIMEZONE] = timezone.StandardName;
            }
            parameters[Constants.Keys.TIMEZONE_OFFSET_SECONDS] =
                timezone.GetUtcOffset(DateTime.UtcNow).TotalSeconds.ToString();
            parameters[Constants.Keys.COUNTRY]  = Constants.Values.DETECT;
            parameters[Constants.Keys.REGION]   = Constants.Values.DETECT;
            parameters[Constants.Keys.CITY]     = Constants.Values.DETECT;
            parameters[Constants.Keys.LOCATION] = Constants.Values.DETECT;
            if (attributes != null)
            {
                parameters[Constants.Params.USER_ATTRIBUTES] = Json.Serialize(attributes);
            }

            // Issue start API call.
            LeanplumRequest req = LeanplumRequest.Post(Constants.Methods.START, parameters);

            req.Response += delegate(object responsesObject)
            {
                IDictionary <string, object> response =
                    Util.GetLastResponse(responsesObject) as IDictionary <string, object>;
                IDictionary <string, object> values =
                    Util.GetValueOrDefault(response, Constants.Keys.VARS) as
                    IDictionary <string, object> ?? new Dictionary <string, object>();
                IDictionary <string, object> fileAttributes =
                    Util.GetValueOrDefault(response, Constants.Keys.FILE_ATTRIBUTES) as
                    IDictionary <string, object> ?? new Dictionary <string, object>();
                List <object> variants = Util.GetValueOrDefault(response, Constants.Keys.VARIANTS) as
                                         List <object> ?? new List <object>();
                bool isRegistered = (bool)Util.GetValueOrDefault(response,
                                                                 Constants.Keys.IS_REGISTERED, false);

                LeanplumRequest.Token = Util.GetValueOrDefault(response, Constants.Keys.TOKEN) as
                                        string ?? "";

                // Allow bidirectional realtime variable updates.
                if (Constants.isDevelopmentModeEnabled)
                {
                    VarCache.SetDevModeValuesFromServer(
                        Util.GetValueOrDefault(response, Constants.Keys.VARS_FROM_CODE) as
                        Dictionary <string, object>);

                    if (Constants.EnableRealtimeUpdatesInDevelopmentMode &&
                        SocketUtilsFactory.Utils.AreSocketsAvailable)
                    {
                        leanplumSocket = new LeanplumSocket(delegate() {
                            // Callback when we receive an updateVars command through the
                            // development socket.
                            // Set a flag so that the next time VarCache.CheckVarsUpdate() is
                            // called the variables are updated.
                            VarCache.VarsNeedUpdate = true;
                        });
                    }

                    // Register device.
                    if (isRegistered)
                    {
                        // Check for updates.
                        string latestVersion = Util.GetValueOrDefault(response,
                                                                      Constants.Keys.LATEST_VERSION) as string;
                        if (latestVersion != null)
                        {
                            CompatibilityLayer.Log("Leanplum Unity SDK " + latestVersion +
                                                   " available. Go to https://www.leanplum.com/dashboard to " +
                                                   "download it.");
                        }
                        OnHasStartedAndRegisteredAsDeveloper();
                    }
                }

                VarCache.ApplyVariableDiffs(values, fileAttributes, variants);
                _hasStarted     = true;
                startSuccessful = true;
                OnStarted(true);
                CompatibilityLayer.Init();
            };
            req.Error += delegate
            {
                VarCache.ApplyVariableDiffs(null, null);
                _hasStarted     = true;
                startSuccessful = false;
                OnStarted(false);
                CompatibilityLayer.Init();
            };
            req.SendIfConnected();
        }
Beispiel #18
0
        public override void DownloadMessages(OnForceContentUpdate completedHandler)
        {
            LeanplumRequest request = LeanplumRequest.Post(Constants.Methods.GET_INBOX_MESSAGES, null);

            request.Response += delegate(object data)
            {
                try
                {
                    var response      = Util.GetLastResponse(data) as IDictionary <string, object>;
                    var messages      = Util.GetValueOrDefault(response, Constants.Keys.INBOX_MESSAGES) as IDictionary <string, object>;
                    var inboxMessages = new List <Message>();

                    if (messages != null)
                    {
                        foreach (var pair in messages)
                        {
                            var id = pair.Key;
                            if (pair.Value is IDictionary <string, object> value)
                            {
                                var message = new Message
                                {
                                    Id = id
                                };

                                if (value.TryGetValue(Constants.Keys.MESSAGE_IS_READ, out var isRead))
                                {
                                    if (isRead is bool b)
                                    {
                                        message.IsRead = b;
                                    }
                                }

                                if (value.TryGetValue(Constants.Keys.DELIVERY_TIMESTAMP, out var deliveryTimestamp))
                                {
                                    if (deliveryTimestamp is long l)
                                    {
                                        TimeSpan ts   = TimeSpan.FromMilliseconds(l);
                                        DateTime date = new DateTime(1970, 1, 1).AddTicks(ts.Ticks);
                                        message.DeliveryTimestamp = date;
                                    }
                                }

                                if (value.TryGetValue(Constants.Keys.EXPIRATION_TIMESTAMP, out var expirationTimestamp))
                                {
                                    if (expirationTimestamp is long l)
                                    {
                                        TimeSpan ts   = TimeSpan.FromMilliseconds(l);
                                        DateTime date = new DateTime(1970, 1, 1).AddTicks(ts.Ticks);
                                        message.ExpirationTimestamp = date;
                                    }
                                }

                                if (value.TryGetValue(Constants.Keys.MESSAGE_DATA, out var messageData))
                                {
                                    if (messageData is IDictionary <string, object> dict)
                                    {
                                        if (dict.TryGetValue(Constants.Keys.VARS, out var vars))
                                        {
                                            if (vars is Dictionary <string, object> varsDict)
                                            {
                                                message.ActionContext = varsDict;

                                                if (varsDict.TryGetValue(Constants.Keys.TITLE, out var title))
                                                {
                                                    message.Title = title as string;
                                                }

                                                if (varsDict.TryGetValue(Constants.Keys.SUBTITLE, out var subtitle))
                                                {
                                                    message.Subtitle = subtitle as string;
                                                }

                                                if (varsDict.TryGetValue(Constants.Keys.IMAGE, out var image))
                                                {
                                                    message.ImageURL = image as string;
                                                }
                                            }
                                        }
                                    }
                                }

                                inboxMessages.Add(message);
                            }
                        }
                    }
                    UpdateMessages(inboxMessages);
                    TriggerInboxSyncedWithStatus(true, completedHandler);
                }
                catch (Exception exception)
                {
                    Debug.Log("exception getting messages: " + exception.Message);
                    TriggerInboxSyncedWithStatus(false, completedHandler);
                }
            };

            request.Error += delegate
            {
                TriggerInboxSyncedWithStatus(false, completedHandler);
            };

            request.SendIfConnected();
        }
Beispiel #19
0
        public override void Update()
        {
            object newValue = VarCache.GetMergedValueFromComponentArray(NameComponents);

            if (newValue == null)
            {
                newValue = GetDefaultValue();
            }

            if (Kind == Constants.Kinds.FILE)
            {
                if (VarCache.IsSilent)
                {
                    return;
                }
                string newFile = newValue.ToString();
                string url     = null;

                if (String.IsNullOrEmpty(newFile))
                {
                    return;
                }

                if (VarCache.FileAttributes != null && VarCache.FileAttributes.ContainsKey(newFile))
                {
                    IDictionary <string, object> currentFile =
                        (VarCache.FileAttributes[newFile] as IDictionary <string, object>)
                        [String.Empty] as IDictionary <string, object>;
                    if (currentFile.ContainsKey(Constants.Keys.URL))
                    {
                        url = ((VarCache.FileAttributes[newFile] as IDictionary <string, object>)
                               [String.Empty] as IDictionary <string, object>)[Constants.Keys.URL] as string;
                    }
                }

                // Update if the file is different from what we currently have and if we have started downloading it
                // already. Also update if we don't have the file but don't update if realtime updating is disabled -
                // wait 'til we get the value from the serve so that the correct file is displayed.
                if (currentlyDownloadingFile != newFile && !String.IsNullOrEmpty(url) &&
                    ((newFile != FileName && realtimeAssetUpdating && fileReady) ||
                     (Value == null && realtimeAssetUpdating)))
                {
                    VarCache.downloadsPending++;
                    currentlyDownloadingFile = newFile;
                    FileName  = newFile;
                    fileReady = false;

                    LeanplumRequest downloadRequest = LeanplumRequest.Get(url.Substring(1));
                    downloadRequest.Response += delegate(object obj) {
                        _value = (T)obj;
                        if (newFile == FileName && !fileReady)
                        {
                            fileReady = true;
                            OnValueChanged();
                            currentlyDownloadingFile = null;
                        }
                        VarCache.downloadsPending--;
                    };
                    downloadRequest.Error += delegate(Exception obj) {
                        if (newFile == FileName && !fileReady)
                        {
                            LeanplumNative.CompatibilityLayer.LogError("Error downloading assetbundle \"" +
                                                                       FileName + "\". " + obj.ToString());
                            currentlyDownloadingFile = null;
                        }
                        VarCache.downloadsPending--;
                    };
                    downloadRequest.DownloadAssetNow();
                }
            }
            else
            {
                if (Json.Serialize(newValue) != Json.Serialize(Value))
                {
                    try
                    {
                        if (newValue is IDictionary || newValue is IList)
                        {
                            // If the value is a container, copy all the values from the newValue container to Value.
                            SharedUtil.FillInValues(newValue, Value);
                        }
                        else
                        {
                            _value = (T)Convert.ChangeType(newValue, typeof(T));
                        }
                        if (VarCache.IsSilent)
                        {
                            return;
                        }
                        OnValueChanged();
                    }
                    catch (Exception ex)
                    {
                        Util.MaybeThrow(new LeanplumException("Error parsing values from server. " + ex.ToString()));
                        return;
                    }
                }
            }
        }
 /// <summary>
 ///     Must call either this or SetAppIdForDevelopmentMode
 ///     before issuing any calls to the API, including start.
 /// </summary>
 /// <param name="appId"> Your app ID. </param>
 /// <param name="accessKey"> Your production key. </param>
 public override void SetAppIdForProductionMode(string appId, string accessKey)
 {
     Constants.isDevelopmentModeEnabled = false;
     LeanplumRequest.SetAppId(appId, accessKey);
 }