[CalendarServer-changes] [15056] CalendarServer/branches/users/sredmond/clientsim/contrib/ performance/loadtest

source_changes at macosforge.org source_changes at macosforge.org
Tue Aug 18 16:39:55 PDT 2015


Revision: 15056
          http://trac.calendarserver.org//changeset/15056
Author:   sredmond at apple.com
Date:     2015-08-18 16:39:55 -0700 (Tue, 18 Aug 2015)
Log Message:
-----------
Moves configuration into dedicated folder

Modified Paths:
--------------
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/distributions.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/ical.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/push.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/records.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/resources.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/templates.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_ical.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_push.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_resources.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_sim.py
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_templates.py

Added Paths:
-----------
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/calendars-only.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/clients-old.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/clients.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/config.dist.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/config.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/demo-clients.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/event-updates-only.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/events-only.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-accepts.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-only-recurring.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-only.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/python/
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/preset_distributions.py

Removed Paths:
-------------
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/calendars-only.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients-old.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.dist.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/demo-clients.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/event-updates-only.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/events-only.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-accepts.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-only-recurring.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-only.plist
    CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/standard-configs/

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/distributions.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/distributions.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/distributions.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -54,7 +54,7 @@
     def sample(): #@NoSelf
         pass
 
-class Bounded
+# class Bounded
 
 
 class UniformDiscreteDistribution(object, FancyEqMixin):

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/ical.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/ical.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/ical.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -902,7 +902,7 @@
         Called before connections are closed, giving a chance to clean up
         """
         self.serialize()
-        return self.monitor.unsubscribeFromAll()
+        return self.monitor.end()
 
 
     def serializeLocation(self):

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/push.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/push.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/push.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -25,36 +25,41 @@
             for that resource
         @type callback: one-argument callable
         """
-        self.reactor = reactor
-        self.ampPushHost = ampPushHost
-        self.ampPushPort = ampPushPort
+        self._reactor = reactor
+        self._ampPushHost = ampPushHost
+        self._ampPushPort = ampPushPort
 
         # Keep track of AMP parameters for calendar homes we encounter.  This
         # dictionary has calendar home URLs as keys and pushkeys as
         # values.
-        self.ampPushkeys = {}
+        self._ampPushkeys = {}
 
     def begin(self):
-        self._monitorAmpPush()
+        """
+        Start monitoring for AMP-based push notifications
+        """
+        self._subscribeToIDs(self.ampPushkeys)
 
     def end(self):
-        pass
+        """
+        Finish monitoring push notifications. Any other cleanup should be done here
+        """
+        self._unsubscribeFromAll()
 
+    def _subscribeToIDs(self, ids):
 
-    def _monitorAmpPush(self):
-        """
-        Start monitoring for AMP-based push notifications
-        """
         subscribeToIDs(
-            self.ampPushHost, self.ampPushPort, self.ampPushkeys,
-            self._receivedAMPPush, self.reactor
+            self._ampPushHost,
+            self._ampPushPort,
+            ids,
+            self._receivedAmpPush,
+            self._reactor
         )
 
-
     def _receivedAMPPush(self, inboundID, dataChangedTimestamp, priority=5):
         print("-" * 64)
         print("{} received a PUSH with ID={}, timestamp={}, priority={}".format(self.record.commonName, inboundID, dataChangedTimestamp, priority))
-        print("By the way, my AMP keys are {}".format(self.ampPushkeys))
+        print("By the way, my AMP keys are {}".format(self._ampPushkeys))
         print("-" * 64)
 
         for href, calendar_id in self.ampPushkeys.iteritems():
@@ -66,15 +71,21 @@
             print("*" * 16 + "Oh no - we're not subscribed to " + str(inboundID) + " but we received a notification anyway!")
             pass
 
-    def unsubscribeFromAll(self):
-        return succeed(None)
+    def _unsubscribeFromAll(self):
+        # For now, the server doesn't support unsubscribing from pushkeys, so we simply
+        # "forget" about our registered pushkeys
+        self._ampPushkeys = {}
 
 
     def addPushkey(self, href, pushkey):
-        pass # Should I subscribe to IDs right now?
+        self._ampPushkeys[href] = pushkey
+        self.subscribeToIDs()
 
+
     def removePushkey(self, pushkey):
-        pass # Should I unsubscribe right now
+        # if self.ampPushkeys.has_value(pushkey):
+        #     del self.ampPushKeys
+        pass
 
     def isSubscribedTo(self, href):
         return href in self.ampPushkeys

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/records.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/records.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/records.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -11,19 +11,6 @@
     def __repr__(self):
         return "Record(%s:%s %s %s %s)" % (self.uid, self.password, self.commonName, self.email, self.guid)
 
-# def generateRecords(
-#     count, uidPattern="user%d", passwordPattern="user%d",
-#     namePattern="User %d", emailPattern="user%d at example.com",
-#     guidPattern="user%d"
-# ):
-#     for i in xrange(count):
-#         i += 1
-#         uid = uidPattern % (i,)
-#         password = passwordPattern % (i,)
-#         name = namePattern % (i,)
-#         email = emailPattern % (i,)
-#         guid = guidPattern % (i,)
-#         yield DirectoryRecord(uid, password, name, email, guid)
 
 def recordsFromCSVFile(path):
     if path:

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/resources.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/resources.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/resources.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -15,83 +15,6 @@
     return data.encode("utf-8") if type(data) is unicode else data
 
 
-
-# class EventComponent(object):
-#     """Utilities for event modification (which will always change the *.ics file)"""
-#     # HARD THINGS
-# # Event Location
-# # Attachments
-# # Inviting people (and rooms) to events
-
-# # Alarms + acknowledgements and all that fun stuff
-# RRULES
-
-#     def _modifyEvent(self, event):
-#         component = event.component
-#         vevent = component.mainComponent()
-#         vevent.replaceProperty(Property("DTSTAMP", DateTime.getNowUTC()))
-#         # Do some stuff
-#         pass
-#         event.component = component
-
-# # setEventTitle, setEventNotes, setEventURL, and setEventTransparency
-# # all simply modify a VEVENT passed to them
-#     def setEventTitle(self, vevent, title):
-#         vevent.replaceProperty(Property("SUMMARY", title))
-
-#     def setEventNotes(self, vevent, notes):
-#         vevent.replaceProperty(Property("DESCRIPTION", notes))
-
-
-
-#     def setEventTimes(self, vevent, dtstart, dtend):
-#         timezone = {"TZID": "America/Los_Angeles"}
-#         vevent.replaceProperty(Property("DTSTART", dtstart, params=timezone))
-#         vevent.replaceProperty(Property("DTEND", dtend, params=timezone))
-
-#     def setEventTravelDuration(self, vevent, duration):
-#         # X-APPLE-TRAVEL-START;ROUTING=WALKING;VALUE=URI: ?
-#         if duration == 0:
-#             vevent.removeProperty('X-APPLE-TRAVEL-DURATION')
-#             return
-
-#         hours = duration / 60
-#         minutes = duration % 60
-#         if hours == 0:
-#             durationText = "PT{minutes}M".format(minutes=minutes)
-#         else:
-#             durationText = "PT{hours}H{minutes}M".format(hours=hours, minutes=minutes)
-#         vevent.replaceProperty("X-APPLE-TRAVEL-DURATION", durationText, valuetype=Value.VALUETYPE_DURATION)
-
-# # setEventLocation
-# # modify the internal VCALENDAR, and perhaps make request to the server along the way
-#     def addRawEventLocation(self, vevent, location):
-#         vevent.replaceProperty("LOCATION", location)
-
-#     def addStructuredEventLocation(self, vevent, location):
-#         """Adds a structured event to the given VEVENT. Since the client is usually
-#         responsible for determining all of the extra information, we'll forgo that,
-#         and instead just add Stanford
-#         """
-#         vevent.addRawEventLocation(vevent, "Stanford University\n450 Serra Mall\nStanford\, CA  94305-2004")
-#         vevent.replaceProperty(Property("X-APPLE-STRUCTURED-LOCATION", "geo:37.428183,-122.170050", valuetype=Value.VALUETYPE_URI, params={
-#             "X-ADDRESS": "450 Serra Mall\nStanford, CA  94305-2004",
-#             "X-APPLE-RADIUS": "14164.55109758551",
-#             "X-TITLE": "Stanford University"
-#         }))
-
-#     def addEventRoom(self, vevent, location):
-#         # Do a bunch of principal searches and freebusy lookups
-#         pass
-
-#     def addAttachment(self, event, attachmentSize):
-#         # Post a large attachment to the event
-#         ch = chr(self.random.randint(0, 255))
-#         text = ch * attachmentSize
-#         self._client.addAttachment()
-#         # Get the updated event from the server and cache the response
-
-
 class Event(object):
     def __init__(self, serializeBasePath, url, etag, component=None):
         self.serializeBasePath = serializeBasePath

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/calendars-only.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/calendars-only.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/calendars-only.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<!-- Define the kinds of software and user behavior the load simulation
+			will simulate. -->
+		<key>clients</key>
+
+		<!-- Have as many different kinds of software and user behavior configurations
+			as you want. Each is a dict -->
+		<array>
+			<dict>
+				<!-- Here is a El Capitan iCal simulator. -->
+				<key>software</key>
+				<string>contrib.performance.loadtest.ical.OS_X_10_11</string>
+
+				<!-- Arguments to use to initialize the client instance. -->
+				<key>params</key>
+				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.11</string>
+
+					<!-- Client can poll the calendar home at some interval. This is
+						in seconds. -->
+					<key>calendarHomePollInterval</key>
+					<integer>5</integer>
+
+					<!-- If the server advertises xmpp push, OS X 10.11 can wait for notifications
+						about calendar home changes instead of polling for them periodically. If
+						this option is true, then look for the server advertisement for xmpp push
+						and use it if possible. Still fall back to polling if there is no xmpp push
+						advertised. -->
+					<key>supportPush</key>
+					<false />
+					<key>supportAmpPush</key>
+					<true />
+				</dict>
+
+				<!-- The profiles define certain types of user behavior on top of the
+					client software being simulated. -->
+				<key>profiles</key>
+				<array>
+
+					<!-- First an calendar-creating profile, which will periodically create a new calendar -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.CalendarMaker</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true />
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new calendar. -->
+							<key>interval</key>
+							<integer>15</integer>
+						</dict>
+					</dict>
+
+					<!-- This profile will create a new event, and then periodically change something about the event. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.CalendarUpdater</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true />
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to update an existing calendar. -->
+							<key>interval</key>
+							<integer>5</integer>
+						</dict>
+					</dict>
+
+					<!-- This profile randomly shares calendars. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.CalendarSharer</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false />
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to share an existing calendar. -->
+							<key>interval</key>
+							<integer>30</integer>
+						</dict>
+					</dict>
+
+					<!-- This profile randomly deletes calendars. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.CalendarDeleter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true />
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to delete an existing calendar. -->
+							<key>interval</key>
+							<integer>30</integer>
+						</dict>
+					</dict>
+				</array>
+
+				<!-- Determine the frequency at which this client configuration will
+					appear in the clients which are created by the load tester. -->
+				<key>weight</key>
+				<integer>1</integer>
+			</dict>
+		</array>
+	</dict>
+</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/clients-old.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/clients-old.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/clients-old.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,527 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<!-- Define the kinds of software and user behavior the load simulation
+			will simulate. -->
+		<key>clients</key>
+
+		<!-- Have as many different kinds of software and user behavior configurations
+			as you want. Each is a dict -->
+		<array>
+
+			<dict>
+
+				<!-- Here is a OS X client simulator. -->
+				<key>software</key>
+				<string>contrib.performance.loadtest.clients.OS_X_10_7</string>
+
+				<!-- Arguments to use to initialize the OS_X_10_7 instance. -->
+				<key>params</key>
+				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.7</string>
+	
+					<!-- OS_X_10_7 can poll the calendar home at some interval. This is
+						in seconds. -->
+					<key>calendarHomePollInterval</key>
+					<integer>30</integer>
+
+					<!-- If the server advertises xmpp push, OS_X_10_7 can wait for notifications
+						about calendar home changes instead of polling for them periodically. If
+						this option is true, then look for the server advertisement for xmpp push
+						and use it if possible. Still fall back to polling if there is no xmpp push
+						advertised. -->
+					<key>supportPush</key>
+					<false />
+
+					<key>supportAmpPush</key>
+					<true/>
+					<key>ampPushHost</key>
+					<string>localhost</string>
+					<key>ampPushPort</key>
+					<integer>62311</integer>
+				</dict>
+
+				<!-- The profiles define certain types of user behavior on top of the
+					client software being simulated. -->
+				<key>profiles</key>
+				<array>
+
+					<!-- First an event-creating profile, which will periodically create
+						new events at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Eventer</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>300</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events
+								will be selected. This is an example of a "Distribution" parameter. The value
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps
+									in the near future, limited to certain days of the week and certain hours
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>300</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events
+								will be selected. This is an example of a "Distribution" parameter. The value
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps
+									in the near future, limited to certain days of the week and certain hours
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>25</integer>
+										<key>weekly</key>
+										<integer>25</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>0</integer>
+										<key>yearly</key>
+										<integer>0</integer>
+										<key>dailylimit</key>
+										<integer>0</integer>
+										<key>weeklylimit</key>
+										<integer>0</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>0</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile invites some number of new attendees to new events. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the frequency at which new invitations will be sent out. -->
+							<key>sendInvitationDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.NormalDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- mu gives the mean of the normal distribution (in seconds). -->
+									<key>mu</key>
+									<integer>60</integer>
+
+									<!-- and sigma gives its standard deviation. -->
+									<key>sigma</key>
+									<integer>5</integer>
+								</dict>
+							</dict>
+
+							<!-- Define the distribution of who will be invited to an event.
+							
+								When inviteeClumping is turned on each invitee is based on a sample of
+								users "close to" the organizer based on account index. If the clumping
+								is too "tight" for the requested number of attendees, then invites for
+								those larger numbers will simply fail (the sim will report that situation).
+								
+								When inviteeClumping is off invitees will be sampled across an entire
+								range of account indexes. In this case the distribution ought to be a
+								UniformIntegerDistribution with min=0 and max set to the number of accounts.
+							-->
+							<key>inviteeDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.UniformIntegerDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- The minimum value (inclusive) of the uniform distribution. -->
+									<key>min</key>
+									<integer>0</integer>
+									<!-- The maximum value (exclusive) of the uniform distribution. -->
+									<key>max</key>
+									<integer>99</integer>
+								</dict>
+							</dict>
+
+							<key>inviteeClumping</key>
+							<true/>
+
+							<!-- Define the distribution of how many attendees will be invited to an event.
+							
+								LogNormal is the best fit to observed data.
+
+
+								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
+								mode should typically be 1, and mean whatever matches the user behavior.
+								Our typical mean is 6. 							
+							     -->
+							<key>inviteeCountDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- mode - peak-->
+									<key>mode</key>
+									<integer>1</integer>
+									<!-- mean - average-->
+									<key>median</key>
+									<integer>6</integer>
+									<!-- maximum -->
+									<key>maximum</key>
+									<real>60</real>
+								</dict>
+							</dict>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events
+								will be selected. This is an example of a "Distribution" parameter. The value
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps
+									in the near future, limited to certain days of the week and certain hours
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile accepts invitations to events, handles cancels, and
+					     handles replies received. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Accepter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define how long to wait after seeing a new invitation before
+								accepting it.
+
+								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
+								(i.e., half of the user have accepted by that time).								
+							-->
+							<key>acceptDelayDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- mode - peak-->
+									<key>mode</key>
+									<integer>300</integer>
+									<!-- median - 50% done-->
+									<key>median</key>
+									<integer>1800</integer>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- A task-creating profile, which will periodically create
+						new tasks at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Tasker</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new task. -->
+							<key>interval</key>
+							<integer>300</integer>
+						</dict>
+					</dict>
+
+					<!-- A task-updating profile, which will periodically create
+						new tasks at a random time on a random calendar and then
+						update them in some way -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.TaskUpdater</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new task. -->
+							<key>interval</key>
+							<integer>60</integer>
+						</dict>
+					</dict>
+
+				</array>
+
+				<!-- Determine the frequency at which this client configuration will
+					appear in the clients which are created by the load tester. -->
+				<key>weight</key>
+				<integer>1</integer>
+			</dict>
+		</array>
+	</dict>
+</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/clients.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/clients.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/clients.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<!-- Define the kinds of software and user behavior the load simulation
+			will simulate. -->
+		<key>clients</key>
+
+		<!-- Have as many different kinds of software and user behavior configurations
+			as you want. Each is a dict -->
+		<array>
+
+			<dict>
+
+				<!-- Here is a OS X client simulator. -->
+				<key>software</key>
+				<string>contrib.performance.loadtest.clients.OS_X_10_11</string>
+
+				<!-- Arguments to use to initialize the OS_X_10_7 instance. -->
+				<key>params</key>
+				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.11 Intern</string>
+
+					<!-- OS_X_10_7 can poll the calendar home at some interval. This is
+						in seconds. -->
+					<key>calendarHomePollInterval</key>
+					<integer>30</integer>
+
+					<!-- If the server advertises AMP push, the client can wait for notifications about calendar home changes in addition to polling them periodically. If this option is true, look for the server advertisement for AMP push and use it if possible
+						about calendar home changes instead of polling for them periodically. If
+						this option is true, then look for the server advertisement for xmpp push
+						and use it if possible. Still fall back to polling if there is no xmpp push
+						advertised. -->
+					<key>supportAmpPush</key>
+					<true/>
+					<key>ampPushHost</key>
+					<string>localhost</string>
+					<key>ampPushPort</key>
+					<integer>62311</integer>
+				</dict>
+
+				<!-- The profiles define certain types of user behavior on top of the
+					client software being simulated. -->
+				<key>profiles</key>
+				<array>
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Inviter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>1</integer>
+						</dict>
+					</dict>
+				</array>
+
+				<!-- Determine the frequency at which this client configuration will
+					appear in the clients which are created by the load tester. -->
+				<key>weight</key>
+				<integer>1</integer>
+			</dict>
+		</array>
+	</dict>
+</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/config.dist.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/config.dist.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/config.dist.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<!-- This is a distributed orchestrator configuration; 'workers' is a list of
+							shell commands to run sub-processes.
+							-->
+		<key>workers</key>
+		<array>
+			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
+			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
+			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
+			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
+			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
+			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
+		</array>
+
+		<!-- Identify the server to be load tested. -->
+		<key>server</key>
+		<string>https://127.0.0.1:8443</string>
+
+		<!-- Configure Admin Web UI. -->
+		<key>webadmin</key>
+		<dict>
+			<key>enabled</key>
+			<true/>
+
+			<key>HTTPPort</key>
+			<integer>8080</integer>
+		</dict>
+
+		<!--  Define whether server supports stats socket. -->
+		<key>serverStats</key>
+		<dict>
+			<key>enabled</key>
+			<true/>
+			<key>Port</key>
+			<integer>8100</integer>
+		</dict>
+
+		<!--  Define whether client data should be re-used. It will always be saved to the specified path.-->
+		<key>clientDataSerialization</key>
+		<dict>
+			<key>UseOldData</key>
+			<true/>
+			<key>Path</key>
+			<string>/tmp/sim</string>
+		</dict>
+
+		<!-- Define the credentials of the clients which will be used to load test
+			the server. These credentials must already be valid on the server. -->
+		<key>accounts</key>
+		<dict>
+			<!-- The loader is the fully-qualified Python name of a callable which
+				returns a list of directory service records defining all of the client accounts
+				to use. contrib.performance.loadtest.sim.recordsFromCSVFile reads username,
+				password, mailto triples from a CSV file and returns them as a list of faked
+				directory service records. -->
+			<key>loader</key>
+			<string>contrib.performance.loadtest.sim.recordsFromCSVFile</string>
+
+			<!-- Keyword arguments may be passed to the loader. -->
+			<key>params</key>
+			<dict>
+				<!-- recordsFromCSVFile interprets the path relative to the config.plist,
+					to make it independent of the script's working directory while still allowing
+					a relative path. This isn't a great solution. -->
+				<key>path</key>
+				<string>contrib/performance/loadtest/accounts.csv</string>
+			</dict>
+		</dict>
+
+		<!-- Define how many clients will participate in the load test and how
+			they will show up. -->
+		<key>arrival</key>
+		<dict>
+
+			<!-- Specify a class which creates new clients and introduces them into
+				the test. contrib.performance.loadtest.population.SmoothRampUp introduces
+				groups of new clients at fixed intervals up to a maximum. The size of the
+				group, interval, and maximum are configured by the parameters below. The
+				total number of clients is groups * groupSize, which needs to be no larger
+				than the number of credentials created in the accounts section. -->
+			<key>factory</key>
+			<string>contrib.performance.loadtest.population.SmoothRampUp</string>
+
+			<key>params</key>
+			<dict>
+				<!-- groups gives the total number of groups of clients to introduce. -->
+				<key>groups</key>
+				<integer>99</integer>
+
+				<!-- groupSize is the number of clients in each group of clients. It's
+					really only a "smooth" ramp up if this is pretty small. -->
+				<key>groupSize</key>
+				<integer>1</integer>
+
+				<!-- Number of seconds between the introduction of each group. -->
+				<key>interval</key>
+				<integer>3</integer>
+
+				<!-- Number of clients each user is assigned to. -->
+				<!-- Set weight of clients to 1 if this is > 1. Number of clients must match this value if > 1. -->
+				<key>clientsPerUser</key>
+				<integer>1</integer>
+			</dict>
+
+		</dict>
+
+		<!-- Define some log observers to report on the load test. -->
+		<key>observers</key>
+		<array>
+			<!-- ReportStatistics generates an end-of-run summary of the HTTP requests
+				made, their timings, and their results. -->
+			<dict>
+				<key>type</key>
+				<string>contrib.performance.loadtest.logger.ReportStatistics</string>
+				<key>params</key>
+				<dict>
+					<!-- The thresholds for each request type -->
+					<key>thresholdsPath</key>
+					<string>contrib/performance/loadtest/thresholds.json</string>
+
+					<!-- The benchmarks for overall QoS -->
+					<key>benchmarksPath</key>
+					<string>contrib/performance/loadtest/benchmarks.json</string>
+
+					<!-- The % of failures that constitute a failed test -->
+					<key>failCutoff</key>
+					<real>1.0</real>
+				</dict>
+			</dict>
+
+			<!-- RequestLogger generates a realtime log of all HTTP requests made
+				during the load test. -->
+			<dict>
+				<key>type</key>
+				<string>contrib.performance.loadtest.logger.RequestLogger</string>
+				<key>params</key>
+				<dict>
+				</dict>
+			</dict>
+
+			<!-- OperationLogger generates an end-of-run summary of the gross operations
+				performed (logical operations which may span more than one HTTP request,
+				such as inviting an attendee to an event). -->
+			<dict>
+				<key>type</key>
+				<string>contrib.performance.loadtest.logger.OperationLogger</string>
+				<key>params</key>
+				<dict>
+					<!-- The thresholds for each operation type -->
+					<key>thresholdsPath</key>
+					<string>contrib/performance/loadtest/thresholds.json</string>
+
+					<!-- The % of operations beyond the lag cut-off that constitute a failed test -->
+					<key>lagCutoff</key>
+					<real>1.0</real>
+
+					<!-- The % of failures that constitute a failed test -->
+					<key>failCutoff</key>
+					<real>1.0</real>
+				</dict>
+			</dict>
+		</array>
+	</dict>
+</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/config.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/config.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/config.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<!-- Identify the server to be load tested. -->
+		<key>server</key>
+		<string>https://127.0.0.1:8443</string>
+
+		<!-- Configure Admin Web UI. -->
+		<key>webadmin</key>
+		<dict>
+			<key>enabled</key>
+			<true/>
+
+			<key>HTTPPort</key>
+			<integer>8080</integer>
+		</dict>
+
+		<!--  Define whether server supports stats socket. -->
+		<key>serverStats</key>
+		<dict>
+			<key>enabled</key>
+			<true/>
+			<key>Port</key>
+			<integer>8100</integer>
+		</dict>
+
+		<!--  Define whether client data should be re-used. It will always be saved to the specified path.-->
+		<key>clientDataSerialization</key>
+		<dict>
+			<key>UseOldData</key>
+			<true/>
+			<key>Path</key>
+			<string>/tmp/sim</string>
+		</dict>
+
+		<!-- Define the credentials of the clients which will be used to load test
+			the server. These credentials must already be valid on the server. -->
+		<key>accounts</key>
+		<dict>
+			<!-- The loader is the fully-qualified Python name of a callable which
+				returns a list of directory service records defining all of the client accounts
+				to use. contrib.performance.loadtest.sim.recordsFromCSVFile reads username,
+				password, mailto triples from a CSV file and returns them as a list of faked
+				directory service records. -->
+			<key>loader</key>
+			<string>contrib.performance.loadtest.records.recordsFromCSVFile</string>
+
+			<!-- Keyword arguments may be passed to the loader. -->
+			<key>params</key>
+			<dict>
+				<!-- recordsFromCSVFile interprets the path relative to the config.plist,
+					to make it independent of the script's working directory while still allowing
+					a relative path. This isn't a great solution. -->
+				<key>path</key>
+				<string>contrib/performance/loadtest/accounts.csv</string>
+			</dict>
+		</dict>
+
+		<!-- Define how many clients will participate in the load test and how
+			they will show up. -->
+		<key>arrival</key>
+		<dict>
+
+			<!-- Specify a class which creates new clients and introduces them into
+				the test. contrib.performance.loadtest.population.SmoothRampUp introduces
+				groups of new clients at fixed intervals up to a maximum. The size of the
+				group, interval, and maximum are configured by the parameters below. The
+				total number of clients is groups * groupSize, which needs to be no larger
+				than the number of credentials created in the accounts section. -->
+			<key>factory</key>
+			<string>contrib.performance.loadtest.population.SmoothRampUp</string>
+
+			<key>params</key>
+			<dict>
+				<!-- groups gives the total number of groups of clients to introduce. -->
+				<key>groups</key>
+				<integer>3</integer>
+
+				<!-- groupSize is the number of clients in each group of clients. It's
+					really only a "smooth" ramp up if this is pretty small. -->
+				<key>groupSize</key>
+				<integer>1</integer>
+
+				<!-- Number of seconds between the introduction of each group. -->
+				<key>interval</key>
+				<integer>15</integer>
+
+				<!-- Number of clients each user is assigned to. -->
+				<!-- Set weight of clients to 1 if this is > 1. Number of clients must match this value if > 1. -->
+				<key>clientsPerUser</key>
+				<integer>1</integer>
+			</dict>
+
+		</dict>
+
+		<!-- Define some log observers to report on the load test. -->
+		<key>observers</key>
+		<array>
+			<!-- ReportStatistics generates an end-of-run summary of the HTTP requests
+				made, their timings, and their results. -->
+			<dict>
+				<key>type</key>
+				<string>contrib.performance.loadtest.logger.ReportStatistics</string>
+				<key>params</key>
+				<dict>
+					<!-- The thresholds for each request type -->
+					<key>thresholdsPath</key>
+					<string>contrib/performance/loadtest/thresholds.json</string>
+
+					<!-- The benchmarks for overall QoS -->
+					<key>benchmarksPath</key>
+					<string>contrib/performance/loadtest/benchmarks.json</string>
+
+					<!-- The % of failures that constitute a failed test -->
+					<key>failCutoff</key>
+					<real>1.0</real>
+				</dict>
+			</dict>
+
+			<!-- RequestLogger generates a realtime log of all HTTP requests made
+				during the load test. -->
+			<dict>
+				<key>type</key>
+				<string>contrib.performance.loadtest.logger.RequestLogger</string>
+				<key>params</key>
+				<dict>
+				</dict>
+			</dict>
+
+			<!-- OperationLogger generates an end-of-run summary of the gross operations
+				performed (logical operations which may span more than one HTTP request,
+				such as inviting an attendee to an event). -->
+			<dict>
+				<key>type</key>
+				<string>contrib.performance.loadtest.logger.OperationLogger</string>
+				<key>params</key>
+				<dict>
+					<!-- The thresholds for each operation type -->
+					<key>thresholdsPath</key>
+					<string>contrib/performance/loadtest/thresholds.json</string>
+
+					<!-- The % of operations beyond the lag cut-off that constitute a failed test -->
+					<key>lagCutoff</key>
+					<real>1.0</real>
+
+					<!-- The % of failures that constitute a failed test -->
+					<key>failCutoff</key>
+					<real>1.0</real>
+				</dict>
+			</dict>
+		</array>
+	</dict>
+</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/demo-clients.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/demo-clients.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/demo-clients.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<key>clients</key>
+		<array>
+			<dict>
+				<!-- Here is a OS X client simulator. -->
+				<key>software</key>
+				<string>contrib.performance.loadtest.clients.OS_X_10_11</string>
+
+				<!-- Arguments to use to initialize the OS_X_10_7 instance. -->
+				<key>params</key>
+				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.11</string>
+
+					<!-- OS_X_10_11 can poll the calendar home at some interval. This is
+						in seconds. -->
+					<key>calendarHomePollInterval</key>
+					<integer>30</integer>
+
+					<!-- If the server advertises AMP push, the client can wait for notifications about calendar home changes in addition to polling them periodically. If this option is true, look for the server advertisement for AMP push and use it if possible. Still fall back to polling if there is no AMP push						advertised. -->
+					<key>supportAmpPush</key>
+					<true/>
+					<key>ampPushHost</key>
+					<string>localhost</string>
+					<key>ampPushPort</key>
+					<integer>62311</integer>
+				</dict>
+
+				<!-- The profiles define certain types of user behavior on top of the
+					client software being simulated. -->
+				<key>profiles</key>
+				<array>
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Eventer</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>1</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events
+								will be selected. This is an example of a "Distribution" parameter. The value
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps
+									in the near future, limited to certain days of the week and certain hours
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Rescheduler</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+							<key>interval</key>
+							<integer>5</integer>
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps
+									in the near future, limited to certain days of the week and certain hours
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+				</array>
+
+				<!-- Determine the frequency at which this client configuration will
+					appear in the clients which are created by the load tester. -->
+				<key>weight</key>
+				<integer>1</integer>
+			</dict>
+		</array>
+	</dict>
+</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/event-updates-only.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/event-updates-only.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/event-updates-only.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,543 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<!-- Define the kinds of software and user behavior the load simulation
+			will simulate. -->
+		<key>clients</key>
+
+		<!-- Have as many different kinds of software and user behavior configurations
+			as you want. Each is a dict -->
+		<array>
+
+			<dict>
+
+				<!-- Here is a Lion iCal simulator. -->
+				<key>software</key>
+				<string>contrib.performance.loadtest.ical.OS_X_10_7</string>
+
+				<!-- Arguments to use to initialize the client instance. -->
+				<key>params</key>
+				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.7</string>
+
+					<!-- Client can poll the calendar home at some interval. This is 
+						in seconds. -->
+					<key>calendarHomePollInterval</key>
+					<integer>300000</integer>
+
+					<!-- If the server advertises xmpp push, OS X 10.6 can wait for notifications 
+						about calendar home changes instead of polling for them periodically. If 
+						this option is true, then look for the server advertisement for xmpp push 
+						and use it if possible. Still fall back to polling if there is no xmpp push 
+						advertised. -->
+					<key>supportPush</key>
+					<false />
+					<key>supportAmpPush</key>
+					<false />
+				</dict>
+
+				<!-- The profiles define certain types of user behavior on top of the 
+					client software being simulated. -->
+				<key>profiles</key>
+				<array>
+
+					<!-- First an event-creating profile, which will periodically create 
+						new events at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Eventer</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use 
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>20</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<false/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>5</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events
+								will be selected. This is an example of a "Distribution" parameter. The value
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps
+									in the near future, limited to certain days of the week and certain hours
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>25</integer>
+										<key>weekly</key>
+										<integer>25</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>0</integer>
+										<key>yearly</key>
+										<integer>0</integer>
+										<key>dailylimit</key>
+										<integer>0</integer>
+										<key>weeklylimit</key>
+										<integer>0</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>0</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile invites some number of new attendees to new events. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the frequency at which new invitations will be sent out. -->
+							<key>sendInvitationDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.NormalDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- mu gives the mean of the normal distribution (in seconds). -->
+									<key>mu</key>
+									<integer>10</integer>
+
+									<!-- and sigma gives its standard deviation. -->
+									<key>sigma</key>
+									<integer>5</integer>
+								</dict>
+							</dict>
+
+							<!-- Define the distribution of who will be invited to an event.
+							
+								When inviteeClumping is turned on each invitee is based on a sample of
+								users "close to" the organizer based on account index. If the clumping
+								is too "tight" for the requested number of attendees, then invites for
+								those larger numbers will simply fail (the sim will report that situation).
+								
+								When inviteeClumping is off invitees will be sampled across an entire
+								range of account indexes. In this case the distribution ought to be a
+								UniformIntegerDistribution with min=0 and max set to the number of accounts.
+							-->
+							<key>inviteeDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.UniformIntegerDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- The minimum value (inclusive) of the uniform distribution. -->
+									<key>min</key>
+									<integer>0</integer>
+									<!-- The maximum value (exclusive) of the uniform distribution. -->
+									<key>max</key>
+									<integer>99</integer>
+								</dict>
+							</dict>
+
+							<key>inviteeClumping</key>
+							<true/>
+
+							<!-- Define the distribution of how many attendees will be invited to an event.
+							
+								LogNormal is the best fit to observed data.
+
+
+								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
+								mode should typically be 1, and mean whatever matches the user behavior.
+								Our typical mean is 6. 							
+							     -->
+							<key>inviteeCountDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- mode - peak-->
+									<key>mode</key>
+									<integer>1</integer>
+									<!-- mean - average-->
+									<key>median</key>
+									<integer>6</integer>
+									<!-- maximum -->
+									<key>maximum</key>
+									<real>100</real>
+								</dict>
+							</dict>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile accepts invitations to events, handles cancels, and
+					     handles replies received. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Accepter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define how long to wait after seeing a new invitation before
+								accepting it.
+
+								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
+								(i.e., half of the user have accepted by that time).								
+							-->
+							<key>acceptDelayDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- mode - peak-->
+									<key>mode</key>
+									<integer>300</integer>
+									<!-- median - 50% done-->
+									<key>median</key>
+									<integer>1800</integer>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- A task-creating profile, which will periodically create 
+						new tasks at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Tasker</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use 
+								its client to create a new task. -->
+							<key>interval</key>
+							<integer>300</integer>
+
+							<!-- Define how due times (DUE) for the randomly generated tasks 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>taskDueDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+				</array>
+
+				<!-- Determine the frequency at which this client configuration will 
+					appear in the clients which are created by the load tester. -->
+				<key>weight</key>
+				<integer>1</integer>
+			</dict>
+		</array>
+	</dict>
+</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/events-only.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/events-only.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/events-only.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<!-- Define the kinds of software and user behavior the load simulation
+			will simulate. -->
+		<key>clients</key>
+
+		<!-- Have as many different kinds of software and user behavior configurations
+			as you want. Each is a dict -->
+		<array>
+
+			<dict>
+
+				<!-- Here is an El Captian iCal simulator. -->
+				<key>software</key>
+				<string>contrib.performance.loadtest.ical.OS_X_10_11</string>
+
+				<!-- Arguments to use to initialize the client instance. -->
+				<key>params</key>
+				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.11</string>
+
+					<!-- Client can poll the calendar home at some interval. This is 
+						in seconds. -->
+					<key>calendarHomePollInterval</key>
+					<integer>30</integer>
+
+					<!-- If the server advertises xmpp push, OS X 10.11 can wait for notifications 
+						about calendar home changes instead of polling for them periodically. If 
+						this option is true, then look for the server advertisement for xmpp push 
+						and use it if possible. Still fall back to polling if there is no xmpp push 
+						advertised. -->
+					<key>supportPush</key>
+					<false />
+					<key>supportAmpPush</key>
+					<false />
+				</dict>
+
+				<!-- The profiles define certain types of user behavior on top of the 
+					client software being simulated. -->
+				<key>profiles</key>
+				<array>
+
+					<!-- First an event-creating profile, which will periodically create 
+						new events at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Eventer</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the interval (in seconds) at which this profile will use 
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>20</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<false/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>5</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events
+								will be selected. This is an example of a "Distribution" parameter. The value
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps
+									in the near future, limited to certain days of the week and certain hours
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>25</integer>
+										<key>weekly</key>
+										<integer>25</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>0</integer>
+										<key>yearly</key>
+										<integer>0</integer>
+										<key>dailylimit</key>
+										<integer>0</integer>
+										<key>weeklylimit</key>
+										<integer>0</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>0</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+				</array>
+
+				<!-- Determine the frequency at which this client configuration will 
+					appear in the clients which are created by the load tester. -->
+				<key>weight</key>
+				<integer>1</integer>
+			</dict>
+		</array>
+	</dict>
+</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-accepts.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-accepts.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-accepts.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,522 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<!-- Define the kinds of software and user behavior the load simulation
+			will simulate. -->
+		<key>clients</key>
+
+		<!-- Have as many different kinds of software and user behavior configurations
+			as you want. Each is a dict -->
+		<array>
+
+			<dict>
+
+				<!-- Here is a Lion iCal simulator. -->
+				<key>software</key>
+				<string>contrib.performance.loadtest.ical.OS_X_10_7</string>
+
+				<!-- Arguments to use to initialize the client instance. -->
+				<key>params</key>
+				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.7</string>
+
+					<!-- Client can poll the calendar home at some interval. This is 
+						in seconds. -->
+					<key>calendarHomePollInterval</key>
+					<integer>300000</integer>
+
+					<!-- If the server advertises xmpp push, OS X 10.6 can wait for notifications 
+						about calendar home changes instead of polling for them periodically. If 
+						this option is true, then look for the server advertisement for xmpp push 
+						and use it if possible. Still fall back to polling if there is no xmpp push 
+						advertised. -->
+					<key>supportPush</key>
+					<false />
+					<key>supportAmpPush</key>
+					<true />
+				</dict>
+
+				<!-- The profiles define certain types of user behavior on top of the 
+					client software being simulated. -->
+				<key>profiles</key>
+				<array>
+
+					<!-- First an event-creating profile, which will periodically create 
+						new events at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Eventer</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use 
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>20</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<false/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>5</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events
+								will be selected. This is an example of a "Distribution" parameter. The value
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps
+									in the near future, limited to certain days of the week and certain hours
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>25</integer>
+										<key>weekly</key>
+										<integer>25</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>0</integer>
+										<key>yearly</key>
+										<integer>0</integer>
+										<key>dailylimit</key>
+										<integer>0</integer>
+										<key>weeklylimit</key>
+										<integer>0</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>0</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile invites some number of new attendees to new events. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the frequency at which new invitations will be sent out. -->
+							<key>sendInvitationDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- interval (in seconds). -->
+									<key>value</key>
+									<integer>150</integer>
+								</dict>
+							</dict>
+
+							<!-- Define the distribution of who will be invited to an event.
+							
+								When inviteeClumping is turned on each invitee is based on a sample of
+								users "close to" the organizer based on account index. If the clumping
+								is too "tight" for the requested number of attendees, then invites for
+								those larger numbers will simply fail (the sim will report that situation).
+								
+								When inviteeClumping is off invitees will be sampled across an entire
+								range of account indexes. In this case the distribution ought to be a
+								UniformIntegerDistribution with min=0 and max set to the number of accounts.
+							-->
+							<key>inviteeDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.UniformIntegerDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- The minimum value (inclusive) of the uniform distribution. -->
+									<key>min</key>
+									<integer>0</integer>
+									<!-- The maximum value (exclusive) of the uniform distribution. -->
+									<key>max</key>
+									<integer>99</integer>
+								</dict>
+							</dict>
+
+							<key>inviteeClumping</key>
+							<true/>
+
+							<!-- Define the distribution of how many attendees will be invited to an event.
+							
+								LogNormal is the best fit to observed data.
+
+
+								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
+								mode should typically be 1, and mean whatever matches the user behavior.
+								Our typical mean is 6. 							
+							     -->
+							<key>inviteeCountDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- Number of attendees. -->
+									<key>value</key>
+									<integer>5</integer>
+								</dict>
+							</dict>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<false/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>100</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile accepts invitations to events, handles cancels, and
+					     handles replies received. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Accepter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define how long to wait after seeing a new invitation before
+								accepting it.
+
+								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
+								(i.e., half of the user have accepted by that time).								
+							-->
+							<key>acceptDelayDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.UniformDiscreteDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- Set of values to use - will be chosen in random order. -->
+									<key>values</key>
+									<array>
+										<integer>0</integer>
+										<integer>5</integer>
+										<integer>10</integer>
+										<integer>15</integer>
+										<integer>20</integer>
+										<integer>25</integer>
+										<integer>30</integer>
+									</array>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- A task-creating profile, which will periodically create 
+						new tasks at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Tasker</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use 
+								its client to create a new task. -->
+							<key>interval</key>
+							<integer>300</integer>
+
+							<!-- Define how due times (DUE) for the randomly generated tasks 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>taskDueDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+				</array>
+
+				<!-- Determine the frequency at which this client configuration will 
+					appear in the clients which are created by the load tester. -->
+				<key>weight</key>
+				<integer>1</integer>
+			</dict>
+		</array>
+
+		<!-- Determine the interval between client creation. -->
+		<key>arrivalInterval</key>
+		<integer>5</integer>
+	</dict>
+</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-only-recurring.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-only-recurring.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-only-recurring.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,517 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<!-- Define the kinds of software and user behavior the load simulation
+			will simulate. -->
+		<key>clients</key>
+
+		<!-- Have as many different kinds of software and user behavior configurations
+			as you want. Each is a dict -->
+		<array>
+
+			<dict>
+
+				<!-- Here is a Lion iCal simulator. -->
+				<key>software</key>
+				<string>contrib.performance.loadtest.ical.OS_X_10_7</string>
+
+				<!-- Arguments to use to initialize the client instance. -->
+				<key>params</key>
+				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.7</string>
+
+					<!-- Client can poll the calendar home at some interval. This is 
+						in seconds. -->
+					<key>calendarHomePollInterval</key>
+					<integer>300000</integer>
+
+					<!-- If the server advertises xmpp push, OS X 10.6 can wait for notifications 
+						about calendar home changes instead of polling for them periodically. If 
+						this option is true, then look for the server advertisement for xmpp push 
+						and use it if possible. Still fall back to polling if there is no xmpp push 
+						advertised. -->
+					<key>supportPush</key>
+					<false />
+					<key>supportAmpPush</key>
+					<false />
+				</dict>
+
+				<!-- The profiles define certain types of user behavior on top of the 
+					client software being simulated. -->
+				<key>profiles</key>
+				<array>
+
+					<!-- First an event-creating profile, which will periodically create 
+						new events at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Eventer</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use 
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>20</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<false/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>5</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events
+								will be selected. This is an example of a "Distribution" parameter. The value
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps
+									in the near future, limited to certain days of the week and certain hours
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>25</integer>
+										<key>weekly</key>
+										<integer>25</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>0</integer>
+										<key>yearly</key>
+										<integer>0</integer>
+										<key>dailylimit</key>
+										<integer>0</integer>
+										<key>weeklylimit</key>
+										<integer>0</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>0</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile invites some number of new attendees to new events. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the frequency at which new invitations will be sent out. -->
+							<key>sendInvitationDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- interval (in seconds). -->
+									<key>value</key>
+									<integer>120</integer>
+								</dict>
+							</dict>
+
+							<!-- Define the distribution of who will be invited to an event.
+							
+								When inviteeClumping is turned on each invitee is based on a sample of
+								users "close to" the organizer based on account index. If the clumping
+								is too "tight" for the requested number of attendees, then invites for
+								those larger numbers will simply fail (the sim will report that situation).
+								
+								When inviteeClumping is off invitees will be sampled across an entire
+								range of account indexes. In this case the distribution ought to be a
+								UniformIntegerDistribution with min=0 and max set to the number of accounts.
+							-->
+							<key>inviteeDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.UniformIntegerDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- The minimum value (inclusive) of the uniform distribution. -->
+									<key>min</key>
+									<integer>0</integer>
+									<!-- The maximum value (exclusive) of the uniform distribution. -->
+									<key>max</key>
+									<integer>99</integer>
+								</dict>
+							</dict>
+
+							<key>inviteeClumping</key>
+							<true/>
+
+							<!-- Define the distribution of how many attendees will be invited to an event.
+							
+								LogNormal is the best fit to observed data.
+
+
+								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
+								mode should typically be 1, and mean whatever matches the user behavior.
+								Our typical mean is 6. 							
+							     -->
+							<key>inviteeCountDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- Number of attendees. -->
+									<key>value</key>
+									<integer>5</integer>
+								</dict>
+							</dict>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>100</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile accepts invitations to events, handles cancels, and
+					     handles replies received. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Accepter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define how long to wait after seeing a new invitation before
+								accepting it.
+
+								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
+								(i.e., half of the user have accepted by that time).								
+							-->
+							<key>acceptDelayDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- mode - peak-->
+									<key>mode</key>
+									<integer>300</integer>
+									<!-- median - 50% done-->
+									<key>median</key>
+									<integer>1800</integer>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- A task-creating profile, which will periodically create 
+						new tasks at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Tasker</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use 
+								its client to create a new task. -->
+							<key>interval</key>
+							<integer>300</integer>
+
+							<!-- Define how due times (DUE) for the randomly generated tasks 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>taskDueDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+				</array>
+
+				<!-- Determine the frequency at which this client configuration will 
+					appear in the clients which are created by the load tester. -->
+				<key>weight</key>
+				<integer>1</integer>
+			</dict>
+		</array>
+
+		<!-- Determine the interval between client creation. -->
+		<key>arrivalInterval</key>
+		<integer>4</integer>
+	</dict>
+</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-only.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-only.plist	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/alt-settings/plist/invites-only.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,533 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+		<!-- Define the kinds of software and user behavior the load simulation
+			will simulate. -->
+		<key>clients</key>
+
+		<!-- Have as many different kinds of software and user behavior configurations
+			as you want. Each is a dict -->
+		<array>
+
+			<dict>
+
+				<!-- Here is a Lion iCal simulator. -->
+				<key>software</key>
+				<string>contrib.performance.loadtest.ical.OS_X_10_7</string>
+
+				<!-- Arguments to use to initialize the client instance. -->
+				<key>params</key>
+				<dict>
+					<!-- Name that appears in logs. -->
+					<key>title</key>
+					<string>10.7</string>
+
+					<!-- Client can poll the calendar home at some interval. This is 
+						in seconds. -->
+					<key>calendarHomePollInterval</key>
+					<integer>300000</integer>
+
+					<!-- If the server advertises xmpp push, OS X 10.6 can wait for notifications 
+						about calendar home changes instead of polling for them periodically. If 
+						this option is true, then look for the server advertisement for xmpp push 
+						and use it if possible. Still fall back to polling if there is no xmpp push 
+						advertised. -->
+					<key>supportPush</key>
+					<false />
+					<key>supportAmpPush</key>
+					<false />
+				</dict>
+
+				<!-- The profiles define certain types of user behavior on top of the 
+					client software being simulated. -->
+				<key>profiles</key>
+				<array>
+
+					<!-- First an event-creating profile, which will periodically create 
+						new events at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Eventer</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use 
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>20</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<false/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use
+								its client to create a new event. -->
+							<key>interval</key>
+							<integer>5</integer>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events
+								will be selected. This is an example of a "Distribution" parameter. The value
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps
+									in the near future, limited to certain days of the week and certain hours
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<true/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>25</integer>
+										<key>weekly</key>
+										<integer>25</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>0</integer>
+										<key>yearly</key>
+										<integer>0</integer>
+										<key>dailylimit</key>
+										<integer>0</integer>
+										<key>weeklylimit</key>
+										<integer>0</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>0</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile invites some number of new attendees to new events. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<true/>
+
+							<!-- Define the frequency at which new invitations will be sent out. -->
+							<key>sendInvitationDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- interval (in seconds). -->
+									<key>value</key>
+									<integer>120</integer>
+								</dict>
+							</dict>
+
+							<!-- Define the distribution of who will be invited to an event.
+							
+								When inviteeClumping is turned on each invitee is based on a sample of
+								users "close to" the organizer based on account index. If the clumping
+								is too "tight" for the requested number of attendees, then invites for
+								those larger numbers will simply fail (the sim will report that situation).
+								
+								When inviteeClumping is off invitees will be sampled across an entire
+								range of account indexes. In this case the distribution ought to be a
+								UniformIntegerDistribution with min=0 and max set to the number of accounts.
+							-->
+							<key>inviteeDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.UniformIntegerDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- The minimum value (inclusive) of the uniform distribution. -->
+									<key>min</key>
+									<integer>0</integer>
+									<!-- The maximum value (exclusive) of the uniform distribution. -->
+									<key>max</key>
+									<integer>99</integer>
+								</dict>
+							</dict>
+
+							<key>inviteeClumping</key>
+							<true/>
+
+							<!-- Define the distribution of how many attendees will be invited to an event.
+							
+								LogNormal is the best fit to observed data.
+
+
+								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
+								mode should typically be 1, and mean whatever matches the user behavior.
+								Our typical mean is 6. 							
+							     -->
+							<key>inviteeCountDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- Number of attendees. -->
+									<key>value</key>
+									<integer>5</integer>
+								</dict>
+							</dict>
+
+							<!-- Define how start times (DTSTART) for the randomly generated events 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>eventStartDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+
+							<!-- Define how recurrences are created. -->
+							<key>recurrenceDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized.  We have a fixed set of
+								     RRULEs defined for this distribution and pick each based on a
+								     weight. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- False to disable RRULEs -->
+									<key>allowRecurrence</key>
+									<false/>
+
+									<!-- These are the weights for the specific set of RRULEs. -->
+									<key>weights</key>
+									<dict>
+										<!-- Half of all events will be non-recurring -->
+										<key>none</key>
+										<integer>50</integer>
+										
+										<!-- Daily and weekly are pretty common -->
+										<key>daily</key>
+										<integer>10</integer>
+										<key>weekly</key>
+										<integer>20</integer>
+										
+										<!-- Monthly, yearly, daily & weekly limit not so common -->
+										<key>monthly</key>
+										<integer>2</integer>
+										<key>yearly</key>
+										<integer>1</integer>
+										<key>dailylimit</key>
+										<integer>2</integer>
+										<key>weeklylimit</key>
+										<integer>5</integer>
+										
+										<!-- Work days pretty common -->
+										<key>workdays</key>
+										<integer>10</integer>
+									</dict>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- This profile accepts invitations to events, handles cancels, and
+					     handles replies received. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Accepter</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define how long to wait after seeing a new invitation before
+								accepting it.
+
+								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
+								(i.e., half of the user have accepted by that time).								
+							-->
+							<key>acceptDelayDistribution</key>
+							<dict>
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
+								<key>params</key>
+								<dict>
+									<!-- mode - peak-->
+									<key>mode</key>
+									<integer>300</integer>
+									<!-- median - 50% done-->
+									<key>median</key>
+									<integer>1800</integer>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+					<!-- A task-creating profile, which will periodically create 
+						new tasks at a random time on a random calendar. -->
+					<dict>
+						<key>class</key>
+						<string>contrib.performance.loadtest.profiles.Tasker</string>
+
+						<key>params</key>
+						<dict>
+							<key>enabled</key>
+							<false/>
+
+							<!-- Define the interval (in seconds) at which this profile will use 
+								its client to create a new task. -->
+							<key>interval</key>
+							<integer>300</integer>
+
+							<!-- Define how due times (DUE) for the randomly generated tasks 
+								will be selected. This is an example of a "Distribution" parameter. The value 
+								for most "Distribution" parameters are interchangeable and extensible. -->
+							<key>taskDueDistribution</key>
+							<dict>
+
+								<!-- This distribution is pretty specialized. It produces timestamps 
+									in the near future, limited to certain days of the week and certain hours 
+									of the day. -->
+								<key>type</key>
+								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
+
+								<key>params</key>
+								<dict>
+									<!-- These are the days of the week the distribution will use. -->
+									<key>daysOfWeek</key>
+									<array>
+										<string>mon</string>
+										<string>tue</string>
+										<string>wed</string>
+										<string>thu</string>
+										<string>fri</string>
+									</array>
+
+									<!-- The earliest hour of a day at which an event might be scheduled. -->
+									<key>beginHour</key>
+									<integer>8</integer>
+
+									<!-- And the latest hour of a day (at which an event will be scheduled 
+										to begin!). -->
+									<key>endHour</key>
+									<integer>16</integer>
+
+									<!-- The timezone in which the event is scheduled. (XXX Does this 
+										really work right?) -->
+									<key>tzname</key>
+									<string>America/Los_Angeles</string>
+								</dict>
+							</dict>
+						</dict>
+					</dict>
+
+				</array>
+
+				<!-- Determine the frequency at which this client configuration will 
+					appear in the clients which are created by the load tester. -->
+				<key>weight</key>
+				<integer>1</integer>
+			</dict>
+		</array>
+	</dict>
+</plist>

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/calendars-only.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/calendars-only.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/calendars-only.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<!-- Define the kinds of software and user behavior the load simulation
-			will simulate. -->
-		<key>clients</key>
-
-		<!-- Have as many different kinds of software and user behavior configurations
-			as you want. Each is a dict -->
-		<array>
-			<dict>
-				<!-- Here is a El Capitan iCal simulator. -->
-				<key>software</key>
-				<string>contrib.performance.loadtest.ical.OS_X_10_11</string>
-
-				<!-- Arguments to use to initialize the client instance. -->
-				<key>params</key>
-				<dict>
-					<!-- Name that appears in logs. -->
-					<key>title</key>
-					<string>10.11</string>
-
-					<!-- Client can poll the calendar home at some interval. This is
-						in seconds. -->
-					<key>calendarHomePollInterval</key>
-					<integer>5</integer>
-
-					<!-- If the server advertises xmpp push, OS X 10.11 can wait for notifications
-						about calendar home changes instead of polling for them periodically. If
-						this option is true, then look for the server advertisement for xmpp push
-						and use it if possible. Still fall back to polling if there is no xmpp push
-						advertised. -->
-					<key>supportPush</key>
-					<false />
-					<key>supportAmpPush</key>
-					<true />
-				</dict>
-
-				<!-- The profiles define certain types of user behavior on top of the
-					client software being simulated. -->
-				<key>profiles</key>
-				<array>
-
-					<!-- First an calendar-creating profile, which will periodically create a new calendar -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.CalendarMaker</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true />
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new calendar. -->
-							<key>interval</key>
-							<integer>15</integer>
-						</dict>
-					</dict>
-
-					<!-- This profile will create a new event, and then periodically change something about the event. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.CalendarUpdater</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true />
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to update an existing calendar. -->
-							<key>interval</key>
-							<integer>5</integer>
-						</dict>
-					</dict>
-
-					<!-- This profile randomly shares calendars. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.CalendarSharer</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false />
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to share an existing calendar. -->
-							<key>interval</key>
-							<integer>30</integer>
-						</dict>
-					</dict>
-
-					<!-- This profile randomly deletes calendars. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.CalendarDeleter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true />
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to delete an existing calendar. -->
-							<key>interval</key>
-							<integer>30</integer>
-						</dict>
-					</dict>
-				</array>
-
-				<!-- Determine the frequency at which this client configuration will
-					appear in the clients which are created by the load tester. -->
-				<key>weight</key>
-				<integer>1</integer>
-			</dict>
-		</array>
-	</dict>
-</plist>

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients-old.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients-old.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients-old.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,527 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<!-- Define the kinds of software and user behavior the load simulation
-			will simulate. -->
-		<key>clients</key>
-
-		<!-- Have as many different kinds of software and user behavior configurations
-			as you want. Each is a dict -->
-		<array>
-
-			<dict>
-
-				<!-- Here is a OS X client simulator. -->
-				<key>software</key>
-				<string>contrib.performance.loadtest.clients.OS_X_10_7</string>
-
-				<!-- Arguments to use to initialize the OS_X_10_7 instance. -->
-				<key>params</key>
-				<dict>
-					<!-- Name that appears in logs. -->
-					<key>title</key>
-					<string>10.7</string>
-	
-					<!-- OS_X_10_7 can poll the calendar home at some interval. This is
-						in seconds. -->
-					<key>calendarHomePollInterval</key>
-					<integer>30</integer>
-
-					<!-- If the server advertises xmpp push, OS_X_10_7 can wait for notifications
-						about calendar home changes instead of polling for them periodically. If
-						this option is true, then look for the server advertisement for xmpp push
-						and use it if possible. Still fall back to polling if there is no xmpp push
-						advertised. -->
-					<key>supportPush</key>
-					<false />
-
-					<key>supportAmpPush</key>
-					<true/>
-					<key>ampPushHost</key>
-					<string>localhost</string>
-					<key>ampPushPort</key>
-					<integer>62311</integer>
-				</dict>
-
-				<!-- The profiles define certain types of user behavior on top of the
-					client software being simulated. -->
-				<key>profiles</key>
-				<array>
-
-					<!-- First an event-creating profile, which will periodically create
-						new events at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Eventer</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>300</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events
-								will be selected. This is an example of a "Distribution" parameter. The value
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps
-									in the near future, limited to certain days of the week and certain hours
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<true/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>10</integer>
-										<key>weekly</key>
-										<integer>20</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>2</integer>
-										<key>yearly</key>
-										<integer>1</integer>
-										<key>dailylimit</key>
-										<integer>2</integer>
-										<key>weeklylimit</key>
-										<integer>5</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>10</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>300</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events
-								will be selected. This is an example of a "Distribution" parameter. The value
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps
-									in the near future, limited to certain days of the week and certain hours
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<true/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>25</integer>
-										<key>weekly</key>
-										<integer>25</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>0</integer>
-										<key>yearly</key>
-										<integer>0</integer>
-										<key>dailylimit</key>
-										<integer>0</integer>
-										<key>weeklylimit</key>
-										<integer>0</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>0</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile invites some number of new attendees to new events. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the frequency at which new invitations will be sent out. -->
-							<key>sendInvitationDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.NormalDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- mu gives the mean of the normal distribution (in seconds). -->
-									<key>mu</key>
-									<integer>60</integer>
-
-									<!-- and sigma gives its standard deviation. -->
-									<key>sigma</key>
-									<integer>5</integer>
-								</dict>
-							</dict>
-
-							<!-- Define the distribution of who will be invited to an event.
-							
-								When inviteeClumping is turned on each invitee is based on a sample of
-								users "close to" the organizer based on account index. If the clumping
-								is too "tight" for the requested number of attendees, then invites for
-								those larger numbers will simply fail (the sim will report that situation).
-								
-								When inviteeClumping is off invitees will be sampled across an entire
-								range of account indexes. In this case the distribution ought to be a
-								UniformIntegerDistribution with min=0 and max set to the number of accounts.
-							-->
-							<key>inviteeDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.UniformIntegerDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- The minimum value (inclusive) of the uniform distribution. -->
-									<key>min</key>
-									<integer>0</integer>
-									<!-- The maximum value (exclusive) of the uniform distribution. -->
-									<key>max</key>
-									<integer>99</integer>
-								</dict>
-							</dict>
-
-							<key>inviteeClumping</key>
-							<true/>
-
-							<!-- Define the distribution of how many attendees will be invited to an event.
-							
-								LogNormal is the best fit to observed data.
-
-
-								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
-								mode should typically be 1, and mean whatever matches the user behavior.
-								Our typical mean is 6. 							
-							     -->
-							<key>inviteeCountDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- mode - peak-->
-									<key>mode</key>
-									<integer>1</integer>
-									<!-- mean - average-->
-									<key>median</key>
-									<integer>6</integer>
-									<!-- maximum -->
-									<key>maximum</key>
-									<real>60</real>
-								</dict>
-							</dict>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events
-								will be selected. This is an example of a "Distribution" parameter. The value
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps
-									in the near future, limited to certain days of the week and certain hours
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<true/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>10</integer>
-										<key>weekly</key>
-										<integer>20</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>2</integer>
-										<key>yearly</key>
-										<integer>1</integer>
-										<key>dailylimit</key>
-										<integer>2</integer>
-										<key>weeklylimit</key>
-										<integer>5</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>10</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile accepts invitations to events, handles cancels, and
-					     handles replies received. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Accepter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define how long to wait after seeing a new invitation before
-								accepting it.
-
-								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
-								(i.e., half of the user have accepted by that time).								
-							-->
-							<key>acceptDelayDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- mode - peak-->
-									<key>mode</key>
-									<integer>300</integer>
-									<!-- median - 50% done-->
-									<key>median</key>
-									<integer>1800</integer>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- A task-creating profile, which will periodically create
-						new tasks at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Tasker</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new task. -->
-							<key>interval</key>
-							<integer>300</integer>
-						</dict>
-					</dict>
-
-					<!-- A task-updating profile, which will periodically create
-						new tasks at a random time on a random calendar and then
-						update them in some way -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.TaskUpdater</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new task. -->
-							<key>interval</key>
-							<integer>60</integer>
-						</dict>
-					</dict>
-
-				</array>
-
-				<!-- Determine the frequency at which this client configuration will
-					appear in the clients which are created by the load tester. -->
-				<key>weight</key>
-				<integer>1</integer>
-			</dict>
-		</array>
-	</dict>
-</plist>

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<!-- Define the kinds of software and user behavior the load simulation
-			will simulate. -->
-		<key>clients</key>
-
-		<!-- Have as many different kinds of software and user behavior configurations
-			as you want. Each is a dict -->
-		<array>
-
-			<dict>
-
-				<!-- Here is a OS X client simulator. -->
-				<key>software</key>
-				<string>contrib.performance.loadtest.clients.OS_X_10_11</string>
-
-				<!-- Arguments to use to initialize the OS_X_10_7 instance. -->
-				<key>params</key>
-				<dict>
-					<!-- Name that appears in logs. -->
-					<key>title</key>
-					<string>10.11 Intern</string>
-
-					<!-- OS_X_10_7 can poll the calendar home at some interval. This is
-						in seconds. -->
-					<key>calendarHomePollInterval</key>
-					<integer>30</integer>
-
-					<!-- If the server advertises AMP push, the client can wait for notifications about calendar home changes in addition to polling them periodically. If this option is true, look for the server advertisement for AMP push and use it if possible
-						about calendar home changes instead of polling for them periodically. If
-						this option is true, then look for the server advertisement for xmpp push
-						and use it if possible. Still fall back to polling if there is no xmpp push
-						advertised. -->
-					<key>supportAmpPush</key>
-					<true/>
-					<key>ampPushHost</key>
-					<string>localhost</string>
-					<key>ampPushPort</key>
-					<integer>62311</integer>
-				</dict>
-
-				<!-- The profiles define certain types of user behavior on top of the
-					client software being simulated. -->
-				<key>profiles</key>
-				<array>
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Inviter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>1</integer>
-						</dict>
-					</dict>
-				</array>
-
-				<!-- Determine the frequency at which this client configuration will
-					appear in the clients which are created by the load tester. -->
-				<key>weight</key>
-				<integer>1</integer>
-			</dict>
-		</array>
-	</dict>
-</plist>

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/clients.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,45 +1,9 @@
 from contrib.performance.loadtest.clients import iOS_5, OS_X_10_6, OS_X_10_7, OS_X_10_11
 from contrib.performance.loadtest.profiles import CalendarMaker, CalendarUpdater, CalendarSharer, CalendarDeleter
-from contrib.performance.loadtest.distributions import WorkDistribution, RecurrenceDistribution
-
 from contrib.performance.loadtest.population import ProfileType
 
+from preset_distributions import STANDARD_WORK_DISTRIBUTION, LOW_RECURRENCE_DISTRIBUTION, MEDIUM_RECURRENCE_DISTRIBUTION
 
-STANDARD_WORK_DISTRIBUTION = WorkDistribution(
-    daysOfWeek=["mon", "tue", "wed", "thu", "fri"],
-    beginHour=8,
-    endHour=16,
-    tzname="America/Los_Angeles"
-)
-
-LOW_RECURRENCE_DISTRIBUTION = RecurrenceDistribution(
-    allowRecurrence=True,
-    weights={
-        "none": 50,
-        "daily": 25,
-        "weekly": 25,
-        "monthly": 0,
-        "yearly": 0,
-        "dailylimit": 0,
-        "weeklylimit": 0,
-        "workdays": 0
-    }
-)
-
-MEDIUM_RECURRENCE_DISTRIBUTION = RecurrenceDistribution(
-    allowRecurrence=True,
-    weights={
-        "none": 50,
-        "daily": 10,
-        "weekly": 20,
-        "monthly": 2,
-        "yearly": 1,
-        "dailylimit": 2,
-        "weeklylimit": 5,
-        "workdays": 10
-    }
-)
-
 # We have to roll our own deep copy method because you can't deep copy Twisted's reactor
 class ClientFactory(object):
 

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.dist.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.dist.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.dist.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,184 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<!-- This is a distributed orchestrator configuration; 'workers' is a list of
-							shell commands to run sub-processes.
-							-->
-		<key>workers</key>
-		<array>
-			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
-			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
-			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
-			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
-			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
-			<string>./bin/python contrib/performance/loadtest/ampsim.py</string>
-		</array>
-
-		<!-- Identify the server to be load tested. -->
-		<key>server</key>
-		<string>https://127.0.0.1:8443</string>
-
-		<!-- Configure Admin Web UI. -->
-		<key>webadmin</key>
-		<dict>
-			<key>enabled</key>
-			<true/>
-
-			<key>HTTPPort</key>
-			<integer>8080</integer>
-		</dict>
-
-		<!--  Define whether server supports stats socket. -->
-		<key>serverStats</key>
-		<dict>
-			<key>enabled</key>
-			<true/>
-			<key>Port</key>
-			<integer>8100</integer>
-		</dict>
-
-		<!--  Define whether client data should be re-used. It will always be saved to the specified path.-->
-		<key>clientDataSerialization</key>
-		<dict>
-			<key>UseOldData</key>
-			<true/>
-			<key>Path</key>
-			<string>/tmp/sim</string>
-		</dict>
-
-		<!-- Define the credentials of the clients which will be used to load test
-			the server. These credentials must already be valid on the server. -->
-		<key>accounts</key>
-		<dict>
-			<!-- The loader is the fully-qualified Python name of a callable which
-				returns a list of directory service records defining all of the client accounts
-				to use. contrib.performance.loadtest.sim.recordsFromCSVFile reads username,
-				password, mailto triples from a CSV file and returns them as a list of faked
-				directory service records. -->
-			<key>loader</key>
-			<string>contrib.performance.loadtest.sim.recordsFromCSVFile</string>
-
-			<!-- Keyword arguments may be passed to the loader. -->
-			<key>params</key>
-			<dict>
-				<!-- recordsFromCSVFile interprets the path relative to the config.plist,
-					to make it independent of the script's working directory while still allowing
-					a relative path. This isn't a great solution. -->
-				<key>path</key>
-				<string>contrib/performance/loadtest/accounts.csv</string>
-			</dict>
-		</dict>
-
-		<!-- Define how many clients will participate in the load test and how
-			they will show up. -->
-		<key>arrival</key>
-		<dict>
-
-			<!-- Specify a class which creates new clients and introduces them into
-				the test. contrib.performance.loadtest.population.SmoothRampUp introduces
-				groups of new clients at fixed intervals up to a maximum. The size of the
-				group, interval, and maximum are configured by the parameters below. The
-				total number of clients is groups * groupSize, which needs to be no larger
-				than the number of credentials created in the accounts section. -->
-			<key>factory</key>
-			<string>contrib.performance.loadtest.population.SmoothRampUp</string>
-
-			<key>params</key>
-			<dict>
-				<!-- groups gives the total number of groups of clients to introduce. -->
-				<key>groups</key>
-				<integer>99</integer>
-
-				<!-- groupSize is the number of clients in each group of clients. It's
-					really only a "smooth" ramp up if this is pretty small. -->
-				<key>groupSize</key>
-				<integer>1</integer>
-
-				<!-- Number of seconds between the introduction of each group. -->
-				<key>interval</key>
-				<integer>3</integer>
-
-				<!-- Number of clients each user is assigned to. -->
-				<!-- Set weight of clients to 1 if this is > 1. Number of clients must match this value if > 1. -->
-				<key>clientsPerUser</key>
-				<integer>1</integer>
-			</dict>
-
-		</dict>
-
-		<!-- Define some log observers to report on the load test. -->
-		<key>observers</key>
-		<array>
-			<!-- ReportStatistics generates an end-of-run summary of the HTTP requests
-				made, their timings, and their results. -->
-			<dict>
-				<key>type</key>
-				<string>contrib.performance.loadtest.logger.ReportStatistics</string>
-				<key>params</key>
-				<dict>
-					<!-- The thresholds for each request type -->
-					<key>thresholdsPath</key>
-					<string>contrib/performance/loadtest/thresholds.json</string>
-
-					<!-- The benchmarks for overall QoS -->
-					<key>benchmarksPath</key>
-					<string>contrib/performance/loadtest/benchmarks.json</string>
-
-					<!-- The % of failures that constitute a failed test -->
-					<key>failCutoff</key>
-					<real>1.0</real>
-				</dict>
-			</dict>
-
-			<!-- RequestLogger generates a realtime log of all HTTP requests made
-				during the load test. -->
-			<dict>
-				<key>type</key>
-				<string>contrib.performance.loadtest.logger.RequestLogger</string>
-				<key>params</key>
-				<dict>
-				</dict>
-			</dict>
-
-			<!-- OperationLogger generates an end-of-run summary of the gross operations
-				performed (logical operations which may span more than one HTTP request,
-				such as inviting an attendee to an event). -->
-			<dict>
-				<key>type</key>
-				<string>contrib.performance.loadtest.logger.OperationLogger</string>
-				<key>params</key>
-				<dict>
-					<!-- The thresholds for each operation type -->
-					<key>thresholdsPath</key>
-					<string>contrib/performance/loadtest/thresholds.json</string>
-
-					<!-- The % of operations beyond the lag cut-off that constitute a failed test -->
-					<key>lagCutoff</key>
-					<real>1.0</real>
-
-					<!-- The % of failures that constitute a failed test -->
-					<key>failCutoff</key>
-					<real>1.0</real>
-				</dict>
-			</dict>
-		</array>
-	</dict>
-</plist>

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,171 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<!-- Identify the server to be load tested. -->
-		<key>server</key>
-		<string>https://127.0.0.1:8443</string>
-
-		<!-- Configure Admin Web UI. -->
-		<key>webadmin</key>
-		<dict>
-			<key>enabled</key>
-			<true/>
-
-			<key>HTTPPort</key>
-			<integer>8080</integer>
-		</dict>
-
-		<!--  Define whether server supports stats socket. -->
-		<key>serverStats</key>
-		<dict>
-			<key>enabled</key>
-			<true/>
-			<key>Port</key>
-			<integer>8100</integer>
-		</dict>
-
-		<!--  Define whether client data should be re-used. It will always be saved to the specified path.-->
-		<key>clientDataSerialization</key>
-		<dict>
-			<key>UseOldData</key>
-			<true/>
-			<key>Path</key>
-			<string>/tmp/sim</string>
-		</dict>
-
-		<!-- Define the credentials of the clients which will be used to load test
-			the server. These credentials must already be valid on the server. -->
-		<key>accounts</key>
-		<dict>
-			<!-- The loader is the fully-qualified Python name of a callable which
-				returns a list of directory service records defining all of the client accounts
-				to use. contrib.performance.loadtest.sim.recordsFromCSVFile reads username,
-				password, mailto triples from a CSV file and returns them as a list of faked
-				directory service records. -->
-			<key>loader</key>
-			<string>contrib.performance.loadtest.records.recordsFromCSVFile</string>
-
-			<!-- Keyword arguments may be passed to the loader. -->
-			<key>params</key>
-			<dict>
-				<!-- recordsFromCSVFile interprets the path relative to the config.plist,
-					to make it independent of the script's working directory while still allowing
-					a relative path. This isn't a great solution. -->
-				<key>path</key>
-				<string>contrib/performance/loadtest/accounts.csv</string>
-			</dict>
-		</dict>
-
-		<!-- Define how many clients will participate in the load test and how
-			they will show up. -->
-		<key>arrival</key>
-		<dict>
-
-			<!-- Specify a class which creates new clients and introduces them into
-				the test. contrib.performance.loadtest.population.SmoothRampUp introduces
-				groups of new clients at fixed intervals up to a maximum. The size of the
-				group, interval, and maximum are configured by the parameters below. The
-				total number of clients is groups * groupSize, which needs to be no larger
-				than the number of credentials created in the accounts section. -->
-			<key>factory</key>
-			<string>contrib.performance.loadtest.population.SmoothRampUp</string>
-
-			<key>params</key>
-			<dict>
-				<!-- groups gives the total number of groups of clients to introduce. -->
-				<key>groups</key>
-				<integer>3</integer>
-
-				<!-- groupSize is the number of clients in each group of clients. It's
-					really only a "smooth" ramp up if this is pretty small. -->
-				<key>groupSize</key>
-				<integer>1</integer>
-
-				<!-- Number of seconds between the introduction of each group. -->
-				<key>interval</key>
-				<integer>15</integer>
-
-				<!-- Number of clients each user is assigned to. -->
-				<!-- Set weight of clients to 1 if this is > 1. Number of clients must match this value if > 1. -->
-				<key>clientsPerUser</key>
-				<integer>1</integer>
-			</dict>
-
-		</dict>
-
-		<!-- Define some log observers to report on the load test. -->
-		<key>observers</key>
-		<array>
-			<!-- ReportStatistics generates an end-of-run summary of the HTTP requests
-				made, their timings, and their results. -->
-			<dict>
-				<key>type</key>
-				<string>contrib.performance.loadtest.logger.ReportStatistics</string>
-				<key>params</key>
-				<dict>
-					<!-- The thresholds for each request type -->
-					<key>thresholdsPath</key>
-					<string>contrib/performance/loadtest/thresholds.json</string>
-
-					<!-- The benchmarks for overall QoS -->
-					<key>benchmarksPath</key>
-					<string>contrib/performance/loadtest/benchmarks.json</string>
-
-					<!-- The % of failures that constitute a failed test -->
-					<key>failCutoff</key>
-					<real>1.0</real>
-				</dict>
-			</dict>
-
-			<!-- RequestLogger generates a realtime log of all HTTP requests made
-				during the load test. -->
-			<dict>
-				<key>type</key>
-				<string>contrib.performance.loadtest.logger.RequestLogger</string>
-				<key>params</key>
-				<dict>
-				</dict>
-			</dict>
-
-			<!-- OperationLogger generates an end-of-run summary of the gross operations
-				performed (logical operations which may span more than one HTTP request,
-				such as inviting an attendee to an event). -->
-			<dict>
-				<key>type</key>
-				<string>contrib.performance.loadtest.logger.OperationLogger</string>
-				<key>params</key>
-				<dict>
-					<!-- The thresholds for each operation type -->
-					<key>thresholdsPath</key>
-					<string>contrib/performance/loadtest/thresholds.json</string>
-
-					<!-- The % of operations beyond the lag cut-off that constitute a failed test -->
-					<key>lagCutoff</key>
-					<real>1.0</real>
-
-					<!-- The % of failures that constitute a failed test -->
-					<key>failCutoff</key>
-					<real>1.0</real>
-				</dict>
-			</dict>
-		</array>
-	</dict>
-</plist>

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/config.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,6 +1,6 @@
 # Generally, the defaults are good enough for us.
 
-config = Config(dict(
+config = dict(
     server=server,
     webadminPort=8080,
     serverStatsPort=8100,
@@ -19,7 +19,4 @@
     observers=[_requestLogger, _operationLogger, _statisticsReporter],
     records=accounts,
     workers=["./bin/python contrib/performance/loadtest/ampsim.py"] * 6,
-)
-
-# if __name__ == "__main__":
-#     print("Verifying Python games")
+)
\ No newline at end of file

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/demo-clients.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/demo-clients.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/demo-clients.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,166 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<key>clients</key>
-		<array>
-			<dict>
-				<!-- Here is a OS X client simulator. -->
-				<key>software</key>
-				<string>contrib.performance.loadtest.clients.OS_X_10_11</string>
-
-				<!-- Arguments to use to initialize the OS_X_10_7 instance. -->
-				<key>params</key>
-				<dict>
-					<!-- Name that appears in logs. -->
-					<key>title</key>
-					<string>10.11</string>
-
-					<!-- OS_X_10_11 can poll the calendar home at some interval. This is
-						in seconds. -->
-					<key>calendarHomePollInterval</key>
-					<integer>30</integer>
-
-					<!-- If the server advertises AMP push, the client can wait for notifications about calendar home changes in addition to polling them periodically. If this option is true, look for the server advertisement for AMP push and use it if possible. Still fall back to polling if there is no AMP push						advertised. -->
-					<key>supportAmpPush</key>
-					<true/>
-					<key>ampPushHost</key>
-					<string>localhost</string>
-					<key>ampPushPort</key>
-					<integer>62311</integer>
-				</dict>
-
-				<!-- The profiles define certain types of user behavior on top of the
-					client software being simulated. -->
-				<key>profiles</key>
-				<array>
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Eventer</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>1</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events
-								will be selected. This is an example of a "Distribution" parameter. The value
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps
-									in the near future, limited to certain days of the week and certain hours
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Rescheduler</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-							<key>interval</key>
-							<integer>5</integer>
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps
-									in the near future, limited to certain days of the week and certain hours
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-				</array>
-
-				<!-- Determine the frequency at which this client configuration will
-					appear in the clients which are created by the load tester. -->
-				<key>weight</key>
-				<integer>1</integer>
-			</dict>
-		</array>
-	</dict>
-</plist>

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/event-updates-only.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/event-updates-only.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/event-updates-only.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,543 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<!-- Define the kinds of software and user behavior the load simulation
-			will simulate. -->
-		<key>clients</key>
-
-		<!-- Have as many different kinds of software and user behavior configurations
-			as you want. Each is a dict -->
-		<array>
-
-			<dict>
-
-				<!-- Here is a Lion iCal simulator. -->
-				<key>software</key>
-				<string>contrib.performance.loadtest.ical.OS_X_10_7</string>
-
-				<!-- Arguments to use to initialize the client instance. -->
-				<key>params</key>
-				<dict>
-					<!-- Name that appears in logs. -->
-					<key>title</key>
-					<string>10.7</string>
-
-					<!-- Client can poll the calendar home at some interval. This is 
-						in seconds. -->
-					<key>calendarHomePollInterval</key>
-					<integer>300000</integer>
-
-					<!-- If the server advertises xmpp push, OS X 10.6 can wait for notifications 
-						about calendar home changes instead of polling for them periodically. If 
-						this option is true, then look for the server advertisement for xmpp push 
-						and use it if possible. Still fall back to polling if there is no xmpp push 
-						advertised. -->
-					<key>supportPush</key>
-					<false />
-					<key>supportAmpPush</key>
-					<false />
-				</dict>
-
-				<!-- The profiles define certain types of user behavior on top of the 
-					client software being simulated. -->
-				<key>profiles</key>
-				<array>
-
-					<!-- First an event-creating profile, which will periodically create 
-						new events at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Eventer</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use 
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>20</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<false/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>10</integer>
-										<key>weekly</key>
-										<integer>20</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>2</integer>
-										<key>yearly</key>
-										<integer>1</integer>
-										<key>dailylimit</key>
-										<integer>2</integer>
-										<key>weeklylimit</key>
-										<integer>5</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>10</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>5</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events
-								will be selected. This is an example of a "Distribution" parameter. The value
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps
-									in the near future, limited to certain days of the week and certain hours
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<true/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>25</integer>
-										<key>weekly</key>
-										<integer>25</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>0</integer>
-										<key>yearly</key>
-										<integer>0</integer>
-										<key>dailylimit</key>
-										<integer>0</integer>
-										<key>weeklylimit</key>
-										<integer>0</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>0</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile invites some number of new attendees to new events. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the frequency at which new invitations will be sent out. -->
-							<key>sendInvitationDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.NormalDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- mu gives the mean of the normal distribution (in seconds). -->
-									<key>mu</key>
-									<integer>10</integer>
-
-									<!-- and sigma gives its standard deviation. -->
-									<key>sigma</key>
-									<integer>5</integer>
-								</dict>
-							</dict>
-
-							<!-- Define the distribution of who will be invited to an event.
-							
-								When inviteeClumping is turned on each invitee is based on a sample of
-								users "close to" the organizer based on account index. If the clumping
-								is too "tight" for the requested number of attendees, then invites for
-								those larger numbers will simply fail (the sim will report that situation).
-								
-								When inviteeClumping is off invitees will be sampled across an entire
-								range of account indexes. In this case the distribution ought to be a
-								UniformIntegerDistribution with min=0 and max set to the number of accounts.
-							-->
-							<key>inviteeDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.UniformIntegerDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- The minimum value (inclusive) of the uniform distribution. -->
-									<key>min</key>
-									<integer>0</integer>
-									<!-- The maximum value (exclusive) of the uniform distribution. -->
-									<key>max</key>
-									<integer>99</integer>
-								</dict>
-							</dict>
-
-							<key>inviteeClumping</key>
-							<true/>
-
-							<!-- Define the distribution of how many attendees will be invited to an event.
-							
-								LogNormal is the best fit to observed data.
-
-
-								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
-								mode should typically be 1, and mean whatever matches the user behavior.
-								Our typical mean is 6. 							
-							     -->
-							<key>inviteeCountDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- mode - peak-->
-									<key>mode</key>
-									<integer>1</integer>
-									<!-- mean - average-->
-									<key>median</key>
-									<integer>6</integer>
-									<!-- maximum -->
-									<key>maximum</key>
-									<real>100</real>
-								</dict>
-							</dict>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<true/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>10</integer>
-										<key>weekly</key>
-										<integer>20</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>2</integer>
-										<key>yearly</key>
-										<integer>1</integer>
-										<key>dailylimit</key>
-										<integer>2</integer>
-										<key>weeklylimit</key>
-										<integer>5</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>10</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile accepts invitations to events, handles cancels, and
-					     handles replies received. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Accepter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define how long to wait after seeing a new invitation before
-								accepting it.
-
-								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
-								(i.e., half of the user have accepted by that time).								
-							-->
-							<key>acceptDelayDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- mode - peak-->
-									<key>mode</key>
-									<integer>300</integer>
-									<!-- median - 50% done-->
-									<key>median</key>
-									<integer>1800</integer>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- A task-creating profile, which will periodically create 
-						new tasks at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Tasker</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use 
-								its client to create a new task. -->
-							<key>interval</key>
-							<integer>300</integer>
-
-							<!-- Define how due times (DUE) for the randomly generated tasks 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>taskDueDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-				</array>
-
-				<!-- Determine the frequency at which this client configuration will 
-					appear in the clients which are created by the load tester. -->
-				<key>weight</key>
-				<integer>1</integer>
-			</dict>
-		</array>
-	</dict>
-</plist>

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/events-only.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/events-only.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/events-only.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,280 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<!-- Define the kinds of software and user behavior the load simulation
-			will simulate. -->
-		<key>clients</key>
-
-		<!-- Have as many different kinds of software and user behavior configurations
-			as you want. Each is a dict -->
-		<array>
-
-			<dict>
-
-				<!-- Here is an El Captian iCal simulator. -->
-				<key>software</key>
-				<string>contrib.performance.loadtest.ical.OS_X_10_11</string>
-
-				<!-- Arguments to use to initialize the client instance. -->
-				<key>params</key>
-				<dict>
-					<!-- Name that appears in logs. -->
-					<key>title</key>
-					<string>10.11</string>
-
-					<!-- Client can poll the calendar home at some interval. This is 
-						in seconds. -->
-					<key>calendarHomePollInterval</key>
-					<integer>30</integer>
-
-					<!-- If the server advertises xmpp push, OS X 10.11 can wait for notifications 
-						about calendar home changes instead of polling for them periodically. If 
-						this option is true, then look for the server advertisement for xmpp push 
-						and use it if possible. Still fall back to polling if there is no xmpp push 
-						advertised. -->
-					<key>supportPush</key>
-					<false />
-					<key>supportAmpPush</key>
-					<false />
-				</dict>
-
-				<!-- The profiles define certain types of user behavior on top of the 
-					client software being simulated. -->
-				<key>profiles</key>
-				<array>
-
-					<!-- First an event-creating profile, which will periodically create 
-						new events at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Eventer</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the interval (in seconds) at which this profile will use 
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>20</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<false/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>10</integer>
-										<key>weekly</key>
-										<integer>20</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>2</integer>
-										<key>yearly</key>
-										<integer>1</integer>
-										<key>dailylimit</key>
-										<integer>2</integer>
-										<key>weeklylimit</key>
-										<integer>5</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>10</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>5</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events
-								will be selected. This is an example of a "Distribution" parameter. The value
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps
-									in the near future, limited to certain days of the week and certain hours
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<true/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>25</integer>
-										<key>weekly</key>
-										<integer>25</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>0</integer>
-										<key>yearly</key>
-										<integer>0</integer>
-										<key>dailylimit</key>
-										<integer>0</integer>
-										<key>weeklylimit</key>
-										<integer>0</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>0</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-				</array>
-
-				<!-- Determine the frequency at which this client configuration will 
-					appear in the clients which are created by the load tester. -->
-				<key>weight</key>
-				<integer>1</integer>
-			</dict>
-		</array>
-	</dict>
-</plist>

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-accepts.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-accepts.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-accepts.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,522 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<!-- Define the kinds of software and user behavior the load simulation
-			will simulate. -->
-		<key>clients</key>
-
-		<!-- Have as many different kinds of software and user behavior configurations
-			as you want. Each is a dict -->
-		<array>
-
-			<dict>
-
-				<!-- Here is a Lion iCal simulator. -->
-				<key>software</key>
-				<string>contrib.performance.loadtest.ical.OS_X_10_7</string>
-
-				<!-- Arguments to use to initialize the client instance. -->
-				<key>params</key>
-				<dict>
-					<!-- Name that appears in logs. -->
-					<key>title</key>
-					<string>10.7</string>
-
-					<!-- Client can poll the calendar home at some interval. This is 
-						in seconds. -->
-					<key>calendarHomePollInterval</key>
-					<integer>300000</integer>
-
-					<!-- If the server advertises xmpp push, OS X 10.6 can wait for notifications 
-						about calendar home changes instead of polling for them periodically. If 
-						this option is true, then look for the server advertisement for xmpp push 
-						and use it if possible. Still fall back to polling if there is no xmpp push 
-						advertised. -->
-					<key>supportPush</key>
-					<false />
-					<key>supportAmpPush</key>
-					<true />
-				</dict>
-
-				<!-- The profiles define certain types of user behavior on top of the 
-					client software being simulated. -->
-				<key>profiles</key>
-				<array>
-
-					<!-- First an event-creating profile, which will periodically create 
-						new events at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Eventer</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use 
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>20</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<false/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>10</integer>
-										<key>weekly</key>
-										<integer>20</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>2</integer>
-										<key>yearly</key>
-										<integer>1</integer>
-										<key>dailylimit</key>
-										<integer>2</integer>
-										<key>weeklylimit</key>
-										<integer>5</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>10</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>5</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events
-								will be selected. This is an example of a "Distribution" parameter. The value
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps
-									in the near future, limited to certain days of the week and certain hours
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<true/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>25</integer>
-										<key>weekly</key>
-										<integer>25</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>0</integer>
-										<key>yearly</key>
-										<integer>0</integer>
-										<key>dailylimit</key>
-										<integer>0</integer>
-										<key>weeklylimit</key>
-										<integer>0</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>0</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile invites some number of new attendees to new events. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the frequency at which new invitations will be sent out. -->
-							<key>sendInvitationDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- interval (in seconds). -->
-									<key>value</key>
-									<integer>150</integer>
-								</dict>
-							</dict>
-
-							<!-- Define the distribution of who will be invited to an event.
-							
-								When inviteeClumping is turned on each invitee is based on a sample of
-								users "close to" the organizer based on account index. If the clumping
-								is too "tight" for the requested number of attendees, then invites for
-								those larger numbers will simply fail (the sim will report that situation).
-								
-								When inviteeClumping is off invitees will be sampled across an entire
-								range of account indexes. In this case the distribution ought to be a
-								UniformIntegerDistribution with min=0 and max set to the number of accounts.
-							-->
-							<key>inviteeDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.UniformIntegerDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- The minimum value (inclusive) of the uniform distribution. -->
-									<key>min</key>
-									<integer>0</integer>
-									<!-- The maximum value (exclusive) of the uniform distribution. -->
-									<key>max</key>
-									<integer>99</integer>
-								</dict>
-							</dict>
-
-							<key>inviteeClumping</key>
-							<true/>
-
-							<!-- Define the distribution of how many attendees will be invited to an event.
-							
-								LogNormal is the best fit to observed data.
-
-
-								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
-								mode should typically be 1, and mean whatever matches the user behavior.
-								Our typical mean is 6. 							
-							     -->
-							<key>inviteeCountDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- Number of attendees. -->
-									<key>value</key>
-									<integer>5</integer>
-								</dict>
-							</dict>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<false/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>100</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile accepts invitations to events, handles cancels, and
-					     handles replies received. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Accepter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define how long to wait after seeing a new invitation before
-								accepting it.
-
-								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
-								(i.e., half of the user have accepted by that time).								
-							-->
-							<key>acceptDelayDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.UniformDiscreteDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- Set of values to use - will be chosen in random order. -->
-									<key>values</key>
-									<array>
-										<integer>0</integer>
-										<integer>5</integer>
-										<integer>10</integer>
-										<integer>15</integer>
-										<integer>20</integer>
-										<integer>25</integer>
-										<integer>30</integer>
-									</array>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- A task-creating profile, which will periodically create 
-						new tasks at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Tasker</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use 
-								its client to create a new task. -->
-							<key>interval</key>
-							<integer>300</integer>
-
-							<!-- Define how due times (DUE) for the randomly generated tasks 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>taskDueDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-				</array>
-
-				<!-- Determine the frequency at which this client configuration will 
-					appear in the clients which are created by the load tester. -->
-				<key>weight</key>
-				<integer>1</integer>
-			</dict>
-		</array>
-
-		<!-- Determine the interval between client creation. -->
-		<key>arrivalInterval</key>
-		<integer>5</integer>
-	</dict>
-</plist>

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-only-recurring.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-only-recurring.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-only-recurring.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,517 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<!-- Define the kinds of software and user behavior the load simulation
-			will simulate. -->
-		<key>clients</key>
-
-		<!-- Have as many different kinds of software and user behavior configurations
-			as you want. Each is a dict -->
-		<array>
-
-			<dict>
-
-				<!-- Here is a Lion iCal simulator. -->
-				<key>software</key>
-				<string>contrib.performance.loadtest.ical.OS_X_10_7</string>
-
-				<!-- Arguments to use to initialize the client instance. -->
-				<key>params</key>
-				<dict>
-					<!-- Name that appears in logs. -->
-					<key>title</key>
-					<string>10.7</string>
-
-					<!-- Client can poll the calendar home at some interval. This is 
-						in seconds. -->
-					<key>calendarHomePollInterval</key>
-					<integer>300000</integer>
-
-					<!-- If the server advertises xmpp push, OS X 10.6 can wait for notifications 
-						about calendar home changes instead of polling for them periodically. If 
-						this option is true, then look for the server advertisement for xmpp push 
-						and use it if possible. Still fall back to polling if there is no xmpp push 
-						advertised. -->
-					<key>supportPush</key>
-					<false />
-					<key>supportAmpPush</key>
-					<false />
-				</dict>
-
-				<!-- The profiles define certain types of user behavior on top of the 
-					client software being simulated. -->
-				<key>profiles</key>
-				<array>
-
-					<!-- First an event-creating profile, which will periodically create 
-						new events at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Eventer</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use 
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>20</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<false/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>10</integer>
-										<key>weekly</key>
-										<integer>20</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>2</integer>
-										<key>yearly</key>
-										<integer>1</integer>
-										<key>dailylimit</key>
-										<integer>2</integer>
-										<key>weeklylimit</key>
-										<integer>5</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>10</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>5</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events
-								will be selected. This is an example of a "Distribution" parameter. The value
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps
-									in the near future, limited to certain days of the week and certain hours
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<true/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>25</integer>
-										<key>weekly</key>
-										<integer>25</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>0</integer>
-										<key>yearly</key>
-										<integer>0</integer>
-										<key>dailylimit</key>
-										<integer>0</integer>
-										<key>weeklylimit</key>
-										<integer>0</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>0</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile invites some number of new attendees to new events. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the frequency at which new invitations will be sent out. -->
-							<key>sendInvitationDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- interval (in seconds). -->
-									<key>value</key>
-									<integer>120</integer>
-								</dict>
-							</dict>
-
-							<!-- Define the distribution of who will be invited to an event.
-							
-								When inviteeClumping is turned on each invitee is based on a sample of
-								users "close to" the organizer based on account index. If the clumping
-								is too "tight" for the requested number of attendees, then invites for
-								those larger numbers will simply fail (the sim will report that situation).
-								
-								When inviteeClumping is off invitees will be sampled across an entire
-								range of account indexes. In this case the distribution ought to be a
-								UniformIntegerDistribution with min=0 and max set to the number of accounts.
-							-->
-							<key>inviteeDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.UniformIntegerDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- The minimum value (inclusive) of the uniform distribution. -->
-									<key>min</key>
-									<integer>0</integer>
-									<!-- The maximum value (exclusive) of the uniform distribution. -->
-									<key>max</key>
-									<integer>99</integer>
-								</dict>
-							</dict>
-
-							<key>inviteeClumping</key>
-							<true/>
-
-							<!-- Define the distribution of how many attendees will be invited to an event.
-							
-								LogNormal is the best fit to observed data.
-
-
-								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
-								mode should typically be 1, and mean whatever matches the user behavior.
-								Our typical mean is 6. 							
-							     -->
-							<key>inviteeCountDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- Number of attendees. -->
-									<key>value</key>
-									<integer>5</integer>
-								</dict>
-							</dict>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<true/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>100</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile accepts invitations to events, handles cancels, and
-					     handles replies received. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Accepter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define how long to wait after seeing a new invitation before
-								accepting it.
-
-								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
-								(i.e., half of the user have accepted by that time).								
-							-->
-							<key>acceptDelayDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- mode - peak-->
-									<key>mode</key>
-									<integer>300</integer>
-									<!-- median - 50% done-->
-									<key>median</key>
-									<integer>1800</integer>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- A task-creating profile, which will periodically create 
-						new tasks at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Tasker</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use 
-								its client to create a new task. -->
-							<key>interval</key>
-							<integer>300</integer>
-
-							<!-- Define how due times (DUE) for the randomly generated tasks 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>taskDueDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-				</array>
-
-				<!-- Determine the frequency at which this client configuration will 
-					appear in the clients which are created by the load tester. -->
-				<key>weight</key>
-				<integer>1</integer>
-			</dict>
-		</array>
-
-		<!-- Determine the interval between client creation. -->
-		<key>arrivalInterval</key>
-		<integer>4</integer>
-	</dict>
-</plist>

Deleted: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-only.plist
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-only.plist	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/invites-only.plist	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,533 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-    Copyright (c) 2011-2015 Apple Inc. All rights reserved.
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-  -->
-
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-	<dict>
-		<!-- Define the kinds of software and user behavior the load simulation
-			will simulate. -->
-		<key>clients</key>
-
-		<!-- Have as many different kinds of software and user behavior configurations
-			as you want. Each is a dict -->
-		<array>
-
-			<dict>
-
-				<!-- Here is a Lion iCal simulator. -->
-				<key>software</key>
-				<string>contrib.performance.loadtest.ical.OS_X_10_7</string>
-
-				<!-- Arguments to use to initialize the client instance. -->
-				<key>params</key>
-				<dict>
-					<!-- Name that appears in logs. -->
-					<key>title</key>
-					<string>10.7</string>
-
-					<!-- Client can poll the calendar home at some interval. This is 
-						in seconds. -->
-					<key>calendarHomePollInterval</key>
-					<integer>300000</integer>
-
-					<!-- If the server advertises xmpp push, OS X 10.6 can wait for notifications 
-						about calendar home changes instead of polling for them periodically. If 
-						this option is true, then look for the server advertisement for xmpp push 
-						and use it if possible. Still fall back to polling if there is no xmpp push 
-						advertised. -->
-					<key>supportPush</key>
-					<false />
-					<key>supportAmpPush</key>
-					<false />
-				</dict>
-
-				<!-- The profiles define certain types of user behavior on top of the 
-					client software being simulated. -->
-				<key>profiles</key>
-				<array>
-
-					<!-- First an event-creating profile, which will periodically create 
-						new events at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Eventer</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use 
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>20</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<false/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>10</integer>
-										<key>weekly</key>
-										<integer>20</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>2</integer>
-										<key>yearly</key>
-										<integer>1</integer>
-										<key>dailylimit</key>
-										<integer>2</integer>
-										<key>weeklylimit</key>
-										<integer>5</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>10</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile will create a new event, and then periodically update the ACKNOWLEDGED property. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.EventUpdater</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use
-								its client to create a new event. -->
-							<key>interval</key>
-							<integer>5</integer>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events
-								will be selected. This is an example of a "Distribution" parameter. The value
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps
-									in the near future, limited to certain days of the week and certain hours
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<true/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>25</integer>
-										<key>weekly</key>
-										<integer>25</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>0</integer>
-										<key>yearly</key>
-										<integer>0</integer>
-										<key>dailylimit</key>
-										<integer>0</integer>
-										<key>weeklylimit</key>
-										<integer>0</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>0</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile invites some number of new attendees to new events. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.RealisticInviter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<true/>
-
-							<!-- Define the frequency at which new invitations will be sent out. -->
-							<key>sendInvitationDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- interval (in seconds). -->
-									<key>value</key>
-									<integer>120</integer>
-								</dict>
-							</dict>
-
-							<!-- Define the distribution of who will be invited to an event.
-							
-								When inviteeClumping is turned on each invitee is based on a sample of
-								users "close to" the organizer based on account index. If the clumping
-								is too "tight" for the requested number of attendees, then invites for
-								those larger numbers will simply fail (the sim will report that situation).
-								
-								When inviteeClumping is off invitees will be sampled across an entire
-								range of account indexes. In this case the distribution ought to be a
-								UniformIntegerDistribution with min=0 and max set to the number of accounts.
-							-->
-							<key>inviteeDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.UniformIntegerDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- The minimum value (inclusive) of the uniform distribution. -->
-									<key>min</key>
-									<integer>0</integer>
-									<!-- The maximum value (exclusive) of the uniform distribution. -->
-									<key>max</key>
-									<integer>99</integer>
-								</dict>
-							</dict>
-
-							<key>inviteeClumping</key>
-							<true/>
-
-							<!-- Define the distribution of how many attendees will be invited to an event.
-							
-								LogNormal is the best fit to observed data.
-
-
-								For LogNormal "mode" is the peak, "mean" is the mean value.	For invites,
-								mode should typically be 1, and mean whatever matches the user behavior.
-								Our typical mean is 6. 							
-							     -->
-							<key>inviteeCountDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.FixedDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- Number of attendees. -->
-									<key>value</key>
-									<integer>5</integer>
-								</dict>
-							</dict>
-
-							<!-- Define how start times (DTSTART) for the randomly generated events 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>eventStartDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-
-							<!-- Define how recurrences are created. -->
-							<key>recurrenceDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized.  We have a fixed set of
-								     RRULEs defined for this distribution and pick each based on a
-								     weight. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.RecurrenceDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- False to disable RRULEs -->
-									<key>allowRecurrence</key>
-									<false/>
-
-									<!-- These are the weights for the specific set of RRULEs. -->
-									<key>weights</key>
-									<dict>
-										<!-- Half of all events will be non-recurring -->
-										<key>none</key>
-										<integer>50</integer>
-										
-										<!-- Daily and weekly are pretty common -->
-										<key>daily</key>
-										<integer>10</integer>
-										<key>weekly</key>
-										<integer>20</integer>
-										
-										<!-- Monthly, yearly, daily & weekly limit not so common -->
-										<key>monthly</key>
-										<integer>2</integer>
-										<key>yearly</key>
-										<integer>1</integer>
-										<key>dailylimit</key>
-										<integer>2</integer>
-										<key>weeklylimit</key>
-										<integer>5</integer>
-										
-										<!-- Work days pretty common -->
-										<key>workdays</key>
-										<integer>10</integer>
-									</dict>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- This profile accepts invitations to events, handles cancels, and
-					     handles replies received. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Accepter</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define how long to wait after seeing a new invitation before
-								accepting it.
-
-								For LogNormal "mode" is the peak, "median" is the 50% cummulative value
-								(i.e., half of the user have accepted by that time).								
-							-->
-							<key>acceptDelayDistribution</key>
-							<dict>
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.LogNormalDistribution</string>
-								<key>params</key>
-								<dict>
-									<!-- mode - peak-->
-									<key>mode</key>
-									<integer>300</integer>
-									<!-- median - 50% done-->
-									<key>median</key>
-									<integer>1800</integer>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-					<!-- A task-creating profile, which will periodically create 
-						new tasks at a random time on a random calendar. -->
-					<dict>
-						<key>class</key>
-						<string>contrib.performance.loadtest.profiles.Tasker</string>
-
-						<key>params</key>
-						<dict>
-							<key>enabled</key>
-							<false/>
-
-							<!-- Define the interval (in seconds) at which this profile will use 
-								its client to create a new task. -->
-							<key>interval</key>
-							<integer>300</integer>
-
-							<!-- Define how due times (DUE) for the randomly generated tasks 
-								will be selected. This is an example of a "Distribution" parameter. The value 
-								for most "Distribution" parameters are interchangeable and extensible. -->
-							<key>taskDueDistribution</key>
-							<dict>
-
-								<!-- This distribution is pretty specialized. It produces timestamps 
-									in the near future, limited to certain days of the week and certain hours 
-									of the day. -->
-								<key>type</key>
-								<string>contrib.performance.loadtest.distributions.WorkDistribution</string>
-
-								<key>params</key>
-								<dict>
-									<!-- These are the days of the week the distribution will use. -->
-									<key>daysOfWeek</key>
-									<array>
-										<string>mon</string>
-										<string>tue</string>
-										<string>wed</string>
-										<string>thu</string>
-										<string>fri</string>
-									</array>
-
-									<!-- The earliest hour of a day at which an event might be scheduled. -->
-									<key>beginHour</key>
-									<integer>8</integer>
-
-									<!-- And the latest hour of a day (at which an event will be scheduled 
-										to begin!). -->
-									<key>endHour</key>
-									<integer>16</integer>
-
-									<!-- The timezone in which the event is scheduled. (XXX Does this 
-										really work right?) -->
-									<key>tzname</key>
-									<string>America/Los_Angeles</string>
-								</dict>
-							</dict>
-						</dict>
-					</dict>
-
-				</array>
-
-				<!-- Determine the frequency at which this client configuration will 
-					appear in the clients which are created by the load tester. -->
-				<key>weight</key>
-				<integer>1</integer>
-			</dict>
-		</array>
-	</dict>
-</plist>

Added: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/preset_distributions.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/preset_distributions.py	                        (rev 0)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/settings/preset_distributions.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,36 @@
+from contrib.performance.loadtest.distributions import WorkDistribution, RecurrenceDistribution
+
+STANDARD_WORK_DISTRIBUTION = WorkDistribution(
+    daysOfWeek=["mon", "tue", "wed", "thu", "fri"],
+    beginHour=8,
+    endHour=16,
+    tzname="America/Los_Angeles"
+)
+
+LOW_RECURRENCE_DISTRIBUTION = RecurrenceDistribution(
+    allowRecurrence=True,
+    weights={
+        "none": 50,
+        "daily": 25,
+        "weekly": 25,
+        "monthly": 0,
+        "yearly": 0,
+        "dailylimit": 0,
+        "weeklylimit": 0,
+        "workdays": 0
+    }
+)
+
+MEDIUM_RECURRENCE_DISTRIBUTION = RecurrenceDistribution(
+    allowRecurrence=True,
+    weights={
+        "none": 50,
+        "daily": 10,
+        "weekly": 20,
+        "monthly": 2,
+        "yearly": 1,
+        "dailylimit": 2,
+        "weeklylimit": 5,
+        "workdays": 10
+    }
+)
\ No newline at end of file

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/templates.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/templates.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/templates.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -1,4 +1,3 @@
-# -*- test-case-name: contrib.performance.loadtest.test_population -*-
 ##
 # Copyright (c) 2010-2015 Apple Inc. All rights reserved.
 #
@@ -21,9 +20,9 @@
 
 from twistedcaldav.ical import Component
 
-_baseTemplate = Component.newCalendar()
 
-_veventTemplate = Component.fromString("""\
+# Default Event
+eventTemplate = Component.fromString("""
 BEGIN:VCALENDAR
 VERSION:2.0
 PRODID:-//Apple Inc.//Mac OS X 10.11//EN
@@ -34,35 +33,28 @@
 UID:00000000-0000-0000-0000-000000000000
 CREATED:00000000T000000Z
 DTSTAMP:00000000T000000Z
-DTSTART;TZID=America/Los_Angeles:00000000T000000
-DTEND;TZID=America/Los_Angeles:00000000T000000
-SEQUENCE:0
+DTSTART:00000000T000000
+DTEND:00000000T000000
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n"))
+""")
 
-_valarmTemplate = Component.fromString("""\
-BEGIN:VALARM
-X-WR-ALARMUID:00000000-0000-0000-0000-000000000000
-UID:00000000-0000-0000-0000-000000000000
-DESCRIPTION:Sample Alarm
-TRIGGER:-PT5M
-ACTION:DISPLAY
-END:VALARM
-""".replace("\n", "\r\n"))
 
-_vtodoTemplate = Component.fromString("""\
+# Default Task
+taskTemplate = Component.fromString("""\
+BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//Mac OS X 10.11//EN
+CALSCALE:GREGORIAN
 BEGIN:VTODO
 SUMMARY:Sample Task
 UID:00000000-0000-0000-0000-000000000000
 CREATED:00000000T000000Z
 DTSTAMP:00000000T000000Z
-SEQUENCE:0
 END:VTODO
-""".replace("\n", "\r\n"))
+END:VCALENDAR
+""")
 
-# Default Event
-eventTemplate = _baseTemplate.duplicate()
 
 # Default Alarm
 alarmTemplate = Component.fromString("""\
@@ -71,27 +63,10 @@
 PRODID:-//Apple Inc.//Mac OS X 10.11//EN
 CALSCALE:GREGORIAN
 BEGIN:VALARM
-X-WR-ALARMUID:00000000-0000-0000-0000-000000000000
+ACTION:DISPLAY
+TRIGGER:-PT5M
 UID:00000000-0000-0000-0000-000000000000
 DESCRIPTION:Sample Alarm
-TRIGGER:-PT5M
-ACTION:DISPLAY
 END:VALARM
 END:VCALENDAR
 """)
-
-# Default task
-taskTemplate = Component.fromString("""\
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//Apple Inc.//Mac OS X 10.11//EN
-CALSCALE:GREGORIAN
-BEGIN:VTODO
-SUMMARY:Sample Task
-UID:00000000-0000-0000-0000-000000000000
-CREATED:00000000T000000Z
-DTSTAMP:00000000T000000Z
-SEQUENCE:0
-END:VTODO
-END:VCALENDAR
-""".replace("\n", "\r\n"))

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_ical.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_ical.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_ical.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -404,30 +404,6 @@
 """.replace("\n", "\r\n") % {'UID': EVENT_UID}
 
 
-
-class EventTests(TestCase):
-    """
-    Tests for L{Event}.
-    """
-    def test_uid(self):
-        """
-        When the C{vevent} attribute of an L{Event} instance is set,
-        L{Event.getUID} returns the UID value from it.
-        """
-        event = Event(None, u'/foo/bar', u'etag', Component.fromString(EVENT))
-        self.assertEquals(event.getUID(), EVENT_UID)
-
-
-    def test_withoutUID(self):
-        """
-        When an L{Event} has a C{vevent} attribute set to C{None},
-        L{Event.getUID} returns C{None}.
-        """
-        event = Event(None, u'/bar/baz', u'etag')
-        self.assertIdentical(event.getUID(), None)
-
-
-
 PRINCIPAL_PROPFIND_RESPONSE = """\
 <?xml version='1.0' encoding='UTF-8'?>
 <multistatus xmlns='DAV:'>
@@ -1736,25 +1712,25 @@
 
     _CALENDAR_PROPFIND_RESPONSE_BODY = """\
 <?xml version='1.0' encoding='UTF-8'?>
-<multistatus xmlns='DAV:'>
-  <response>
-    <href>/something/anotherthing.ics</href>
-    <propstat>
-      <prop>
-        <resourcetype>
-          <collection/>
-        </resourcetype>
-        <getetag>"None"</getetag>
-      </prop>
-      <status>HTTP/1.1 200 OK</status>
-    </propstat>
-    <propstat>
-      <prop>
-      </prop>
-      <status>HTTP/1.1 404 Not Found</status>
-    </propstat>
-  </response>
+<multistatus xmlns='DAV:'>
   <response>
+    <href>/something/anotherthing.ics</href>
+    <propstat>
+      <prop>
+        <resourcetype>
+          <collection/>
+        </resourcetype>
+        <getetag>"None"</getetag>
+      </prop>
+      <status>HTTP/1.1 200 OK</status>
+    </propstat>
+    <propstat>
+      <prop>
+      </prop>
+      <status>HTTP/1.1 404 Not Found</status>
+    </propstat>
+  </response>
+  <response>
     <href>/something/else.ics</href>
     <propstat>
       <prop>

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_push.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_push.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_push.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -5,8 +5,8 @@
 from contrib.performance.loadtest.push import PushMonitor
 
 class PushMonitorTests(TestCase):
-    def receivedPush(self, href):
-        print href
+    def fakePush(self, inboundID, dataChangedTimestamp, priority=5):
+        self.monitor._receivedAMPPush(inboundID, dataChangedTimestamp, priority)
 
     def setUp(self):
         self.pushMaster = AMPPushMaster()
@@ -17,6 +17,7 @@
             62311,
             self.receivedPush
         )
+        self.monitor.begin()
 
     def sendNotification(self, href, pushkey):
         self.pushMaster.notify(href, pushkey, None, None)
@@ -26,3 +27,6 @@
 
     def test_removePushkey(self):
         pass
+
+    def tearDown(self):
+        self.monitor.end()

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_resources.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_resources.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_resources.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -0,0 +1,40 @@
+##
+# Copyright (c) 2010-2015 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from twisted.trial.unittest import TestCase
+
+from contrib.performance.loadtest.resources import Event, Calendar
+class EventTests(TestCase):
+    """
+    Tests for L{Event}.
+    """
+    def test_uid(self):
+        """
+        When the C{vevent} attribute of an L{Event} instance is set,
+        L{Event.getUID} returns the UID value from it.
+        """
+        event = Event(None, u'/foo/bar', u'etag', Component.fromString(EVENT))
+        self.assertEquals(event.getUID(), EVENT_UID)
+
+
+    def test_withoutUID(self):
+        """
+        When an L{Event} has a C{vevent} attribute set to C{None},
+        L{Event.getUID} returns C{None}.
+        """
+        event = Event(None, u'/bar/baz', u'etag')
+        self.assertIdentical(event.getUID(), None)
+

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_sim.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_sim.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_sim.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -281,125 +281,6 @@
         self.assertEquals(calsim.server, server)
 
 
-    def test_loadAccountsFromFile(self):
-        """
-        L{LoadSimulator.fromCommandLine} takes an account loader from the
-        config file and uses it to create user records for use in the
-        simulation.
-        """
-        accounts = FilePath(self.mktemp())
-        accounts.setContent("foo,bar,baz,quux,goo\nfoo2,bar2,baz2,quux2,goo2\n")
-        config = VALID_CONFIG.copy()
-        config["accounts"] = {
-            "loader": "contrib.performance.loadtest.sim.recordsFromCSVFile",
-            "params": {
-                "path": accounts.path
-            },
-        }
-        configpath = FilePath(self.mktemp())
-        configpath.setContent(writePlistToString(config))
-        io = StringIO()
-        sim = LoadSimulator.fromCommandLine(['--config', configpath.path], io)
-        self.assertEquals(io.getvalue(), "Loaded 2 accounts.\n")
-        self.assertEqual(2, len(sim.records))
-        self.assertEqual(sim.records[0].uid, 'foo')
-        self.assertEqual(sim.records[0].password, 'bar')
-        self.assertEqual(sim.records[0].commonName, 'baz')
-        self.assertEqual(sim.records[0].email, 'quux')
-        self.assertEqual(sim.records[1].uid, 'foo2')
-        self.assertEqual(sim.records[1].password, 'bar2')
-        self.assertEqual(sim.records[1].commonName, 'baz2')
-        self.assertEqual(sim.records[1].email, 'quux2')
-
-
-    def test_loadDefaultAccountsFromFile(self):
-        """
-        L{LoadSimulator.fromCommandLine} takes an account loader (with
-        empty path)from the config file and uses it to create user
-        records for use in the simulation.
-        """
-        config = VALID_CONFIG.copy()
-        config["accounts"] = {
-            "loader": "contrib.performance.loadtest.sim.recordsFromCSVFile",
-            "params": {
-                "path": ""
-            },
-        }
-        configpath = FilePath(self.mktemp())
-        configpath.setContent(writePlistToString(config))
-        sim = LoadSimulator.fromCommandLine(['--config', configpath.path],
-                                            StringIO())
-        self.assertEqual(99, len(sim.records))
-        self.assertEqual(sim.records[0].uid, 'user01')
-        self.assertEqual(sim.records[0].password, 'user01')
-        self.assertEqual(sim.records[0].commonName, 'User 01')
-        self.assertEqual(sim.records[0].email, 'user01 at example.com')
-        self.assertEqual(sim.records[98].uid, 'user99')
-        self.assertEqual(sim.records[98].password, 'user99')
-        self.assertEqual(sim.records[98].commonName, 'User 99')
-        self.assertEqual(sim.records[98].email, 'user99 at example.com')
-
-
-    def test_generateRecordsDefaultPatterns(self):
-        """
-        L{LoadSimulator.fromCommandLine} takes an account loader from the
-        config file and uses it to generate user records for use in the
-        simulation.
-        """
-        config = VALID_CONFIG.copy()
-        config["accounts"] = {
-            "loader": "contrib.performance.loadtest.sim.generateRecords",
-            "params": {
-                "count": 2
-            },
-        }
-        configpath = FilePath(self.mktemp())
-        configpath.setContent(writePlistToString(config))
-        sim = LoadSimulator.fromCommandLine(['--config', configpath.path],
-                                            StringIO())
-        self.assertEqual(2, len(sim.records))
-        self.assertEqual(sim.records[0].uid, 'user1')
-        self.assertEqual(sim.records[0].password, 'user1')
-        self.assertEqual(sim.records[0].commonName, 'User 1')
-        self.assertEqual(sim.records[0].email, 'user1 at example.com')
-        self.assertEqual(sim.records[1].uid, 'user2')
-        self.assertEqual(sim.records[1].password, 'user2')
-        self.assertEqual(sim.records[1].commonName, 'User 2')
-        self.assertEqual(sim.records[1].email, 'user2 at example.com')
-
-
-    def test_generateRecordsNonDefaultPatterns(self):
-        """
-        L{LoadSimulator.fromCommandLine} takes an account loader from the
-        config file and uses it to generate user records for use in the
-        simulation.
-        """
-        config = VALID_CONFIG.copy()
-        config["accounts"] = {
-            "loader": "contrib.performance.loadtest.sim.generateRecords",
-            "params": {
-                "count": 3,
-                "uidPattern": "USER%03d",
-                "passwordPattern": "PASSWORD%03d",
-                "namePattern": "Test User %03d",
-                "emailPattern": "USER%03d at example2.com",
-            },
-        }
-        configpath = FilePath(self.mktemp())
-        configpath.setContent(writePlistToString(config))
-        sim = LoadSimulator.fromCommandLine(['--config', configpath.path],
-                                            StringIO())
-        self.assertEqual(3, len(sim.records))
-        self.assertEqual(sim.records[0].uid, 'USER001')
-        self.assertEqual(sim.records[0].password, 'PASSWORD001')
-        self.assertEqual(sim.records[0].commonName, 'Test User 001')
-        self.assertEqual(sim.records[0].email, 'USER001 at example2.com')
-        self.assertEqual(sim.records[2].uid, 'USER003')
-        self.assertEqual(sim.records[2].password, 'PASSWORD003')
-        self.assertEqual(sim.records[2].commonName, 'Test User 003')
-        self.assertEqual(sim.records[2].email, 'USER003 at example2.com')
-
-
     def test_specifyRuntime(self):
         """
         L{LoadSimulator.fromCommandLine} recognizes the I{--runtime} option to

Modified: CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_templates.py
===================================================================
--- CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_templates.py	2015-08-18 22:46:11 UTC (rev 15055)
+++ CalendarServer/branches/users/sredmond/clientsim/contrib/performance/loadtest/tests/test_templates.py	2015-08-18 23:39:55 UTC (rev 15056)
@@ -23,24 +23,25 @@
 
 from contrib.performance.loadtest.templates import eventTemplate, alarmTemplate, taskTemplate
 
-"""
-ensure they're all comps
-and that they are all vcalendars
-with the right prodid and calscale and version
-and that they have the corresponding component
-and that each comp has its required properties
-and that they are all v***
 
-"""
-
 class TemplateTests(TestCase):
+    def assertVCalendar(self, vcal):
+        self.assertEqual(vcal.name(), 'VCALENDAR')
+        self.assertEqual(vcal.propertyValue('VERSION'), '2.0')
 
+    def test_eventTemplate(self):
+        self.assertVCalendar(eventTemplate)
+        vevent = eventTemplate.mainComponent()
+        self.assertEqual(vevent.name(), 'VEVENT')
 
-    def assertTemplateIs(self, component, ):
-        pass
+    def test_taskTemplate(self):
+        self.assertVCalendar(taskTemplate)
+        vtodo = taskTemplate.mainComponent()
+        self.assertEqual(vtodo.name(), 'VTODO')
 
-    def test_components(self):
-
-
-    def test_eventTemplate(self):
-        runTests(eventTemplate, component_name="VEVENT", required="")
+    def test_alarmTemplate(self):
+        self.assertVCalendar(alarmTemplate)
+        valarm = alarmTemplate.mainComponent()
+        self.assertEqual(valarm.name(), 'VALARM')
+        self.assertTrue(valarm.hasProperty('ACTION'))
+        self.assertTrue(valarm.hasProperty('TRIGGER'))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20150818/4e745052/attachment-0001.html>


More information about the calendarserver-changes mailing list