diff options
Diffstat (limited to 'StoneIsland/plugins/cordova-plugin-google-analytics/wp8')
4 files changed, 1110 insertions, 0 deletions
diff --git a/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/PhoneHelpers.cs b/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/PhoneHelpers.cs new file mode 100644 index 00000000..4bf4f895 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/PhoneHelpers.cs @@ -0,0 +1,30 @@ +using System; +using System.Xml; + +namespace UniversalAnalyticsPlugin +{ + internal static class Helpers + { + public static string GetAppAttribute(string attributeName) + { + try + { + XmlReaderSettings xmlReaderSettings = new XmlReaderSettings(); + xmlReaderSettings.XmlResolver = new XmlXapResolver(); + using (XmlReader xmlReader = XmlReader.Create("WMAppManifest.xml", xmlReaderSettings)) + { + xmlReader.ReadToDescendant("App"); + if (!xmlReader.IsStartElement()) + { + throw new FormatException("WMAppManifest.xml is missing"); + } + return xmlReader.GetAttribute(attributeName); + } + } + catch + { + return null; + } + } + } +} diff --git a/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/PhoneNameResolver.cs b/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/PhoneNameResolver.cs new file mode 100644 index 00000000..261739d0 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/PhoneNameResolver.cs @@ -0,0 +1,578 @@ +/* + * Copyright (c) 2013 by Alan Mendelevich + * + * Licensed under MIT license. + * + * See license.txt for details. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace UniversalAnalyticsPlugin +{ + public static class PhoneNameResolver + { + public static CanonicalPhoneName Resolve(string manufacturer, string model) + { + var manufacturerNormalized = manufacturer.Trim().ToUpper(); + + switch (manufacturerNormalized) + { + case "NOKIA": + case "MICROSOFT": + case "MICROSOFTMDG": + return ResolveNokia(manufacturer, model); + case "HTC": + return ResolveHtc(manufacturer, model); + case "SAMSUNG": + return ResolveSamsung(manufacturer, model); + case "LG": + return ResolveLg(manufacturer, model); + case "HUAWEI": + return ResolveHuawei(manufacturer, model); + default: + return new CanonicalPhoneName() + { + ReportedManufacturer = manufacturer, + ReportedModel = model, + CanonicalManufacturer = manufacturer, + CanonicalModel = model, + IsResolved = false + }; + } + } + + private static CanonicalPhoneName ResolveHuawei(string manufacturer, string model) + { + var modelNormalized = model.Trim().ToUpper(); + + var result = new CanonicalPhoneName() + { + ReportedManufacturer = manufacturer, + ReportedModel = model, + CanonicalManufacturer = "HUAWEI", + CanonicalModel = model, + IsResolved = false + }; + + var lookupValue = modelNormalized; + + if (lookupValue.StartsWith("HUAWEI H883G")) + { + lookupValue = "HUAWEI H883G"; + } + + if (lookupValue.StartsWith("HUAWEI W1")) + { + lookupValue = "HUAWEI W1"; + } + + if (modelNormalized.StartsWith("HUAWEI W2")) + { + lookupValue = "HUAWEI W2"; + } + + if (huaweiLookupTable.ContainsKey(lookupValue)) + { + var modelMetadata = huaweiLookupTable[lookupValue]; + result.CanonicalModel = modelMetadata.CanonicalModel; + result.Comments = modelMetadata.Comments; + result.IsResolved = true; + } + + return result; + } + + private static CanonicalPhoneName ResolveLg(string manufacturer, string model) + { + var modelNormalized = model.Trim().ToUpper(); + + var result = new CanonicalPhoneName() + { + ReportedManufacturer = manufacturer, + ReportedModel = model, + CanonicalManufacturer = "LG", + CanonicalModel = model, + IsResolved = false + }; + + var lookupValue = modelNormalized; + + if (lookupValue.StartsWith("LG-C900")) + { + lookupValue = "LG-C900"; + } + + if (lookupValue.StartsWith("LG-E900")) + { + lookupValue = "LG-E900"; + } + + if (lgLookupTable.ContainsKey(lookupValue)) + { + var modelMetadata = lgLookupTable[lookupValue]; + result.CanonicalModel = modelMetadata.CanonicalModel; + result.Comments = modelMetadata.Comments; + result.IsResolved = true; + } + + return result; + } + + private static CanonicalPhoneName ResolveSamsung(string manufacturer, string model) + { + var modelNormalized = model.Trim().ToUpper(); + + var result = new CanonicalPhoneName() + { + ReportedManufacturer = manufacturer, + ReportedModel = model, + CanonicalManufacturer = "SAMSUNG", + CanonicalModel = model, + IsResolved = false + }; + + var lookupValue = modelNormalized; + + if (lookupValue.StartsWith("GT-S7530")) + { + lookupValue = "GT-S7530"; + } + + if (lookupValue.StartsWith("SGH-I917")) + { + lookupValue = "SGH-I917"; + } + + if (samsungLookupTable.ContainsKey(lookupValue)) + { + var modelMetadata = samsungLookupTable[lookupValue]; + result.CanonicalModel = modelMetadata.CanonicalModel; + result.Comments = modelMetadata.Comments; + result.IsResolved = true; + } + + return result; + } + + private static CanonicalPhoneName ResolveHtc(string manufacturer, string model) + { + var modelNormalized = model.Trim().ToUpper(); + + var result = new CanonicalPhoneName() + { + ReportedManufacturer = manufacturer, + ReportedModel = model, + CanonicalManufacturer = "HTC", + CanonicalModel = model, + IsResolved = false + }; + + var lookupValue = modelNormalized; + + if (lookupValue.StartsWith("A620")) + { + lookupValue = "A620"; + } + + if (lookupValue.StartsWith("C625")) + { + lookupValue = "C625"; + } + + if (lookupValue.StartsWith("C620")) + { + lookupValue = "C620"; + } + + if (htcLookupTable.ContainsKey(lookupValue)) + { + var modelMetadata = htcLookupTable[lookupValue]; + result.CanonicalModel = modelMetadata.CanonicalModel; + result.Comments = modelMetadata.Comments; + result.IsResolved = true; + } + + return result; + } + + private static CanonicalPhoneName ResolveNokia(string manufacturer, string model) + { + var modelNormalized = model.Trim().ToUpper(); + + var result = new CanonicalPhoneName() + { + ReportedManufacturer = manufacturer, + ReportedModel = model, + CanonicalManufacturer = "NOKIA", + CanonicalModel = model, + IsResolved = false + }; + + var lookupValue = modelNormalized; + if (modelNormalized.StartsWith("RM-")) + { + var rms = Regex.Match(modelNormalized, "(RM-)([0-9]+)"); + lookupValue = rms.Value; + } + + if (nokiaLookupTable.ContainsKey(lookupValue)) + { + var modelMetadata = nokiaLookupTable[lookupValue]; + + if (!string.IsNullOrEmpty(modelMetadata.CanonicalManufacturer)) + { + result.CanonicalManufacturer = modelMetadata.CanonicalManufacturer; + } + result.CanonicalModel = modelMetadata.CanonicalModel; + result.Comments = modelMetadata.Comments; + result.IsResolved = true; + } + + return result; + } + + + private static Dictionary<string, CanonicalPhoneName> huaweiLookupTable = new Dictionary<string, CanonicalPhoneName>() + { + // Huawei W1 + { "HUAWEI H883G", new CanonicalPhoneName() { CanonicalModel = "Ascend W1" } }, + { "HUAWEI W1", new CanonicalPhoneName() { CanonicalModel = "Ascend W1" } }, + + // Huawei Ascend W2 + { "HUAWEI W2", new CanonicalPhoneName() { CanonicalModel = "Ascend W2" } }, + }; + + private static Dictionary<string, CanonicalPhoneName> lgLookupTable = new Dictionary<string, CanonicalPhoneName>() + { + // Optimus 7Q/Quantum + { "LG-C900", new CanonicalPhoneName() { CanonicalModel = "Optimus 7Q/Quantum" } }, + + // Optimus 7 + { "LG-E900", new CanonicalPhoneName() { CanonicalModel = "Optimus 7" } }, + + // Jil Sander + { "LG-E906", new CanonicalPhoneName() { CanonicalModel = "Jil Sander" } }, + + // Lancet + { "LGVW820", new CanonicalPhoneName() { CanonicalModel = "Lancet" } }, + }; + + private static Dictionary<string, CanonicalPhoneName> samsungLookupTable = new Dictionary<string, CanonicalPhoneName>() + { + // OMNIA W + { "GT-I8350", new CanonicalPhoneName() { CanonicalModel = "Omnia W" } }, + { "GT-I8350T", new CanonicalPhoneName() { CanonicalModel = "Omnia W" } }, + { "OMNIA W", new CanonicalPhoneName() { CanonicalModel = "Omnia W" } }, + + // OMNIA 7 + { "GT-I8700", new CanonicalPhoneName() { CanonicalModel = "Omnia 7" } }, + { "OMNIA7", new CanonicalPhoneName() { CanonicalModel = "Omnia 7" } }, + + // OMNIA M + { "GT-S7530", new CanonicalPhoneName() { CanonicalModel = "Omnia 7" } }, + + // Focus + { "I917", new CanonicalPhoneName() { CanonicalModel = "Focus" } }, + { "SGH-I917", new CanonicalPhoneName() { CanonicalModel = "Focus" } }, + + // Focus 2 + { "SGH-I667", new CanonicalPhoneName() { CanonicalModel = "Focus 2" } }, + + // Focus Flash + { "SGH-I677", new CanonicalPhoneName() { CanonicalModel = "Focus Flash" } }, + + // Focus S + { "HADEN", new CanonicalPhoneName() { CanonicalModel = "Focus S" } }, + { "SGH-I937", new CanonicalPhoneName() { CanonicalModel = "Focus S" } }, + + // ATIV S + { "GT-I8750", new CanonicalPhoneName() { CanonicalModel = "ATIV S" } }, + { "SGH-T899M", new CanonicalPhoneName() { CanonicalModel = "ATIV S" } }, + + // ATIV Odyssey + { "SCH-I930", new CanonicalPhoneName() { CanonicalModel = "ATIV Odyssey" } }, + { "SCH-R860U", new CanonicalPhoneName() { CanonicalModel = "ATIV Odyssey", Comments="US Cellular" } }, + + // ATIV S Neo + { "SPH-I800", new CanonicalPhoneName() { CanonicalModel = "ATIV S Neo", Comments="Sprint" } }, + { "SGH-I187", new CanonicalPhoneName() { CanonicalModel = "ATIV S Neo", Comments="AT&T" } }, + { "GT-I8675", new CanonicalPhoneName() { CanonicalModel = "ATIV S Neo" } }, + + // ATIV SE + { "SM-W750V", new CanonicalPhoneName() { CanonicalModel = "ATIV SE", Comments="Verizon" } }, + }; + + private static Dictionary<string, CanonicalPhoneName> htcLookupTable = new Dictionary<string, CanonicalPhoneName>() + { + // Surround + { "7 MONDRIAN T8788", new CanonicalPhoneName() { CanonicalModel = "Surround" } }, + { "T8788", new CanonicalPhoneName() { CanonicalModel = "Surround" } }, + { "SURROUND", new CanonicalPhoneName() { CanonicalModel = "Surround" } }, + { "SURROUND T8788", new CanonicalPhoneName() { CanonicalModel = "Surround" } }, + + // Mozart + { "7 MOZART", new CanonicalPhoneName() { CanonicalModel = "Mozart" } }, + { "7 MOZART T8698", new CanonicalPhoneName() { CanonicalModel = "Mozart" } }, + { "HTC MOZART", new CanonicalPhoneName() { CanonicalModel = "Mozart" } }, + { "MERSAD 7 MOZART T8698", new CanonicalPhoneName() { CanonicalModel = "Mozart" } }, + { "MOZART", new CanonicalPhoneName() { CanonicalModel = "Mozart" } }, + { "MOZART T8698", new CanonicalPhoneName() { CanonicalModel = "Mozart" } }, + { "PD67100", new CanonicalPhoneName() { CanonicalModel = "Mozart" } }, + { "T8697", new CanonicalPhoneName() { CanonicalModel = "Mozart" } }, + + // Pro + { "7 PRO T7576", new CanonicalPhoneName() { CanonicalModel = "7 Pro" } }, + { "MWP6885", new CanonicalPhoneName() { CanonicalModel = "7 Pro" } }, + { "USCCHTC-PC93100", new CanonicalPhoneName() { CanonicalModel = "7 Pro" } }, + + // Arrive + { "PC93100", new CanonicalPhoneName() { CanonicalModel = "Arrive", Comments = "Sprint" } }, + { "T7575", new CanonicalPhoneName() { CanonicalModel = "Arrive", Comments = "Sprint" } }, + + // HD2 + { "HD2", new CanonicalPhoneName() { CanonicalModel = "HD2" } }, + { "HD2 LEO", new CanonicalPhoneName() { CanonicalModel = "HD2" } }, + { "LEO", new CanonicalPhoneName() { CanonicalModel = "HD2" } }, + + // HD7 + { "7 SCHUBERT T9292", new CanonicalPhoneName() { CanonicalModel = "HD7" } }, + { "GOLD", new CanonicalPhoneName() { CanonicalModel = "HD7" } }, + { "HD7", new CanonicalPhoneName() { CanonicalModel = "HD7" } }, + { "HD7 T9292", new CanonicalPhoneName() { CanonicalModel = "HD7" } }, + { "MONDRIAN", new CanonicalPhoneName() { CanonicalModel = "HD7" } }, + { "SCHUBERT", new CanonicalPhoneName() { CanonicalModel = "HD7" } }, + { "Schubert T9292", new CanonicalPhoneName() { CanonicalModel = "HD7" } }, + { "T9296", new CanonicalPhoneName() { CanonicalModel = "HD7", Comments = "Telstra, AU" } }, + { "TOUCH-IT HD7", new CanonicalPhoneName() { CanonicalModel = "HD7" } }, + + // HD7S + { "T9295", new CanonicalPhoneName() { CanonicalModel = "HD7S" } }, + + // Trophy + { "7 TROPHY", new CanonicalPhoneName() { CanonicalModel = "Trophy" } }, + { "7 TROPHY T8686", new CanonicalPhoneName() { CanonicalModel = "Trophy" } }, + { "PC40100", new CanonicalPhoneName() { CanonicalModel = "Trophy", Comments = "Verizon" } }, + { "SPARK", new CanonicalPhoneName() { CanonicalModel = "Trophy" } }, + { "TOUCH-IT TROPHY", new CanonicalPhoneName() { CanonicalModel = "Trophy" } }, + { "MWP6985", new CanonicalPhoneName() { CanonicalModel = "Trophy" } }, + + // 8S + { "A620", new CanonicalPhoneName() { CanonicalModel = "8S" } }, + { "WINDOWS PHONE 8S BY HTC", new CanonicalPhoneName() { CanonicalModel = "8S" } }, + + // 8X + { "C620", new CanonicalPhoneName() { CanonicalModel = "8X" } }, + { "C625", new CanonicalPhoneName() { CanonicalModel = "8X" } }, + { "HTC6990LVW", new CanonicalPhoneName() { CanonicalModel = "8X", Comments="Verizon" } }, + { "PM23300", new CanonicalPhoneName() { CanonicalModel = "8X", Comments="AT&T" } }, + { "WINDOWS PHONE 8X BY HTC", new CanonicalPhoneName() { CanonicalModel = "8X" } }, + + // 8XT + { "HTCPO881", new CanonicalPhoneName() { CanonicalModel = "8XT", Comments="Sprint" } }, + { "HTCPO881 SPRINT", new CanonicalPhoneName() { CanonicalModel = "8XT", Comments="Sprint" } }, + { "HTCPO881 HTC", new CanonicalPhoneName() { CanonicalModel = "8XT", Comments="Sprint" } }, + + // Titan + { "ETERNITY", new CanonicalPhoneName() { CanonicalModel = "Titan", Comments = "China" } }, + { "PI39100", new CanonicalPhoneName() { CanonicalModel = "Titan", Comments = "AT&T" } }, + { "TITAN X310E", new CanonicalPhoneName() { CanonicalModel = "Titan" } }, + { "ULTIMATE", new CanonicalPhoneName() { CanonicalModel = "Titan" } }, + { "X310E", new CanonicalPhoneName() { CanonicalModel = "Titan" } }, + { "X310E TITAN", new CanonicalPhoneName() { CanonicalModel = "Titan" } }, + + // Titan II + { "PI86100", new CanonicalPhoneName() { CanonicalModel = "Titan II", Comments = "AT&T" } }, + { "RADIANT", new CanonicalPhoneName() { CanonicalModel = "Titan II" } }, + + // Radar + { "RADAR", new CanonicalPhoneName() { CanonicalModel = "Radar" } }, + { "RADAR 4G", new CanonicalPhoneName() { CanonicalModel = "Radar", Comments = "T-Mobile USA" } }, + { "RADAR C110E", new CanonicalPhoneName() { CanonicalModel = "Radar" } }, + + // One M8 + { "HTC6995LVW", new CanonicalPhoneName() { CanonicalModel = "One (M8)", Comments="Verizon" } }, + { "0P6B180", new CanonicalPhoneName() { CanonicalModel = "One (M8)", Comments="AT&T" } }, + { "0P6B140", new CanonicalPhoneName() { CanonicalModel = "One (M8)", Comments="Dual SIM?" } }, + }; + + private static Dictionary<string, CanonicalPhoneName> nokiaLookupTable = new Dictionary<string, CanonicalPhoneName>() + { + // Lumia 505 + { "LUMIA 505", new CanonicalPhoneName() { CanonicalModel = "Lumia 505" } }, + // Lumia 510 + { "LUMIA 510", new CanonicalPhoneName() { CanonicalModel = "Lumia 510" } }, + { "NOKIA 510", new CanonicalPhoneName() { CanonicalModel = "Lumia 510" } }, + // Lumia 610 + { "LUMIA 610", new CanonicalPhoneName() { CanonicalModel = "Lumia 610" } }, + { "LUMIA 610 NFC", new CanonicalPhoneName() { CanonicalModel = "Lumia 610", Comments = "NFC" } }, + { "NOKIA 610", new CanonicalPhoneName() { CanonicalModel = "Lumia 610" } }, + { "NOKIA 610C", new CanonicalPhoneName() { CanonicalModel = "Lumia 610" } }, + // Lumia 620 + { "LUMIA 620", new CanonicalPhoneName() { CanonicalModel = "Lumia 620" } }, + { "RM-846", new CanonicalPhoneName() { CanonicalModel = "Lumia 620" } }, + // Lumia 710 + { "LUMIA 710", new CanonicalPhoneName() { CanonicalModel = "Lumia 710" } }, + { "NOKIA 710", new CanonicalPhoneName() { CanonicalModel = "Lumia 710" } }, + // Lumia 800 + { "LUMIA 800", new CanonicalPhoneName() { CanonicalModel = "Lumia 800" } }, + { "LUMIA 800C", new CanonicalPhoneName() { CanonicalModel = "Lumia 800" } }, + { "NOKIA 800", new CanonicalPhoneName() { CanonicalModel = "Lumia 800" } }, + { "NOKIA 800C", new CanonicalPhoneName() { CanonicalModel = "Lumia 800", Comments = "China" } }, + // Lumia 810 + { "RM-878", new CanonicalPhoneName() { CanonicalModel = "Lumia 810" } }, + // Lumia 820 + { "RM-824", new CanonicalPhoneName() { CanonicalModel = "Lumia 820" } }, + { "RM-825", new CanonicalPhoneName() { CanonicalModel = "Lumia 820" } }, + { "RM-826", new CanonicalPhoneName() { CanonicalModel = "Lumia 820" } }, + // Lumia 822 + { "RM-845", new CanonicalPhoneName() { CanonicalModel = "Lumia 822", Comments = "Verizon" } }, + // Lumia 900 + { "LUMIA 900", new CanonicalPhoneName() { CanonicalModel = "Lumia 900" } }, + { "NOKIA 900", new CanonicalPhoneName() { CanonicalModel = "Lumia 900" } }, + // Lumia 920 + { "RM-820", new CanonicalPhoneName() { CanonicalModel = "Lumia 920" } }, + { "RM-821", new CanonicalPhoneName() { CanonicalModel = "Lumia 920" } }, + { "RM-822", new CanonicalPhoneName() { CanonicalModel = "Lumia 920" } }, + { "RM-867", new CanonicalPhoneName() { CanonicalModel = "Lumia 920", Comments = "920T" } }, + { "NOKIA 920", new CanonicalPhoneName() { CanonicalModel = "Lumia 920" } }, + { "LUMIA 920", new CanonicalPhoneName() { CanonicalModel = "Lumia 920" } }, + // Lumia 520 + { "RM-914", new CanonicalPhoneName() { CanonicalModel = "Lumia 520" } }, + { "RM-915", new CanonicalPhoneName() { CanonicalModel = "Lumia 520" } }, + { "RM-913", new CanonicalPhoneName() { CanonicalModel = "Lumia 520", Comments="520T" } }, + // Lumia 521? + { "RM-917", new CanonicalPhoneName() { CanonicalModel = "Lumia 521", Comments="T-Mobile 520" } }, + // Lumia 720 + { "RM-885", new CanonicalPhoneName() { CanonicalModel = "Lumia 720" } }, + { "RM-887", new CanonicalPhoneName() { CanonicalModel = "Lumia 720", Comments="China 720T" } }, + // Lumia 928 + { "RM-860", new CanonicalPhoneName() { CanonicalModel = "Lumia 928" } }, + // Lumia 925 + { "RM-892", new CanonicalPhoneName() { CanonicalModel = "Lumia 925" } }, + { "RM-893", new CanonicalPhoneName() { CanonicalModel = "Lumia 925" } }, + { "RM-910", new CanonicalPhoneName() { CanonicalModel = "Lumia 925" } }, + { "RM-955", new CanonicalPhoneName() { CanonicalModel = "Lumia 925", Comments="China 925T" } }, + // Lumia 1020 + { "RM-875", new CanonicalPhoneName() { CanonicalModel = "Lumia 1020" } }, + { "RM-876", new CanonicalPhoneName() { CanonicalModel = "Lumia 1020" } }, + { "RM-877", new CanonicalPhoneName() { CanonicalModel = "Lumia 1020" } }, + // Lumia 625 + { "RM-941", new CanonicalPhoneName() { CanonicalModel = "Lumia 625" } }, + { "RM-942", new CanonicalPhoneName() { CanonicalModel = "Lumia 625" } }, + { "RM-943", new CanonicalPhoneName() { CanonicalModel = "Lumia 625" } }, + // Lumia 1520 + { "RM-937", new CanonicalPhoneName() { CanonicalModel = "Lumia 1520" } }, + { "RM-938", new CanonicalPhoneName() { CanonicalModel = "Lumia 1520", Comments="AT&T" } }, + { "RM-939", new CanonicalPhoneName() { CanonicalModel = "Lumia 1520" } }, + { "RM-940", new CanonicalPhoneName() { CanonicalModel = "Lumia 1520", Comments="AT&T" } }, + // Lumia 525 + { "RM-998", new CanonicalPhoneName() { CanonicalModel = "Lumia 525" } }, + // Lumia 1320 + { "RM-994", new CanonicalPhoneName() { CanonicalModel = "Lumia 1320" } }, + { "RM-995", new CanonicalPhoneName() { CanonicalModel = "Lumia 1320" } }, + { "RM-996", new CanonicalPhoneName() { CanonicalModel = "Lumia 1320" } }, + // Lumia Icon + { "RM-927", new CanonicalPhoneName() { CanonicalModel = "Lumia Icon", Comments="Verizon" } }, + // Lumia 630 + { "RM-976", new CanonicalPhoneName() { CanonicalModel = "Lumia 630" } }, + { "RM-977", new CanonicalPhoneName() { CanonicalModel = "Lumia 630" } }, + { "RM-978", new CanonicalPhoneName() { CanonicalModel = "Lumia 630" } }, + { "RM-979", new CanonicalPhoneName() { CanonicalModel = "Lumia 630" } }, + // Lumia 635 + { "RM-974", new CanonicalPhoneName() { CanonicalModel = "Lumia 635" } }, + { "RM-975", new CanonicalPhoneName() { CanonicalModel = "Lumia 635" } }, + { "RM-1078", new CanonicalPhoneName() { CanonicalModel = "Lumia 635", Comments="Sprint" } }, + // Lumia 526 + { "RM-997", new CanonicalPhoneName() { CanonicalModel = "Lumia 526", Comments="China Mobile" } }, + // Lumia 930 + { "RM-1045", new CanonicalPhoneName() { CanonicalModel = "Lumia 930" } }, + { "RM-1087", new CanonicalPhoneName() { CanonicalModel = "Lumia 930" } }, + // Lumia 636 + { "RM-1027", new CanonicalPhoneName() { CanonicalModel = "Lumia 636", Comments="China" } }, + // Lumia 638 + { "RM-1010", new CanonicalPhoneName() { CanonicalModel = "Lumia 638", Comments="China" } }, + // Lumia 530 + { "RM-1017", new CanonicalPhoneName() { CanonicalModel = "Lumia 530", Comments="Single SIM" } }, + { "RM-1018", new CanonicalPhoneName() { CanonicalModel = "Lumia 530", Comments="Single SIM" } }, + { "RM-1019", new CanonicalPhoneName() { CanonicalModel = "Lumia 530", Comments="Dual SIM" } }, + { "RM-1020", new CanonicalPhoneName() { CanonicalModel = "Lumia 530", Comments="Dual SIM" } }, + // Lumia 730 + { "RM-1040", new CanonicalPhoneName() { CanonicalModel = "Lumia 730", Comments="Dual SIM" } }, + // Lumia 735 + { "RM-1038", new CanonicalPhoneName() { CanonicalModel = "Lumia 735" } }, + { "RM-1039", new CanonicalPhoneName() { CanonicalModel = "Lumia 735" } }, + { "RM-1041", new CanonicalPhoneName() { CanonicalModel = "Lumia 735", Comments="Verizon" } }, + // Lumia 830 + { "RM-983", new CanonicalPhoneName() { CanonicalModel = "Lumia 830" } }, + { "RM-984", new CanonicalPhoneName() { CanonicalModel = "Lumia 830" } }, + { "RM-985", new CanonicalPhoneName() { CanonicalModel = "Lumia 830" } }, + { "RM-1049", new CanonicalPhoneName() { CanonicalModel = "Lumia 830" } }, + // Lumia 535 + { "RM-1089", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 535" } }, + { "RM-1090", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 535" } }, + { "RM-1091", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 535" } }, + { "RM-1092", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 535" } }, + // Lumia 435 + { "RM-1068", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 435", Comments="DS" } }, + { "RM-1069", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 435", Comments="DS" } }, + { "RM-1070", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 435", Comments="DS" } }, + { "RM-1071", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 435", Comments="DS" } }, + { "RM-1114", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 435", Comments="DS" } }, + // Lumia 532 + { "RM-1031", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 532", Comments="DS" } }, + { "RM-1032", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 532", Comments="DS" } }, + { "RM-1034", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 532", Comments="DS" } }, + { "RM-1115", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 532", Comments="DS" } }, + // Lumia 640 + { "RM-1072", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640" } }, + { "RM-1073", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640" } }, + { "RM-1074", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640" } }, + { "RM-1075", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640" } }, + { "RM-1077", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640" } }, + { "RM-1109", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640" } }, + { "RM-1113", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640" } }, + // Lumia 640XL + { "RM-1062", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640 XL" } }, + { "RM-1063", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640 XL" } }, + { "RM-1064", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640 XL" } }, + { "RM-1065", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640 XL" } }, + { "RM-1066", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640 XL" } }, + { "RM-1067", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640 XL" } }, + { "RM-1096", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 640 XL" } }, + // Lumia 540 + { "RM-1140", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 540" } }, + { "RM-1141", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 540" } }, + // Lumia 430 + { "RM-1099", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 430", Comments="DS" } }, + // Lumia 950 + { "RM-1104", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 950", Comments="DS" } }, + { "RM-1105", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 950", Comments="DS" } }, + { "RM-1118", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 950", Comments="DS" } }, + // Lumia 950 XL + { "RM-1085", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 950 XL" } }, + { "RM-1116", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 950 XL", Comments="DS" } }, + // Lumia 550 + { "RM-1127", new CanonicalPhoneName() { CanonicalManufacturer="MICROSOFT", CanonicalModel = "Lumia 550" } }, + }; + } + + public class CanonicalPhoneName + { + public string ReportedManufacturer { get; set; } + public string ReportedModel { get; set; } + public string CanonicalManufacturer { get; set; } + public string CanonicalModel { get; set; } + public string Comments { get; set; } + public bool IsResolved { get; set; } + + public string FullCanonicalName + { + get { return CanonicalManufacturer + " " + CanonicalModel; } + } + } +}
\ No newline at end of file diff --git a/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/PlatformInfoProvider.WP.cs b/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/PlatformInfoProvider.WP.cs new file mode 100644 index 00000000..4e1257f9 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/PlatformInfoProvider.WP.cs @@ -0,0 +1,103 @@ +// PlatformInfoProvider.WP.cs + +using GoogleAnalytics.Core; +using System; +using System.IO.IsolatedStorage; +using System.Threading.Tasks; +using System.Windows; + +namespace UniversalAnalyticsPlugin +{ + public sealed class PlatformInfoProvider : IPlatformInfoProvider + { + const string Key_AnonymousClientId = "GoogleAnaltyics.AnonymousClientId"; + string anonymousClientId; + Dimensions _screenResolution = new Dimensions(0,0); + +#pragma warning disable 0067 + public event EventHandler ViewPortResolutionChanged; + + public event EventHandler ScreenResolutionChanged; +#pragma warning restore 0067 + + public PlatformInfoProvider() + { + Deployment.Current.Dispatcher.BeginInvoke(() => { + double scale = (double)Application.Current.Host.Content.ScaleFactor / 100; + int h = (int)Math.Ceiling(Application.Current.Host.Content.ActualHeight * scale); + int w = (int)Math.Ceiling(Application.Current.Host.Content.ActualWidth * scale); + _screenResolution = new Dimensions(h, w); + }); + } + + public string AnonymousClientId + { + get + { + if (anonymousClientId == null) + { + var appSettings = IsolatedStorageSettings.ApplicationSettings; + if (!appSettings.Contains(Key_AnonymousClientId)) + { + anonymousClientId = Guid.NewGuid().ToString(); + appSettings.Add(Key_AnonymousClientId, anonymousClientId); + appSettings.Save(); + } + else + { + anonymousClientId = (string)appSettings[Key_AnonymousClientId]; + } + } + return anonymousClientId; + } + set { anonymousClientId = value; } + } + + public Dimensions ScreenResolution + { + get + { + return _screenResolution; + } + } + + public Dimensions ViewPortResolution + { + get { return ScreenResolution; } + } + + public string UserLanguage + { + get { return System.Globalization.CultureInfo.CurrentUICulture.Name; } + } + + public int? ScreenColorDepthBits + { + get { return null; } + } + + public void OnTracking() + { } + + public string GetUserAgent() + { + var sysInfo = UniversalAnalyticsPlugin.PhoneNameResolver.Resolve(Microsoft.Phone.Info.DeviceStatus.DeviceManufacturer, Microsoft.Phone.Info.DeviceStatus.DeviceName); + Version osVer = Environment.OSVersion.Version; + string uaMask; + + if (osVer.Minor == 10) + { + // Windows Phone 8.1 + uaMask = "Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0; Touch; rv11.0; IEMobile/11.0; {1}; {2}) like Gecko"; + } + else + { + // Windows Phone 8.0 + uaMask = "Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone OS {0}; Trident/6.0; IEMobile/10.0; ARM; Touch; {1}; {2})"; + } + + //var userAgentMask = "Mozilla/[version] ([system and browser information]) [platform] ([platform details]) [extensions]"; + return string.Format(uaMask, Environment.OSVersion.Version, sysInfo.CanonicalManufacturer, sysInfo.CanonicalModel); + } + } +} diff --git a/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/UniversalAnalytics.cs b/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/UniversalAnalytics.cs new file mode 100644 index 00000000..b4307922 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-google-analytics/wp8/UniversalAnalytics.cs @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2016 Dan Polivy + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +using System; +using GoogleAnalytics.Core; +using WPCordovaClassLib.Cordova; +using WPCordovaClassLib.Cordova.Commands; +using WPCordovaClassLib.Cordova.JSON; +using System.Collections.Generic; +using System.Windows; +using System.Diagnostics; +using System.Threading.Tasks; +using Microsoft.Phone.Shell; + +namespace Cordova.Extension.Commands +{ + /// <summary> + /// UniversalAnalytics plugin class containing methods called from JavaScript + /// </summary> + public class UniversalAnalytics : BaseCommand + { + private TrackerManager _trackerManager = new TrackerManager(new UniversalAnalyticsPlugin.PlatformInfoProvider()); + private Tracker _tracker; + private bool _trackerStarted = false; + DateTime? _suspended; + private IDictionary<int, string> _customDimensions = new Dictionary<int, string>(); + + public UniversalAnalytics() + { + this.AutoAppLifetimeTracking = false; + this.SessionTimeout = 30; + } + + /// <summary> + /// Session timeout length, in seconds. + /// </summary> + public int? SessionTimeout { + get; + set; + } + + /// <summary> + /// Determines whether events are automatically sent for app lifetime tracking. + /// </summary> + public bool AutoAppLifetimeTracking { get; set; } + + public void startTrackerWithId(string options) + { + // If the tracker is already started, don't start it again + if (_trackerStarted) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Tracker is already started")); + return; + } + + string[] args = JsonHelper.Deserialize<string[]>(options); + + if (!_trackerStarted && args.Length > 0 && args[0].Length > 0) + { + _tracker = _trackerManager.GetTracker(args[0]); + + // Set additional Tracker parameters here + _tracker.SetStartSession(true); + _tracker.IsUseSecure = true; + _tracker.AppName = UniversalAnalyticsPlugin.Helpers.GetAppAttribute("Title"); + _tracker.AppVersion = UniversalAnalyticsPlugin.Helpers.GetAppAttribute("Version"); + + _trackerStarted = true; + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + Application.Current.UnhandledException += Analytics_UnhandledException; + TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; + }); + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "Tracker started")); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Tracker id is not valid")); + } + } + + public override void OnResume(object sender, ActivatedEventArgs e) + { + if (_suspended.HasValue && SessionTimeout.HasValue) + { + var suspendedAgo = DateTime.UtcNow.Subtract(_suspended.Value); + if (suspendedAgo > TimeSpan.FromSeconds((double)SessionTimeout)) + { + _tracker.SetStartSession(true); + } + } + + if (_trackerStarted && AutoAppLifetimeTracking) + { + _tracker.SendEvent("app", "resume", !e.IsApplicationInstancePreserved ? "tombstoned" : null, 0); + } + } + + public override void OnPause(object sender, DeactivatedEventArgs e) + { + if (_trackerStarted && AutoAppLifetimeTracking) + { + _tracker.SendEvent("app", "suspend", e.Reason.ToString(), 0); + } + + _suspended = DateTime.UtcNow; + } + + private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) + { + var ex = e.Exception.InnerException ?? e.Exception; // inner exception contains better info for unobserved tasks + _tracker.SendException(ex.ToString(), false); + } + + private void Analytics_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) + { + _tracker.SendException(e.ExceptionObject.ToString(), true); + + if (Debugger.IsAttached) + { + // An unhandled exception has occurred; break into the debugger + Debugger.Break(); + } + } + + public void setUserId(string options) + { + if (!_trackerStarted) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Tracker not started")); + return; + } + + string[] args = JsonHelper.Deserialize<string[]>(options); + string userId = null; + + if (args.Length > 0) userId = args[0]; + + _tracker.UserId = userId; + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "Set user id: " + args[0])); + } + + public void debugMode(string options) + { + _trackerManager.IsDebugEnabled = true; + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "debugMode enabled")); + } + + public void trackView(string options) + { + if (!_trackerStarted) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Tracker not started")); + return; + } + + string[] args = JsonHelper.Deserialize<string[]>(options); + + if (args.Length > 0 && args[0] != null && args[0].Length > 0) + { + addCustomDimensionsToTracker(_tracker); + _tracker.SendView(args[0]); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "Track Screen: " + args[0])); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Expected one non-empty string argument")); + } + } + + public void addCustomDimension(string options) + { + string[] args = JsonHelper.Deserialize<string[]>(options); + + int index = 0; + bool hasIndex = false; + string value = null; + + if (args.Length > 0) hasIndex = int.TryParse(args[0], out index); + if (args.Length > 1) value = args[1]; + + if (hasIndex && value != null) + { + // Remove the key if it already exists + _customDimensions.Remove(index); + _customDimensions.Add(index, value); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "Add Custom Dimension: " + index)); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Expected non-empty integer, string arguments")); + } + } + + public void trackEvent(string options) + { + if (!_trackerStarted) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Tracker not started")); + return; + } + + string[] args = JsonHelper.Deserialize<string[]>(options); + + // Default values + string category = null, action = null, label = null; + long value = 0; + + if (args.Length > 0) category = args[0]; + if (args.Length > 1) action = args[1]; + if (args.Length > 2) label = args[2]; + if (args.Length > 3) long.TryParse(args[3], out value); + + addCustomDimensionsToTracker(_tracker); + _tracker.SendEvent(category, action, label, value); + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "Track Event: " + category)); + } + + public void trackException(string options) + { + if (!_trackerStarted) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Tracker not started")); + return; + } + + string[] args = JsonHelper.Deserialize<string[]>(options); + + if (args.Length == 0 || args[0] == null || args[0].Length == 0) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Expected non-empty string arguments.")); + return; + } + + // Default values + string description = null; + bool isFatal = false; + + if (args.Length > 0) description = args[0]; + if (args.Length > 1) bool.TryParse(args[1], out isFatal); + + addCustomDimensionsToTracker(_tracker); + _tracker.SendException(description, isFatal); + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "Track Exception: " + description)); + } + + public void trackTiming(string options) + { + if (!_trackerStarted) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Tracker not started")); + return; + } + + string[] args = JsonHelper.Deserialize<string[]>(options); + + if (args.Length == 0 || args[0] == null || args[0].Length == 0) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Expected non-empty string arguments.")); + return; + } + + // Default values + string category = null, variable = null, label = null; + long intervalInMs = 0; + + if (args.Length > 0) category = args[0]; + if (args.Length > 1) long.TryParse(args[1], out intervalInMs); + if (args.Length > 2) variable = args[2]; + if (args.Length > 3) label = args[3]; + + addCustomDimensionsToTracker(_tracker); + _tracker.SendTiming(TimeSpan.FromMilliseconds(intervalInMs), category, variable, label); + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "Track Timing: " + category)); + } + + public void addTransaction(string options) + { + if (!_trackerStarted) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Tracker not started")); + return; + } + + string[] args = JsonHelper.Deserialize<string[]>(options); + + if (args.Length == 0 || args[0] == null || args[0].Length == 0) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Expected non-empty ID.")); + return; + } + + Transaction transaction = new Transaction(); + + // Default values + double revenue = 0, tax = 0, shipping = 0; + + if (args.Length > 0) transaction.TransactionId = args[0]; + if (args.Length > 1) transaction.Affiliation = args[1]; + if (args.Length > 2) + { + double.TryParse(args[2], out revenue); + transaction.TotalCostInMicros = (long)(revenue * 1000000); + } + if (args.Length > 3) + { + double.TryParse(args[3], out tax); + transaction.TotalTaxInMicros = (long)(tax * 1000000); + } + if (args.Length > 4) + { + double.TryParse(args[4], out shipping); + transaction.ShippingCostInMicros = (long)(shipping * 1000000); + } + if (args.Length > 5) transaction.CurrencyCode = args[5]; + + addCustomDimensionsToTracker(_tracker); + _tracker.SendTransaction(transaction); + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "Add Transaction: " + transaction.TransactionId)); + } + + public void addTransactionItem(string options) + { + if (!_trackerStarted) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Tracker not started")); + return; + } + + string[] args = JsonHelper.Deserialize<string[]>(options); + + if (args.Length == 0 || args[0] == null || args[0].Length == 0) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Expected non-empty ID.")); + return; + } + + TransactionItem transactionItem = new TransactionItem(); + + // Default values + double price = 0; + long quantity = 0; + + if (args.Length > 0) transactionItem.TransactionId = args[0]; + if (args.Length > 1) transactionItem.Name = args[1]; + if (args.Length > 2) transactionItem.SKU = args[2]; + if (args.Length > 3) transactionItem.Category = args[3]; + if (args.Length > 4) + { + double.TryParse(args[4], out price); + transactionItem.PriceInMicros = (long)(price * 1000000); + } + if (args.Length > 5) + { + long.TryParse(args[5], out quantity); + transactionItem.Quantity = quantity; + } + if (args.Length > 6) transactionItem.CurrencyCode = args[6]; + + addCustomDimensionsToTracker(_tracker); + _tracker.SendTransactionItem(transactionItem); + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "Add Transaction Item: " + transactionItem.TransactionId)); + } + + private void addCustomDimensionsToTracker(Tracker tracker) + { + foreach (KeyValuePair<int, string> dimension in _customDimensions) + { + tracker.SetCustomDimension(dimension.Key, dimension.Value); + } + } + } +}
\ No newline at end of file |
