示例#1
0
        internal Identify(string userId,
		                  IDictionary<string, object> traits, 
						  Options options)
	
			: base("identify", userId, options)
        {
            this.Traits = traits ?? new Traits();
        }
示例#2
0
        internal Identify(string userId,
		                  Traits traits, 
						  Options options)
	
			: base("identify", userId, options)
        {
            this.Traits = traits ?? new Traits();
        }
示例#3
0
        internal Identify(string userId,
		                  Traits traits, 
						  Options options)
	
			: base("identify", options)
        {
			UserId = userId;
            Traits = traits ?? new Traits();
        }
示例#4
0
		internal Group(string userId, 
					   string groupId,
                       IDictionary<string, object> traits, 
					   Options options)
			: base("group", userId, options)
        {
			this.GroupId = groupId;
			this.Traits = traits ?? new Traits();
        }
示例#5
0
 internal Group(string userId,
     string groupId,
     Traits traits,
     Options options)
     : base("group", userId, options)
 {
     this.GroupId = groupId;
     this.Traits = traits ?? new Traits();
 }
示例#6
0
        internal Track(string userId, 
		               string eventName,
            		   Properties properties, 
					   Options options)

			: base("track", userId, options)
        {
            this.EventName = eventName;
            this.Properties = properties ?? new Properties();
        }
示例#7
0
		internal Group(string userId, 
					   string groupId,
					   Traits traits, 
					   Options options)
			: base("group", options)
        {
			UserId = userId;
			GroupId = groupId;
			Traits = traits ?? new Traits();
        }
示例#8
0
        internal Track(string userId, 
		               string eventName,
            		   Properties properties, 
					   Options options)

			: base("track", options)
        {
			UserId = userId;
            EventName = eventName;
            Properties = properties ?? new Properties();
        }
示例#9
0
		internal Page(string userId, 
					  string name,
					  string category,
            		  Properties properties, 
					  Options options)

			: base("page", userId, options)
		{
			this.Name = name;
			this.Category = category;
            this.Properties = properties ?? new Properties();
        }
示例#10
0
		internal Screen(string userId, 
						string name,
					    string category,
                        IDictionary<string, object> properties, 
					    Options options)

			: base("screen", userId, options)
		{
			this.Name = name;
			this.Category = category;
            this.Properties = properties ?? new Properties();
        }
示例#11
0
		internal Screen(string userId, 
						string name,
					    string category,
            		    Properties properties, 
					    Options options)

			: base("screen", options)
		{
			UserId = userId;
			Name = name;
			Category = category;
            Properties = properties ?? new Properties();
        }
		internal BaseAction(string type, Options options)
		{
			options = options ?? new Options ();

			this.Type = type;
			this.MessageId = Guid.NewGuid ().ToString();
			if (options.Timestamp.HasValue)
				this.Timestamp = options.Timestamp.ToString ();
            else
                this.Timestamp = DateTime.Now.ToString("o");
			this.Context = options.Context;
			this.Integrations = options.Integrations;
        }
示例#13
0
        static AnalyticsManager()
        {
            //anonymise the machine name so it's not too stalkery
            anonymousUserID = GetHashString(Environment.MachineName);

            userProperties = new Segment.Model.Properties()
                            {
                                {"version",UpdateManager.CurrentVersion},
                                {"game",GameConfigurationManager.GameConfiguration.Name}
                            };

            options = new Options {Context = {{"direct", true}}};
        }
示例#14
0
		internal BaseAction(string type, Options options)
		{
			options = options ?? new Options ();

			Type = type;
			MessageId = Guid.NewGuid ().ToString();
			if (options.Timestamp.HasValue)
				Timestamp = options.Timestamp.ToString ();
            else
                Timestamp = DateTime.Now.ToString("o");
			Context = options.Context;
			Integrations = options.Integrations;
			AnonymousId = options.AnonymousId;
        }
示例#15
0
        /// <summary>
        /// The `page` method let your record whenever a user sees a webpage on 
        /// your website, and attach a `name`, `category` or `properties` to the webpage load. 
        /// </summary>
        ///
        /// <param name="userId">The visitor's identifier after they log in, or you know
        /// who they are. By explicitly identifying a user, you tie all of their actions to their identity.
        /// This makes it possible for you to run things like segment-based email campaigns.</param>
        ///
        /// <param name="name">The name of the webpage, like "Signup", "Login"</param>
        /// 
        /// <param name="category">The (optional) category of the mobile screen, like "Authentication", "Sports"</param>
        ///
        /// <param name="properties"> A dictionary with items that describe the page
        /// in more detail. This argument is optional, but highly recommended —
        /// you’ll find these properties extremely useful later.</param>
        ///
        /// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
        /// and the context of th emessage.</param>
        ///
        public void Page(string userId, string name, string category, Properties properties, Options options)
        {
            EnsureId(userId, options);

            if (string.IsNullOrEmpty(name))
                throw new InvalidOperationException("Please supply a valid name to #Page.");

            Enqueue(new Page(userId, name, category, properties, options));
        }
示例#16
0
		/// <summary>
		/// The `screen` method let your record whenever a user sees a mobile screen on 
		/// your mobile app, and attach a `name`, `category` or `properties` to the screen. 
		/// </summary>
		///
		/// <param name="userId">The visitor's identifier after they log in, or you know
		/// who they are. By
		/// explicitly identifying a user, you tie all of their actions to their identity.
		/// This makes it possible for you to run things like segment-based email campaigns.</param>
		///
		/// <param name="name">The name of the mobile screen, like "Signup", "Login"</param>
		/// 
		/// <param name="category">The (optional) category of the mobile screen, like "Authentication", "Sports"</param>
		///
		/// <param name="properties"> A dictionary with items that describe the screen
		/// in more detail. This argument is optional, but highly recommended —
		/// you’ll find these properties extremely useful later.</param>
		///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
		///
		public void Screen(string userId, string name, string category, Properties properties, Options options)
		{
			if (String.IsNullOrEmpty(userId))
				throw new InvalidOperationException("Please supply a valid userId to #Screen.");

			if (String.IsNullOrEmpty(name))
				throw new InvalidOperationException("Please supply a valid name to #Screen.");

			Enqueue(new Screen(userId, name, category, properties, options));
		}
示例#17
0
		/// <summary>
		/// The `screen` method let your record whenever a user sees a mobile screen on 
		/// your mobile app, and attach a `name`, `category` or `properties` to the screen. 
		/// </summary>
		///
		/// <param name="userId">The visitor's identifier after they log in, or you know
		/// who they are. By
		/// explicitly identifying a user, you tie all of their actions to their identity.
		/// This makes it possible for you to run things like segment-based email campaigns.</param>
		///
		/// <param name="name">The name of the mobile screen, like "Signup", "Login"</param>
		///
		/// <param name="properties"> A dictionary with items that describe the screen
		/// in more detail. This argument is optional, but highly recommended —
		/// you’ll find these properties extremely useful later.</param>
		///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
		///
		public void Screen(string userId, string name, Properties properties, Options options)
		{
			Screen (userId, name, null, properties, options);
		}
示例#18
0
		/// <summary>
		/// The `screen` method let your record whenever a user sees a mobile screen on 
		/// your mobile app, and attach a `name`, `category` or `properties` to the screen. 
		/// </summary>
		///
		/// <param name="userId">The visitor's identifier after they log in, or you know
		/// who they are. By
		/// explicitly identifying a user, you tie all of their actions to their identity.
		/// This makes it possible for you to run things like segment-based email campaigns.</param>
		///
		/// <param name="name">The name of the mobile screen, like "Signup", "Login"</param>
		///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
		///
		public void Screen(string userId, string name, Options options)
		{
			Screen (userId, name, null, null, options);
		}
示例#19
0
		/// <summary>
		/// The `page` method let your record whenever a user sees a webpage on 
		/// your website, and attach a `name`, `category` or `properties` to the webpage load. 
		/// </summary>
		///
		/// <param name="userId">The visitor's identifier after they log in, or you know
		/// who they are. By explicitly identifying a user, you tie all of their actions to their identity.
		/// This makes it possible for you to run things like segment-based email campaigns.</param>
		///
		/// <param name="name">The name of the webpage, like "Signup", "Login"</param>
		///
		/// <param name="properties"> A dictionary with items that describe the page
		/// in more detail. This argument is optional, but highly recommended —
		/// you’ll find these properties extremely useful later.</param>
		///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
		///
		public void Page(string userId, string name, Properties properties, Options options)
		{
			Page (userId, name, null, properties, options);
		}
示例#20
0
		/// <summary>
		/// The `page` method let your record whenever a user sees a webpage on 
		/// your website, and attach a `name`, `category` or `properties` to the webpage load. 
		/// </summary>
		///
		/// <param name="userId">The visitor's identifier after they log in, or you know
		/// who they are. By explicitly identifying a user, you tie all of their actions to their identity.
		/// This makes it possible for you to run things like segment-based email campaigns.</param>
		///
		/// <param name="name">The name of the webpage, like "Signup", "Login"</param>
		///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
		///
		public void Page(string userId, string name, Options options)
		{
			Page (userId, name, null, null, options);
		}
示例#21
0
		/// <summary>
		/// Initialized a singleton; after calling this, use Analytics.Track() for each event.
		/// </summary>
		/// <param name="apiSecret">The segment.com apiSecret</param>
		/// <param name="userInfo">Information about the user that you have previous collected</param>
		/// <param name="propertiesThatGoWithEveryEvent">A set of key-value pairs to send with *every* event</param>
		/// <param name="allowTracking">If false, this will not do any communication with segment.io</param>
		public Analytics(string apiSecret, UserInfo userInfo, Dictionary<string, string> propertiesThatGoWithEveryEvent, bool allowTracking = true)
		{
			if (_singleton != null)
			{
				throw new ApplicationException("You can only construct a single Analytics object.");
			}
			_singleton = this;
			_propertiesThatGoWithEveryEvent = propertiesThatGoWithEveryEvent;

			_userInfo = userInfo;

			AllowTracking = allowTracking;
			//UrlThatReturnsExternalIpAddress is a static and should really be set before this is called, so don't mess with it if the client has given us a different url to us
			if (string.IsNullOrEmpty(UrlThatReturnsExternalIpAddress))
				UrlThatReturnsExternalIpAddress = "http://icanhazip.com"; //went down: "http://ipecho.net/plain";

			if (!AllowTracking)
				return;


			//bring in settings from any previous version
			if (AnalyticsSettings.Default.NeedUpgrade)
			{
				//see http://stackoverflow.com/questions/3498561/net-applicationsettingsbase-should-i-call-upgrade-every-time-i-load
				AnalyticsSettings.Default.Upgrade();
				AnalyticsSettings.Default.NeedUpgrade = false;
				AnalyticsSettings.Default.Save();
			}

			if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics))
			{
				// Apparently a first-time install. Any chance we can migrate settings from another channel of this app?
				// We really want to use the same ID if possible to keep our statistics valid.
				try
				{
					AttemptToGetUserIdSettingsFromDifferentChannel();
				}
				catch (Exception)
				{
					// Oh, well, we tried.
				}
			}

			Segment.Analytics.Initialize(apiSecret);
			Segment.Analytics.Client.Failed += Client_Failed;
			Segment.Analytics.Client.Succeeded += Client_Succeeded;

			if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics))
			{

				AnalyticsSettings.Default.IdForAnalytics = Guid.NewGuid().ToString();
				AnalyticsSettings.Default.Save();
			}

			var context = new Context();
			context.Add("language", _userInfo.UILanguageCode);

			_options = new Options();
			_options.SetContext(context);

			UpdateSegmentIOInformationOnThisUser();
			ReportIpAddressOfThisMachineAsync(); //this will take a while and may fail, so just do it when/if we can
			string versionNumberWithBuild = "";
			try
			{
				versionNumberWithBuild = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString();
			}
			catch (NullReferenceException)
			{
				try
				{
					// GetEntryAssembly is null for MAF plugins
					versionNumberWithBuild = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
				}
				catch (NullReferenceException)
				{
					// This probably can't happen, but if it does, just roll with it.
				}
			}
			string versionNumber = versionNumberWithBuild.Split('.').Take(2).Aggregate((a, b) => a + "." + b);
			SetApplicationProperty("Version", versionNumber);
			SetApplicationProperty("FullVersion", versionNumberWithBuild);
			SetApplicationProperty("UserName", GetUserNameForEvent());
			SetApplicationProperty("Browser", GetOperatingSystemLabel());


			if (string.IsNullOrEmpty(AnalyticsSettings.Default.LastVersionLaunched))
			{
				//"Created" is a special property that segment.io understands and coverts to equivalents in various analytics services
				//So it's not as descriptive for us as "FirstLaunchOnSystem", but it will give the best experience on the analytics sites.
				TrackWithApplicationProperties("Created");
			}
			else if (AnalyticsSettings.Default.LastVersionLaunched != versionNumberWithBuild)
			{
				TrackWithApplicationProperties("Upgrade", new Properties
				{
					{"OldVersion", AnalyticsSettings.Default.LastVersionLaunched},
				});
			}

			// We want to record the launch event independent of whether we also recorded a special first launch
			// But that is done after we retrieve (or fail to retrieve) our external ip address.
			// See http://issues.bloomlibrary.org/youtrack/issue/BL-4011.

			AnalyticsSettings.Default.LastVersionLaunched = versionNumberWithBuild;
			AnalyticsSettings.Default.Save();

		}
示例#22
0
		/// <summary>
		/// Whenever a user triggers an event on your site, you’ll want to track it
		/// so that you can analyze and segment by those events later.
		/// </summary>
		///
		/// <param name="userId">The visitor's identifier after they log in, or you know
		/// who they are. By
		/// explicitly identifying a user, you tie all of their actions to their identity.
		/// This makes it possible for you to run things like segment-based email campaigns.</param>
		///
		/// <param name="eventName">The event name you are tracking. It is recommended
		/// that it is in human readable form. For example, "Bought T-Shirt"
		/// or "Started an exercise"</param>
		///
		/// <param name="properties"> A dictionary with items that describe the event
		/// in more detail. This argument is optional, but highly recommended —
		/// you’ll find these properties extremely useful later.</param>
		///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
		/// 
		///
		public void Track(string userId, string eventName, Properties properties, Options options)
		{
			if (String.IsNullOrEmpty(userId))
				throw new InvalidOperationException("Please supply a valid userId to Track.");

			if (String.IsNullOrEmpty(eventName))
				throw new InvalidOperationException("Please supply a valid event to Track.");

			Enqueue(new Track(userId, eventName, properties, options));
		}
示例#23
0
		/// <summary>
		/// Whenever a user triggers an event on your site, you’ll want to track it
		/// so that you can analyze and segment by those events later.
		/// </summary>
		///
		/// <param name="userId">The visitor's identifier after they log in, or you know
		/// who they are. By
		/// explicitly identifying a user, you tie all of their actions to their identity.
		/// This makes it possible for you to run things like segment-based email campaigns.</param>
		///
		/// <param name="eventName">The event name you are tracking. It is recommended
		/// that it is in human readable form. For example, "Bought T-Shirt"
		/// or "Started an exercise"</param>
		///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
		/// 
		///
		public void Track(string userId, string eventName, Options options)
		{
			Track(userId, eventName, null, options);
		}
示例#24
0
		/// <summary>
		/// The `group` method lets you associate a user with a group. Be it a company, 
		/// organization, account, project, team or whatever other crazy name you came up 
		/// with for the same concept! It also lets you record custom traits about the 
		/// group, like industry or number of employees.
		/// </summary>
		///
		/// <param name="userId">The visitor's database identifier after they log in, or you know
		/// who they are. By explicitly grouping a user, you tie all of their actions to their group.</param>
		///
		/// <param name="groupId">The group's database identifier after they log in, or you know
		/// who they are.</param>
		///
		/// <param name="traits">A dictionary with group keys like "name", “subscriptionPlan”. 
		/// You can segment your users by any trait you record. Pass in values in key-value format. 
		/// String key, then its value { String, Integer, Boolean, Double, or Date are acceptable types for a value. } </param>
		///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
		///
		public void Group(string userId, string groupId, Traits traits, Options options)
		{
			if (String.IsNullOrEmpty(userId))
				throw new InvalidOperationException("Please supply a valid userId to call #Group.");

			if (String.IsNullOrEmpty(groupId))
				throw new InvalidOperationException("Please supply a valid groupId to call #Group.");

			Enqueue(new Group(userId, groupId, traits, options));
		}
示例#25
0
		/// <summary>
		/// The `group` method lets you associate a user with a group. Be it a company, 
		/// organization, account, project, team or whatever other crazy name you came up 
		/// with for the same concept! It also lets you record custom traits about the 
		/// group, like industry or number of employees.
		/// </summary>
		///
		/// <param name="userId">The visitor's database identifier after they log in, or you know
		/// who they are. By explicitly grouping a user, you tie all of their actions to their group.</param>
		///
		/// <param name="groupId">The group's database identifier after they log in, or you know
		/// who they are.</param>
		///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
		///
		public void Group(string userId, string groupId, Options options)
		{
			Group (userId, groupId, null, options);
		}
示例#26
0
        /// <summary>
        /// Identifying a visitor ties all of their actions to an ID you
        /// recognize and records visitor traits you can segment by.
        /// </summary>
        ///
        /// <param name="userId">The visitor's identifier after they log in, or you know
        /// who they are. By
        /// explicitly identifying a user, you tie all of their actions to their identity.</param>
        ///
        /// <param name="traits">A dictionary with keys like "email", "name", “subscriptionPlan” or
        /// "friendCount”. You can segment your users by any trait you record.
        /// Pass in values in key-value format. String key, then its value
        /// { String, Integer, Boolean, Double, or Date are acceptable types for a value. } </param>
        ///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
        ///
		public void Identify(string userId, Traits traits, Options options)
        {
			if (String.IsNullOrEmpty(userId))
				throw new InvalidOperationException("Please supply a valid userId to Identify.");

			Enqueue(new Identify(userId, traits, options));
        }
示例#27
0
 private static void EnsureId(string userId, Options options)
 {
     if (userId == null) throw new InvalidOperationException(nameof(userId));
     if (options == null) throw new InvalidOperationException(nameof(options));
     if (string.IsNullOrEmpty(userId) && string.IsNullOrEmpty(options.AnonymousId))
         throw new InvalidOperationException("Please supply a valid id (either userId or anonymousId.");
 }
示例#28
0
		/// <summary>
		/// Aliases an anonymous user into an identified user.
		/// </summary>
		/// 
		/// <param name="previousId">The anonymous user's id before they are logged in.</param>
		/// 
		/// <param name="userId">the identified user's id after they're logged in.</param>
		///
		/// <param name="options">Options allowing you to set timestamp, anonymousId, target integrations,
		/// and the context of th emessage.</param>
		/// 
		public void Alias(string previousId, string userId, Options options)
		{
			if (String.IsNullOrEmpty(previousId))
				throw new InvalidOperationException("Please supply a valid 'previousId' to Alias.");

			if (String.IsNullOrEmpty(userId))
				throw new InvalidOperationException("Please supply a valid 'to' to Alias.");

			Enqueue(new Alias(previousId, userId, options));
		}
		/// <summary>
		/// Initialized a singleton; after calling this, use Analytics.Track() for each event.
		/// </summary>
		/// <param name="apiSecret">The segment.com apiSecret</param>
		/// <param name="userInfo">Information about the user that you have previous collected</param>
		/// <param name="propertiesThatGoWithEveryEvent">A set of key-value pairs to send with *every* event</param>
		/// <param name="allowTracking">If false, this will not do any communication with segment.io</param>
		public Analytics(string apiSecret, UserInfo userInfo, Dictionary<string, string> propertiesThatGoWithEveryEvent, bool allowTracking = true)
		{
			if (_singleton != null)
			{
				throw new ApplicationException("You can only construct a single Analytics object.");
			}
			_singleton = this;
			_propertiesThatGoWithEveryEvent = propertiesThatGoWithEveryEvent;

			_userInfo = userInfo;

			AllowTracking = allowTracking;
			//UrlThatReturnsExternalIpAddress is a static and should really be set before this is called, so don't mess with it if the clien has given us a different url to us
			if (string.IsNullOrEmpty(UrlThatReturnsExternalIpAddress))
				UrlThatReturnsExternalIpAddress = "http://icanhazip.com";//went down: "http://ipecho.net/plain";

			if (!AllowTracking)
				return;


			//bring in settings from any previous version
			if (AnalyticsSettings.Default.NeedUpgrade)
			{
				//see http://stackoverflow.com/questions/3498561/net-applicationsettingsbase-should-i-call-upgrade-every-time-i-load
				AnalyticsSettings.Default.Upgrade();
				AnalyticsSettings.Default.NeedUpgrade = false;
				AnalyticsSettings.Default.Save();
			}

			const string UserConfigFileName = "user.config";

			if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics))
			{
				// Apparently a first-time install. Any chance we can migrate settings from another channel of this app?
				// We really want to use the same ID if possible to keep our statistics valid.

				// We need to get the company name and exe name of the main application, without introducing a dependency on
				// Windows.Forms, so we can't use the Windows.Forms.Application methods.
				var entryAssembly = Assembly.GetEntryAssembly(); // the main exe assembly
				var productExe = Path.GetFileNameWithoutExtension(entryAssembly.Location);
				AssemblyCompanyAttribute companyAttribute = AssemblyCompanyAttribute.GetCustomAttribute(entryAssembly, typeof(AssemblyCompanyAttribute)) as AssemblyCompanyAttribute;
				if (companyAttribute != null && !string.IsNullOrEmpty(productExe))
				{
					string companyName = companyAttribute.Company;
					var settingsLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
						companyName);
					// Coincidentally, 5 is a good length for Bloom...better heuristic later?
					// For example, we could
					// - look for the last capital letter, and truncate to there. BloomAlpha->Bloom; HearThisAlpha->HearThis; *HearThis->Hear; TEX->?TE; TEXAlpha->TEX; BloomBetaOne->*BloomBeta
					// - look for the first non-initial capital letter, and truncate from there on. BloomAlpha->Bloom, HearThisAlpha->*Hear; HearThis->*Hear; TEX->*T' TEXAlpha->TEX; BloomBetaOne->Bloom
					// - look for a non-initial capital letter following at least one LC letter. Similar except TEX->TEX, TEXAlpha->*TEXAlpha.
					// In general, truncating too much is better than too little; too much just makes us slow, while too little may make us miss useful results.
					// It's true that truncating too much (like TEX->TE) may cause us to fetch an analytics ID from the wrong program. But even this is harmless, AFAIK.
					var index = Math.Min(5, productExe.Length);
					var prefix = productExe.Substring(0, index);
					var pattern = prefix + "*";
					var possibleParentFolders = Directory.GetDirectories(settingsLocation, pattern);
					var possibleFolders = new List<string>();
					foreach (var folder in possibleParentFolders)
					{
						possibleFolders.AddRange(Directory.GetDirectories(folder).Where(f => File.Exists(Path.Combine(f, UserConfigFileName))));
					}

					possibleFolders.Sort((first, second) =>
					{
						if (first == second)
							return 0;
						var firstConfigPath = Path.Combine(first, UserConfigFileName);
						var secondConfigPath = Path.Combine(second, UserConfigFileName);
						// Reversing the arguments like this means that second comes before first if it has a LARGER mod time.
						// That is, we end up with the most recently modified user.config first.
						return new FileInfo(secondConfigPath).LastWriteTimeUtc.CompareTo(new FileInfo(firstConfigPath).LastWriteTimeUtc);
					});
					foreach (var folder in possibleFolders)
					{
						try
						{
							var doc = XDocument.Load(Path.Combine(folder, UserConfigFileName));
							var idSetting =
								doc.XPathSelectElement(
									"configuration/userSettings/DesktopAnalytics.AnalyticsSettings/setting[@name='IdForAnalytics']");
							if (idSetting == null)
								continue;
							string analyticsId = idSetting.Value;
							if (string.IsNullOrEmpty(analyticsId))
								continue;
							AnalyticsSettings.Default.IdForAnalytics = analyticsId;
							AnalyticsSettings.Default.FirstName = ExtractSetting(AnalyticsSettings.Default.FirstName, doc, "FirstName");
							AnalyticsSettings.Default.LastName = ExtractSetting(AnalyticsSettings.Default.LastName, doc, "LastName");
							AnalyticsSettings.Default.LastVersionLaunched = ExtractSetting(AnalyticsSettings.Default.LastVersionLaunched, doc, "LastVersionLaunched");
							AnalyticsSettings.Default.Email = ExtractSetting(AnalyticsSettings.Default.Email, doc, "Email");
							AnalyticsSettings.Default.Save();
							break;
						}
						catch (Exception)
						{
							// If anything goes wrong we just won't try to get our ID from this source.
						}
					}
				}
			}

			Segment.Analytics.Initialize(apiSecret);
			Segment.Analytics.Client.Failed += Client_Failed;
			Segment.Analytics.Client.Succeeded += Client_Succeeded;

			if (string.IsNullOrEmpty(AnalyticsSettings.Default.IdForAnalytics))
			{

				AnalyticsSettings.Default.IdForAnalytics = Guid.NewGuid().ToString();
				AnalyticsSettings.Default.Save();
			}

			var context = new Context();
			context.Add("language", _userInfo.UILanguageCode);

			_options = new Options();
			_options.SetContext(context);

			UpdateSegmentIOInformationOnThisUser();
			ReportIpAddressOfThisMachineAsync(); //this will take a while and may fail, so just do it when/if we can
			string versionNumberWithBuild = "";
			try
			{
				versionNumberWithBuild = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString();
			}
			catch (NullReferenceException)
			{
				try
				{
					// GetEntryAssembly is null for MAF plugins
					versionNumberWithBuild = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
				}
				catch (NullReferenceException)
				{
					// This probably can't happen, but if it does, just roll with it.
				}
			}
			string versionNumber = versionNumberWithBuild.Split('.').Take(2).Aggregate((a, b) => a + "." + b);
			SetApplicationProperty("Version", versionNumber);
			SetApplicationProperty("FullVersion", versionNumberWithBuild);
			SetApplicationProperty("UserName", GetUserNameForEvent());
			SetApplicationProperty("Browser", GetOperatingSystemLabel());


			if (string.IsNullOrEmpty(AnalyticsSettings.Default.LastVersionLaunched))
			{
				//"Created" is a special property that segment.io understands and coverts to equivalents in various analytics services
				//So it's not as descriptive for us as "FirstLaunchOnSystem", but it will give the best experience on the analytics sites.
				TrackWithApplicationProperties("Created");
			}
			else if (AnalyticsSettings.Default.LastVersionLaunched != versionNumberWithBuild)
			{
				TrackWithApplicationProperties("Upgrade", new Properties
					{
						{"OldVersion", AnalyticsSettings.Default.LastVersionLaunched},
					});
			}

			//we want to record the launch event independent of whether we also recorded a special first launch
			// But that is done after we retrieve (or fail to retrieve) our external ip address.
			// See http://issues.bloomlibrary.org/youtrack/issue/BL-4011.

			AnalyticsSettings.Default.LastVersionLaunched = versionNumberWithBuild;
			AnalyticsSettings.Default.Save();

		}
示例#30
0
		internal Alias(string previousId, string userId, Options options)
			: base("alias", userId, options)
		{
			this.PreviousId = previousId;
		}