A model that represents a Device's telemetry recording.
        /// <summary>
        /// Loads the most recent Device telemetry.
        /// </summary>
        /// <param name="deviceId">
        /// The ID of the Device for which telemetry should be returned.
        /// </param>
        /// <param name="minTime">
        /// The minimum time of record of the telemetry that should be returned.
        /// </param>
        /// <returns>
        /// Telemetry for the Device specified by deviceId, inclusively since 
        /// minTime.
        /// </returns>
        public async Task<IEnumerable<DeviceTelemetryModel>> LoadLatestDeviceTelemetryAsync(
            string deviceId,
            IList<DeviceTelemetryFieldModel> telemetryFields, 
            DateTime minTime)
        {
            IEnumerable<DeviceTelemetryModel> result = new DeviceTelemetryModel[0];
            IEnumerable<DeviceTelemetryModel> blobModels;

            var telemetryBlobReader = await _blobStorageManager.GetReader(_telemetryDataPrefix, minTime);
            foreach (var telemetryStream in telemetryBlobReader)
            {    
                try
                {
                    blobModels = LoadBlobTelemetryModels(telemetryStream.Data, telemetryFields);
                }
                catch
                {
                    continue;
                }

                if (blobModels == null)
                {
                    break;
                }

                int preFilterCount = blobModels.Count();

                blobModels =
                    blobModels.Where(
                        t =>
                            (t != null) &&
                            t.Timestamp.HasValue &&
                            t.Timestamp.Value >= minTime);

                if (preFilterCount == 0)
                {
                    break;
                }

                result = result.Concat(blobModels);
            }

            if (!string.IsNullOrEmpty(deviceId))
            {
                result = result.Where(t => t.DeviceId == deviceId);
            }

            return result;
        }
        /// <summary>
        /// Loads the most recent Device telemetry.
        /// </summary>
        /// <param name="deviceId">
        /// The ID of the Device for which telemetry should be returned.
        /// </param>
        /// <param name="minTime">
        /// The minimum time of record of the telemetry that should be returned.
        /// </param>
        /// <returns>
        /// Telemetry for the Device specified by deviceId, inclusively since 
        /// minTime.
        /// </returns>
        public async Task<IEnumerable<DeviceTelemetryModel>> LoadLatestDeviceTelemetryAsync(
            string deviceId,
            DateTime minTime)
        {
            IEnumerable<DeviceTelemetryModel> blobModels;
            IEnumerable<IListBlobItem> blobs;
            CloudBlockBlob blockBlob;
            CloudBlobContainer container;
            int preFilterCount;
            IEnumerable<DeviceTelemetryModel> result;

            minTime = minTime.ToUniversalTime();
            result = new DeviceTelemetryModel[0];

            container =
                await BlobStorageHelper.BuildBlobContainerAsync(
                    this._telemetryStoreConnectionString,
                    _telemetryContainerName);

            blobs =
                await BlobStorageHelper.LoadBlobItemsAsync(
                    async (token) =>
                    {
                        return await container.ListBlobsSegmentedAsync(
                            _telemetryDataPrefix,
                            true,
                            BlobListingDetails.None,
                            null,
                            token,
                            null,
                            null);
                    });

            blobs = 
                blobs.OrderByDescending(
                    t => BlobStorageHelper.ExtractBlobItemDate(t));

            foreach (IListBlobItem blob in blobs)
            {
                if ((blockBlob = blob as CloudBlockBlob) == null)
                {
                    continue;
                }

                try
                {
                    blobModels = await LoadBlobTelemetryModelsAsync(blockBlob);
                }
                catch
                {
                    continue;
                }

                if (blobModels == null)
                {
                    break;
                }

                preFilterCount = blobModels.Count();

                blobModels =
                    blobModels.Where(
                        t =>
                            (t != null) &&
                            t.Timestamp.HasValue &&
                            t.Timestamp.Value.ToUniversalTime() >= minTime);

                if (preFilterCount == 0)
                {
                    break;
                }

                result = result.Concat(blobModels);

                if (preFilterCount != blobModels.Count())
                {
                    break;
                }
            }

            if (!string.IsNullOrEmpty(deviceId))
            {
                result = result.Where(t => t.DeviceId == deviceId);
            }

            return result;
        }
        private static List<DeviceTelemetryModel> LoadBlobTelemetryModels(Stream stream, IList<DeviceTelemetryFieldModel> telemetryFields)
        {
            Debug.Assert(stream != null, "stream is a null reference.");

            List<DeviceTelemetryModel> models = new List<DeviceTelemetryModel>();

            TextReader reader = null;
            try
            {
                stream.Position = 0;
                reader = new StreamReader(stream);
                
                IEnumerable<StrDict> strdicts = ParsingHelper.ParseCsv(reader).ToDictionaries();
                DeviceTelemetryModel model;
                string str;
                foreach (StrDict strdict in strdicts)
                {
                    model = new DeviceTelemetryModel();

                    if (strdict.TryGetValue("deviceid", out str))
                    {
                        model.DeviceId = str;
                    }

                    model.Timestamp = DateTime.Parse(
                        strdict["eventenqueuedutctime"],
                        CultureInfo.InvariantCulture,
                        DateTimeStyles.AllowWhiteSpaces);

                    IEnumerable<DeviceTelemetryFieldModel> fields;

                    if (telemetryFields != null && telemetryFields.Count > 0)
                    {
                        fields = telemetryFields;
                    }
                    else
                    {
                        List<string> reservedColumns = new List<string>
                        {
                            "DeviceId",
                            "EventEnqueuedUtcTime",
                            "EventProcessedUtcTime",
                            "IoTHub",
                            "PartitionId"
                        };

                        fields = strdict.Keys
                            .Where((key) => !reservedColumns.Contains(key))
                            .Select((name) => new DeviceTelemetryFieldModel
                            {
                                Name = name,
                                Type = "double"
                            });
                    }

                    foreach (var field in fields)
                    {
                        if (strdict.TryGetValue(field.Name, out str))
                        {
                            switch (field.Type.ToLowerInvariant())
                            {
                                case "int":
                                case "int16":
                                case "int32":
                                case "int64":
                                case "sbyte":
                                case "byte":
                                    int intValue;
                                    if (
                                        int.TryParse(
                                            str,
                                            NumberStyles.Integer,
                                            CultureInfo.InvariantCulture,
                                            out intValue) &&
                                        !model.Values.ContainsKey(field.Name))
                                    {
                                        model.Values.Add(field.Name, intValue);
                                    }
                                    break;

                                case "double":
                                case "decimal":
                                case "single":
                                    double dblValue;
                                    if (
                                        double.TryParse(
                                            str,
                                            NumberStyles.Float,
                                            CultureInfo.InvariantCulture,
                                            out dblValue) &&
                                        !model.Values.ContainsKey(field.Name))
                                    {
                                        model.Values.Add(field.Name, dblValue);
                                    }
                                    break;
                            }
                        }
                    }

                    models.Add(model);
                }
            }
            finally
            {
                IDisposable disp;

                if ((disp = stream) != null)
                {
                    disp.Dispose();
                }

                if ((disp = reader) != null)
                {
                    disp.Dispose();
                }
            }

            return models;
        }
        private async static Task<List<DeviceTelemetryModel>> LoadBlobTelemetryModelsAsync(
            CloudBlockBlob blob)
        {
            DateTime date;
            IDisposable disp;
            DeviceTelemetryModel model;
            List<DeviceTelemetryModel> models;
            double number;
            TextReader reader;
            string str;
            IEnumerable<StrDict> strdicts;
            MemoryStream stream;

            Debug.Assert(blob != null, "blob is a null reference.");

            models = new List<DeviceTelemetryModel>();

            reader = null;
            stream = null;
            try
            {
                stream = new MemoryStream();
                await blob.DownloadToStreamAsync(stream);
                stream.Position = 0;
                reader = new StreamReader(stream);

                strdicts = ParsingHelper.ParseCsv(reader).ToDictionaries();
                foreach (StrDict strdict in strdicts)
                {
                    model = new DeviceTelemetryModel();

                    if (strdict.TryGetValue("DeviceId", out str))
                    {
                        model.DeviceId = str;
                    }

                    if (strdict.TryGetValue("ExternalTemperature", out str) &&
                        double.TryParse(str, out number))
                    {
                        model.ExternalTemperature = number;
                    }

                    if (strdict.TryGetValue("Humidity", out str) &&
                        double.TryParse(str, out number))
                    {
                        model.Humidity = number;
                    }

                    if (strdict.TryGetValue("Temperature", out str) &&
                        double.TryParse(str, out number))
                    {
                        model.Temperature = number;
                    }

                    if (strdict.TryGetValue("EventEnqueuedUtcTime", out str) &&
                        DateTime.TryParse(str, out date))
                    {
                        model.Timestamp = date;
                    }

                    models.Add(model);
                }
            }
            finally
            {
                if ((disp = stream) != null)
                {
                    disp.Dispose();
                }

                if ((disp = reader) != null)
                {
                    disp.Dispose();
                }
            }

            return models;
        }