static void Main(string[] args)
        {
            Console.WriteLine(@"Run Fiddler now, make sure it is capturing requests,
            and set automatic breakpoints in it:
            [Rules]->[Automatic Breakpoints]->[After Responses] or Alt+F11 in Fiddler window

            Then press Enter...");
            Console.ReadLine();

            //using storage emulator credentials as we need any valid name/key pair to force outgoing request to Azure Storage servers.
            var cloudStorageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==");

            var context = new TableServiceContext(cloudStorageAccount.TableEndpoint.AbsoluteUri, cloudStorageAccount.Credentials)
            {
                RetryPolicy = RetryPolicies.Retry(10, TimeSpan.FromSeconds(1)), //just to show that it's not used
            };

            var dataServiceQuery = context.CreateQuery<TableServiceEntity>("TableServiceEntity");

            //var cloudTableQuery = dataServiceQuery.AsTableServiceQuery(); //note that this code doesn't transfer RetryPolicy to CloudTableQuery, so using explicit declaration:
            var cloudTableQuery = new CloudTableQuery<TableServiceEntity>(dataServiceQuery, context.RetryPolicy);

            Console.WriteLine(@"Paused request to devstoreaccount1.table.core.windows.net should appear in Fiddler now.
            Please wait 2 minutes to get exception described");

            foreach (var tableServiceEntity in cloudTableQuery)
            {
                //Notice that Fiddler registered only one attempt to get the resource, so RetryPolicy is not used here
            }
        }
Beispiel #2
0
        /// <summary>
        /// Retrive Performance counter data
        /// </summary>
        /// <param name="counterFullName">Perfomance counter specifier full name</param>
        /// <param name="roleInstanceName">Deployment id</param>
        /// <param name="startPeriod">Start sample date time</param>
        /// <param name="endPeriod">End sample date time</param>
        /// <returns></returns>
        public IEnumerable <PerformanceData> GetPerformanceCounters(String counterFullName, String roleInstanceName, DateTime startPeriod, DateTime endPeriod)
        {
            //create context for WAD table
            WADPerformanceTable context = new WADPerformanceTable(_accountStorage.TableEndpoint.ToString(), _accountStorage.Credentials);

            //query for pefomance counters
            CloudTableQuery <PerformanceData> query = (from row in context.Queryable
                                                       where row.CounterName == counterFullName &&
                                                       row.EventTickCount >= startPeriod.Ticks &&
                                                       row.EventTickCount <= endPeriod.Ticks &&
                                                       row.RoleInstance.Equals(roleInstanceName)
                                                       select row).AsTableServiceQuery();

            List <PerformanceData> selectedData;

            try
            {
                selectedData = query.Execute().ToList();
            }
            catch (Exception exception)
            {
                //TODO: log
                throw;
            }
            return(selectedData);
        }
Beispiel #3
0
        public static IEnumerable <ABTestResult> GetResultsByGoal(string goal, string asofdate)
        {
            Dictionary <string, long> impressions = new Dictionary <string, long>();
            Dictionary <string, long> conversions = new Dictionary <string, long>();
            Dictionary <string, long> totalweight = new Dictionary <string, long>();
            Dictionary <string, long> totalviews  = new Dictionary <string, long>();

            ABTestImpressionClient             abtic           = new ABTestImpressionClient();
            CloudTableQuery <ABTestImpression> impressionQuery = abtic.GetAllByGoal(goal, asofdate);

            foreach (var i in impressionQuery.Execute())
            {
                if (impressions.ContainsKey(i.TestID))
                {
                    impressions[i.TestID]++;
                }
                else
                {
                    impressions[i.TestID] = 1;
                }
            }

            ABTestConversionClient             abtcc           = new ABTestConversionClient();
            CloudTableQuery <ABTestConversion> conversionQuery = abtcc.GetAllByGoal(goal, asofdate);

            foreach (var c in conversionQuery.Execute())
            {
                if (conversions.ContainsKey(c.TestID))
                {
                    conversions[c.TestID]++;
                    totalweight[c.TestID] += c.Weight;
                    totalviews[c.TestID]  += c.Views;
                }
                else
                {
                    conversions[c.TestID] = 1;
                    totalweight[c.TestID] = c.Weight;
                    totalviews[c.TestID]  = c.Views;
                }
            }
            List <ABTestResult> results = new List <ABTestResult>();

            foreach (var k in impressions.Keys)
            {
                results.Add(new ABTestResult
                {
                    TestID = k
                    ,
                    UniqueVisitors = impressions.ContainsKey(k) ? impressions[k] : 0
                    ,
                    TotalViews = totalviews.ContainsKey(k) ? totalviews[k] : 0
                    ,
                    ConversionCount = conversions.ContainsKey(k) ? conversions[k] : 0
                    ,
                    ConversionWeightSum = totalweight.ContainsKey(k) ? totalweight[k] : 0
                });
            }

            return(results);
        }
        public MetricsTransactionsEntity[] GetMetrics(CloudStorageAccount storageAccount, DateTime startDateTimeUTC, DateTime endDateTimeUTC)
        {
            MetricsTransactionsTable table = new MetricsTransactionsTable(storageAccount,
                                                                          storageAccount.Credentials);
            //convert datetimes to partition keys
            String startingPartitionKey = startDateTimeUTC.ToString(StorageResource.TransactionPrimaryKeyTimeFormat);
            String endingPartitionKey   = endDateTimeUTC.ToString(StorageResource.TransactionPrimaryKeyTimeFormat);

            var query = from transactionsEntity in table.Queryable
                        where transactionsEntity.PartitionKey.CompareTo(startingPartitionKey) >= 0 &&
                        transactionsEntity.PartitionKey.CompareTo(endingPartitionKey) <= 0
                        select transactionsEntity;

            CloudTableQuery <MetricsTransactionsEntity> tableServiceQuery = query.AsTableServiceQuery();

            MetricsTransactionsEntity[] metricsTransactionsEntities;

            try
            {
                //execute query
                metricsTransactionsEntities = tableServiceQuery.Execute().ToArray();
            }
            catch (Exception exception)
            {
                //TODO:log
                throw;
            }

            return(metricsTransactionsEntities);
        }
        public string FixDemoSource(string startdate)
        {
            int cnt = 0;

            SkillCowRequestSubmissionClient rsc = new SkillCowRequestSubmissionClient();

            DateTime cursordate = DateTime.ParseExact(startdate, "yyyyMMdd", CultureInfo.InvariantCulture);

            List <SkillCowRequestSubmission> submissions = new List <SkillCowRequestSubmission>();

            while (cursordate < DateTime.UtcNow.AddDays(1))
            {
                CloudTableQuery <SkillCowRequestSubmission> query = rsc.GetAll(cursordate.ToString("yyyyMMdd"));

                foreach (SkillCowRequestSubmission s in query.Execute().Where(x => x.UtmSource == "demo"))
                {
                    submissions.Add(s);
                }

                cursordate = cursordate.AddDays(1);
            }

            foreach (SkillCowRequestSubmission x in submissions)
            {
                x.UtmSource   = "Kiosks";
                x.UtmCampaign = "JerseyGardens";
                x.UtmTerm     = "Station1";
                rsc.Update(x);
            }

            return(cnt.ToString() + " leads fixed");
        }
        /// <summary>
        /// Returns all entities from given table
        /// </summary>
        /// <param name="serviceContext"></param>
        /// <param name="entitySetName"></param>
        /// <returns></returns>
        public CloudTableQuery <Object> GetEntities(TableServiceContext serviceContext, string entitySetName)
        {
            CloudTableQuery <Object> partitionQuery =
                (from e in serviceContext.CreateQuery <Object>(entitySetName)
                 select e).AsTableServiceQuery <Object>();

            return(partitionQuery);
        }
Beispiel #7
0
        /// <summary>
        /// Initializes a new instance of the <see cref="QueryHelper&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="query">The query.</param>
        public QueryHelper(CloudTableQuery <T> query)
        {
            if (query == null)
            {
                throw new ArgumentNullException("query");
            }

            _query = query;
        }
Beispiel #8
0
        static void BeginExecuteSegmentedIsDone(IAsyncResult result)
        {
            CloudTableQuery <Entities.Product> CloudQuery = result.AsyncState as CloudTableQuery <Entities.Product>;
            var resultSegment = CloudQuery.EndExecuteSegmented(result);

            List <Entities.Product> listSongs = resultSegment.Results.ToList <Entities.Product>();

            if (resultSegment.HasMoreResults)
            {
                IAsyncResult iAsyncResult = CloudQuery.BeginExecuteSegmented(resultSegment.ContinuationToken, BeginExecuteSegmentedIsDone, CloudQuery);
            }
        }
Beispiel #9
0
        private static void TestTableService()
        {
            TableStorageHelper tableHelper = new TableStorageHelper();

            tableHelper.GetCloudTableClient();

            tableHelper.CreateTable("sampleTable");

            TableServiceContext tableContext = tableHelper.GetTableContext();

            AddData(tableContext, "sampleTable");

            CloudTableQuery <Object> tableQuery = tableHelper.GetEntities(tableContext, "sampleTable");
        }
        public List <SkillCowRequestSubmission> GetByUtmSource(DateTime startdate, DateTime enddate, string source)
        {
            List <SkillCowRequestSubmission> allrecords = new List <SkillCowRequestSubmission>();

            DateTime cursordate = startdate;

            while (cursordate <= enddate)
            {
                CloudTableQuery <SkillCowRequestSubmission> query = this.GetAll(cursordate.ToString("yyyyMMdd"));
                allrecords.AddRange(query.Execute().Where(x => x.UtmSource == source).OrderBy(x => x.Timestamp));
                cursordate = cursordate.AddDays(1);
            }

            return(allrecords);
        }
Beispiel #11
0
 public IEnumerable <StatusEntry> GetStatusEntriesForJob(Guid jobId)
 {
     if (_tableClient.DoesTableExist("status"))
     {
         CloudTableQuery <StatusEntry> qry =
             (from s in Context.StatusEntries
              where s.RequestId == jobId
              select s).AsTableServiceQuery <StatusEntry>();
         return(qry.Execute());
     }
     else
     {
         return(null);
     }
 }
Beispiel #12
0
        public ApiKeyEntity RetrieveApiKey(string apiKey)
        {
            CloudTableClient tableClient = _storageAccount.CreateCloudTableClient();

            // Get the data service context
            TableServiceContext serviceContext = tableClient.GetDataServiceContext();

            CloudTableQuery <ApiKeyEntity> partitionQuery = (from e in serviceContext.CreateQuery <ApiKeyEntity>("keys")
                                                             where e.PartitionKey == apiKey
                                                             select e).AsTableServiceQuery <ApiKeyEntity>();

            foreach (ApiKeyEntity apiKeyEntity in partitionQuery)
            {
                return(apiKeyEntity);
            }

            return(null);
        }
Beispiel #13
0
        public IEnumerable <JobEntry> GetJobsForClient(String clientId, ResultContinuation token = null)
        {
            if (_tableClient.DoesTableExist("jobs"))
            {
                CloudTableQuery <JobEntry> qry =
                    (from j in Context.Jobs
                     where j.PartitionKey == clientId
                     select j).AsTableServiceQuery <JobEntry>();

                // this will return ALL jobs for given client - alternative is to use BeginExecuteSegmented and
                // manage pagination via continuation tokens or filter criteria on client side
                return(qry.Execute());
            }
            else
            {
                return(null);
            }
        }
Beispiel #14
0
        public static Dictionary <string, RoutingInfo> GetConfigDictionary()
        {
            Dictionary <string, RoutingInfo> config = (Dictionary <string, RoutingInfo>)_configCache.Get(_partitionKey);

            if (config == null)
            {
                new Dictionary <string, RoutingInfo>();
                TableServiceContext           tableContext = GetTableContext();
                CloudTableQuery <RouteEntity> routeQuery   =
                    (from e in tableContext.CreateQuery <RouteEntity>(_tableName)
                     where e.PartitionKey == _partitionKey
                     select e)
                    .AsTableServiceQuery <RouteEntity>();
                IEnumerable <RouteEntity> re = routeQuery.Execute();
                config = re.ToDictionary(r => r.RowKey, v => v.GetRoutingInfo());
                _configCache.Remove(_partitionKey);
                _configCache.Add(_partitionKey, config, DateTimeOffset.Now.AddMinutes(_expireMinutes));
            }
            return(config);
        }
        public List <SkillCowRequestSubmission> GetKioskLeads(DateTime startdate, DateTime enddate)
        {
            List <SkillCowRequestSubmission> allrecords = new List <SkillCowRequestSubmission>();

            DateTime cursordate = startdate;

            while (cursordate <= enddate)
            {
                CloudTableQuery <SkillCowRequestSubmission> query = null;

                query = (from e in TableContext().CreateQuery <SkillCowRequestSubmission>(tableName)
                         where e.PartitionKey == cursordate.ToString("yyyyMMdd") &&
                         e.UtmSource == "Kiosks" &&
                         e.SourceForm == "schoolform"
                         select e).AsTableServiceQuery <SkillCowRequestSubmission>();

                allrecords.AddRange(query.Execute().OrderBy(x => x.Timestamp));
                cursordate = cursordate.AddDays(1);
            }

            return(allrecords);
        }
        /// <summary>
        /// Returns the entity if present from the table service. Should only be called after
        /// checking the entity is not already present in the context.
        /// </summary>
        /// <param name="record">Request record of the entity being sought.</param>
        /// <returns>The entity if present in the table service.</returns>
        private RequestEntity GetEntityFromTable(RequestRecord record)
        {
            // Create query to return all matching entities for this record.
            CloudTableQuery <RequestEntity> query = (from entity
                                                     in _serviceContext.CreateQuery <RequestEntity>(_tableName)
                                                     where entity.PartitionKey == record.PartitionKey && entity.RowKey == record.RowKey
                                                     select entity).AsTableServiceQuery <RequestEntity>();

            // Return the first or default entity found.
            try
            {
                return(query.Execute().FirstOrDefault());
            }
            catch (DataServiceQueryException ex)
            {
                //If an exception occurs checked for a 404 error code meaning the resource was not found.
                if (ex.Response.StatusCode == 404)
                {
                    return(null);
                }
                throw ex;
            }
        }
Beispiel #17
0
        public IEnumerable <ItemDeContrato> ObterItensDoContrato(int atual)
        {
            try
            {
                string partitionKey  = Contrato.ObterPartitionKey(atual);
                string rowKeyInicial = ItemDeContrato.ObterRowKey(atual, 0);
                string rowKeyFinal   = ItemDeContrato.ObterRowKey(atual, int.MaxValue);

                CloudTableQuery <ItemDeContrato> query =
                    (from e in ServiceContext.CreateQuery <ItemDeContrato>(Nome)
                     where
                     e.PartitionKey == partitionKey &&
                     e.RowKey.CompareTo(rowKeyInicial) >= 0 &&
                     e.RowKey.CompareTo(rowKeyFinal) <= 0
                     select e).AsTableServiceQuery <ItemDeContrato>();

                return(query.ToList());
            }
            catch (Exception ex)
            {
                throw new RepositorioCloudTableException(
                          String.Format("Erro obtendo itens do contrato '{0}'.", atual), ex);
            }
        }
        /// <summary>
        /// Read data entries and their corresponding eTags from the Azure table.
        /// </summary>
        /// <param name="predicate">Predicate function to use for querying the table and filtering the results.</param>
        /// <returns>Enumeration of entries in the table which match the query condition.</returns>
        internal async Task <IEnumerable <Tuple <T, string> > > ReadTableEntriesAndEtagsAsync(Expression <Func <T, bool> > predicate)
        {
            const string operation = "ReadTableEntriesAndEtags";
            var          startTime = DateTime.UtcNow;

            try
            {
                TableServiceContext svc = tableOperationsClient.GetDataServiceContext();
                // Improve performance when table name differs from class name
                // http://www.gtrifonov.com/2011/06/15/improving-performance-for-windows-azure-tables/
                svc.ResolveType = ResolveEntityType;

                //IQueryable<T> query = svc.CreateQuery<T>(TableName).Where(predicate);
                CloudTableQuery <T> cloudTableQuery = svc.CreateQuery <T>(TableName).Where(predicate).AsTableServiceQuery(); // turn IQueryable into CloudTableQuery

                try
                {
                    Func <Task <List <T> > > executeQueryHandleContinuations = async() =>
                    {
                        // Read table with continuation token
                        // http://convective.wordpress.com/2013/11/03/queries-in-the-windows-azure-storage-client-library-v2-1/

                        // 1) First wrong sync way to read:
                        // List<T> queryResults = query.ToList(); // ToList will actually execute the query and add entities to svc. However, this will not handle continuation tokens.
                        // 2) Second correct sync way to read:
                        // http://convective.wordpress.com/2010/02/06/queries-in-azure-tables/
                        // CloudTableQuery.Execute will properly retrieve all the records from a table through the automatic handling of continuation tokens:
                        Task <ResultSegment <T> > firstSegmentPromise = Task <ResultSegment <T> > .Factory.FromAsync(
                            cloudTableQuery.BeginExecuteSegmented,
                            cloudTableQuery.EndExecuteSegmented,
                            null);

                        // 3) Third wrong async way to read:
                        // return firstSegmentPromise;
                        // 4) Forth correct async way to read - handles continuation tokens:

                        var list = new List <T>();

                        Task <ResultSegment <T> > nextSegmentAsync = firstSegmentPromise;
                        while (true)
                        {
                            ResultSegment <T> resultSegment = await nextSegmentAsync;
                            var capture = resultSegment.Results;
                            if (capture != null) // don't call Count or Any or anything else that can potentialy cause multiple evaluations of the IEnumerable
                            {
                                list.AddRange(capture);
                            }

                            if (!resultSegment.HasMoreResults)
                            {
                                // All data was read successfully if we got to here
                                break;
                            }

                            // ask to read the next segment
                            nextSegmentAsync = Task <ResultSegment <T> > .Factory.FromAsync(
                                resultSegment.BeginGetNext,
                                resultSegment.EndGetNext,
                                null);
                        }

                        return(list);
                    };

                    IBackoffProvider backoff = new FixedBackoff(AzureTableDefaultPolicies.PauseBetweenTableOperationRetries);

                    List <T> results = await AsyncExecutorWithRetries.ExecuteWithRetries(
                        counter => executeQueryHandleContinuations(),
                        AzureTableDefaultPolicies.MaxTableOperationRetries,
                        (exc, counter) => AzureStorageUtils.AnalyzeReadException(exc.GetBaseException(), counter, TableName, Logger),
                        AzureTableDefaultPolicies.TableOperationTimeout,
                        backoff);

                    // Data was read successfully if we got to here
                    return(PairEntitiesWithEtags(svc, results));
                }
                catch (Exception exc)
                {
                    // Out of retries...
                    var errorMsg = string.Format("Failed to read Azure storage table {0}: {1}", TableName, exc.Message);
                    if (!AzureStorageUtils.TableStorageDataNotFound(exc))
                    {
                        Logger.Warn(ErrorCode.AzureTable_09, errorMsg, exc);
                    }
                    throw new OrleansException(errorMsg, exc);
                }
            }
            finally
            {
                CheckAlertSlowAccess(startTime, operation);
            }
        }
Beispiel #19
0
        protected override Task<object> ExecuteQuery(DataRequest request, Dictionary<string, object> options)
        {
            DataQuery query = request.Query;
            string tableName = request.Query.Collection.Name;

            Deferred<object> deferred = Deferred.Create<object>();

            if (query.IsLookup) {
                if (String.IsNullOrEmpty(request.Partition)) {
                    throw new Exception("Missing partition information to perform lookup.");
                }

                Runtime.TraceInfo("Querying table service on table %s with pk = %s, rk = %s", tableName, request.Partition, query.ID);

                _tableService.QueryEntity(tableName, request.Partition, query.ID, delegate(Exception e, CloudTableEntity entity) {
                    if (e != null) {
                        deferred.Resolve(null);
                    }
                    else {
                        CleanEntity(entity);
                        deferred.Resolve(entity);
                    }
                });
            }
            else {
                Runtime.TraceInfo("Querying table service on table %s", tableName);

                // TODO: Apply actual query
                CloudTableQuery tableQuery = new CloudTableQuery().From(tableName);
                if (String.IsNullOrEmpty(request.Partition) == false) {
                    tableQuery = tableQuery.WhereKeys(request.Partition, null);
                }

                _tableService.QueryEntities(tableQuery, delegate(Exception e, List<CloudTableEntity> entities) {
                    List<string> partitions = null;
                    if (options != null) {
                        partitions = (List<string>)options["partitions"];
                        if (partitions != null) {
                            entities = entities.Filter(delegate(CloudTableEntity entity) {
                                return partitions.Contains(entity.PartitionKey);
                            });
                        }
                    }

                    entities.ForEach(CleanEntity);
                    object[] items = query.Evaluate((object[])entities);

                    deferred.Resolve(items);
                });
            }

            return deferred.Task;
        }
Beispiel #20
0
        /// <summary>
        /// Executes the query and returns the first element, if any.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <returns>The first element.</returns>
        public static T FirstOrDefault(CloudTableQuery <T> query)
        {
            QueryHelper <T> helper = new QueryHelper <T>(query);

            return(helper.ExecuteSegmented(true).FirstOrDefault());
        }
Beispiel #21
0
        /// <summary>
        /// Executes the query.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <returns>The returned elements.</returns>
        public static IList <T> All(CloudTableQuery <T> query)
        {
            QueryHelper <T> helper = new QueryHelper <T>(query);

            return(helper.ExecuteSegmented(false));
        }
Beispiel #22
0
        protected override Task <object> ExecuteQuery(DataRequest request, Dictionary <string, object> options)
        {
            DataQuery query     = request.Query;
            string    tableName = request.Query.Collection.Name;

            Deferred <object> deferred = Deferred.Create <object>();

            if (query.IsLookup)
            {
                if (String.IsNullOrEmpty(request.Partition))
                {
                    throw new Exception("Missing partition information to perform lookup.");
                }

                Runtime.TraceInfo("Querying table service on table %s with pk = %s, rk = %s", tableName, request.Partition, query.ID);

                _tableService.QueryEntity(tableName, request.Partition, query.ID, delegate(Exception e, CloudTableEntity entity) {
                    if (e != null)
                    {
                        deferred.Resolve(null);
                    }
                    else
                    {
                        CleanEntity(entity);
                        deferred.Resolve(entity);
                    }
                });
            }
            else
            {
                Runtime.TraceInfo("Querying table service on table %s", tableName);

                // TODO: Apply actual query
                CloudTableQuery tableQuery = new CloudTableQuery().From(tableName);
                if (String.IsNullOrEmpty(request.Partition) == false)
                {
                    tableQuery = tableQuery.WhereKeys(request.Partition, null);
                }

                _tableService.QueryEntities(tableQuery, delegate(Exception e, List <CloudTableEntity> entities) {
                    List <string> partitions = null;
                    if (options != null)
                    {
                        partitions = (List <string>)options["partitions"];
                        if (partitions != null)
                        {
                            entities = entities.Filter(delegate(CloudTableEntity entity) {
                                return(partitions.Contains(entity.PartitionKey));
                            });
                        }
                    }

                    entities.ForEach(CleanEntity);
                    object[] items = query.Evaluate((object[])entities);

                    deferred.Resolve(items);
                });
            }

            return(deferred.Task);
        }
Beispiel #23
0
        public HttpResponse logoff(string location, string agent, string code)
        {
            try
            {
                Response.ContentType = "application/json";

                AgentClient ac = new AgentClient();
                Agent       a  = ac.GetAll().Execute().Where(x => x.LoginName == agent).SingleOrDefault();

                if (a == null)
                {
                    throw new Exception("Invalid agent ID or code");
                }

                if (a.LoginCode == code)
                {
                    DateTime nowTime = EasternTimeConverter.Convert(DateTime.UtcNow);


                    AgentEventClient aec       = new AgentEventClient();
                    AgentEvent       lastEvent = aec.GetAll().Execute().Where(x => x.Agent == agent).OrderByDescending(x => x.EventTime).FirstOrDefault();

                    string hoursworked = "No prior logon.";
                    string production  = "No results.";
                    if (lastEvent.EventType == "logon")
                    {
                        long     elapsedTicks = nowTime.Ticks - lastEvent.EventTime.Ticks;
                        TimeSpan ts           = new TimeSpan(elapsedTicks);
                        hoursworked = ts.Hours.ToString() + "h : " + ts.Minutes + "m logged.";

                        //Count how many leads
                        List <SkillCowRequestSubmission> allrecords = new List <SkillCowRequestSubmission>();

                        DateTime cursordate = lastEvent.EventTime;

                        SkillCowRequestSubmissionClient rsc = new SkillCowRequestSubmissionClient();
                        while (cursordate <= nowTime)
                        {
                            CloudTableQuery <SkillCowRequestSubmission> query = rsc.GetAll(cursordate.ToString("yyyyMMdd"));
                            allrecords.AddRange(query.Execute().Where(x => x.UtmCampaign == location && x.UtmContent == agent).OrderBy(x => x.Timestamp));
                            cursordate = cursordate.AddDays(1);
                        }

                        //tally up
                        int totalschoolleads = 0;
                        int totalindeedjobs  = 0;
                        int totalcourses     = 0;
                        foreach (SkillCowRequestSubmission x in allrecords)
                        {
                            switch (x.SourceForm)
                            {
                            case "schoolform":
                                totalschoolleads++;
                                break;

                            case "indeedjob":
                                totalindeedjobs++;
                                break;

                            case "udemycourse":
                                totalcourses++;
                                break;
                            }
                        }
                        if (totalschoolleads + totalindeedjobs + totalcourses > 0)
                        {
                            production  = "\n";
                            production += totalschoolleads + " school leads\n";
                            production += totalindeedjobs + " indeed jobs\n";
                            production += totalcourses + " udemy courses";
                        }
                    }

                    //Log event
                    aec.AddNewItem(new AgentEvent(agent, "logoff", location));

                    a.CurrentLocation = "";
                    a.CurrentStatus   = "loggedoff";
                    ac.Update(a);

#if DEBUG
#else
                    Telephony t = new Telephony();

                    string message = agent + " logged OFF at " + location + "\n" + hoursworked + "\n" + production;
                    //Send to Rick
                    //t.SendSMS("+19174340659", message);

                    t.SendSMS("+19179578770", message);
#endif

                    Response.Write("{\"result\": \"ok\", \"logonname\": \"" + a.LoginName + "\"}");
                    Response.End();
                }
                else
                {
                    throw new Exception("Invalid agent ID or code");
                }
            }
            catch (Exception ex)
            {
                Response.ContentType = "application/json";
                Response.Write(DefaultErrorResponse(ex.Message));
                Response.End();
            }

            return(null);
        }