private void SaveSettingsCollectionStylesCss() { string path = FolderPath.CombineForPath("settingsCollectionStyles.css"); try { var sb = new StringBuilder(); sb.AppendLine("/* These styles are controlled by the Settings dialog box in Bloom. */"); sb.AppendLine("/* They many be over-ridden by rules in customCollectionStyles.css or customBookStyles.css */"); AddSelectorCssRule(sb, "BODY", GetDefaultFontName(), false, 0, false); // note: css pseudo elements cannot have a @lang attribute. So this is needed to show page numbers in scripts // not covered by Andika New Basic. AddSelectorCssRule(sb, ".numberedPage::after", DefaultLanguage1FontName, IsLanguage1Rtl, Language1LineHeight, Language1BreaksLinesOnlyAtSpaces); AddSelectorCssRule(sb, "[lang='" + Language1Iso639Code + "']", DefaultLanguage1FontName, IsLanguage1Rtl, Language1LineHeight, Language1BreaksLinesOnlyAtSpaces); AddSelectorCssRule(sb, "[lang='" + Language2Iso639Code + "']", DefaultLanguage2FontName, IsLanguage2Rtl, Language2LineHeight, Language2BreaksLinesOnlyAtSpaces); if (!string.IsNullOrEmpty(Language3Iso639Code)) { AddSelectorCssRule(sb, "[lang='" + Language3Iso639Code + "']", DefaultLanguage3FontName, IsLanguage3Rtl, Language3LineHeight, Language3BreaksLinesOnlyAtSpaces); } RobustFile.WriteAllText(path, sb.ToString()); } catch (Exception error) { ErrorReport.NotifyUserOfProblem(error, "Bloom was unable to update this file: {0}", path); } }
/// ------------------------------------------------------------------------------------ public void Load() { try { XElement library = XElement.Load(SettingsFilePath); Language1Iso639Code = GetValue(library, "Language1Iso639Code", /* old name */ GetValue(library, "Language1Iso639Code", "")); Language2Iso639Code = GetValue(library, "Language2Iso639Code", /* old name */ GetValue(library, "National1Iso639Code", "en")); Language3Iso639Code = GetValue(library, "Language3Iso639Code", /* old name */ GetValue(library, "National2Iso639Code", "")); XMatterPackName = GetValue(library, "XMatterPack", "Factory"); Language1Name = GetValue(library, "Language1Name", /* old name */ GetValue(library, "LanguageName", "")); DefaultLanguage1FontName = GetValue(library, "DefaultLanguage1FontName", GetDefaultFontName()); DefaultLanguage2FontName = GetValue(library, "DefaultLanguage2FontName", GetDefaultFontName()); DefaultLanguage3FontName = GetValue(library, "DefaultLanguage3FontName", GetDefaultFontName()); IsLanguage1Rtl = GetBoolValue(library, "IsLanguage1Rtl", false); IsLanguage2Rtl = GetBoolValue(library, "IsLanguage2Rtl", false); IsLanguage3Rtl = GetBoolValue(library, "IsLanguage3Rtl", false); Country = GetValue(library, "Country", ""); Province = GetValue(library, "Province", ""); District = GetValue(library, "District", ""); AllowNewBooks = GetBoolValue(library, "AllowNewBooks", true); IsSourceCollection = GetBoolValue(library, "IsSourceCollection", GetBoolValue(library, "IsShellLibrary" /*the old name*/, GetBoolValue(library, "IsShellMakingProject" /*an even older name*/, false))); } catch (Exception e) { ApplicationException a = new ApplicationException(File.ReadAllText(SettingsFilePath), e); Palaso.Reporting.ErrorReport.NotifyUserOfProblem(e, "There was an error reading the library settings file. Please report this error to the developers. To get access to your books, you should make a new library, then copy your book folders from this broken library into the new one, then run Bloom again."); throw; } try { string oldcustomCollectionStylesPath = FolderPath.CombineForPath("collection.css"); if (File.Exists(oldcustomCollectionStylesPath)) { string newcustomCollectionStylesPath = FolderPath.CombineForPath("customCollectionStyles.css"); File.Move(oldcustomCollectionStylesPath, newcustomCollectionStylesPath); } } catch (Exception) { //ah well, we tried, no big deal, only a couple of beta testers used this old name } }
private void SavesettingsCollectionStylesCss() { string path = FolderPath.CombineForPath("settingsCollectionStyles.css"); try { var sb = new StringBuilder(); sb.AppendLine("/* These styles are controlled by the Settings dialog box in Bloom. */"); sb.AppendLine("/* They many be over-ridden by rules in customCollectionStyles.css or customBookStyles.css */"); sb.AppendLine(); sb.AppendLine("BODY"); sb.AppendLine("{"); sb.AppendLine(" font-family: '" + DefaultLanguage1FontName + "';"); sb.AppendLine("}"); File.WriteAllText(path, sb.ToString()); } catch (Exception error) { Palaso.Reporting.ErrorReport.NotifyUserOfProblem(error, "Bloom was unable to update this file: {0}", path); } }
private void SavesettingsCollectionStylesCss() { string path = FolderPath.CombineForPath("settingsCollectionStyles.css"); try { var sb = new StringBuilder(); sb.AppendLine("/* These styles are controlled by the Settings dialog box in Bloom. */"); sb.AppendLine("/* They many be over-ridden by rules in customCollectionStyles.css or customBookStyles.css */"); AddFontCssRule(sb, "BODY", GetDefaultFontName()); AddFontCssRule(sb, "DIV:lang(" + Language1Iso639Code + ")", DefaultLanguage1FontName); AddFontCssRule(sb, "DIV:lang(" + Language2Iso639Code + ")", DefaultLanguage2FontName); if (!string.IsNullOrEmpty(Language3Iso639Code)) { AddFontCssRule(sb, "DIV:lang(" + Language3Iso639Code + ")", DefaultLanguage3FontName); } File.WriteAllText(path, sb.ToString()); } catch (Exception error) { Palaso.Reporting.ErrorReport.NotifyUserOfProblem(error, "Bloom was unable to update this file: {0}", path); } }
/// ------------------------------------------------------------------------------------ public void Load() { try { XElement library = SIL.IO.RobustIO.LoadXElement(SettingsFilePath); Language1Iso639Code = GetValue(library, "Language1Iso639Code", /* old name */ GetValue(library, "Language1Iso639Code", "")); Language2Iso639Code = GetValue(library, "Language2Iso639Code", /* old name */ GetValue(library, "National1Iso639Code", "en")); Language3Iso639Code = GetValue(library, "Language3Iso639Code", /* old name */ GetValue(library, "National2Iso639Code", "")); XMatterPackName = GetValue(library, "XMatterPack", "Factory"); var style = GetValue(library, "PageNumberStyle", "Decimal"); PageNumberStyle = PageNumberStyleKeys.Contains(style) ? style : "Decimal"; BrandingProjectName = GetValue(library, "BrandingProjectName", "Default"); Language1Name = GetValue(library, "Language1Name", /* old name */ GetValue(library, "LanguageName", "")); DefaultLanguage1FontName = GetValue(library, "DefaultLanguage1FontName", GetDefaultFontName()); DefaultLanguage2FontName = GetValue(library, "DefaultLanguage2FontName", GetDefaultFontName()); DefaultLanguage3FontName = GetValue(library, "DefaultLanguage3FontName", GetDefaultFontName()); OneTimeCheckVersionNumber = GetIntegerValue(library, "OneTimeCheckVersionNumber", 0); IsLanguage1Rtl = GetBoolValue(library, "IsLanguage1Rtl", false); IsLanguage2Rtl = GetBoolValue(library, "IsLanguage2Rtl", false); IsLanguage3Rtl = GetBoolValue(library, "IsLanguage3Rtl", false); Language1LineHeight = GetDecimalValue(library, "Language1LineHeight", 0); Language2LineHeight = GetDecimalValue(library, "Language2LineHeight", 0); Language3LineHeight = GetDecimalValue(library, "Language3LineHeight", 0); Country = GetValue(library, "Country", ""); Province = GetValue(library, "Province", ""); District = GetValue(library, "District", ""); AllowNewBooks = GetBoolValue(library, "AllowNewBooks", true); IsSourceCollection = GetBoolValue(library, "IsSourceCollection", GetBoolValue(library, "IsShellLibrary" /*the old name*/, GetBoolValue(library, "IsShellMakingProject" /*an even older name*/, false))); } catch (Exception e) { string settingsContents = ""; try { settingsContents = RobustFile.ReadAllText(SettingsFilePath); } catch (Exception error) { settingsContents = error.Message; } Logger.WriteEvent("Contents of " + SettingsFilePath + ": /r/n" + settingsContents); SIL.Reporting.ErrorReport.NotifyUserOfProblem(e, "There was an error reading the file {0}. Please report this error to the developers. To get access to your books, you should make a new collection, then copy your book folders from this broken collection into the new one, then run Bloom again.", SettingsFilePath); throw; } try { string oldcustomCollectionStylesPath = FolderPath.CombineForPath("collection.css"); if (RobustFile.Exists(oldcustomCollectionStylesPath)) { string newcustomCollectionStylesPath = FolderPath.CombineForPath("customCollectionStyles.css"); RobustFile.Move(oldcustomCollectionStylesPath, newcustomCollectionStylesPath); } } catch (Exception) { //ah well, we tried, no big deal, only a couple of beta testers used this old name } // Check if we need to do a one time check (perhaps migrate to a new Settings value) if (OneTimeCheckVersionNumber < kCurrentOneTimeCheckVersionNumber) { DoOneTimeCheck(); } }
/// ------------------------------------------------------------------------------------ public void Load() { try { // Previously was SIL.IO.RobustIO.LoadXElement(SettingsFilePath). However, we had problems with this // using some non-roman collection names...specifically, one involving the Northern Pashto // localization of 'books' (┌й╪к╪з╪и┘И┘Ж┘З)...see BL-5416. It seems that somewhere in the // implementation of Linq.XElement.Load() the path is converted to a URL and then back // to a path and something changes in that process so that a valid path passed to Load() // raises an invalid path exception. Reading the file directly and then parsing the string // works around this problem. var settingsContent = RobustFile.ReadAllText(SettingsFilePath, Encoding.UTF8); var nameMigrations = new[] { new[] { "LanguageName", "Language1Name" }, new[] { "IsShellLibrary", "IsSourceCollection" }, new[] { "National1Iso639Code", "Language2Iso639Code" }, new[] { "National2Iso639Code", "Language3Iso639Code" }, new[] { "IsShellMakingProject", "IsSourceCollection" }, new[] { "Local Community", "Local-Community" } // migrate for 4.4 }; foreach (var fromTo in nameMigrations) { settingsContent = settingsContent.Replace(fromTo[0], fromTo[1]); } var xml = XElement.Parse(settingsContent); // The default if we don't find one is the arbitrary ID generated when we initialized // the variable (at its declaration). CollectionId = ReadString(xml, "CollectionId", CollectionId); Language1.ReadFromXml(xml, true, "en"); Language2.ReadFromXml(xml, true, "self"); Language3.ReadFromXml(xml, true, Language2.Iso639Code); SignLanguageIso639Code = ReadString(xml, "SignLanguageIso639Code", /* old name */ ReadString(xml, "SignLanguageIso639Code", "")); XMatterPackName = ReadString(xml, "XMatterPack", "Factory"); var style = ReadString(xml, "PageNumberStyle", "Decimal"); //for historical (and maybe future?) reasons, we collect the page number style as one of the //CSS counter number styles PageNumberStyle = CssNumberStylesToCultureOrDigits.Keys.Contains(style) ? style : "Decimal"; OneTimeCheckVersionNumber = ReadInteger(xml, "OneTimeCheckVersionNumber", 0); BrandingProjectKey = ReadString(xml, "BrandingProjectName", "Default"); SubscriptionCode = ReadString(xml, "SubscriptionCode", null); if (BrandingProjectKey != "Default" && BrandingProjectKey != "Local-Community" && !Program.RunningHarvesterMode) { // Validate branding, so things can't be circumvented by just typing something random into settings var expirationDate = CollectionSettingsApi.GetExpirationDate(SubscriptionCode); if (expirationDate < DateTime.Now) // no longer require branding files to exist yet { InvalidBranding = BrandingProjectKey; BrandingProjectKey = "Default"; // keep the code, but don't use it as active branding. } } SignLanguageName = ReadString(xml, "SignLanguageName", GetSignLanguageName_NoCache()); Country = ReadString(xml, "Country", ""); Province = ReadString(xml, "Province", ""); District = ReadString(xml, "District", ""); AllowNewBooks = ReadBoolean(xml, "AllowNewBooks", true); IsSourceCollection = ReadBoolean(xml, "IsSourceCollection", false); string audioRecordingModeStr = ReadString(xml, "AudioRecordingMode", "Unknown"); TalkingBookApi.AudioRecordingMode parsedAudioRecordingMode; if (!Enum.TryParse(audioRecordingModeStr, out parsedAudioRecordingMode)) { parsedAudioRecordingMode = TalkingBookApi.AudioRecordingMode.Unknown; } AudioRecordingMode = parsedAudioRecordingMode; AudioRecordingTrimEndMilliseconds = ReadInteger(xml, "AudioRecordingTrimEndMilliseconds", kDefaultAudioRecordingTrimEndMilliseconds); Administrators = ReadString(xml, "Administrators", "") .Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); var defaultTags = ReadString(xml, "DefaultBookTags", "").Split(','); var defaultBookshelfTag = defaultTags.Where(t => t.StartsWith("bookshelf:")).FirstOrDefault(); DefaultBookshelf = defaultBookshelfTag == null ? "" : defaultBookshelfTag.Substring("bookshelf:".Length); var bulkPublishSettingsFromXml = BulkBloomPubPublishSettings.LoadFromXElement(xml); if (bulkPublishSettingsFromXml != null) { BulkPublishBloomPubSettings = bulkPublishSettingsFromXml; } } catch (Exception) { string settingsContents; try { settingsContents = RobustFile.ReadAllText(SettingsFilePath); } catch (Exception error) { settingsContents = error.Message; } Logger.WriteEvent("Contents of " + SettingsFilePath + ": /r/n" + settingsContents); // We used to notify the user of a problem here. // But now we decided it is better to catch at a higher level, at OpenProjectWindow(), else we have two different // error UI dialogs for the same problem. See BL-9916. throw; } try { string oldcustomCollectionStylesPath = FolderPath.CombineForPath("collection.css"); if (RobustFile.Exists(oldcustomCollectionStylesPath)) { string newcustomCollectionStylesPath = FolderPath.CombineForPath("customCollectionStyles.css"); RobustFile.Move(oldcustomCollectionStylesPath, newcustomCollectionStylesPath); } } catch (Exception) { //ah well, we tried, no big deal, only a couple of beta testers used this old name } // Check if we need to do a one time check (perhaps migrate to a new Settings value) if (OneTimeCheckVersionNumber < kCurrentOneTimeCheckVersionNumber) { DoOneTimeCheck(); } SetAnalyticsProperties(); }
/// ------------------------------------------------------------------------------------ public void Load() { try { // Previously was SIL.IO.RobustIO.LoadXElement(SettingsFilePath). However, we had problems with this // using some non-roman collection names...specifically, one involving the Northern Pashti // localization of 'books' (┌й╪к╪з╪и┘И┘Ж┘З)...see BL-5416. It seems that somewhere in the // implementation of Linq.XElement.Load() the path is converted to a URL and then back // to a path and something changes in that process so that a valid path passed to Load() // raises an invalid path exception. Reading the file directly and then parsing the string // works around this problem. var settingsContent = RobustFile.ReadAllText(SettingsFilePath, Encoding.UTF8); var nameMigrations = new[] { new[] { "LanguageName", "Language1Name" }, new[] { "IsShellLibrary", "IsSourceCollection" }, new[] { "National1Iso639Code", "Language2Iso639Code" }, new[] { "National2Iso639Code", "Language3Iso639Code" }, new[] { "IsShellMakingProject", "IsSourceCollection" }, new[] { "Local Community", "Local-Community" } // migrate for 4.4 }; foreach (var fromTo in nameMigrations) { settingsContent = settingsContent.Replace(fromTo[0], fromTo[1]); } var xml = XElement.Parse(settingsContent); Language1.ReadFromXml(xml, true, "en"); Language2.ReadFromXml(xml, true, "self"); Language3.ReadFromXml(xml, true, Language2.Iso639Code); SignLanguageIso639Code = ReadString(xml, "SignLanguageIso639Code", /* old name */ ReadString(xml, "SignLanguageIso639Code", "")); XMatterPackName = ReadString(xml, "XMatterPack", "Factory"); var style = ReadString(xml, "PageNumberStyle", "Decimal"); //for historical (and maybe future?) reasons, we collect the page number style as one of the //CSS counter number styles PageNumberStyle = CssNumberStylesToCultureOrDigits.Keys.Contains(style) ? style : "Decimal"; OneTimeCheckVersionNumber = ReadInteger(xml, "OneTimeCheckVersionNumber", 0); BrandingProjectKey = ReadString(xml, "BrandingProjectName", "Default"); SubscriptionCode = ReadString(xml, "SubscriptionCode", null); if (BrandingProjectKey != "Default" && BrandingProjectKey != "Local-Community" && !Program.RunningHarvesterMode) { // Validate branding, so things can't be circumvented by just typing something into settings var expirationDate = CollectionSettingsApi.GetExpirationDate(SubscriptionCode); if (expirationDate < DateTime.Now || BrandingProject.GetProjectChoices().All(bp => bp.Key != BrandingProjectKey)) { InvalidBranding = BrandingProjectKey; BrandingProjectKey = "Default"; // keep the code, but don't use it as active branding. } } SignLanguageName = ReadString(xml, "SignLanguageName", GetSignLanguageName_NoCache()); Country = ReadString(xml, "Country", ""); Province = ReadString(xml, "Province", ""); District = ReadString(xml, "District", ""); AllowNewBooks = ReadBoolean(xml, "AllowNewBooks", true); IsSourceCollection = ReadBoolean(xml, "IsSourceCollection", false); string audioRecordingModeStr = ReadString(xml, "AudioRecordingMode", "Unknown"); TalkingBookApi.AudioRecordingMode parsedAudioRecordingMode; if (!Enum.TryParse(audioRecordingModeStr, out parsedAudioRecordingMode)) { parsedAudioRecordingMode = TalkingBookApi.AudioRecordingMode.Unknown; } AudioRecordingMode = parsedAudioRecordingMode; AudioRecordingTrimEndMilliseconds = ReadInteger(xml, "AudioRecordingTrimEndMilliseconds", kDefaultAudioRecordingTrimEndMilliseconds); } catch (Exception e) { string settingsContents = ""; try { settingsContents = RobustFile.ReadAllText(SettingsFilePath); } catch (Exception error) { settingsContents = error.Message; } Logger.WriteEvent("Contents of " + SettingsFilePath + ": /r/n" + settingsContents); SIL.Reporting.ErrorReport.NotifyUserOfProblem(e, "There was an error reading the file {0}. Please report this error to the developers. To get access to your books, you should make a new collection, then copy your book folders from this broken collection into the new one, then run Bloom again.", SettingsFilePath); throw; } try { string oldcustomCollectionStylesPath = FolderPath.CombineForPath("collection.css"); if (RobustFile.Exists(oldcustomCollectionStylesPath)) { string newcustomCollectionStylesPath = FolderPath.CombineForPath("customCollectionStyles.css"); RobustFile.Move(oldcustomCollectionStylesPath, newcustomCollectionStylesPath); } } catch (Exception) { //ah well, we tried, no big deal, only a couple of beta testers used this old name } // Check if we need to do a one time check (perhaps migrate to a new Settings value) if (OneTimeCheckVersionNumber < kCurrentOneTimeCheckVersionNumber) { DoOneTimeCheck(); } SetAnalyticsProperties(); }
/// ------------------------------------------------------------------------------------ public void Load() { try { // Previously was SIL.IO.RobustIO.LoadXElement(SettingsFilePath). However, we had problems with this // using some non-roman collection names...specifically, one involving the Northern Pashti // localization of 'books' (┌й╪к╪з╪и┘И┘Ж┘З)...see BL-5416. It seems that somewhere in the // implementation of Linq.XElement.Load() the path is converted to a URL and then back // to a path and something changes in that process so that a valid path passed to Load() // raises an invalid path exception. Reading the file directly and then parsing the string // works around this problem. var settingsContent = RobustFile.ReadAllText(SettingsFilePath, Encoding.UTF8); XElement library = XElement.Parse(settingsContent); Language1Iso639Code = GetValue(library, "Language1Iso639Code", /* old name */ GetValue(library, "Language1Iso639Code", "")); Language2Iso639Code = GetValue(library, "Language2Iso639Code", /* old name */ GetValue(library, "National1Iso639Code", "en")); Language3Iso639Code = GetValue(library, "Language3Iso639Code", /* old name */ GetValue(library, "National2Iso639Code", "")); XMatterPackName = GetValue(library, "XMatterPack", "Factory"); var style = GetValue(library, "PageNumberStyle", "Decimal"); //for historical (and maybe future?) reasons, we collect the page number style as one of the //CSS counter number styles PageNumberStyle = CssNumberStylesToCultureOrDigits.Keys.Contains(style) ? style : "Decimal"; BrandingProjectKey = GetValue(library, "BrandingProjectName", "Default"); Language1Name = GetValue(library, "Language1Name", /* old name */ GetValue(library, "LanguageName", "")); Language2Name = GetValue(library, "Language2Name", GetLanguage2Name_NoCache(Language2Iso639Code)); Language3Name = GetValue(library, "Language3Name", GetLanguage3Name_NoCache(Language2Iso639Code)); DefaultLanguage1FontName = GetValue(library, "DefaultLanguage1FontName", GetDefaultFontName()); DefaultLanguage2FontName = GetValue(library, "DefaultLanguage2FontName", GetDefaultFontName()); DefaultLanguage3FontName = GetValue(library, "DefaultLanguage3FontName", GetDefaultFontName()); OneTimeCheckVersionNumber = GetIntegerValue(library, "OneTimeCheckVersionNumber", 0); IsLanguage1Rtl = GetBoolValue(library, "IsLanguage1Rtl", false); IsLanguage2Rtl = GetBoolValue(library, "IsLanguage2Rtl", false); IsLanguage3Rtl = GetBoolValue(library, "IsLanguage3Rtl", false); Language1LineHeight = GetDecimalValue(library, "Language1LineHeight", 0); Language2LineHeight = GetDecimalValue(library, "Language2LineHeight", 0); Language3LineHeight = GetDecimalValue(library, "Language3LineHeight", 0); Language1BreaksLinesOnlyAtSpaces = GetBoolValue(library, "Language1BreaksLinesOnlyAtSpaces", false); Language2BreaksLinesOnlyAtSpaces = GetBoolValue(library, "Language2BreaksLinesOnlyAtSpaces", false); Language3BreaksLinesOnlyAtSpaces = GetBoolValue(library, "Language3BreaksLinesOnlyAtSpaces", false); Country = GetValue(library, "Country", ""); Province = GetValue(library, "Province", ""); District = GetValue(library, "District", ""); AllowNewBooks = GetBoolValue(library, "AllowNewBooks", true); IsSourceCollection = GetBoolValue(library, "IsSourceCollection", GetBoolValue(library, "IsShellLibrary" /*the old name*/, GetBoolValue(library, "IsShellMakingProject" /*an even older name*/, false))); } catch (Exception e) { string settingsContents = ""; try { settingsContents = RobustFile.ReadAllText(SettingsFilePath); } catch (Exception error) { settingsContents = error.Message; } Logger.WriteEvent("Contents of " + SettingsFilePath + ": /r/n" + settingsContents); SIL.Reporting.ErrorReport.NotifyUserOfProblem(e, "There was an error reading the file {0}. Please report this error to the developers. To get access to your books, you should make a new collection, then copy your book folders from this broken collection into the new one, then run Bloom again.", SettingsFilePath); throw; } try { string oldcustomCollectionStylesPath = FolderPath.CombineForPath("collection.css"); if (RobustFile.Exists(oldcustomCollectionStylesPath)) { string newcustomCollectionStylesPath = FolderPath.CombineForPath("customCollectionStyles.css"); RobustFile.Move(oldcustomCollectionStylesPath, newcustomCollectionStylesPath); } } catch (Exception) { //ah well, we tried, no big deal, only a couple of beta testers used this old name } // Check if we need to do a one time check (perhaps migrate to a new Settings value) if (OneTimeCheckVersionNumber < kCurrentOneTimeCheckVersionNumber) { DoOneTimeCheck(); } // Remove an obsolete page numbering rule if it exists in the collection styles file. // See https://issues.bloomlibrary.org/youtrack/issue/BL-5017. // Saving the styles doesn't write the obsolete rule, effectively removing it. Doing // this unconditionally ensures any future similar problems are covered automatically. SaveSettingsCollectionStylesCss(); SetAnalyticsProperties(); }