Beispiel #1
0
    protected void Page_Load(object sender, EventArgs e)
    {
        Server.ScriptTimeout = 300;

        Label3.Text = "";
        Label4.Text = "";

        if (Label1.Text == "" && Label2.Text == "")
        {
            Label1.Text                    = "1";
            Label2.Text                    = "0";
            Session["Memberships"]         = Memberships.ForOrganization(Organization.PPSE);
            Session["memberAccountLookup"] = new Dictionary <int, bool>();
            Button1.Text                   = "Press OK to converting Person forumaccountIDs to new forum";
        }
        else if (Label1.Text == "1")
        {
            IForumDatabase         forumDatabase       = SwedishForumDatabase.GetDatabase(2, TextBox1.Text);
            Dictionary <int, bool> memberAccountLookup = Session["memberAccountLookup"] as Dictionary <int, bool>;
            Memberships            memberships         = Session["Memberships"] as Memberships;
            int startRec = int.Parse(Label2.Text);

            SetMembers(startRec, forumDatabase, memberAccountLookup, memberships);
            Button1.Text = "continuing setting memberships";
        }

        else if (Label1.Text == "2")
        {
            IForumDatabase forumDatabase = SwedishForumDatabase.GetDatabase(2, TextBox1.Text);
            Session["accountIds"] = forumDatabase.GetAccountList();

            Label1.Text  = "3";
            Label2.Text  = "0";
            Button1.Text = "removing memberships";
        }
        else if (Label1.Text == "3")
        {
            IForumDatabase         forumDatabase       = SwedishForumDatabase.GetDatabase(2, TextBox1.Text);
            Dictionary <int, bool> memberAccountLookup = Session["memberAccountLookup"] as Dictionary <int, bool>;
            int[] accountIds = Session["accountIds"] as int[];

            int startRec = int.Parse(Label2.Text);

            RemoveMembers(startRec, forumDatabase, memberAccountLookup, accountIds);

            Button1.Text = "removing memberships";
        }

        if (Label1.Text == "4")
        {
            Button1.Text = "DONE!";
        }

        if (Label1.Text != "4" && Label1.Text != "" && Label3.Text == "")
        {
            ScriptManager.RegisterStartupScript(this, this.GetType(), "reloadscript", "document.getElementById('" + Button1.ClientID + "').click();", true);
        }
    }
Beispiel #2
0
 public Memberships GetMemberships(bool includeTerminated)
 {
     return(Memberships.ForOrganization(this, includeTerminated));
 }
    SeriesCollection GetSeriesCollection()
    {
        SeriesCollection result = new SeriesCollection();

        Memberships memberships = Memberships.ForOrganization(Organization.PPSE, true);

        string[] seriesNames =
        {
            "Renewed 3+ times", "Renewed twice",           "Renewed once",         "Not renewed yet",
            "Churn 6+",         "Churn after 3-5th years", "Churn at 2nd renewal", "Churn at 1st renewal","Churned before 1st year",
            "Still Active"
        };

        Color[] colors =
        {
            Color.Black,      Color.DarkGreen, Color.Green,   Color.GreenYellow,
            Color.DarkViolet, Color.Crimson,   Color.DarkRed, Color.Red,        Color.DarkSalmon,
            Color.Green
        };

        int seriesDividerIndex = 4;
        int stillActiveIndex   = seriesNames.Length - 1;

        int[]    data = new int[seriesNames.Length];
        DateTime now  = DateTime.Now;        // cache this value

        foreach (Membership membership in memberships)
        {
            if (membership.Active)
            {
                data [stillActiveIndex]++;

                TimeSpan span = now - membership.MemberSince;

                int seriesIndex = seriesDividerIndex - 1 - span.Days / 365;

                if (seriesIndex < 0)
                {
                    seriesIndex = 0;
                }

                data[seriesIndex]++;
            }
            else
            {
                TimeSpan span = (DateTime)membership.DateTerminated - membership.MemberSince;

                int yearCount = (span.Days + 30) / 365;
                int seriesIndex;

                if (yearCount >= 6)
                {
                    seriesIndex = stillActiveIndex - 5;
                }
                else if (yearCount >= 3)
                {
                    seriesIndex = stillActiveIndex - 4;
                }
                else
                {
                    seriesIndex = stillActiveIndex - 1 - yearCount;
                }

                if (seriesIndex < stillActiveIndex || seriesIndex > stillActiveIndex - 1)
                {
                    seriesIndex = stillActiveIndex - 1;
                }

                data [seriesIndex]++;
            }
        }

        Series series1 = new Series();
        Series series2 = new Series();

        for (int index = 0; index <= stillActiveIndex; index++)
        {
            if (data[index] == 0)
            {
                continue;
            }

            Element element = new Element(seriesNames [index], data[index]);

            if (index < seriesDividerIndex)
            {
                series1.Elements.Add(element);
                element.Color = colors[index];
            }
            else
            {
                series2.Elements.Add(element);
            }
        }

        series1.Name = "Active Memberships";
        series2.Name = "Total Throughput";

        result.Add(series1);
        // result.Add (series2);

        return(result);
    }
Beispiel #4
0
    SeriesCollection GetSeriesCollection()
    {
        SeriesCollection result = new SeriesCollection();

        Memberships memberships = Memberships.ForOrganization(Organization.PPSE, true);

        string[] elementNames = { "Still active, renewed", "Still active, unrenewed", "Hesitating, unrenewed", "Churn at 4th+ renewal", "Churn at 3rd renewal",
                                  "Churn at 2nd renewal",  "Churn at 1st renewal",    "Churn in 1st year",     };

        Color[] colors =
        {
            Color.Green, Color.LimeGreen, Color.Lime, Color.White, Color.Wheat, Color.Orange,
            Color.Red,   Color.DarkRed
        };

        int currentYear = DateTime.Today.Year;

        int seriesCount  = currentYear - 2006 + 1;
        int elementCount = elementNames.Length;

        // Create one series per year starting at 2006

        int[,] data = new int[seriesCount, elementCount];

        foreach (Membership membership in memberships)
        {
            if (membership.Active)
            {
                if (membership.Expires.Year > DateTime.Today.Year) // Renewed this year?
                {
                    data[membership.MemberSince.Year - 2006, 0]++;
                }
                else if (DateTime.Today.AddDays(25) > membership.Expires)
                {
                    data[membership.MemberSince.Year - 2006, 2]++; // Not renewed 3 days after first reminder
                }
                else
                {
                    data[membership.MemberSince.Year - 2006, 1]++;
                }
            }
            else
            {
                TimeSpan span = (DateTime)membership.DateTerminated - membership.MemberSince;

                int membershipDurationYears = (int)((span.Days + 30) / 365.25);                  // Add 30d for margin at renewal process

                if (membershipDurationYears < 0)
                {
                    membershipDurationYears = 0; // compensate for some bogus data in db
                }

                int index = 4 - membershipDurationYears;

                if (index < 0)
                {
                    index = 0;
                }

                data[membership.MemberSince.Year - 2006, index + 3]++;
            }
        }

        for (int year = 2006 + seriesCount - 1; year >= 2006; year--)
        {
            Series series = new Series();
            series.Name = string.Empty;

            for (int elementLoop = 0; elementLoop < elementCount; elementLoop++)
            {
                Element element = new Element(elementNames[elementLoop], data[year - 2006, elementLoop]);
                element.Color = colors[elementLoop];
                series.Elements.Add(element);
            }

            result.Add(series);
        }

        return(result);
    }
Beispiel #5
0
        public static void Run()
        {
            BotLog.Write(1, "SeForumCheck", "Entering");

            Memberships    memberships   = Memberships.ForOrganization(Organization.PPSE);
            IForumDatabase forumDatabase = SwedishForumDatabase.GetDatabase();

            int[] accountIds;
            try
            {
                accountIds = forumDatabase.GetAccountList();
            }
            catch (Exception e)
            {
                ExceptionMail.Send(new Exception("Failed to connect to vBulletin", e), true);
                BotLog.Write(1, "SeForumCheck", "Failed to connect -- exiting");

                return;
            }

            BotLog.Write(1, "SeForumCheck", "Primed db - entering promotion cycle");

            Dictionary <int, bool> memberAccountLookup = new Dictionary <int, bool>();

            // This is kind of suboptimal, but hey, it only runs once a night in the wolf hour.

            Person currentMember = null;

            foreach (Membership membership in memberships)
            {
                if (!membership.Active)
                {
                    continue;
                }

                currentMember = membership.Person;

                try
                {
                    if (currentMember.SwedishForumAccountId != 0)
                    {
                        if (!forumDatabase.IsPartyMember(currentMember.SwedishForumAccountId))
                        {
                            // This guy is not listed as a party member, but should be.

                            BotLog.Write(2, "SeForumCheck", "Promoting " + currentMember.Name);
                            forumDatabase.SetPartyMember(currentMember.SwedishForumAccountId);
                        }

                        memberAccountLookup[currentMember.SwedishForumAccountId] = true;
                    }
                }
                catch (Exception e)
                {
                    // The forum account probably doesn't exist. Just remove it from the profile.

                    BotLog.Write(2, "SeForumCheck", "Exception reading " + currentMember.Name + ": " + e.ToString());

                    try
                    {
                        currentMember.SwedishForumAccountId = 0;
                    }
                    catch (Exception e2)
                    {
                        string logMessage = "Exception removing " + currentMember.Name + "'s forum account: " + e2.ToString();
                        BotLog.Write(2, "SeForumCheck", logMessage);
                        ExceptionMail.Send(new Exception(logMessage, e2));
                    }
                }
            }

            // Now that we have flagged all member accounts as member accounts, flag the rest as
            // non-party members.

            BotLog.Write(1, "SeForumCheck", "Promotion cycle done - entering demotion cycle");

            foreach (int accountId in accountIds)
            {
                if (!memberAccountLookup.ContainsKey(accountId))
                {
                    if (forumDatabase.IsPartyMember(accountId))
                    {
                        BotLog.Write(2, "SeForumCheck", "Demoting forum account " + forumDatabase.GetAccountName(accountId));
                        forumDatabase.SetPartyNonmember(accountId);
                    }
                }
            }
            BotLog.Write(1, "SeForumCheck", "Demotion cycle complete -- exiting");
        }
Beispiel #6
0
    protected void Button1_Click(object sender, EventArgs e)
    {
        int col_firstNames   = 0;
        int col_lastName     = 1;
        int col_dateOfBirth  = 2;
        int col_email        = 3;
        int col_municipality = 4;
        int col_address      = 5;
        int col_postalCode   = 6;
        int col_city         = 7;
        int col_phone        = 8;
        int col_dateJoined   = 9;
        int col_active       = 10;

        int currentRow      = -1;
        int currentImported = 0;

        DateTime T0 = DateTime.Now;

        Dictionary <string, BasicCity> postcodes   = PirateDb.GetDatabase().GetCitiesPerPostalCode(loadCntry.Identity);
        Dictionary <string, BasicCity> cityPerName = new Dictionary <string, BasicCity>();
        Dictionary <int, BasicCity>    cityPerId   = new Dictionary <int, BasicCity>();

        foreach (BasicCity bc in postcodes.Values)
        {
            cityPerName[bc.Name.ToLower().Replace(" ", "")] = bc;
            cityPerId[bc.Identity] = bc;
        }

        People allpeople = People.GetAll();
        Dictionary <string, Person> peoplePerKey = new Dictionary <string, Person>();

        foreach (Person p in allpeople)
        {
            peoplePerKey[p.Email.ToLower().Replace(" ", "") + p.Birthdate.ToString("yyMMdd")] = p;
        }

        Memberships memberships = Memberships.ForOrganization(currentOrg);
        Dictionary <int, Membership> membershipsDict = new Dictionary <int, Membership>();

        foreach (Membership ms in memberships)
        {
            membershipsDict[ms.PersonId] = ms;
        }

        string[] rows = TextBoxImport.Text.Replace("\r\n", "\n").Split('\n');
        using (TransactionScope txScope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 30, 0)))
        {
            foreach (string row in rows)
            {
                ++currentRow;
                string[] cols = (row + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t").Split('\t');

                Geography mainGeo = null;
                string    name    = cols[col_firstNames] + " " + cols[col_lastName];
                if (!Formatting.ValidateEmailFormat(cols[col_email]))
                {
                    AddError(currentRow, "Bad email format:" + cols[col_email]);
                    continue;
                }
                BasicCity foundCity = null;
                Dictionary <int, Geography> geos = new Dictionary <int, Geography>();
                string pcode = cols[col_postalCode].Trim();
                if (pcode != "")
                {
                    while (pcode.Length < loadCntry.PostalCodeLength)
                    {
                        pcode = "0" + pcode;
                    }

                    if (!postcodes.ContainsKey(pcode))
                    {
                        AddError(currentRow, "Invalid postal code:" + pcode);
                    }
                    else
                    {
                        foundCity = postcodes[pcode];
                        mainGeo   = Geography.FromIdentity(foundCity.GeographyId);
                        geos[foundCity.GeographyId] = mainGeo;
                    }
                }
                else if (cols[col_city].Trim() != "")
                {
                    if (!cityPerName.ContainsKey(cols[col_city].ToLower().Replace(" ", "")))
                    {
                        AddError(currentRow, "Invalid postal code:" + pcode);
                    }
                    else
                    {
                        foundCity = cityPerName[cols[col_city].ToLower().Replace(" ", "")];
                        mainGeo   = Geography.FromIdentity(foundCity.GeographyId);
                        geos[foundCity.GeographyId] = mainGeo;
                    }
                }

                foreach (Geography g in geotree)
                {
                    string[] names = g.Name.ToLower().Replace(" ", "").Split('/');
                    foreach (string partName in names)
                    {
                        if (partName == cols[col_municipality].ToLower().Replace(" ", ""))
                        {
                            mainGeo          = g;
                            geos[g.Identity] = g;
                        }
                    }
                }

                if (geos.Count == 0 || geos.Count > 1)
                {
                    AddError(currentRow, "Warning only: can not find a specific local geography");
                }


                DateTime dob           = NormalizeDate(cols[col_dateOfBirth]);
                DateTime doj           = NormalizeDate(cols[col_dateJoined]);
                string   key           = cols[col_email].ToLower().Replace(" ", "") + dob.ToString("yyMMdd");
                Person   currentPerson = null;

                if (!peoplePerKey.ContainsKey(key))
                {
                    if (mainGeo == null)
                    {
                        mainGeo = loadCntry.Geography;
                    }
                    currentPerson           = Person.Create(name, cols[col_email], "ABCABCABCABC", cols[col_phone], cols[col_address], pcode, cols[col_city], loadCntry.Code, dob, PersonGender.Unknown);
                    currentPerson.Geography = mainGeo;
                    PWLog.Write(PWLogItem.Person, currentPerson.Identity, PWLogAction.PersonCreated, "Created Person from Import", "Import for " + currentOrg.Name);
                }
                else
                {
                    currentPerson = peoplePerKey[key];
                    AddError(currentRow, "Warning only: Person with email already existed ");

                    if (currentPerson.Birthdate < new DateTime(1901, 1, 1))
                    {
                        currentPerson.Birthdate = dob;
                    }
                    if (currentPerson.Phone.Length < cols[col_phone].Length)
                    {
                        currentPerson.Phone = cols[col_phone];
                    }
                    if (currentPerson.Street.Length < cols[col_address].Length)
                    {
                        currentPerson.Street = cols[col_address];
                    }
                    if (currentPerson.PostalCode.CompareTo(pcode) < 0)
                    {
                        currentPerson.PostalCode = pcode;
                    }
                    if (currentPerson.CityName.Length < cols[col_city].Length)
                    {
                        currentPerson.CityName = cols[col_city];
                    }

                    if (mainGeo != null && mainGeo.Identity != currentPerson.GeographyId)
                    {
                        currentPerson.Geography = mainGeo;
                    }
                }

                // add membership
                if (!membershipsDict.ContainsKey(currentPerson.Identity))
                {
                    Membership newMs = Membership.Import(currentPerson, currentOrg, doj, nowValue.AddYears(100));
                    newMs.SetPaymentStatus(MembershipPaymentStatus.PaymentRecieved, nowValue);
                }

                // add activist
                if (cols[col_active] == "1")
                {
                    currentPerson.CreateActivist(true, true);
                    PWLog.Write(currentPerson, PWLogItem.Person, currentPerson.Identity, PWLogAction.ActivistJoin, "New activist joined.", "Import for " + currentOrg.Name);
                }

                ++currentImported;
            }
            txScope.Complete();
        }

        StringBuilder sb = new StringBuilder();

        sb.AppendLine("ProcessTime= " + Math.Round(DateTime.Now.Subtract(T0).TotalSeconds));
        sb.AppendLine("Rows read= " + currentRow);
        sb.AppendLine("Rows imported= " + currentImported);
        sb.AppendLine("Errors and warnings");
        foreach (int row in errRows.Keys)
        {
            sb.AppendLine("Line: " + row);
            sb.AppendLine(rows[row]);

            foreach (string err in errRows[row])
            {
                sb.AppendLine("     " + err);
            }
            sb.AppendLine("");
        }
        TextBoxResult.Text = sb.ToString();
    }
Beispiel #7
0
    SeriesCollection GetAgeGenderData(OrganizationMetadata metadata)
    {
        int  orgId       = metadata.OrganizationId;
        bool recurseTree = metadata.Recursive;

        Series seriesMale   = new Series();
        Series seriesFemale = new Series();

        seriesMale.Name   = "Male";
        seriesFemale.Name = "Female";

        Memberships memberships = null;

        if (recurseTree)
        {
            memberships = Memberships.ForOrganizations(Organization.FromIdentity(orgId).GetTree());
        }
        else
        {
            memberships = Memberships.ForOrganization(Organization.FromIdentity(orgId));
        }

        BasicPerson[] allPeople = PirateDb.GetDatabase().GetAllPeople();

        Dictionary <int, int>          geoLookup       = new Dictionary <int, int>();
        Dictionary <int, PersonGender> genderLookup    = new Dictionary <int, PersonGender>();
        Dictionary <int, int>          birthYearLookup = new Dictionary <int, int>();
        Dictionary <int, bool>         personLookup    = new Dictionary <int, bool>();

        foreach (BasicPerson person in allPeople)
        {
            geoLookup[person.Identity]       = person.GeographyId;
            genderLookup[person.Identity]    = person.IsMale ? PersonGender.Male : PersonGender.Female;
            birthYearLookup[person.Identity] = person.Birthdate.Year;
        }

        int[] male   = new int[200];
        int[] female = new int[200];

        foreach (Membership membership in memberships)
        {
            int          birthYear = 0;
            PersonGender gender    = PersonGender.Unknown;

            if (personLookup.ContainsKey(membership.PersonId))
            {
                continue; // If a person was already counted, do not count again
            }

            if (genderLookup.ContainsKey(membership.PersonId) &&
                (membership.OrganizationId == orgId ||
                 (recurseTree && membership.Organization.Inherits(orgId))))
            {
                birthYear = birthYearLookup[membership.PersonId];
                gender    = genderLookup[membership.PersonId];

                int index = birthYear - 1900;

                if (index < 30 || index >= 100)
                {
                    index = 90; // Put invalid years on 1990, where it won't show up in the noise
                }

                if (gender == PersonGender.Male)
                {
                    male[index]++;
                }
                else
                {
                    female[index]++;
                }

                personLookup[membership.PersonId] = true;
            }
        }

        Element newElement = new Element();

        for (int yearIndex = 30; yearIndex < 100; yearIndex++)
        {
            newElement        = new Element();
            newElement.Name   = (1900 + yearIndex).ToString();
            newElement.YValue = male[yearIndex];
            seriesMale.Elements.Add(newElement);

            newElement        = new Element();
            newElement.Name   = (1900 + yearIndex).ToString();
            newElement.YValue = female[yearIndex];
            seriesFemale.Elements.Add(newElement);
        }

        seriesMale.DefaultElement.Color   = Color.Blue;
        seriesFemale.DefaultElement.Color = Color.Red;

        SeriesCollection collection = new SeriesCollection();

        collection.Add(seriesFemale);
        collection.Add(seriesMale);

        return(collection);
    }
    SeriesCollection GetAgeGenderData()
    {
        string orgIdString       = Request.QueryString["OrgId"];
        string recurseTreeString = Request.QueryString["RecurseTree"];

        int  orgId       = Organization.PPSEid;
        bool recurseTree = false;

        if (orgIdString != null)
        {
            orgId = Int32.Parse(orgIdString);
        }

        if (recurseTreeString == "1")
        {
            recurseTree = true;
        }

        Chart.ChartArea.YAxis.Label.Text = "Medlems\xE5ldrar och k\xF6n - " + Organization.FromIdentity(orgId).Name;

        Series seriesMale   = new Series();
        Series seriesFemale = new Series();

        seriesMale.Name   = "M\xE4n";
        seriesFemale.Name = "Kvinnor";

        Memberships memberships = null;

        if (recurseTree)
        {
            memberships = Memberships.ForOrganizations(Organization.FromIdentity(orgId).GetTree());
        }
        else
        {
            memberships = Memberships.ForOrganization(Organization.FromIdentity(orgId));
        }

        BasicPerson[] allPeople = PirateDb.GetDatabase().GetAllPeople();

        Dictionary <int, int>          geoLookup       = new Dictionary <int, int>();
        Dictionary <int, PersonGender> genderLookup    = new Dictionary <int, PersonGender>();
        Dictionary <int, int>          birthYearLookup = new Dictionary <int, int>();
        Dictionary <int, int>          personLookup    = new Dictionary <int, int>();

        foreach (BasicPerson person in allPeople)
        {
            geoLookup[person.Identity]       = person.GeographyId;
            genderLookup[person.Identity]    = person.IsMale ? PersonGender.Male : PersonGender.Female;
            birthYearLookup[person.Identity] = person.Birthdate.Year;
        }

        int[] male   = new int[200];
        int[] female = new int[200];

        foreach (Membership membership in memberships)
        {
            int          birthYear = 0;
            PersonGender gender    = PersonGender.Unknown;

            if (genderLookup.ContainsKey(membership.PersonId) &&
                !personLookup.ContainsKey(membership.PersonId) &&
                (membership.OrganizationId == orgId ||
                 (recurseTree && membership.Organization.Inherits(orgId))))
            {
                personLookup[membership.PersonId] = 1;

                birthYear = birthYearLookup[membership.PersonId];
                gender    = genderLookup[membership.PersonId];

                if (birthYear > 1900 && birthYear < (1900 + 200))
                {
                    if (gender == PersonGender.Male)
                    {
                        male[birthYear - 1900]++;
                    }
                    else
                    {
                        female[birthYear - 1900]++;
                    }
                }
            }
        }

        Element newElement = new Element();

        for (int yearIndex = 30; yearIndex <= 100; yearIndex++)
        {
            newElement        = new Element();
            newElement.Name   = (1900 + yearIndex).ToString();
            newElement.YValue = male[yearIndex];
            seriesMale.Elements.Add(newElement);

            newElement        = new Element();
            newElement.Name   = (1900 + yearIndex).ToString();
            newElement.YValue = female[yearIndex];
            seriesFemale.Elements.Add(newElement);
        }


        seriesMale.DefaultElement.Color   = Color.Blue;
        seriesFemale.DefaultElement.Color = Color.Red;

        SeriesCollection collection = new SeriesCollection();

        collection.Add(seriesFemale);
        collection.Add(seriesMale);

        return(collection);
    }
Beispiel #9
0
    SeriesCollection GetSeriesCollection()
    {
        SeriesCollection result = new SeriesCollection();

        ChurnData   churnData   = ChurnData.ForOrganization(Organization.PPSE);
        Memberships memberships = Memberships.ForOrganization(Organization.PPSE, true);

        // Build a hash table with memberships, based on person id

        Dictionary <int, Membership> membershipHash = new Dictionary <int, Membership>();

        foreach (Membership membership in memberships)
        {
            membershipHash[membership.PersonId] = membership;
        }

        string[] elementNames = { "Churn", "Retention" };

        Color[] colors =
        {
            Color.Red, Color.Green
        };

        int currentYear = DateTime.Today.Year;

        int seriesCount = currentYear - 2006;

        // Create one series per year starting at 2006

        int[,] data = new int[seriesCount, 2];

        DateTime now = DateTime.Now; // cache this value

        foreach (ChurnDataPoint churnDataPoint in churnData)
        {
            if (membershipHash.ContainsKey(churnDataPoint.PersonId))
            {
                Membership membership = membershipHash[churnDataPoint.PersonId];

                // If not part of the renewal cycle, ignore - statistically uninteresting

                if ((churnDataPoint.ExpiryDate - churnDataPoint.DecisionDateTime).Days > 35)
                {
                    if (churnDataPoint.DecisionDateTime < new DateTime(2006, 12, 1) || churnDataPoint.DecisionDateTime > new DateTime(2007, 1, 15))
                    {
                        continue;
                    }
                }


                TimeSpan span = churnDataPoint.ExpiryDate - membership.MemberSince;
                int      membershipDurationYears = (int)((span.Days + 40) / 365.25); // Add 40d for margin at renewal process
                if (membershipDurationYears < 0)
                {
                    membershipDurationYears = 0; // some bogus data in db
                }

                int dataIndex = 0;

                if (churnDataPoint.DataType == Activizr.Basic.Enums.ChurnDataType.Retention)
                {
                    dataIndex = 1;
                }

                if (membershipDurationYears == 0)
                {
                    membershipDurationYears = 1; // pretend first-year events happen at first cycle
                }

                data[membershipDurationYears - 1, dataIndex]++;
            }
            else
            {
                Response.Write("<!-- " + churnDataPoint.PersonId + " -->");
            }
        }


        for (int renewalIndex = seriesCount - 1; renewalIndex >= 0; renewalIndex--)
        {
            Series series = new Series();
            series.Name = "Renewal #" + (renewalIndex + 1).ToString();

            for (int elementLoop = 0; elementLoop < 2; elementLoop++)
            {
                Element element = new Element(elementNames[elementLoop], data[renewalIndex, elementLoop]);
                element.Color = colors[elementLoop];
                series.Elements.Add(element);
            }

            result.Add(series);
        }

        return(result);
    }