diff --git a/README.md b/README.md
index 9429ac4b047d901b8c31a5e02f0946a447db8a68..8f8b164dada0ecb235928871dc3e0c92206871a9 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-## Get Started
+## Get Started.
 
 In this example the web root is /Library/WebServer/Documents and Apache runs as _www - modify the instructions below according to your setup
 
@@ -103,10 +103,6 @@ In this example the web root is /Library/WebServer/Documents and Apache runs as
 
      - Fix so that drush pulls in the correct uri parameter. See http://drupal.org/node/1331106
 
-  *  form_builder/modules/webform/form_builder_webform.module
-
-     - In form_builder_webform_components_page() load jquery.ui.datepicker.min.js so the Date element will work on a new form that does not have ui.datepicker loaded. See http://drupal.org/node/1307838
-
   *  Add Trigger Support Patch to Workbench Moderation
 
      - Trigger support not in 7.x-1.1 - See http://drupal.org/files/issues/trigger_support_for_wb_moderation-1079134-23.patch from http://drupal.org/node/1079134
diff --git a/sites/all/modules/date/CHANGELOG.txt b/sites/all/modules/date/CHANGELOG.txt
new file mode 100644
index 0000000000000000000000000000000000000000..38ecaf947210b5b8c4b6092ffb718f387cfcd90c
--- /dev/null
+++ b/sites/all/modules/date/CHANGELOG.txt
@@ -0,0 +1,592 @@
+Date Module 7.x
+=================
+
+===================
+Version 7.x-2.x-dev
+===================
+
+======================
+Version 7.x-2.5
+======================
+
+- Fix nasty errors on views that have no row indexes, like the frontage view.
+
+======================
+Version 7.x-2.4
+======================
+
+- Issue #1534342 by bass, Make name of clean pager option easier to translate.
+- Add a hook to alter the default date for a Date argument.
+- Issue #1531904, Make sure that multiple value dates that have the delta set only display the selected value.
+- Revert Issue #1266688 by fago, This change broke Entity token support.
+
+======================
+Version 7.x-2.3
+======================
+
+- Issue #1444804, Remove html placeholder on text widget.
+- Issue #1286230, Clean up date pager documentation, it contains deprecated information.
+- Issue #1469020, Make sure page not found is working right for dates outside the specified range.
+- Issue #1111626, Fix some problems caused by passing in a date string with an offset.
+- Issue #1477860, Avoid undefined index errors in date_views_select_validate().
+- Issue #1469038, Add some clarity to the BYDAY description options and make sure a valid value is selected.
+- Issue #1405364 by snufkin, Add display options to format_interval to match Views interval options.
+- Issue #1266688 by linclark, Add microdata support to Date metadata.
+- Issue #1509434 by casey, Add timezone info in hook_field_presave() instead of hook_field_insert() and hook_field_update().
+- Issue #1509012, Fix fatal error when viewing repeat tab.
+- Issue #1037174 by dealancer, More work to allow ajax to work on other widgets.
+- Issue #1473592 by zabelc, Make sure migrated date with missing end date still gets imported correctly.
+- Issue #1442718 by jastraat and bones, Make sure show end date checkbox does not display when end date is empty.
+- Issue #1504556, Fix invalid access permission name in Date API configuration menu.
+- Issue #1484458, Vega timepicker code was incorrectly computing the default date because of the wrong format for the value passed to it.
+- Issue #1459668, Add back Remove date_field_get_sql_handler() function temporarily since Signup module is still using it. Mark it deprecated.
+- Issue #1478296, Display longer abbreviations for day names in date repeat widget so they can be translated.
+- Issue #1488662 by martin.heidegger, Make error message more easily translatable.
+- Issue #1478848 by onelittleant, Don't set default values on new translation entities.
+- Issue #1360672, Fix limit format code to remove leftover non-ascii text as well as leftover ascii text.
+- Issue #1464280 by geerlingguy Georgique and dealancer: Fix notice when using exposed between filter.
+- Issue #1484640 by onelittleant, Some entities may not have base tables.
+- Issue #1472966, Get rid of notice that appears for entities without repeats.
+- Move pager css around. Some code in Calendar and Date API belongs in Date Views.
+- Fix Date Popup default format which was ending up using 24 hour time no matter what format was used for short format.
+- Remove outdated _repeat widget name from Date Tools.
+- Date Tools is defaulting to creating a calendar even if Calendar module is not enabled.
+- Issue #1472148 by arlinsandbulte: wvega jQuery time-picker doesn't show scrollbar.
+- Issue #1392128 by kidrobot, tim.plunkett, willvincent: Fixed Repeats tab shows on nodes with non-repeating dates.
+- Issue #1452882 by coredumperror: Fixed Date Migrate Example doesn't deregister it's migration when disabled.
+- Issue #1452408 by reglogge: Fixed Trailing dots are removed from date formats even if they are needed for the format.
+- Issue #1285260 by Steven Jones: Fixed 'Starting from' display option.
+- Issue #1467244 by bluetegu: Fixed Recurring Sunday errors.
+- Issue #1442718, Empty default values were getting populated by the code that tried to fix default values on hidden fields.
+- Make sure date_handler->placeholders gets initialized even for queries that don't execute so the pager won't throw an exception if the value is missing.
+
+======================
+Version 7.x-2.2
+======================
+
+NOTES:
+The iCal templates were removed and moved to the new Date iCal module (http://drupal.org/project/date_ical).
+
+- Issue #1423364 by emptyvoid, Move Date context plugin into its own file.
+- Issue #1447372 by yched, Memory friendlier version of date_repeat_field_bundles().
+- Issue #1447140 by tim.plunkett: Remove iCal-related theme functions/files.
+- Issue #1284170 by benjifisher, Lots of cleanup of the iCal export and its template to be sure all day items are exported correctly.
+- Issue #1346424, The calendar title got left out of the latest ical template changes.
+- Add more information to the date_views_base_tables() function about why we can't use the entity type from views_fetch_data().
+- Additional handling is needed so that revisions are handled correctly in Views.
+- Remove date_field_get_sql_handler() function which isn't being used anywhere.
+- Rework the Date Views hooks that queue up the right fields and base tables so they work better across all types of entities.
+- Fix the hooks for file tables, it is file_managed, not files.
+- Add a helper function to map entity types to Views base tables to make it easier to know what type of entity is being used on a view.
+- Add status information to Date help screen, hide the non-working change tab on the Date Tools screen, and remove some code that goes to the calendar module from Date Tools.
+
+======================
+Version 7.x-2.1
+======================
+
+- Issue #1437242 by zerbash, Remove extraneous leading slashes in module_load_include().
+- Issue #1436722 by hefox: Fixed Undefined variable $form_set_error() used as function.
+- Issue #1250626 by G�bor Hojtsy, B-Prod, hefox: Added start date and end date labels.
+- Issue #1253482, Make sure $argument->is_default gets reset by the Date pager when altering results.
+- Adjust Date Tools to work with changes to use Views templates to create calendars.
+- Issue #1398584 by dhalbert and , Make sure groupby times is initialized.
+- Issue #1394248, Make sure all date parts are selected when using an exposed select filter.
+- Issue #1425774 by sgabe, Fix error in exposed filter, array_filter() -- first argument should be an array in date_select_input_date().
+- Issue #1432992 by bart.hanssens, Fix typo in php documentation.
+- Issue #323852 by tim.plunkett and arlinsandbulte, Dropdowns shouldn't include a blank option when required.
+- Issue #323852, Validation was broken for unlimited value select widgets with required dates, they were incorrectly getting their end dates cleared out.
+- Issue #1424656 by tim.plunkett, Unify signature and alters of #process callbacks.
+- Issue #1408014 by dasjo, We no longer need the $error_element value to display errors properly, second follow-up.
+- Issue #1299030 by Vincent B: Ensure that 'To Date' is properly marked when required.
+
+======================
+Version 7.x-2.0-rc2
+======================
+
+New Features/Major Changes
+
+- Issue #1358790 by tim.plunkett and redndahead, Store date objects in field_load to speed up processing, with a field setting option to control it.
+
+Bugfixes
+
+- Issue #1423598, Found a way to flag items that are new so we know when to add default values.
+- Made some fixes to find and test the right entities when checking whether to use default values. More work is needed.
+- Issue #1422600, Make sure end date cannot cause validation errors when show end date checkbox is not checked.
+- Issue #1417872, Remove code to compute missing date parts from empty values now that the new validation prevents that from working.
+- Issue #1417872, Make sure empty year field is validated in the same way other date parts are validated.
+- Alter date field test to test with a complete end date instead of using empty elements.
+- Fix broken logic in repeat additions.
+- Fix test broken by date repeat clean up.
+- Issue #1419106 by hanoii: Added more info to hook_date_text_process_alter().
+- Issue #1209026, When date validation fails, Date Popup value is getting cleared.
+- Issue #1017216 by tim.plunkett, arlinsandbulte: Added custom date format without time shows 'all day'.
+- Issue #1408014 by dasjo, We no longer need the $error_element value to display errors properly.
+- Issue #554546 by master-of-magic: Fix Timezone list translation
+- Issue #1411038 by jhodgdon: Fixed Date formatting is not obeying granularity.
+- Issue #1359464, Make sure that default values on hidden elements have the same construct as loaded values to avoid errors.
+- Issue #1399744 by tim.plunkett, Rework the way filter groups are used to be sure the Date filter group does not clobber the Views filter group.
+- Issue #1411862, Move the date_views_fields() function into date_view.module to be sure it is always available.
+- Issue #1380350, Rework SQL query handling to pass in a comparison date for computing offsets to better handle dates affected by DST adjustments.
+- Issue #1359464, Temporary fix for broken handling of repeating dates on users with a TODO to figure out where it's coming from.
+- Issue #1404494 by byrond, Make sure hidden formatters don't get switched to date_default in update hook.
+- Issue #1386012, Order weekdays in Date Repeat form to match the site first day of week settings.
+- Issue #1376476 by pbfleetwood, Add commas to default formatting of week and day headers.
+- Issue #1408430, Views pagination with exposed, unset, filters, results in invalid default values. Treat them as empty input.
+- Issue #1408996, Exposed Date Popup widget with time not correctly initialized.
+- Issue #1271726, Text widgets in exposed filters used with pagers produce unexpected results.
+- Issue #1096000, Custom date formats not working right.
+- Issue #1405364, Format interval settings were getting overridden by missing break.
+- Issue #1387890, Make sure disabled fields are shown and retain their original values.
+- Issue #1402232 by timplunkett, Switch 'Implementation of' to 'Implements'
+- Issue #1402236 by timplunkett, All functions should be prefixed with your module name to avoid name clashes
+- Issue #1402238 by timplumkett, Remove references to CCK
+- Issue #1011624, Filters and arguments were not always using the right base table to select field options, causing 'column missing' errors.
+- Issue #1397822, Fix 'Undefined index: field' error on line 207 of date_views_filter_handler_simple.inc.
+- Issue #1396536, Repeating fields weren't getting created with Devel Generate because of the change in widgets. Add new hooks so Date Repeat Field can add the repeats.
+- Issue #1397126 follow-up by arlinsandbulte, Fix broken tests.
+- Issue #1397158, The default value for the end date was using the wrong timezone setting.
+- Issue #1392128 by kidrobot and tim.plunkett, Don't show repeat tab unless the date is repeating.
+- Issue #1397126, Add Date API section to administration menu and consolidate Date Popup and Date Tools settings there.
+- Follow up to Issue #1302052 by benjifisher, More clean up of ical line endings.
+- Issue #1388174 by travist, Remove redundant use of date_default_timezone().
+- Issue #1388586 by Moloc, Don't use check_plain() on system messages with links.
+- Issue #1302052 by benjifisher, penguin25, and helmo, Fix linespace ending problems in ical files.
+- Issue #1357216, The Date Views field list was including the Date Views filter itself, creating errors about missing node.date_filter values.
+- Issue #1259870, Reinstate the test for a missing date argument for the pager.
+- The new option to hide the add_delta for simple fields needs to be adjusted to work right where there is no field.
+- Tweak the all day formula to check for 59:59 even for items that use increments, to help fix problems when the calendar creates all day values.
+- Our test for whether this is a Date argument or filter needs to include a check that the field was actually processed by Date Views. Some dates are not.
+- Revert the change to 7.8. It breaks the modules page.
+- Issue #1379172 by deviantpixel, Note that the Date Repeat form uses a function that was re-named in 7.8.
+- Store the locale format in a static cache to avoid re-computing it dozens of times on calendar views.
+- Sheesh. Fix syntax error in api.date.php.
+
+======================
+Version 7.x-2.0-rc1
+======================
+
+Notes:
+The Date Browser has been removed. Please use the Date Pager instead. If you have existing views using the Date
+Browser the navigation will just disappear from them. If you add a Date Pager to the view you should get it back.
+Then delete the Date Browser attachment from the view, since it doesn't do anything any more.
+
+The UNTIL date was not getting included in repeating results and that is now fixed. This is an API change of sorts 
+for anyone who worked around the issue by setting it ahead.
+
+The All Day checkbox and All Day themes were moved into a separate module, using new hooks added to the date
+processing. This module should serve as an example of how other modules can inject functionality into date fields.
+
+A new module has been added for integrating the Date Repeat API into date fields. Some of this code has been
+moved into the new module, more of it will be moved later as I figure out how to unwind it from the base
+processing. An update hook has been added to enable this module by default for existing sites. If you don't
+use Repeating dates you can disable it.
+
+New Features/Major Changes
+
+- Issue #1229378 by ksenzee, Sync the end date with the start date on new dates using select widgets.
+- Issue #1236216, Move the repeating date integration out of the Date module and into a separate, Date Repeat Field module.
+- Issue #874322, The All Day functionality has been moved into a separate module and hooks were added to make it easier for other modules to inject steps into date processing.
+- Issue #1267046, Include the UNTIL date in repeating results..
+- Issue #1354606 by temaruk, Rework the repeating date UI to make it more user-friendly.
+- Issue #1362654, Remove Advanced Help integration, it needs a total rewrite.
+- Issue #1357362, Remove Date Browser, use Date Pager instead.
+- Issue #1354606, Make sure COUNT option without UNTIL date can be handled correctly by repeating date computations.
+
+Bugfixes
+
+- Fix to new default date handling, the default date has to set a date in the database timezone, not the display timezone.
+- Issue #1245106 by G�bor Hojtsy, Hide the option to add the delta into the view for single value fields.
+- Issue #1370876, Make sure new Date All Day code does not try to set the popup values if Date Popup is disabled.
+- Issue #874322, Add back the date_field_all_day() function to avoid breaking other modules that are using it.
+- Fix Date text placeholder to display a formatted date instead of a format. Follow up to Date repeat UI changes.
+- Issue #1248520 by fearlsgroove, Use attribute selector on all day and end day checkboxes.
+- Issue #952446 and #1031690, Select dates with only year and month were not working.
+- Issue #1292152 by pfrenssen, Remove debug functions.
+- Issue #1338976 by Josh Benner, Adjust iCal unwrap to allow for leading spaces, per standard.
+- Issue #1352486 by d.novikov, Rework date SQL formatting for Microsoft SQL.
+- Issue #1266536, Keep timezone adjustments from altering the values for repeating date EXCEPTIONS and ADDITIONS.
+- Issue #1353488, Some repeating date calculations using PHP 5.3.6+ were not computing correctly.
+- Issue #1364026, Fix link to documentation, also move help to Date API module.
+- Issue #1276270, Fix fatal error when using repeat date on user.
+- Issue #1362758, Add empty file for the date_plugin_display_attachment.inc file that was removed, to avoid fatal errors if it is missing on a site that formerly used it.
+- Issue #1363460, Make sure widget dates do not end up with the current date when they should be empty.
+- Issue #1353488, Attempt to fix problem using date_date_set() in PHP 5.3.6+.
+- Date Migrate tests needed some fixes to conform to latest code.
+- Issue #1353790, Hide missing index notice if the value in the Date Popup does not match the expected value, it will still get trapped as a validation error.
+- Issue #1353790, Make sure Date Popup properly translates the default value if it includes month or day names.
+- Issue #1217796, Make sure that All Day formatting works correctly even if the All Day label is empty.
+- The repeat description was lost by a recent change to the theme that sent the element through the theme twice.
+- Remove date_get_nested_elements() function. Not being used and I don't want other code to start expecting it.
+- Issue #1266144, The end date should get set to blank if it is optional and matches the start date, but only if it is not populated by default values.
+- Issue #1349510, Make sure default values get populated before processing so they still get set on hidden fields.
+
+======================
+Version 7.x-2.0-alpha5
+======================
+
+Notes:
+The date repeat widgets have been removed to keep users from trying to change repeating dates into non-repeating dates.
+There are now just three widgets, Date Select, Date Text, and Date Popup. Whether or not a date is a repeating date
+is now controlled by a field setting.
+
+New Features/UX Changes/API Changes
+
+- Issue #1304056 by DamienMcKenna, Add option to date_difference to indicate direction of difference.
+- Issue #1238660, Add custom format option for the date format used in summary arguments.
+- Issue #1038482 by somanyfish, iCal import failing due to colon instead of semi-colon
+- Issue #1252952 by eosrei: Make "all day" checkbox configurable on a per field instance basis.
+- Issue #1266144 by arlinsandbulte: Clarify Default End Date Setting
+- Issue #1261478 by stevector and KarenS, Reconfigure the back/next buttons into item lists so Views ajax pager works right.
+- Issue #1262960, Add a new module to work with the Context module to set a condition based on the value of a date field.
+- Issue #1216878, Re-introduce 'repeat' as a field setting rather than a widget type so people can't try to switch back and forth between repeating and non-repeating dates. Eliminate repeat widgets.
+
+Bugfixes
+
+- Issue #1280658 and follow up to Issue #1238660 by KarenS and tockliasteroid, Rework the format control over the summary title and apply it to the title() callback.
+- Issue #1276622 by ArtistConk, Make sure Except date contains no default value.
+- Issue #1153766 by fago, More work on the entity property setters and getters.
+- Issue #1331214, Make sure Date Migrate properly handles empty date values.
+- Issue #1285224, Make sure Date Migrate works for importing repeating dates now that widgets have changed.
+- Issue #1162290, Make sure date for example formats avoids confusing short and long month names.
+- Re-organize handling of custom date formats.
+- Issue #1122038, Make sure empty values are not passed to Views to be themed for repeating dates.
+- Issue #1101284 by pfournier, Expand regex for Month names to catch more possible variations.
+- Issue #1343406 by slashrsm, add back the caching of the views fields list.
+- Issue #1302374 by miro_dietiker, Account for an inconsistency in core handling of non-existant date formats.
+- Issue #1344014 by James Sharpe, Get rid of 'Repeats every 0 days' description.
+- Issue #1302212, Change the way default dates using custom code are created.
+- Issue #1292898, Check for all day checkbox in the basic date element validation so empty time for newly added elements still passes validation.
+- Issue #1252952 follow up, Move checkbox setting to the same spot where time is set, and don't show option on dates without time.
+- Issue #1335818 by joelpitter, Don't create a date for empty values in the date getters and setters.
+- Issue #1271726, Keep default_value out of exposed form so it won't show up in pager.
+- Issue #1017866, Fix miscellaneous problems where filter/argument incorrectly do timezone adjustment.
+- Issue #1103032, Attempt to add setters to date entity metadata so Rules can use them.
+- Issue #1153766, Adapt metadata functions to the pattern in the current Entity code, add $info to the getters.
+- Issue #1278876 by basicmagic.net, Typo in date.css
+- Issue #752550 by Fonant, Week number gets printed twice
+- Issue #1052586 by jpsolero, Problem with Date API when using Calendar with argument set to "Week" granularity and "current date" default argument
+- Issue #1266144, End date same as start date default not being respected.
+- Issue #1239934 by casey, Fix javascript exception in date_year_range.js.
+- Issue #1310558, Don't show extra label on exposed date filter.
+- Fix bug in Date Popup that still uses the current date when the default date is empty.
+- Issue #1335578 by aaronbauman, Make it possible to pass in +/- 1000 years to years back/forward.
+- Issue #1292516 by mcarbone, Fix Uninitialized string offset in Date Migrate.
+- Issue #1084980 by jwilson3, Set default value for $granularity to be array in date_formatter_format.
+- Issue #1227350 by grendzy, Summary view should not be calling date_forbid().
+- Issue #1286570, Fix undefined index error caused by using a remember value without checking if it exists.
+- Issue #1337440 by phoenix, Fix syntax error in vcalendar tpl file.
+- Issue #1103032, Add plain date formatter and set it to be the default token formatter.
+- Issue #1177684 by tim.plunket, Fix typo in last commit.
+- Issue #1177684, Wrong translation of short month name.
+- Issue #1201342 by colinlee and alexprv, Comment out SQLSVR timezone adjustment until it gets fixed properly.
+- Issue #1308274 by sneyerst, SQL Server DATEPART function cannot accept composed datetime formats.
+- Issue #1308266 by sneyerst, Fix arithmetic overflow in SQLSVR.
+- Issue #1333104 by tim.plunkett, Check that $field['settings'] exists in date_is_repeat_field().
+- Error message for years back and forward doesn't match new labels, should be Starting year and Ending year.
+- Issue #1179715, Switch drupal_array_get_nested_value() to use 'values' instead of 'input', where it makes sense, and simplify some of this code.
+- Issue #1179715, Create a helper function for testing hidden/disabled dates and test each date element and validator to skip processing in that case.
+- Issue #1179715, When hidden by #access=FALSE, repeating date fields were getting removed and not replaced.
+- Issue #1179715, By pass date repeat widget processing and validation when element is hidden from user.
+- Issue #1179715, Don't do timezone adjustments in the widget, wait for #process so we can skip it when the date field has been hidden by #access.
+- Issue #1338194, Logic for creating end date wasn't taking into account the possibility that a field might have no value2.
+- Issue #1179715, Default value callback for the timezone widget was not returning an array.
+- Issue #1179716, Remove value_callback for date_repeat and date_combo forms, the default behavior works fine.
+- Issue #1178716 by das-peter, Use drupal_array_get_nested_value() in Date Repeat instead of trying to find it manually.
+- Issue #1178716 by das-peter and KarenS, Tweak the date repeat widget to identify empty input when used on nodes with translation. 
+- Issue #1178716 by das-peter and KarenS, Fix date repeat form values that are not arrays when hidden on a node that has translation.
+- Issue #1178176 by das-peter, Fix date_combo_value_callback to return NULL to avoid data lost on untranslatable dates used with Entity Translation.
+- Date Context module was making incorrect assumptions about the $language of the field.
+- Issue #1237974, Schema module wants the datetime column to be lower case.
+- Issue #1233084, fix a few places that were wrapping $instance['label'] with t().
+- Issue #1188380 by Xen and jherencia, use #title instead of field['label'] in date display because that has the i18n translation.
+- Issue #1330768 by das-peter, remove whitespace.
+- Tweak date_pager_url to allow a way to create non-absolute urls.
+- Make sure deleted displays won't create errors in Views by returning FALSE in date_forbid() if there is no date argument.
+- Issue #1257830, Beef up the logic when creating the date repeat tabs to work for more kinds of entities.
+- Issue #1260962, Repeating date fields should save the date even if there is no repeat information.
+- Issue #1241836 by kzoli, Fix undefined cardinality indexes.
+- Issue #1233722, Fix undefined index notice in pager when other filters are used.
+
+======================
+Version 7.x-2.0-alpha4
+======================
+
+Notes to themers:
+
+Previous versions put dates with both From and To dates into a fieldset and other dates were not.
+The new code adds additional floating elements that are hard to contain, so now all dates are
+enclosed in fieldsets in the node form. There are also new elements on the form, an optional
+checkbox for hiding/showing the To date and an optional checkbox for hiding/showing time.
+Previously dates on the node form had 'From date' and 'To date' labels above them, this
+has been changed to remove those labels, using the Google calendar date entry screen
+as a model. This simplifies the node form and dates take up less space. A light grey border
+has been added around each collection of dates (the From date and the To date). The display
+of labels above the date parts (year, month, day, date, time, etc) is controlled in the
+field settings. Previous versions did not always honor those settings, this one does.
+
+New Features/UX Improvements
+
+- Issue #1249724 by KarenS, G�bor Hojtsy, David_Rothstein, Improve usability of date and time input configuration.
+- Issue #1250784 by David_Rothstein, Add user-friendly labels for start and end date values in Views.
+- Issue #742146, Add option to remove X-WR-CALNAME if VEVENT is not a feed.
+- Add option to change method from PUBLISH to REQUEST in VCALENDAR.
+- Issue #334435, Add a theme function for the 'Date' and 'Time' labels in the Popup widget.
+- Issue #1239956 by David_Rothstein, Change the default separation between from and to dates to use 'to' instead of a hyphen.
+- Issue #1240628 by David_Rothstein, Make the date increment default to 15 instead of 1.
+- Issue #1249724 by David_Rothstein: Improve usability of date and time input configuration
+- Issue #1177198 by tim.plunkett: Allow CTools to process #dependency for date elements.
+- Issue #1245562 by David_Rothstein, Rename the default date display format to something friendlier
+- Issue #1239934 by David_Rothstein and G�bor Hojtsy, Reuse the "years back and forward" dropdown widget on the Views filter settings page.
+- Issue #1239228 by G�bor Hojtsy, Date Views filter form UI improvements, clarify the way absolute and relative dates work.
+- Issue #233047 by ksenzee and David_Rothstein, Add the Vegas jQuery timepicker as a new time selector option.
+- Issue #1145976 by tim.plunkett and KarenS, Add 'is date' identifier to all date handlers.
+- Issue #1234140 by arlinsundbulte, Change terminology in user-facing text from 'From/To Date' to 'Start/End Date'.
+- Issue #1233948 by KarenS, Add 'All Day' checkbox to hide/show the time parts of the date form. If All day is chosen, any time is replaced with 00:00:00 when the form is submitted.
+- Issue #1233612 by KarenS, Add 'Collect end date' checkbox for dates with optional end dates to hide/show the end date.
+- Issue #821200 by scor and KarenS, Add RDF support to the date field.
+- Issue #1211744 by EclipseGC and KarenS, Add a Date pager plugin that is designed to add paging in conjunction with a Date argument.
+- Issue #1180612 by mikeryan, Add support for Migrate module.
+- Issue #1198320 by ksenzee, David_Rothstein, Noyz: Make UI improvements to field settings page.
+- Issue #1215738 by ksenzee, Make granularity settings checkboxes horizontal.
+- Issue #1215686 by ksenzee, Change name of date field types to be more intuitive.
+- Issue #1216996 by ksenzee, Change the years back/forward setting into two drop down boxes.
+- Issue #1222468 by ksenzee, Hide timezone options when using granularity without time.
+- Issue #1229388 by ksenzee, Hide formatter from/to choices on fields without multiple values.
+
+Removed deprecated functions
+
+- Removed date_handler_fields(), only applicable to D6 code.
+- Removed date_views_real_url() and date_views_page_url(), used by older calendar version.
+- Remove unused date_handler_field_multiple.
+
+Tests
+
+- Issue #1251592 by David_Rothstein, Set reasonable default values if date formats have not been configured, and add tests for that.
+- Issue #1242764 Add tests for every possible combination of field type, timezone handling, and granularity.
+- More work on tests, add a foreach loop to run through all field_type/widget_type combinations.
+- Rework tests to use a base class rather than copying the same functions everywhere.
+- Issue #1209408 Make sure date_repeat_calc() returns empty array for FREQ=NONE and INTERVAL=0, also add a test for that.
+- Issue #1161006 by justinrandall, Add tests to check that dates that should have time but do not are correctly caught in validation.
+
+Bugfixes
+
+- Issue #1256406 by q0rban, use variable_get() in hook_requirments().
+- Follow up to Issue #1145976, Make sure 'is date' only gets applied to the date values, not delta, timezone, etc.
+- Issue #1238364, Make sure the Date pager doesn't throw errors if the default date is missing.
+- Issue #1246416, Add info to the Date Popup README.txt about how to download the WVega timepicker.
+- Issue #1253230, Package name of Date Migrate was different than the other Date components.
+- Issue #1251592, Add installation message and system requirements warnings about missing system date settings.
+- Issue #1250784, Don't save psuedo field settings created by the new UI in the field itself.
+- Issue #1239228 by David_Rothstein, Always add Date Views css to View UI edit forms.
+- Issue #1254540 by David_Rothstein, Move borders off of the wrappers so they don't appear when the dates inside them are hidden.
+- Issue #1253248 by David_Rothstein, Move RDF attributes handling to preprocess function.
+- Issue #1087798 by anj, Fix X-WR-CALNAME in VCALENDAR.
+- Issue #1254582 Repeat additions need to be adjusted to use the same time as the original date.
+- Move vcalendar and vevent templates from Date Views to Date API modules.
+- Follow up to Issue #1250344, We don't need extra space when there is a description, only when there is not.
+- Issue #1239228 by G�bor Hojtsy, More tweaks to filter css.
+- Issue #1244924 by G�bor Hojtsy, Minor text improvements in date filter configuration
+- Issue #1245556 by David_Rothstein, Date granularity description incorrectly implies that it affects the date attributes that are displayed
+- Issue #1247444 by G�bor Hojtsy, Give a little breathing space to the date year range "other" field
+- Issue #1250344 by jessebeach, Fix padding around date fields by adding clearfix class.
+- Issue #1249116 by yched, Fix various glitches with D6 migration code.
+- Issue #1243022 by fmosca and KarenS, Make sure all_day #states visibility is only set when there is a value for all_day.
+- Issue #1236192 by loganfsmyth, Make sure #date_label_position has a default value in the Date Popup module.
+- Issue #1246416, Test whether libraries_get_path() returns a valid path before using it.
+- Issue #1235994, Don't display 'All Day' when using a format that has no time.
+- Issue #1245690 by mikeryan, Migration plugin missing seconds from date formats
+- Issue #1229406 by David Rothstein, G�bor Hojtsy, and tim.plunkett Fix broken timepicker in Chrome and Safari.
+- Issue #1239412 by keithm, Fix validation error when #access is false.
+- Issue #1232522, Don't alter field_ui_field_edit form except on date fields.
+- Issue #1243842, Make sure the All Day and Show End Date flags work correctly in unlimited value fields that use ajax.
+- Follow up to Issue #1239956, Fix tests broken by change in date separator.
+- Issue #1241576, Fix date combo validation for all-day dates so they don't fail validation because the format is unexpected.
+- Take the guesswork out of examining Date info for Views, add is_field flag.
+- Follow up to Issue #874322, Date popup field needs to accept date without time for the all day flag to work.
+- Follow up to Issue #1130814, It looks like the modification is not needed in date_repeat_set_month_day and date_repeat_set_year_day.
+- Issue #1160132 by seanbfuller and KarenS, Exposed filter widgets were not displaying the default values.
+- Adjust the way widgets are styled in Views exposed filters after the latest style changes for form elements.
+- Issue #1234114 by arlinsandbulte, Add more space between checkboxes.
+- Issue #1234090, Fix undefined variable 'all_day'.
+- Issue #1232570 by dboulet, Remove some unneeded duplication of core clearfix and other css cleanup.
+- Issue #1232614 by dboulet, Date css should not be setting font family.
+- Timezone and Date Popup weren't obeying the settings for displaying the date part label.
+- Issue #1130814 by cdracars, mikeryan, mayobutter, Fix date_modify difference between PHP 5.3.5 and 5.3.6 so both work to compute repeating dates.
+- Issue #1017866 by KarenS and Jason89s, Make sure views argument and filter don't do timezone adjustment for dates that don't have time.
+- Issue #1204988 by paulsheldrake, Remove IE6 code from datepicker CSS.
+- Issue #1231864 by Damien McKenna, Clean up line endings in vevent and vcalendar tpl files.
+- Issue #1231382 by dboulet, Clean up date css, code style fixes.
+- Date repeat additions and exceptions need to be reworked into full, timezone-adjusted, datetime values when passing them to FAPI as default values.
+- Issue #1223034 by c4rl, Make sure repeating date additions and exceptions work correctly when there is more than one repeating date in the same form.
+- Issue #1229362, Date Popup module needs date_is_date() function, which should not require Date module. Move that to Date API.
+- Issue #1227208 by ksenzee, Minor text changes.
+- Issue #1094408, Change method of identifying Field module filters, using the name of the group is not robust enough.
+- Issue #1227264 by gapa, Fix wrong class in date-pager.tpl.php.
+- Issue #1207540, Summary grouping won't work right unless the formula alias doesn't match an actual field value.
+- Issue #1227350 Summary query still needs the formula, add it back.
+- Fix 'variables cannot be passed by reference' notice on repeats page.
+- Issue #1222736 Fix export errors caused when previous export fix of using export plugins got broken by changes in Views.
+- Issue #1077490 Fix notices about missing #date_flexible.
+- Move the 'top' date pager to below the header instead of below attachment_before so you can add header text above it.
+- The value for variable_get('date_first_day') should default to zero to match core default.
+- Issue #1147620 by KarenS with an assist from tim.plunkett, Fix the query so it will locate dates that span days or months by checking the intersection of the date range and the query range. Also add an option to the argument so you can do a simple query for either the from or to date when checking the whole range isn't the right solution.
+- Issue #307274 by ksenzee, Fix broken validation for absolute value in years back/forward.
+- Issue #1173374 by fietserwin, Remove translation of the jQuery datepicker day and month names, now handled by core.
+- Issue #1192020 by tim.plunkett: Fixed date granularity is too fragile in date_field_all_day().
+- Issue #1110012 Remove 'parent' items from Views plugins, no longer needed? See if this fixes the issue.
+- Issue #1183892, Initialize $identifier in date_views_filter_handler_simple.
+- Issue #1103290 by stickywes and ingaro, Change postgres 'FMYYYY-FMMM-FMDDTFMHH:FMMI:FMSS' to 'FMYYYY-FMMM-FMDDTFMHH24:FMMI:FMSS'.
+- Issue #1186528 by jox, Make date field combo label translatable.
+- Issue #1123186 by KingJoshi, Fix misnamed date_part_hour_prefix in hook_theme().
+- Issue #1032942 by fietserwin, Rename date popup functions that are getting picked up by theme('date').
+- Issue #1206756 More tweaks to the validation changes. They were blocking zero times and causing some test failures.
+- Issue #1197352 Don't display language about from and to dates when there is no todate.
+- Issue #1201288 by rafa0961, fix broken references to SQLSERVER.
+- More work on cleaning up validation, add in some ideas from fearlsgrove about checking the granularity of the input array against the expected granularity.
+- Issue #1161006 Dates that should have time but do not were not correctly caught in validation.
+- Get rid of overlapping formatter functionality. There should be a default formatter with the option to choose a date format as a setting, not a formatter for each format. This was a leftover from the D6 functionality.
+- Issue #1159404 by mikeryan, Fix incorrect call to parse an rrule in date_repeat_build_dates().
+- Issue #1160656 by jjs, Replace missing break in date_api.sql.inc that breaks PostgreSQL.
+- Issue #1150454, Fix undefined index notices for repeat_collapsed value.
+- Issue #1150462, Put length limit on content type names created by Date Tools so block delta won't overflow the allowed size.
+- Issue #1136734, When migrating date format data from D6 to D7, don't try to overwrite existing custom values.
+- Issue #1161042 by Ollie222, Date filters using time were inconsistently formatted.
+- Issue #1130884, Bad logic in 'between' filter SQL, should always join with AND.
+- Issue #1139418 by ankur, Bad logic in week argument SQL, should always join with AND.
+- Issue #1118356, Disabling the Timepicker was having no effect.
+- Issue #408770 by vkareh, Make sure dates with #access = FALSE get passed through date_combo_element_process().
+- Issue #1037174 by das-peter, add ajax support to date popup.
+- Issue #1160614 by joelstein, Make sure date repeat rule gets split correctly no matter which line endings were used.
+- Issue #1110708 by mr.baileys, Fix problem combining date filter with other exposed filters.
+- Switch some references to $node to use $entity instead.
+- Issue #1112206, add a dummy field to the date navigation bar query to keep it from trying to create invalid sql.
+- Issue #1112206, $this->view->query->clear_fields() is still need for date_browser to keep Views from trying to use missing field values.
+- Date browser only works with date_argument, should work with any argument derived from date.
+
+======================
+Version 7.x-2.0-alpha3
+======================
+
+- Issue #1138700, missed a couple references to the construct() function.
+
+======================
+Version 7.x-2.0-alpha2
+======================
+
+- Follow up to Issue #1103290, constructor was not set up correctly and did not get triggered, so none of the date handlers had a db_type.
+- Issue #1138622, preliminary pass at adding support for SQL Server.
+- Issue #1136618 by ksenzee, Fix broken hide/show capability for date filter values.
+- Issue #1059078 Add preliminary support for SQLite dates.
+- Issue #1103290 by kevintheday, Use db_driver() to determine database engine.
+- The 'now' values got broken again somewhere along the line. Now we need to switch the ISO format used by our SQL queries back to the datetime format the widgets use.
+- Looks like Views changed ['expose']['operator'] to ['expose']['operator_id'].
+- Issue #1115770, Make sure filters values are switched back to ISO format so time comparisons work correctly.
+- Issue #1132916 by znerol, Fix a couple more usages of date_default_timezone_name().
+- Issue #1131308 Don't try to do timzone conversion when there is no localzone for a field.
+- Issue #1093222 Fix broken function to remove calendar views.
+- Issue #820670 Add update to move D6 date format data to D7 data.
+- Issue 1074344 Fix problem with date select widget that keeps resetting pm back to am.
+- Issue #1001186 Make sure that a 2 digit year is flagged as an error.
+- Issue #1117420 by threewestwinds, Make timepicker formats more useful.
+- Issue #1126408 by thekevinday, Add more sql formats to date api.
+- Issue #1129326 by robertom, add missing  value to element in date_combo.
+- Issue #998220 by jamsilver and yched, fix handling of validation in date_combo. This also fixes errors when using a date in Profile 2 and Field Collections.
+- Issue #1022592 by andypost and tim.plunkett optimize hook_form_alter into hook_form FORMID_alter.
+- Issue 1021424 by joostvdl and wiizzard, fix context in translations to use core values.
+- Remove extra fields from the Date field. I think the filter and argument now get the right tables joined in without that. We still need the extra fields on calendar, but now we will only add them in the calendar view.
+- Fix some notices in vcalendar theme.
+- Fix the mini calendar querystring.
+- Fix logic for day argument formula.
+- Fix logic for week argument formula.
+- Issue #1086582 by bojanz, summary options are in a different place now, fix the method of removing the summary option on multiple-date arguments.
+- Views renamed 'wildcard' to 'exception'.
+- Apparently the handler->argument value is not always populated.
+- Fix fallback value for date_group.
+- Issue #1103032 by tim.plunkett, Remove token integration code until Token module is fixed.
+- Now that there is no group of 'Fields' we need different tests to tell if this is a field filter.
+- Views changed the group name of fields from 'Fields' to 'Content'. Blech, broke everything.
+- Fix potential error if handler is broken.
+- Remove reference to a function that no longer exists in Views.
+- Issue #1116962 by jpontani, mordonez: Parse Error - date_views_fields.inc on line 119.
+- Fix the logic for year and month only dates.
+- Add helper function to test if handler is a date handler.
+- Fix broken handling when creating dates from timestamps.
+- Set some defaults for dates without month or day.
+- Issue ##1094408 by Boobaa: Date field not showing up in views arguments in localized site
+- Issue #1018412 by omerida: get_class() called without object.
+- There were some problems when creating a year-only date using the select filter caused by trying to create a date with zeros in the month and day. Fix the date building logic to force a valid month and day into them.
+- Complex filters were not using the date handler of the individual fields.
+- Issue #1100934, Replace deprecated date_array() function.
+- #1096246 Date argument also was not applying the group method in the right place in the query, causing that method to be applied to all filters.
+- Missed a couple places when re-naming the get_value() function in the filter.
+- Fix more notices.
+- #1096246 Date filter was not apply the group method in the right place in the query, causing that method to be applied to all filters.
+- Fix undefined index notice.
+- Remove non-used function.
+- Issue #1082654 by arlinsandbulte: Remove master branch files and explain in readme.txt
+- Issue #906622 by bfroehle, Start cleanup of Date token code.
+- Fix typo in form processing.
+- Clean up the admin summary for the date filter.
+- Fix another use of get_value() in the filter.
+- Fix some strict errors in the views filter.
+- #1094408 by Boobaa: Date field not showing up in views arguments in localized site
+- #1041428, by tim.plunkett: Fix logic errors in 'All Day' computations.
+- #1054458: Move date_increment_round() function into Date API module so it is always available.
+- #745074, by rsevero:  Don't test for valid timezone-adjusted date for dates that don't use time.
+- #1076992: The timezone element never got completely updated to D7.
+- #1013662 by developer-x: Remove check for start and end date - this prevented multiday-all day events from showing 'All Day'
+
+======================
+Version 7.x-2.0-alpha1
+======================
+
+- #1082658: Saving the options as arrays breaks other things. Add a custom export plugin instead.
+- #1082658, Views options need to be declared as arrays or they are not saved in the export in Views 3.
+- #1075896 Break out the code into the simple argument and a complex argument that combines date fields.
+- #1075890 Break out the code into the simple filter and a complex filter that combines date fields.
+
+======================
+Version 7.x-1.0-dev
+======================
+
+Abandoned the 7.x-1.x branch.
+
+Start a new 7.x-2.x branch that will contain a complete re-work of the Views handling.
+
+The 7.x-2.x branch will totally re-work and simplify the Views filters. These changes may/will
+break some views and will require that you check views that use the date filter or
+argument to be sure they are still configured correctly.
+
+There is a new date_filter_handler_simple for an individual date field that simplifies
+the Views handling by using most of the core Views field handling but adds in the
+possibility to set a default date using options like 'now', along with a choice of a
+month/day/year drop-down selector or popup calendar selector.
+
+The date_filter_handler is an extension of the simple handler that allows you to combine
+multiple dates into a single filter so that you can control all of them with the same
+filter widget, allowing you to either 'OR' or 'AND' them together.
+
+The arguments will be rewritten in the same way, with a simple argument handler for
+individual dates and another handler that extends that to control multiple dates with
+a single argument.
+
+- Add some error trapping in case the parent dateObject is unable to make a date out of a string to avoid showing the user errors.
+- #1027752 by B-Prod and dboulet, Fix missing table join on argument summary view.
+- #1047412 by das-peter - Using date filter in February causes "The day is invalid" error.
+- #1014162 Now that the datefield processing expands to date & time, the form_value is corrupted.
+- Changes to the data migration code to work with latest iteration of Content Migrate.
+
+======================
+Version 7.x-1.0-alpha2
+======================
+
+- Views made lots of changes to field handling just before the new release, which broke lots of things here.
+- Adding some work-arounds to get things working again and waiting until the dust settles on how the new core fields will be handled in Views before doing much more with the Views integration. These changes should get things working with latest Views release.
+
+======================
+Version 7.x-1.0-alpha1
+======================
+
+- Initial release, probably still buggy.
+- Remove Date PHP4, no longer needed because PHP4 is not supported any more.
+- Remove Date Timezone, now handled by core.
diff --git a/sites/all/modules/date/INSTALL.txt b/sites/all/modules/date/INSTALL.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e85a438b74578ef0344438c1db8c7ec064b08923
--- /dev/null
+++ b/sites/all/modules/date/INSTALL.txt
@@ -0,0 +1,47 @@
+================================================================================
+Date API Installation instructions:
+================================================================================
+1) If you have an earlier version of the Date module on your system, empty the
+   date folder out completely. The files in later versions have different names
+   and are located in different places.
+
+2) Download the whole package of files from http://drupal.org/project/date.
+
+3) Upload the date files to the modules directory. The package includes files
+   needed by the Date API, and optional modules to to create date fields.
+
+4) Go to admin/modules and enable the needed modules from the Date/Time group.
+
+You should end up with a structure like:
+
+   /drupal/sites/all/modules/date/date.info
+   /drupal/sites/all/modules/date/date.install
+   /drupal/sites/all/modules/date/date.module
+   ...
+
+   /drupal/sites/all/modules/date/date_api/date_api.info
+   /drupal/sites/all/modules/date/date_api/date_api.install
+   /drupal/sites/all/modules/date/date_api/date_api.module
+   ...
+
+================================================================================
+Install Date Fields:
+================================================================================
+
+1) The date field type is included in the Date files at
+   http://drupal.org/project/date.
+
+2) Go to admin/modules and enable the Date module. Be sure that the Date API
+   module, the Date Timezone module, and the core Field module are also enabled.
+
+3) Go to admin/structure/types to view content types and edit a content type.
+
+4) Make sure the default timezone name has been set at
+   admin/config/regional/settings.
+
+5) While viewing a content type, select the option to add a new field from the
+   tabs at the top of the page. Several options for date fields will be visible.
+
+================================================================================
+More documentation is available at http://drupal.org/node/92460.
+================================================================================
diff --git a/sites/all/modules/date/LICENSE.txt b/sites/all/modules/date/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1
--- /dev/null
+++ b/sites/all/modules/date/LICENSE.txt
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/sites/all/modules/date/README.txt b/sites/all/modules/date/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..75464988f763e1fa6d8b967e206ea78530300d93
--- /dev/null
+++ b/sites/all/modules/date/README.txt
@@ -0,0 +1,223 @@
+INFORMATION FOR DEVELOPERS
+
+Once the Date API is installed, all functions in the API are available to be
+used anywhere by any module.
+
+The API uses the PHP 5.2 date functions to create and manipulate dates.
+
+Example, the following will create a date for the local value in one
+timezone, adjust it to a different timezone, then return the offset in seconds
+in the new timezone for the input date; The offset will be adjusted for both
+the timezone difference and daylight savings time, if necessary:
+
+$date = date_create('2007-03-11 02:00:00', timezone_open('America/Chicago'));
+$chicago_time = date_format($date, 'Y-m-d H:i');
+
+print 'At '. $chicago_time .' in Chicago, the timezone offset in seconds
+  was '. date_offset_get($date);
+
+date_timezone_set($date, timezone_open('Europe/Berlin');
+$berlin_time = date_format($date, 'Y-m-d H:i');
+
+print 'It was '. $berlin_time .' in Berlin when it
+  was '. $chicago_time .' in Chicago.';
+print 'At that time in Berlin, the timezone offset in seconds was
+  '. date_offset_get($date);
+
+A helper class is available, new DateObject($string, $timezone, $format), where
+$string is a unixtimestamp, an ISO date, or a string like YYYY-MM-DD HH:MM:SS,
+$timezone is the name of the timezone this date is in, and $format is the format
+of date it is (DATE_FORMAT_UNIX, DATE_FORMAT_ISO, or DATE_FORMAT_DATETIME). It
+creates and return a date object set to the right date and timezone.
+
+Simpletest tests for these functions are included in the package.
+
+Available functions include the following (more documentation is provided in
+the files):
+
+============================================================================
+Preconfigured arrays
+============================================================================
+Both translated and untranslated values are available. The
+date_week_days_ordered() function will shift an array of week day names so it
+starts with the site's first day of the week, otherwise the weekday names start
+with Sunday as the first value, which is the expected order for many php and sql
+functions.
+
+date_month_names();
+date_month_names_abbr();
+date_month_names_untranslated();
+date_week_days();
+date_week_days_abbr();
+date_week_days_untranslated();
+date_week_days_ordered();
+date_years();
+date_hours();
+date_minutes();
+date_seconds();
+date_timezone_names();
+date_ampm();
+
+============================================================================
+Miscellaneous date manipulation functions
+============================================================================
+Pre-defined constants and functions that will handle pre-1970 and post-2038
+dates in both PHP 4 and PHP 5, in any OS. Dates can be converted from one
+type to another and date parts can be extracted from any date type.
+
+DATE_DATETIME
+DATE_ISO
+DATE_UNIX
+DATE_ARRAY
+DATE_OBJECT
+DATE_ICAL
+
+date_convert()
+date_is_valid();
+date_part_is_valid();
+date_part_extract();
+
+============================================================================
+Date calculation and navigation
+============================================================================
+date_difference() will find the time difference between any two days, measured
+in seconds, minutes, hours, days, months, weeks, or years.
+
+date_days_in_month();
+date_days_in_year();
+date_weeks_in_year();
+date_last_day_of_month();
+date_day_of_week();
+date_day_of_week_name();
+date_difference();
+
+============================================================================
+Date regex and format helpers
+============================================================================
+Pre-defined constants, an array of date format strings and their
+equivalent regex strings.
+
+DATE_REGEX_LOOSE is a very loose regex that will pull date parts out
+of an ISO date with or without separators, using either 'T' or a space
+to separate date and time, and with or without time.
+
+date_format_date() is similar to format_date(), except it takes a
+date object instead of a timestamp as the first parameter.
+
+DATE_FORMAT_ISO
+DATE_FORMAT_DATETIME
+DATE_FORMAT_UNIX
+DATE_FORMAT_ICAL
+
+DATE_REGEX_ISO
+DATE_REGEX_DATETIME
+DATE_REGEX_LOOSE
+
+date_format_date();
+date_short_formats();
+date_medium_formats();
+date_long_formats();
+date_format_patterns();
+
+============================================================================
+Standardized ical parser and creator
+============================================================================
+The iCal parser is found in date_api_ical.inc, which is not included by default.
+Include that file if you want to use these functions:
+
+Complete rewrite of ical imports to parse vevents, vlocations, valarms,
+and all kinds of timezone options and repeat rules for ical imports.
+The function now sticks to parsing the ical into an array that can be used
+in various ways. It no longer trys to convert timezones while parsing,
+instead a date_ical_date_format() function is provided that can be used to
+convert from the ical timezone to whatever timezone is desired in the
+results. Repeat rules are parsed into an array which other modules can
+manipulate however they like to create additional events from the results.
+
+date_ical_export();
+date_ical_import();
+date_ical_date_format();
+
+============================================================================
+Helpers for portable date SQL
+============================================================================
+The SQL functions are found in date_api_sql.inc, which is not included by
+default. Include that file if you want to use these functions:
+
+date_sql();
+date_server_zone_adj();
+date_sql_concat();
+date_sql_pad();
+
+============================================================================
+Date forms and validators
+============================================================================
+Reusable, configurable, self-validating FAPI date elements are found in
+date_api_elements.inc, which is not included by default. Include it
+if you want to use these elements. To use them, create a form element
+and set the '#type' to one of the following:
+
+date_select
+ The date_select element will create a collection of form elements, with a
+ separate select or textfield for each date part. The whole collection will
+ get reformatted back into a date value of the requested type during validation.
+
+date_text
+ The date_text element will create a textfield that can contain a whole
+ date or any part of a date as text. The user input value will be re-formatted
+ back into a date value of the requested type during validation.
+
+date_timezone
+ The date_timezone element will create a drop-down selector to pick a
+ timezone name.
+
+The custom date elements require a few other pieces of information to work
+correctly, like #date_format and #date_type. See the internal documentation
+for more information.
+
+============================================================================
+Date Popup Module
+============================================================================
+
+A new module is included in the package that will enable a popup jQuery
+calendar date picker and timepicker in date and time fields.
+
+It is implemented as a custom form element, so set '#type' to 'date_popup'
+to use this element. See the internal documentation for more information.
+
+============================================================================
+Date Repeat API
+============================================================================
+
+An API for repeating dates is available if installed. It can be used by
+other modules to create a form element that will allow users to select
+repeat rules and store those selections in an iCal RRULE string, and a
+calculation function that will parse the RRULE and return an array of dates
+that match those rules. The API is implemented in the Date module as a
+new date widget if the Date Repeat API is installed.
+
+============================================================================
+RDF Integration
+============================================================================
+
+To make RDF easier to use, the base date themes (date_display_single and
+date_display_range) have been expanded so they pass attributes and
+RDF mappings for the field, if any, to the theme. If RDF is installed
+and no other mappings are provided, the theme adds RDF information
+to mark both the Start and End dates as 'xsd:dateTime' datatypes with the
+property of 'dc:date'. This occurs in the theme preprocess layer, in
+particular via the functions template_preprocess_date_display_single() and
+template_preprocess_date_display_range().
+
+To mark these as events instead, you could install the schemaorg
+module, which will load the schema.org vocabulary. The mark the content type
+that contains events as an 'Event', using the UI exposed by that
+module and set the event start date field with the 'dateStart'
+property and tag other fields in the content type with the appropriate
+property types. The Date module theme will wrap the start and end
+date output with appropriate markup.
+
+If the result is not quite what you need, you should be able to implement your
+own theme preprocess functions, e.g. MYTHEME_preprocess_date_display_single()
+or MYTHEME_preprocess_date_display_range() and alter the attributes to use the
+values you want.
diff --git a/sites/all/modules/date/date.api.php b/sites/all/modules/date/date.api.php
new file mode 100644
index 0000000000000000000000000000000000000000..17f751443e570eb95903439e1bae14729f350329
--- /dev/null
+++ b/sites/all/modules/date/date.api.php
@@ -0,0 +1,529 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the Date module.
+ */
+
+/**
+ * Alter the default value for a date argument.
+ *
+ * @param object $argument
+ *   The argument object.
+ * @param string $value
+ *   The default value created by the argument handler.
+ */
+function hook_date_default_argument_alter(&$argument, &$value) {
+  $style_options = $style_options = $argument->view->display_handler->get_option('style_options');
+  if (!empty($style_options['track_date'])) {
+    $default_date = date_now();
+    $value = $default_date->format($argument->arg_format);
+  }
+}
+
+/**
+ * Alter the entity before formatting it.
+ *
+ * @param object $entity
+ *   The entity object being viewed.
+ * @param array $variables
+ *   The variables passed to the formatter.
+ *   - entity: The $entity object.
+ *   - entity_type: The $entity_type.
+ *   - field: The $field array.
+ *   - instance: The $instance array.
+ *   - langcode: The $langcode.
+ *   - items: The $items array.
+ *   - display: The $display array.
+ *   - dates: The processed dates array, empty at this point.
+ *   - attributes: The attributes array, empty at this point.
+ *   - rdf_mapping: The RDF mapping array.
+ *   - add_rdf: If module_exists('rdf').
+ */
+function hook_date_formatter_pre_view_alter(&$entity, &$variables) {
+  if (!empty($entity->view)) {
+    $field = $variables['field'];
+    $date_id = 'date_id_' . $field['field_name'];
+    $date_delta = 'date_delta_' . $field['field_name'];
+    $date_item = $entity->view->result[$entity->view->row_index];
+    if (!empty($date_item->$date_id)) {
+      $entity->date_id = 'date.' . $date_item->$date_id . '.' . $field['field_name'] . '.' . $date_item->$date_delta . '.0';
+    }
+  }
+}
+
+/**
+ * Alter the dates array created by date_formatter_process().
+ *
+ * @param array $dates
+ *   The $dates array created by the Date module.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - field: The $field array.
+ *   - instance: The $instance array.
+ *   - format: The string $format.
+ *   - entity_type: The $entity_type.
+ *   - entity: The $entity object.
+ *   - langcode: The string $langcode.
+ *   - item: The $item array.
+ *   - display: The $display array.
+ */
+function hook_date_formatter_dates_alter(&$dates, $context) {
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $format = $context['format'];
+  $entity_type = $context['entity_type'];
+  $entity = $context['entity'];
+  $date1 = $dates['value']['local']['object'];
+  $date2 = $dates['value2']['local']['object'];
+
+  $is_all_day = date_all_day_field($field, $instance, $date1, $date2);
+
+  $all_day1 = '';
+  $all_day2 = '';
+  if ($format != 'format_interval' && $is_all_day) {
+    $all_day1 = theme('date_all_day', array(
+      'field' => $field,
+      'instance' => $instance,
+      'which' => 'date1',
+      'date1' => $date1,
+      'date2' => $date2,
+      'format' => $format,
+      'entity_type' => $entity_type,
+      'entity' => $entity));
+    $all_day2 = theme('date_all_day', array(
+      'field' => $field,
+      'instance' => $instance,
+      'which' => 'date2',
+      'date1' => $date1,
+      'date2' => $date2,
+      'format' => $format,
+      'entity_type' => $entity_type,
+      'entity' => $entity));
+    $dates['value']['formatted_time'] = theme('date_all_day_label');
+    $dates['value2']['formatted_time'] = theme('date_all_day_label');
+    $dates['value']['formatted'] = $all_day1;
+    $dates['value2']['formatted'] = $all_day2;
+  }
+}
+
+/**
+ * Alter the date_text element before the rest of the validation is run.
+ *
+ * @param array $element
+ *   The $element array.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $input
+ *   The array of input values to be validated.
+ */
+function hook_date_text_pre_validate_alter(&$element, &$form_state, &$input) {
+  // Let Date module massage the format for all day values so they will pass
+  // validation. The All day flag, if used, actually exists on the parent
+  // element.
+  date_all_day_value($element, $form_state);
+}
+
+/**
+ * Alter the date_select element before the rest of the validation is run.
+ *
+ * @param array $element
+ *   The $element array.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $input
+ *   The array of input values to be validated.
+ */
+function hook_date_select_pre_validate_alter(&$element, &$form_state, &$input) {
+  // Let Date module massage the format for all day values so they will pass
+  // validation. The All day flag, if used, actually exists on the parent
+  // element.
+  date_all_day_value($element, $form_state);
+}
+
+/**
+ * Alter the date_popup element before the rest of the validation is run.
+ *
+ * @param array $element
+ *   The $element array.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $input
+ *   The array of input values to be validated.
+ */
+function hook_date_popup_pre_validate_alter(&$element, &$form_state, &$input) {
+  // Let Date module massage the format for all day values so they will pass
+  // validation. The All day flag, if used, actually exists on the parent
+  // element.
+  date_all_day_value($element, $form_state);
+}
+
+/**
+ * Alter the date_combo element before the rest of the validation is run.
+ *
+ * @param array $element
+ *   The $element array.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - field: The $field array.
+ *   - instance: The $instance array.
+ *   - item: The $item array.
+ *
+ * @see date_combo_element_process()
+ */
+function hook_date_combo_pre_validate_alter(&$element, &$form_state, $context) {
+  if (!empty($context['item']['all_day'])) {
+
+    $field = $context['field'];
+
+    // If we have an all day flag on this date and the time is empty, change the
+    // format to match the input value so we don't get validation errors.
+    $element['#date_is_all_day'] = TRUE;
+    $element['value']['#date_format'] = date_part_format('date', $element['value']['#date_format']);
+    if (!empty($field['settings']['todate'])) {
+      $element['value2']['#date_format'] = date_part_format('date', $element['value2']['#date_format']);
+    }
+  }
+}
+
+/**
+ * Alter the local start date objects created by the date_combo validation.
+ *
+ * This is called before the objects are converted back to the database timezone
+ * and stored.
+ *
+ * @param object $date
+ *   The $date object.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *  - field: The $field array.
+ *  - instance: The $instance array.
+ *  - item: The $item array.
+ *  - element: The $element array.
+ */
+function hook_date_combo_validate_date_start_alter(&$date, &$form_state, $context) {
+  // If this is an 'All day' value, set the time to midnight.
+  if (!empty($context['element']['#date_is_all_day'])) {
+    $date->setTime(0, 0, 0);
+  }
+}
+
+/**
+ * Alter the local end date objects created by the date_combo validation.
+ *
+ * This is called before the objects are converted back to the database timezone
+ * and stored.
+ *
+ * @param object $date
+ *   The $date object.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *  - field: The $field array.
+ *  - instance: The $instance array.
+ *  - item: The $item array.
+ *  - element: The $element array.
+ */
+function hook_date_combo_validate_date_end_alter(&$date, &$form_state, $context) {
+  // If this is an 'All day' value, set the time to midnight.
+  if (!empty($context['element']['#date_is_all_day'])) {
+    $date->setTime(0, 0, 0);
+  }
+}
+
+/**
+ * Alter the date_text widget element.
+ *
+ * @param array $element
+ *   An associative array containing the properties of the date_text element.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - form: Nested array of form elements that comprise the form.
+ *
+ * @see date_text_element_process()
+ */
+function hook_date_text_process_alter(&$element, &$form_state, $context) {
+  $all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
+  if ($all_day_id != '') {
+    // All Day handling on text dates works only if the user leaves the time out
+    // of the input value. There is no element to hide or show.
+  }
+}
+
+/**
+ * Alter the date_select widget element.
+ *
+ * @param array $element
+ *   An associative array containing the properties of the date_select element.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - form: Nested array of form elements that comprise the form.
+ *
+ * @see date_select_element_process()
+ */
+function hook_date_select_process_alter(&$element, &$form_state, $context) {
+  // Hide or show the element in reaction to the all_day status for the element.
+  $all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
+  if ($all_day_id != '') {
+    foreach (array('hour', 'minute', 'second', 'ampm') as $field) {
+      if (array_key_exists($field, $element)) {
+        $element[$field]['#states'] = array(
+          'visible' => array(
+            'input[name="' . $all_day_id . '"]' => array('checked' => FALSE),
+          ),
+        );
+      }
+    }
+  }
+}
+
+/**
+ * Alter the date_popup widget element.
+ *
+ * @param array $element
+ *   An associative array containing the properties of the date_popup element.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - form: Nested array of form elements that comprise the form.
+ *
+ * @see date_popup_element_process()
+ */
+function hook_date_popup_process_alter(&$element, &$form_state, $context) {
+  // Hide or show the element in reaction to the all_day status for the element.
+  $all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
+  if ($all_day_id != '' && array_key_exists('time', $element)) {
+    $element['time']['#states'] = array(
+      'visible' => array(
+        'input[name="' . $all_day_id . '"]' => array('checked' => FALSE),
+      ),
+    );
+  }
+}
+
+/**
+ * Alter the date_combo element after the Date module is finished with it.
+ *
+ * @param array $element
+ *   The $element array.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - field: The $field array.
+ *   - instance: The $instance array.
+ *   - form: Nested array of form elements that comprise the form.
+ */
+function hook_date_combo_process_alter(&$element, &$form_state, $context) {
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $field_name = $element['#field_name'];
+  $delta = $element['#delta'];
+
+  // Add a date repeat form element, if needed.
+  // We delayed until this point so we don't bother adding it to hidden fields.
+  if (date_is_repeat_field($field, $instance)) {
+    $item = $element['#value'];
+    $element['rrule'] = array(
+      '#type' => 'date_repeat_rrule',
+      '#theme_wrappers' => array('date_repeat_rrule'),
+      '#default_value' => isset($item['rrule']) ? $item['rrule'] : '',
+      '#date_timezone' => $element['#date_timezone'],
+      '#date_format'      => date_limit_format(date_input_format($element, $field, $instance), $field['settings']['granularity']),
+      '#date_text_parts'  => (array) $instance['widget']['settings']['text_parts'],
+      '#date_increment'   => $instance['widget']['settings']['increment'],
+      '#date_year_range'  => $instance['widget']['settings']['year_range'],
+      '#date_label_position' => $instance['widget']['settings']['label_position'],
+      '#prev_value' => isset($item['value']) ? $item['value'] : '',
+      '#prev_value2' => isset($item['value2']) ? $item['value2'] : '',
+      '#prev_rrule' => isset($item['rrule']) ? $item['rrule'] : '',
+      '#date_repeat_widget' => str_replace('_repeat', '', $instance['widget']['type']),
+      '#date_repeat_collapsed' => $instance['widget']['settings']['repeat_collapsed'],
+      '#date_flexible' => 0,
+      '#weight' => $instance['widget']['weight'] + .4,
+    );
+  }
+}
+
+/**
+ * Alter the date_timezone widget element.
+ *
+ * @param array $element
+ *   An associative array containing the properties of the date_select element.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - form: Nested array of form elements that comprise the form.
+ *
+ * @see date_timezone_element_process()
+ */
+function hook_date_timezone_process_alter(&$element, &$form_state, $context) {
+  // @todo.
+}
+
+/**
+ * Alter the date_year_range widget element.
+ *
+ * @param array $element
+ *   An associative array containing the properties of the date_select element.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - form: Nested array of form elements that comprise the form.
+ *
+ * @see date_year_range_element_process()
+ */
+function hook_date_year_range_process_alter(&$element, &$form_state, $context) {
+  // @todo.
+}
+
+/**
+ * Alter a date field settings form.
+ *
+ * @param array $form
+ *   Nested array of form elements that comprise the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - field: The $field array.
+ *   - instance: The $instance array.
+ *   - has_data: The value of $has_data.
+ *
+ * @see hook_field_settings_form()
+ */
+function hook_date_field_settings_form_alter(&$form, $context) {
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $has_data = $context['has_data'];
+
+  $form['repeat'] = array(
+    '#type' => 'select',
+    '#title' => t('Repeating date'),
+    '#default_value' => $field['settings']['repeat'],
+    '#options' => array(0 => t('No'), 1 => t('Yes')),
+    '#attributes' => array('class' => array('container-inline')),
+    '#description' => t("Repeating dates use an 'Unlimited' number of values. Instead of the 'Add more' button, they include a form to select when and how often the date should repeat."),
+    '#disabled' => $has_data,
+  );
+}
+
+/**
+ * Alter a date field instance settings form.
+ *
+ * @param array $form
+ *   Nested array of form elements that comprise the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - field: The $field array.
+ *   - instance: The $instance array.
+ *
+ * @see hook_field_instance_settings_form()
+ */
+function hook_date_field_instance_settings_form_alter(&$form, $context) {
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $form['new_setting'] = array(
+    '#type' => 'textfield',
+    '#default_value' => '',
+    '#title' => t('My new setting'),
+  );
+}
+
+/**
+ * Alter a date field widget settings form.
+ *
+ * @param array $form
+ *   Nested array of form elements that comprise the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - field: The $field array.
+ *   - instance: The $instance array.
+ *
+ * @see hook_field_widget_settings_form()
+ */
+function hook_date_field_widget_settings_form_alter(&$form, $context) {
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $form['new_setting'] = array(
+    '#type' => 'textfield',
+    '#default_value' => '',
+    '#title' => t('My new setting'),
+  );
+}
+
+/**
+ * Alter a date field formatter settings form.
+ *
+ * @param array $form
+ *   Nested array of form elements that comprise the form.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - field: The $field array.
+ *   - instance: The $instance array.
+ *   - view_mode: The formatter view mode.
+ *
+ * @see hook_field_formatter_settings_form()
+ */
+function hook_date_field_formatter_settings_form_alter(&$form, &$form_state, $context) {
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $view_mode = $context['view_mode'];
+  $display = $instance['display'][$view_mode];
+  $formatter = $display['type'];
+  if ($formatter == 'date_default') {
+    $form['show_repeat_rule'] = array(
+      '#title' => t('Repeat rule:'),
+      '#type' => 'select',
+      '#options' => array(
+        'show' => t('Show repeat rule'),
+        'hide' => t('Hide repeat rule')),
+      '#default_value' => $settings['show_repeat_rule'],
+      '#access' => $field['settings']['repeat'],
+      '#weight' => 5,
+    );
+  }
+}
+
+/**
+ * Alter a date field formatter settings summary.
+ *
+ * @param array $summary
+ *   An array of strings to be concatenated into a short summary of the
+ *   formatter settings.
+ * @param array $context
+ *   An associative array containing the following keys:
+ *   - field: The $field array.
+ *   - instance: The $instance array.
+ *   - view_mode: The formatter view mode.
+ *
+ * @see hook_field_formatter_settings_summary()
+ */
+function hook_date_field_formatter_settings_summary_alter(&$summary, $context) {
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $view_mode = $context['view_mode'];
+  $display = $instance['display'][$view_mode];
+  $formatter = $display['type'];
+  $settings = $display['settings'];
+  if (isset($settings['show_repeat_rule']) && !empty($field['settings']['repeat'])) {
+    if ($settings['show_repeat_rule'] == 'show') {
+      $summary[] = t('Show repeat rule');
+    }
+    else {
+      $summary[] = t('Hide repeat rule');
+    }
+  }
+}
diff --git a/sites/all/modules/date/date.devel_generate.inc b/sites/all/modules/date/date.devel_generate.inc
new file mode 100644
index 0000000000000000000000000000000000000000..47de0847c2a92015ba4b517804b4514d09e4d118
--- /dev/null
+++ b/sites/all/modules/date/date.devel_generate.inc
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Date Devel Generate code.
+ */
+
+/**
+ * Implements hook_devel_generate().
+ *
+ * Included only when needed.
+ */
+function date_devel_generate($entity, $field, $instance, $bundle) {
+
+  $entity_field = array();
+  if (isset($instance['widget']['settings']['year_range'])) {
+    $split = explode(':', $instance['widget']['settings']['year_range']);
+    $back = str_replace('-', '', $split[0]);
+    $forward = str_replace('+', '', $split[1]);
+  }
+  else {
+    $back = 2;
+    $forward = 2;
+  }
+  // Pick a random year within the time range,
+  // and a random second within that year.
+  $year = date_format(date_now(), 'Y') - $back + mt_rand(0, ($forward + $back));
+  $start = new DateObject($year . '-01-01 00:00:00', date_get_timezone_db($field['settings']['tz_handling']));
+  $leap = date_format($start, 'L');
+  $max_days = $leap ? 366 : 365;
+  $seconds = mt_rand(0, ($max_days * 86400));
+  date_modify($start, "+$seconds seconds");
+  $increment = $instance['widget']['settings']['increment'];
+  date_increment_round($start, $increment);
+
+  // Modify End date by 1 hour to 3 days, shorter for repeating dates
+  // longer for others.
+  $start2 = clone($start);
+  $max = !empty($field['settings']['repeat']) ? 720 : 4320;
+  $max = 240;
+  date_modify($start2, '+' . mt_rand(60, $max) . ' minutes');
+  date_increment_round($start2, $increment);
+
+  if ($field['settings']['tz_handling'] == 'date') {
+    // Choose a random timezone.
+    // Not all keys exist, so we have to check.
+    $timezones = array_keys(date_timezone_names(TRUE));
+    $key = mt_rand(0, count($timezones) - 1);
+    if (!array_key_exists($key, $timezones)) {
+      $timezone = date_default_timezone();
+    }
+    else {
+      $timezone = $timezones[$key];
+    }
+  }
+  else {
+    $timezone = date_get_timezone($field['settings']['tz_handling']);
+  }
+
+  switch ($field['type']) {
+    case 'date':
+      $format = DATE_FORMAT_ISO;
+      break;
+    case 'datestamp':
+      $format = DATE_FORMAT_UNIX;
+      break;
+    case 'datetime':
+      $format = DATE_FORMAT_DATETIME;
+      break;
+  }
+  $entity_field['value'] = date_format($start, $format);
+  if ($field['settings']['todate']) {
+    $entity_field['value2'] = date_format($start2, $format);
+  }
+  date_timezone_set($start, timezone_open($timezone));
+  $entity_field['timezone'] = $timezone;
+  $entity_field['offset'] = date_offset_get($start);
+  date_timezone_set($start2, timezone_open($timezone));
+  $entity_field['offset2'] = date_offset_get($start2);
+  return $entity_field;
+
+}
diff --git a/sites/all/modules/date/date.field.inc b/sites/all/modules/date/date.field.inc
new file mode 100644
index 0000000000000000000000000000000000000000..5a4fa8134c9282d714f72149b47a3d321665283e
--- /dev/null
+++ b/sites/all/modules/date/date.field.inc
@@ -0,0 +1,532 @@
+<?php
+
+/**
+ * @file
+ * Field hooks to implement a date field.
+ */
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function date_field_formatter_info() {
+  $formatters = array(
+    'date_default' => array(
+      'label' => t('Date and time'),
+      'field types' => array('date', 'datestamp', 'datetime'),
+      'settings' => array(
+        'format_type' => 'long',
+        'multiple_number' => '',
+        'multiple_from' => '',
+        'multiple_to' => '',
+        'fromto' => 'both',
+      ),
+    ),
+    'format_interval' => array(
+      'label' => t('Time ago'),
+      'field types' => array('date', 'datestamp', 'datetime'),
+      'settings' => array(
+        'interval' => 2,
+        'interval_display' => 'time ago',
+      ),
+    ),
+    'date_plain' => array(
+      'label' => t('Plain'),
+      'field types' => array('date', 'datestamp', 'datetime'),
+    ),
+  );
+  return $formatters;
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function date_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $formatter = $display['type'];
+  module_load_include('inc', 'date', 'date_admin');
+  switch ($formatter) {
+    case 'format_interval':
+      $form = date_interval_formatter_settings_form($field, $instance, $view_mode, $form, $form_state);
+      break;
+    default:
+      $form = date_default_formatter_settings_form($field, $instance, $view_mode, $form, $form_state);
+      break;
+  }
+  $context = array(
+    'field' => $field,
+    'instance' => $instance,
+    'view_mode' => $view_mode,
+  );
+  drupal_alter('date_field_formatter_settings_form', $form, $form_state, $context);
+  return $form;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function date_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $formatter = $display['type'];
+  module_load_include('inc', 'date', 'date_admin');
+  switch ($formatter) {
+    case 'format_interval':
+      $summary = date_interval_formatter_settings_summary($field, $instance, $view_mode);
+      break;
+    default:
+      $summary = date_default_formatter_settings_summary($field, $instance, $view_mode);
+      break;
+  }
+  $context = array(
+    'field' => $field,
+    'instance' => $instance,
+    'view_mode' => $view_mode,
+  );
+  drupal_alter('date_field_formatter_settings_summary', $summary, $context);
+
+  return implode('<br />', $summary);
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ *
+ * Useful values:
+ *
+ *   $entity->date_id
+ *     If set, this will show only an individual date on a field with
+ *     multiple dates. The value should be a string that contains
+ *     the following values, separated with periods:
+ *     - module name of the module adding the item
+ *     - node nid
+ *     - field name
+ *     - delta value of the field to be displayed
+ *     - other information the module's custom theme might need
+ *
+ *     Used by the calendar module and available for other uses.
+ *     example: 'date:217:field_date:3:test'
+ *
+ *   $entity->date_repeat_show
+ *     If true, tells the theme to show all the computed values
+ *     of a repeating date. If not true or not set, only the
+ *     start date and the repeat rule will be displayed.
+ */
+function date_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $element = array();
+  $settings = $display['settings'];
+  $formatter = $display['type'];
+  $variables = array(
+    'entity' => $entity,
+    'entity_type' => $entity_type,
+    'field' => $field,
+    'instance' => $instance,
+    'langcode' => $langcode,
+    'items' => $items,
+    'display' => $display,
+    'dates' => array(),
+    'attributes' => array(),
+    'rdf_mapping' => array(),
+    'add_rdf' => module_exists('rdf'),
+  );
+
+  // If there is an RDf mapping for this date field, pass it down to the theme.
+  $rdf_mapping = array();
+  if (!empty($entity->rdf_mapping) && function_exists('rdf_rdfa_attributes')) {
+    if (!empty($entity->rdf_mapping[$field['field_name']])) {
+      $variables['rdf_mapping'] = $rdf_mapping = $entity->rdf_mapping[$field['field_name']];
+    }
+  }
+
+  // Give other modules a chance to prepare the entity before formatting it.
+  drupal_alter('date_formatter_pre_view', $entity, $variables);
+
+  // See if we are only supposed to display a selected
+  // item from multiple value date fields.
+  $selected_deltas = array();
+  if (!empty($entity->date_id)) {
+    foreach ((array) $entity->date_id as $key => $id) {
+      list($module, $nid, $field_name, $selected_delta, $other) = explode('.', $id . '.');
+      if ($field_name == $field['field_name']) {
+        $selected_deltas[] = $selected_delta;
+      }
+    }
+  }
+
+  switch ($display['type']) {
+    case 'date_plain':
+      foreach ($items as $delta => $item) {
+        if (!empty($entity->date_id) && !in_array($delta, $selected_deltas)) {
+          continue;
+        }
+        else {
+          if (empty($item['value2']) || $item['value'] == $item['value2']) {
+            $element[$delta] = array('#markup' => $item['value']);
+          }
+          else {
+            $element[$delta] = array('#markup' => t('!start-date to !end-date', array('!start-date' => $item['value'], '!end-date' => $item['value2'])));
+          }
+        }
+      }
+      break;
+    case 'format_interval':
+      foreach ($items as $delta => $item) {
+        if (!empty($entity->date_id) && !in_array($delta, $selected_deltas)) {
+          continue;
+        }
+        else {
+          $variables['delta'] = $delta;
+          $variables['item'] = $item;
+          $variables['dates'] = date_formatter_process($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display);
+          $variables['attributes'] = !empty($rdf_mapping) ? rdf_rdfa_attributes($rdf_mapping, $item['value']) : array();
+          $element[$delta] = array('#markup' => theme('date_display_interval', $variables));
+        }
+      }
+      break;
+    default:
+      foreach ($items as $delta => $item) {
+        if (!empty($entity->date_id) && !in_array($delta, $selected_deltas)) {
+          continue;
+        }
+        else {
+          $variables['delta'] = $delta;
+          $variables['item'] = $item;
+          $variables['dates'] = date_formatter_process($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display);
+          $variables['attributes'] = !empty($rdf_mapping) ? rdf_rdfa_attributes($rdf_mapping, $item['value']) : array();
+          $output = theme('date_display_combination', $variables);
+          if (!empty($output)) {
+            $element[$delta] = array('#markup' => $output);
+          }
+        }
+      }
+      break;
+  }
+  return $element;
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function date_field_is_empty($item, $field) {
+  // Sometimes a $item is a date object.
+  // Coming from repeating dates. Why??
+  if (!is_array($item)) {
+    return FALSE;
+  }
+  if (empty($item['value'])) {
+    return TRUE;
+  }
+  elseif ($field['settings']['todate'] == 'required' && empty($item['value2'])) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Implements hook_field_info().
+ */
+function date_field_info() {
+  $settings = array(
+    'settings' => array(
+      'todate' => '',
+      'granularity' => drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute')),
+      'tz_handling' => 'site',
+      'timezone_db' => 'UTC',
+    ),
+    'instance_settings' => array(
+      'default_value' => 'now',
+      'default_value_code' => '',
+      'default_value2' => 'same',
+      'default_value_code2' => '',
+    ),
+    // Integrate with the Entity Metadata module.
+    'property_type' => 'date',
+    'property_callbacks' => array('date_entity_metadata_property_info_alter'),
+  );
+  return array(
+    'datetime' => array(
+      'label' => 'Date',
+      'description' => t('Store a date in the database as a datetime field, recommended for complete dates and times that may need timezone conversion.'),
+      'default_widget' => 'date_select',
+      'default_formatter' => 'date_default',
+      'default_token_formatter' => 'date_plain',
+      ) + $settings,
+    'date' => array(
+      'label' => 'Date (ISO format)',
+      'description' => t('Store a date in the database as an ISO date, recommended for historical or partial dates.'),
+      'default_widget' => 'date_select',
+      'default_formatter' => 'date_default',
+      'default_token_formatter' => 'date_plain',
+      ) + $settings,
+    'datestamp' => array(
+      'label' => 'Date (Unix timestamp)',
+      'description' => t('Store a date in the database as a timestamp, deprecated format to support legacy data.'),
+      'default_widget' => 'date_select',
+      'default_formatter' => 'date_default',
+      'default_token_formatter' => 'date_plain',
+      ) + $settings,
+  );
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function date_field_widget_info() {
+  $settings = array(
+    'settings' => array(
+      'input_format' => date_default_format('date_select'),
+      'input_format_custom' => '',
+      'increment' => 15,
+      'text_parts' => array(),
+      'year_range' => '-3:+3',
+      'label_position' => 'above',
+    ),
+    'behaviors' => array(
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+      'default value' => FIELD_BEHAVIOR_NONE,
+    ),
+  );
+
+  $info = array(
+    'date_select' => array(
+      'label' =>  t('Select list'),
+      'field types' => array('date', 'datestamp', 'datetime'),
+    ) + $settings,
+    'date_text' => array(
+      'label' =>  t('Text field'),
+      'field types' => array('date', 'datestamp', 'datetime'),
+     ) + $settings,
+  );
+  if (module_exists('date_popup')) {
+    $info['date_popup'] = array(
+      'label' =>  t('Pop-up calendar'),
+      'field types' => array('date', 'datestamp', 'datetime'),
+    ) + $settings;
+  }
+  return $info;
+}
+
+/**
+ * Implements hook_field_load().
+ */
+function date_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
+  $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
+  $db_format = date_type_format($field['type']);
+  $process = date_process_values($field);
+  foreach ($entities as $id => $entity) {
+    foreach ($items[$id] as $delta => &$item) {
+      // If the file does not exist, mark the entire item as empty.
+      if (is_array($item)) {
+        $timezone = isset($item['timezone']) ? $item['timezone'] : '';
+        $item['timezone'] = date_get_timezone($field['settings']['tz_handling'], $timezone);
+        $item['timezone_db'] = $timezone_db;
+        $item['date_type'] = $field['type'];
+        if (!empty($field['settings']['cache_enabled']) && ($delta < $field['settings']['cache_count'] || $field['settings']['cache_count'] == 0)) {
+          foreach ($process as $processed) {
+            if (!empty($item[$processed])) {
+              $date = new DateObject($item[$processed], $item['timezone_db'], $db_format);
+              $date->limitGranularity($field['settings']['granularity']);
+              $item['db'][$processed] = $date;
+            }
+          }
+          if (!empty($item['db']['value']) && empty($item['db']['value2'])) {
+            $item['db']['value2'] = $item['db']['value'];
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_validate().
+ */
+function date_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
+  $field_name = $field['field_name'];
+  $flexible = 0;
+
+  // Don't try to validate if there were any errors before this point
+  // since the element won't have been munged back into a date.
+  if (!form_get_errors()) {
+    foreach ($items as $delta => $item) {
+      if (is_array($item) && isset($item['value'])) {
+        $process = date_process_values($field, $instance);
+        $date1 = new DateObject($item['value'], $item['timezone'], date_type_format($field['type']));
+        if (count($process) == 1 || (empty($item['value2']) && $item['value2'] !== 0)) {
+          $date2 = clone($date1);
+        }
+        else {
+          $date2 = new DateObject($item['value2'], $item['timezone'], date_type_format($field['type']));
+        }
+        $valid1 = $date1->validGranularity($field['settings']['granularity'], $flexible);
+        $valid2 = $date2->validGranularity($field['settings']['granularity'], $flexible);
+
+        foreach ($process as $processed) {
+          if ($processed == 'value' && $field['settings']['todate'] && !$valid1 && $valid2) {
+            $errors[$field['field_name']][$langcode][$delta][] = array(
+              'error' => 'value',
+              'message' => t("A 'Start date' date is required for field %field #%delta.", array('%delta' => $field['cardinality'] ? intval($delta + 1) : '', '%field' => $instance['label'])),
+            );
+          }
+          if ($processed == 'value2' && $field['settings']['todate'] == 'required' && ($instance['required'] && $valid1 && !$valid2)) {
+            $errors[$field['field_name']][$langcode][$delta][] = array(
+              'error' => 'value2',
+              'message' => t("An 'End date' is required for field %field #%delta.", array('%delta' => $field['cardinality'] ? intval($delta + 1) : '', '%field' => $instance['label'])),
+            );
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_insert().
+ */
+function date_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  $field_name = $field['field_name'];
+
+  if (empty($items)) {
+    return;
+  }
+  // Add some information needed to interpret token values.
+  $values = $items;
+  foreach ($values as $delta => $item) {
+    $timezone = isset($item['timezone']) ? $item['timezone'] : '';
+    if (is_array($item)) {
+      $items[$delta]['timezone'] = date_get_timezone($field['settings']['tz_handling'], $timezone);
+      $items[$delta]['timezone_db'] = date_get_timezone_db($field['settings']['tz_handling']);
+      $items[$delta]['date_type'] = $field['type'];
+    }
+  }
+  $entity->{$field['field_name']}[$langcode] = $items;
+}
+
+/**
+ * Implements hook_field_insert().
+ */
+function date_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  $context = array(
+    'entity_type' => $entity_type,
+    'entity' => $entity,
+    'field' => $field,
+    'instance' => $instance,
+    'langcode' => $langcode,
+  );
+  drupal_alter('date_field_insert', $items, $context);
+}
+
+/**
+ * Implements hook_field_update().
+ */
+function date_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  $context = array(
+    'entity_type' => $entity_type,
+    'entity' => $entity,
+    'field' => $field,
+    'instance' => $instance,
+    'langcode' => $langcode,
+  );
+  drupal_alter('date_field_update', $items, $context);
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ *
+ * Wrapper functions for date administration, included only when processing
+ * field settings.
+ */
+function date_field_instance_settings_form($field, $instance) {
+  module_load_include('inc', 'date', 'date_admin');
+  return _date_field_instance_settings_form($field, $instance);
+}
+
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function date_field_widget_settings_form($field, $instance) {
+  module_load_include('inc', 'date', 'date_admin');
+  return _date_field_widget_settings_form($field, $instance);
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function date_field_settings_form($field, $instance, $has_data) {
+  module_load_include('inc', 'date', 'date_admin');
+  return _date_field_settings_form($field, $instance, $has_data);
+}
+
+/**
+ * Implements hook_content_migrate_field_alter().
+ *
+ * Use this to tweak the conversion of field settings from the D6 style to the
+ * D7 style for specific situations not handled by basic conversion, as when
+ * field types or settings are changed.
+ *
+ * $field_value['widget_type'] is available to see what widget type was
+ * originally used.
+ */
+function date_content_migrate_field_alter(&$field_value, $instance_value) {
+  switch ($field_value['module']) {
+    case 'date':
+      // Those settings do not exist anymore, or have been moved to the instance
+      // level.
+      unset($field_value['settings']['default_format']);
+      unset($field_value['settings']['repeat_collapsed']);
+      break;
+  }
+}
+
+/**
+ * Implements hook_content_migrate_instance_alter().
+ *
+ * Use this to tweak the conversion of instance or widget settings from the D6
+ * style to the D7 style for specific situations not handled by basic
+ * conversion, as when formatter or widget names or settings are changed.
+ */
+function date_content_migrate_instance_alter(&$instance_value, $field_value) {
+  switch ($instance_value['widget']['module']) {
+    case 'date':
+
+      // Some settings have been moved from field to instance.
+      $instance_value['widget']['settings']['repeat_collapsed'] = $field_value['settings']['repeat_collapsed'];
+
+      // Some settings were moved from widget settings to instance settings.
+      $instance_value['settings']['default_value'] = $instance_value['default_value'];
+      unset($instance_value['default_value']);
+      $instance_value['settings']['default_value_code'] = $instance_value['widget']['settings']['default_value_code'];
+      unset($instance_value['widget']['settings']['default_value_code']);
+      $instance_value['settings']['default_value2'] = $instance_value['widget']['settings']['default_value2'];
+      unset($instance_value['widget']['settings']['default_value2']);
+      $instance_value['settings']['default_value_code2'] = $instance_value['widget']['settings']['default_value_code2'];
+      unset($instance_value['widget']['settings']['default_value_code2']);
+
+      // We need to retrieve formatter settings from the variables and store
+      // them in the instance.
+      foreach ($instance_value['display'] as $context => &$display) {
+        if ($display['type'] != 'format_interval') {
+          $old_settings = date_old_formatter_get_settings($instance_value['field_name'], $instance_value['bundle'], $context);
+          $display['settings'] = array_merge($display['settings'], $old_settings);
+          // If the formatter was the 'default', then use the old
+          // 'default_format' field property.
+          $format = ($display['type'] == 'default') ? $field_value['settings']['default_format'] : $display['type'];
+          $display['settings']['format_type'] = $format;
+          $display['type'] = 'date_default';
+        }
+      }
+
+      break;
+  }
+}
+
+/**
+ * Constructs an array of old formatter settings.
+ */
+function date_old_formatter_get_settings($field_name, $type_name, $context) {
+  $options = array();
+  $value = 'date:' . $type_name . ':' . $context . ':' . $field_name;
+  $options['show_repeat_rule'] = variable_get($value . '_show_repeat_rule', 'show');
+  $options['multiple_number'] = variable_get($value . '_multiple_number', '');
+  $options['multiple_from'] = variable_get($value . '_multiple_from', '');
+  $options['multiple_to'] = variable_get($value . '_multiple_to', '');
+  $options['fromto'] = variable_get($value . '_fromto', 'both');
+  return $options;
+}
diff --git a/sites/all/modules/date/date.info b/sites/all/modules/date/date.info
new file mode 100644
index 0000000000000000000000000000000000000000..88eaa6c2ef49f773627a6b863c87376dd83476b2
--- /dev/null
+++ b/sites/all/modules/date/date.info
@@ -0,0 +1,18 @@
+name = Date
+description = Makes date/time fields available.
+dependencies[] = date_api
+package = Date/Time
+core = 7.x
+php = 5.2
+files[] = tests/date_api.test
+files[] = tests/date.test
+files[] = tests/date_field.test
+files[] = tests/date_validation.test
+files[] = tests/date_timezone.test
+
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date.install b/sites/all/modules/date/date.install
new file mode 100644
index 0000000000000000000000000000000000000000..3f250585c2017ff05de89ff4a67f11633b8c140c
--- /dev/null
+++ b/sites/all/modules/date/date.install
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the Date module.
+ */
+
+/**
+ * Implements hook_field_schema().
+ */
+function date_field_schema($field) {
+  $db_columns = array();
+  switch ($field['type']) {
+    case 'datestamp':
+      $db_columns['value'] = array(
+        'type' => 'int',
+        'not null' => FALSE,
+        'sortable' => TRUE,
+        'views' => TRUE,
+      );
+      break;
+    case 'datetime':
+      $db_columns['value'] = array(
+        'type' => 'datetime',
+        'mysql_type' => 'datetime',
+        'pgsql_type' => 'timestamp without time zone',
+        'sqlite_type' => 'varchar',
+        'sqlsrv_type' => 'smalldatetime',
+        'not null' => FALSE,
+        'sortable' => TRUE,
+        'views' => TRUE,
+      );
+      break;
+    default:
+      $db_columns['value'] = array(
+        'type' => 'varchar',
+        'length' => 20,
+        'not null' => FALSE,
+        'sortable' => TRUE,
+        'views' => TRUE,
+      );
+      break;
+  }
+
+  // If a second date is needed for 'End date', make a copy of the first one.
+  if (!empty($field['settings']['todate'])) {
+    $db_columns['value2'] = $db_columns['value'];
+
+    // We don't want Field API to create additional columns, just the first.
+    // We modify them our own way in views data.
+    $db_columns['value2']['views'] = FALSE;
+  }
+  // Timezone and offset columns are used only if date-specific dates are used.
+  if (isset($field['settings']['tz_handling']) && $field['settings']['tz_handling'] == 'date') {
+    $db_columns['timezone'] = array(
+      'type' => 'varchar',
+      'length' => 50,
+      'not null' => FALSE,
+      'sortable' => TRUE,
+      'views' => FALSE,
+    );
+    $db_columns['offset'] = array(
+      'type' => 'int',
+      'not null' => FALSE,
+      'sortable' => TRUE,
+      'views' => FALSE,
+    );
+    if (!empty($field['settings']['todate'])) {
+      $db_columns['offset2'] = array('type' => 'int', 'not null' => FALSE, 'sortable' => TRUE, 'views' => FALSE);
+    }
+  }
+  if (isset($field['settings']['repeat']) && $field['settings']['repeat'] == 1) {
+    $db_columns['rrule'] = array(
+      'type' => 'text',
+      'not null' => FALSE,
+      'sortable' => FALSE,
+      'views' => FALSE,
+    );
+  }
+  return array('columns' => $db_columns);
+}
+
+/**
+ * Implements hook_update_last_removed().
+ */
+function date_update_last_removed() {
+  return 6005;
+}
+
+/**
+ * Get rid of the individual formatters for each format type,
+ * these are now settings in the default formatter.
+ */
+function date_update_7000() {
+  $instances = field_info_instances();
+  foreach ($instances as $entity_type => $entities) {
+    foreach ($entities as $bundle => $fields) {
+      foreach ($fields as $field_name => $instance) {
+        if (in_array($instance['widget']['type'], array('date_popup'))) {
+          $changed = FALSE;
+          foreach ($instance['display'] as $context => $display) {
+            if ($display['type'] != 'date_default' && $display['type'] != 'date_interval' && $display['type'] != 'hidden') {
+              $instance['display'][$context]['type'] = 'date_default';
+              $instance['display'][$context]['settings']['format_type'] = str_replace('date_', '', $display['type']);
+              $changed = TRUE;
+            }
+          }
+          if ($changed) {
+            field_update_instance($instance);
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Get rid of the separate widgets for repeating dates. The code now handles
+ * repeating dates correctly using the regular widgets.
+ */
+function date_update_7001() {
+  $query = db_select('field_config_instance', 'fci', array('fetch' => PDO::FETCH_ASSOC));
+  $query->join('field_config', 'fc', 'fc.id = fci.field_id');
+  $query->fields('fci');
+  $query->condition(db_or()->condition('fc.type', 'date')->condition('fc.type', 'datestamp')->condition('fc.type', 'datetime'));
+  $results = $query->execute();
+
+  foreach ($results as $record) {
+    $instance = unserialize($record['data']);
+    if (in_array($instance['widget']['type'], array('date_popup_repeat', 'date_text_repeat', 'date_select_repeat'))) {
+      $instance['widget']['type'] = str_replace('_repeat', '', $instance['widget']['type']);
+      db_update('field_config_instance')
+        ->fields(array(
+          'data' => serialize($instance),
+        ))
+        ->condition('field_name', $record['field_name'])
+        ->condition('entity_type', $record['entity_type'])
+        ->condition('bundle', $record['bundle'])
+        ->execute();
+    }
+  }
+  field_cache_clear();
+  drupal_set_message(t('The widgets for repeating dates have changed. Please check the Display Fields page for each content type that has repeating date fields and confirm that the right widget has been selected.'), 'warning');
+}
+
+/**
+ * Add a notification about the new Date All Day module, and enable it.
+ */
+function date_update_7002() {
+  drupal_set_message(t("The <em>All Day</em> functionality has been moved into a separate module. This new module provides the option to add an <em>All Day</em> checkbox to toggle time on and off for date fields. It also contains the theme that displays the <em>All Day</em> text on fields that have no time. For consistency with prior code, it has been automatically enabled. If you don't want the <em>All Day</em> functionality you can disable this module."));
+  module_enable(array('date_all_day'));
+}
+
+/**
+ * Adds a notification about the new Date Repeat Field module, and enable it.
+ */
+function date_update_7003() {
+  drupal_set_message(t("The <em>Date Repeat</em> integration for Date fields is being moved into a separate module. For consistency with prior code, it has been automatically enabled if the Date Repeat API module is enabled. If you don't use <em>Date Repeat</em> functionality in your fields, you can disable this module."));
+  if (module_exists('date_repeat')) {
+    module_enable(array('date_repeat_field'));
+  }
+}
diff --git a/sites/all/modules/date/date.js b/sites/all/modules/date/date.js
new file mode 100644
index 0000000000000000000000000000000000000000..2e60175fb17e1e9b8e94df22dfabeacf9317e8b4
--- /dev/null
+++ b/sites/all/modules/date/date.js
@@ -0,0 +1,159 @@
+(function ($) {
+
+
+Drupal.behaviors.dateSelect = {};
+
+Drupal.behaviors.dateSelect.attach = function (context, settings) {
+  var $widget = $('.form-type-date-select').parents('fieldset').once('date');
+  var i;
+  for (i = 0; i < $widget.length; i++) {
+    new Drupal.date.EndDateHandler($widget[i]);
+  }
+};
+
+Drupal.date = Drupal.date || {};
+
+/**
+ * Constructor for the EndDateHandler object.
+ *
+ * The EndDateHandler is responsible for synchronizing a date select widget's
+ * end date with its start date. This behavior lasts until the user
+ * interacts with the end date widget.
+ *
+ * @param widget
+ *   The fieldset DOM element containing the from and to dates.
+ */
+Drupal.date.EndDateHandler = function (widget) {
+  this.$widget = $(widget);
+  this.$start = this.$widget.find('.form-type-date-select[class$=value]');
+  this.$end = this.$widget.find('.form-type-date-select[class$=value2]');
+  if (this.$end.length == 0) {
+    return;
+  }
+  this.initializeSelects();
+  // Only act on date fields where the end date is completely blank or already
+  // the same as the start date. Otherwise, we do not want to override whatever
+  // the default value was.
+  if (this.endDateIsBlank() || this.endDateIsSame()) {
+    this.bindClickHandlers();
+    // Start out with identical start and end dates.
+    this.syncEndDate();
+  }
+};
+
+/**
+ * Store all the select dropdowns in an array on the object, for later use.
+ */
+Drupal.date.EndDateHandler.prototype.initializeSelects = function () {
+  var $starts = this.$start.find('select');
+  var $end, $start, endId, i, id;
+  this.selects = {};
+  for (i = 0; i < $starts.length; i++) {
+    $start = $($starts[i]);
+    id = $start.attr('id');
+    endId = id.replace('-value-', '-value2-');
+    $end = $('#' + endId);
+    this.selects[id] = {
+      'id': id,
+      'start': $start,
+      'end': $end
+    };
+  }
+};
+
+/**
+ * Returns true if all dropdowns in the end date widget are blank.
+ */
+Drupal.date.EndDateHandler.prototype.endDateIsBlank = function () {
+  var id;
+  for (id in this.selects) {
+    if (this.selects.hasOwnProperty(id)) {
+      if (this.selects[id].end.val() != '') {
+        return false;
+      }
+    }
+  }
+  return true;
+};
+
+/**
+ * Returns true if the end date widget has the same value as the start date.
+ */
+Drupal.date.EndDateHandler.prototype.endDateIsSame = function () {
+  var id;
+  for (id in this.selects) {
+    if (this.selects.hasOwnProperty(id)) {
+      if (this.selects[id].end.val() != this.selects[id].start.val()) {
+        return false;
+      }
+    }
+  }
+  return true;
+};
+
+/**
+ * Add a click handler to each of the start date's select dropdowns.
+ */
+Drupal.date.EndDateHandler.prototype.bindClickHandlers = function () {
+  var id;
+  for (id in this.selects) {
+    if (this.selects.hasOwnProperty(id)) {
+      this.selects[id].start.bind('click.endDateHandler', this.startClickHandler.bind(this));
+      this.selects[id].end.bind('focus', this.endFocusHandler.bind(this));
+    }
+  }
+};
+
+/**
+ * Click event handler for each of the start date's select dropdowns.
+ */
+Drupal.date.EndDateHandler.prototype.startClickHandler = function (event) {
+  this.syncEndDate();
+};
+
+/**
+ * Focus event handler for each of the end date's select dropdowns.
+ */
+Drupal.date.EndDateHandler.prototype.endFocusHandler = function (event) {
+  var id;
+  for (id in this.selects) {
+    if (this.selects.hasOwnProperty(id)) {
+      this.selects[id].start.unbind('click.endDateHandler');
+    }
+  }
+  $(event.target).unbind('focus', this.endFocusHandler);
+};
+
+Drupal.date.EndDateHandler.prototype.syncEndDate = function () {
+  var id;
+  for (id in this.selects) {
+    if (this.selects.hasOwnProperty(id)) {
+      this.selects[id].end.val(this.selects[id].start.val());
+    }
+  }
+};
+
+}(jQuery));
+
+/**
+ * Function.prototype.bind polyfill for older browsers.
+ * https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
+ */
+if (!Function.prototype.bind) {
+  Function.prototype.bind = function (oThis) {
+    if (typeof this !== "function") // closest thing possible to the ECMAScript 5 internal IsCallable function
+      throw new TypeError("Function.prototype.bind - what is trying to be fBound is not callable");
+
+    var aArgs = Array.prototype.slice.call(arguments, 1),
+        fToBind = this,
+        fNOP = function () {},
+        fBound = function () {
+          return fToBind.apply(this instanceof fNOP ? this : oThis || window, aArgs.concat(Array.prototype.slice.call(arguments)));
+        };
+
+    fNOP.prototype = this.prototype;
+    fBound.prototype = new fNOP();
+
+    return fBound;
+  };
+}
diff --git a/sites/all/modules/date/date.module b/sites/all/modules/date/date.module
new file mode 100644
index 0000000000000000000000000000000000000000..4f6a0136f6f4f8941ce5a3a18eea9c06d8331033
--- /dev/null
+++ b/sites/all/modules/date/date.module
@@ -0,0 +1,743 @@
+<?php
+
+/**
+ * @file
+ * Defines date/time field types.
+ */
+
+module_load_include('theme', 'date', 'date');
+module_load_include('inc', 'date', 'date.field');
+module_load_include('inc', 'date', 'date_elements');
+
+/**
+ * Helper function to figure out the bundle name for an entity.
+ */
+function date_get_entity_bundle($entity_type, $entity) {
+  switch ($entity_type) {
+    case 'field_collection_item':
+      $bundle = $entity->field_name;
+      break;
+    default:
+      $bundle = field_extract_bundle($entity_type, $entity);
+      break;
+  }
+  // If there is no bundle name, field_info() uses the entity name as the bundle
+  // name in its arrays.
+  if (empty($bundle)) {
+    $bundle = $entity_type;
+  }
+  return $bundle;
+}
+
+/**
+ * Gets the default date format for the given field widget.
+ */
+function date_default_format($type) {
+  // Example input formats must show all possible date parts, so add seconds.
+  $default_format = str_replace('i', 'i:s', variable_get('date_format_short', 'm/d/Y - H:i'));
+  return $default_format;
+}
+
+/**
+ * Wrapper function around each of the widget types for creating a date object.
+ */
+function date_input_date($field, $instance, $element, $input) {
+  switch ($instance['widget']['type']) {
+    case 'date_text':
+      $function = 'date_text_input_date';
+      break;
+    case 'date_popup':
+      $function = 'date_popup_input_date';
+      break;
+    default:
+      $function = 'date_select_input_date';
+  }
+  return $function($element, $input);
+}
+
+/**
+ * Implements hook_theme().
+ */
+function date_theme() {
+  $path = drupal_get_path('module', 'date');
+  module_load_include('theme', 'date', 'date');
+
+  $base = array(
+    'file' => 'date.theme',
+    'path' => "$path",
+  );
+  $themes = array(
+    'date_combo' => $base + array('render element' => 'element'),
+    'date_text_parts' => $base + array('render element' => 'element'),
+    'date' => $base + array('render element' => 'element'),
+    'date_display_single' => $base + array(
+      'variables' => array(
+        'date' => NULL,
+        'timezone' => NULL,
+        'dates' => NULL,
+        'attributes' => array(),
+        'rdf_mapping' => NULL,
+        'add_rdf' => NULL,
+      ),
+    ),
+    'date_display_range' => $base + array(
+      'variables' => array(
+        'date1' => NULL,
+        'date2' => NULL,
+        'timezone' => NULL,
+        'dates' => NULL,
+        // HTML attributes that will be applied to both the start and end dates
+        // (unless overridden).
+        'attributes' => array(),
+        // HTML attributes that will be applied to the start date only.
+        'attributes_start' => array(),
+        // HTML attributes that will be applied to the end date only.
+        'attributes_end' => array(),
+        'rdf_mapping' => NULL,
+        'add_rdf' => NULL,
+    )),
+    'date_display_combination' => $base + array(
+      'variables' => array(
+        'entity_type' => NULL,
+        'entity' => NULL,
+        'field' => NULL,
+        'instance' => NULL,
+        'langcode' => NULL,
+        'item' => NULL,
+        'delta' => NULL,
+        'display' => NULL,
+        'dates' => NULL,
+        'attributes' => array(),
+        'rdf_mapping' => NULL,
+        'add_rdf' => NULL,
+      ),
+    ),
+    'date_display_interval' => $base + array(
+      'variables' => array(
+        'entity_type' => NULL,
+        'entity' => NULL,
+        'field' => NULL,
+        'instance' => NULL,
+        'langcode' => NULL,
+        'item' => NULL,
+        'delta' => NULL,
+        'display' => NULL,
+        'dates' => NULL,
+        'attributes' => array(),
+        'rdf_mapping' => NULL,
+        'add_rdf' => NULL,
+       ),
+    ),
+  );
+
+  return $themes;
+}
+
+/**
+ * Implements hook_element_info().
+ *
+ * date_combo will create a 'start' and optional 'end' date, along with
+ * an optional 'timezone' column for date-specific timezones. Each
+ * 'start' and 'end' date will be constructed from date_select or date_text.
+ */
+function date_element_info() {
+  $type = array();
+  $type['date_combo'] = array(
+    '#input' => TRUE,
+    '#delta' => 0,
+    '#columns' => array('value', 'value2', 'timezone', 'offset', 'offset2'),
+    '#process' => array('date_combo_element_process'),
+    '#element_validate' => array('date_combo_validate'),
+    '#theme_wrappers' => array('date_combo'),
+  );
+  if (module_exists('ctools')) {
+    $type['date_combo']['#pre_render'] = array('ctools_dependent_pre_render');
+  }
+  return $type;
+}
+
+/**
+ * Helper function for creating formatted date arrays from a formatter.
+ *
+ * Use the Date API to get an object representation of a date field.
+ *
+ * @param string $formatter
+ *   The date formatter.
+ * @param string $entity_type
+ *   The entity_type for the instance
+ * @param object $entity
+ *   The entity object.
+ * @param array $field
+ *   The field info array.
+ * @param array $instance
+ *   The field instance array.
+ * @param string $langcode
+ *   The language code used by this field.
+ * @param array $item
+ *   An entity field item, like $entity->myfield[0].
+ * @param array $display
+ *   The instance display settings.
+ *
+ * @return array
+ *   An array that holds the Start and End date objects.
+ *   Each date object looks like:
+ *     date [value] => array (
+ *       [db] => array (  // the value stored in the database
+ *         [object] => the datetime object
+ *         [datetime] => 2007-02-15 20:00:00
+ *       )
+ *       [local] => array (  // the local representation of that value
+ *         [object] => the datetime object
+ *         [datetime] => 2007-02-15 14:00:00
+ *         [timezone] => US/Central
+ *         [offset] => -21600
+ *       )
+ *     )
+ */
+function date_formatter_process($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display) {
+  $dates = array();
+  $timezone = date_default_timezone();
+  if (empty($timezone)) {
+    return $dates;
+  }
+
+  $granularity = date_granularity($field);
+  $settings = $display['settings'];
+  $field_name = $field['field_name'];
+  $format = date_formatter_format($formatter, $settings, $granularity, $langcode);
+  $timezone = isset($item['timezone']) ? $item['timezone'] : '';
+  $timezone = date_get_timezone($field['settings']['tz_handling'], $timezone);
+  $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
+  $db_format = date_type_format($field['type']);
+  $process = date_process_values($field);
+  foreach ($process as $processed) {
+    if (empty($item[$processed])) {
+      $dates[$processed] = NULL;
+    }
+    else {
+      // Create a date object with a GMT timezone from the database value.
+      $dates[$processed] = array();
+
+      // Check to see if this date was already created by date_field_load().
+      if (isset($item['db'][$processed])) {
+        $date = $item['db'][$processed];
+      }
+      else {
+        $date = new DateObject($item[$processed], $timezone_db, $db_format);
+        $date->limitGranularity($field['settings']['granularity']);
+      }
+
+      $dates[$processed]['db']['object'] = $date;
+      $dates[$processed]['db']['datetime'] = date_format($date, DATE_FORMAT_DATETIME);
+
+      date_timezone_set($date, timezone_open($timezone));
+      $dates[$processed]['local']['object'] = $date;
+      $dates[$processed]['local']['datetime'] = date_format($date, DATE_FORMAT_DATETIME);
+      $dates[$processed]['local']['timezone'] = $timezone;
+      $dates[$processed]['local']['offset'] = date_offset_get($date);
+
+      // Format the date, special casing the 'interval' format which doesn't
+      // need to be processed.
+      $dates[$processed]['formatted'] = '';
+      $dates[$processed]['formatted_iso'] = date_format_date($date, 'custom', 'c');
+      if (is_object($date)) {
+        if ($format == 'format_interval') {
+           $dates[$processed]['interval'] = date_format_interval($date);
+        }
+        elseif ($format == 'format_calendar_day') {
+           $dates[$processed]['calendar_day'] = date_format_calendar_day($date);
+        }
+        elseif ($format == 'U') {
+          $dates[$processed]['formatted'] = date_format_date($date, 'custom', $format);
+          $dates[$processed]['formatted_date'] = date_format_date($date, 'custom', $format);
+          $dates[$processed]['formatted_time'] = '';
+          $dates[$processed]['formatted_timezone'] = '';
+        }
+        elseif (!empty($format)) {
+          $dates[$processed]['formatted'] = date_format_date($date, 'custom', $format);
+          $dates[$processed]['formatted_date'] = date_format_date($date, 'custom', date_limit_format($format, array('year', 'month', 'day')));
+          $dates[$processed]['formatted_time'] = date_format_date($date, 'custom', date_limit_format($format, array('hour', 'minute', 'second')));
+          $dates[$processed]['formatted_timezone'] = date_format_date($date, 'custom', date_limit_format($format, array('timezone')));
+        }
+      }
+    }
+  }
+
+  if (empty($dates['value2'])) {
+    $dates['value2'] = $dates['value'];
+  }
+
+  // Allow other modules to alter the date values.
+  $context = array(
+    'field' => $field,
+    'instance' => $instance,
+    'format' => $format,
+    'entity_type' => $entity_type,
+    'entity' => $entity,
+    'langcode' => $langcode,
+    'item' => $item,
+    'display' => $display,
+  );
+  drupal_alter('date_formatter_dates', $dates, $context);
+
+  $dates['format'] = $format;
+  return $dates;
+}
+
+/**
+ * Retrieves the granularity for a field.
+ *
+ * $field['settings']['granularity'] will contain an array like
+ * ('hour' => 'hour', 'month' => 0) where the values turned on return their own
+ * names and the values turned off return a zero need to reconfigure this into
+ * simple array of the turned on values
+ *
+ * @param array $field
+ *   The field array.
+ */
+function date_granularity($field) {
+  if (!is_array($field) || !is_array($field['settings']['granularity'])) {
+    $field['settings']['granularity'] = drupal_map_assoc(array('year', 'month', 'day'));
+  }
+  return array_values(array_filter($field['settings']['granularity']));
+}
+
+/**
+ * Helper function to create an array of the date values in a
+ * field that need to be processed.
+ */
+function date_process_values($field) {
+  return $field['settings']['todate'] ? array('value', 'value2') : array('value');
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for field_ui_field_edit_form().
+ */
+function date_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
+  $field = $form['#field'];
+  $instance = $form['#instance'];
+
+  if (!in_array($field['type'], array('date', 'datetime', 'datestamp'))) {
+    return;
+  }
+
+  // Reorganize the instance settings and widget settings sections into a more
+  // intuitive combined fieldset.
+  $form['instance']['defaults'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('More settings and values'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  $form['instance']['date_format'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Date entry'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+  $form['instance']['default_values'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Default values'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+  $form['instance']['years_back_and_forward'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Starting and ending year'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+
+  $form['instance']['#pre_render'][] = 'date_field_ui_field_edit_form_pre_render';
+}
+
+/**
+ * Rearrange form elements into fieldsets for presentation only.
+ */
+function date_field_ui_field_edit_form_pre_render($form) {
+  foreach ($form as $name => $element) {
+    if (is_array($element) && isset($element['#fieldset'])) {
+      $fieldset = $element['#fieldset'];
+      $form[$fieldset][$name] = $element;
+      unset($form[$name]);
+    }
+  }
+  foreach (array('date_format', 'default_values', 'years_back_and_forward') as $name) {
+    if (element_children($form[$name])) {
+      // Force the items in the fieldset to be resorted now that the instance
+      // and widget settings are combined.
+      $form[$name]['#sorted'] = FALSE;
+      $form['defaults'][$name] = $form[$name];
+    }
+    unset($form[$name]);
+  }
+  return $form;
+}
+
+/**
+ * Implements hook_field_widget_error().
+ */
+function date_field_widget_error($element, $error, $form, &$form_state) {
+  form_error($element[$error['error']], $error['message']);
+}
+
+/**
+ * Retrieve a date format string from formatter settings.
+ */
+function date_formatter_format($formatter, $settings, $granularity = array(), $langcode = NULL) {
+  $format_type = !empty($settings['format_type']) ? $settings['format_type'] : 'format_interval';
+
+  switch ($formatter) {
+    case 'format_interval':
+      return 'format_interval';
+      break;
+    case 'date_plain':
+      return 'date_plain';
+      break;
+    default:
+      $format = date_format_type_format($format_type, $langcode);
+      break;
+  }
+
+  // A selected format might include timezone information.
+  array_push($granularity, 'timezone');
+  return date_limit_format($format, $granularity);
+}
+
+/**
+ * Helper function to get the right format for a format type.
+ * Checks for locale-based format first.
+ */
+function date_format_type_format($format_type, $langcode = NULL) {
+  $static = &drupal_static(__FUNCTION__);
+  if (!isset($static[$langcode][$format_type])) {
+    $format = system_date_format_locale($langcode, $format_type);
+
+    // If locale enabled and $format_type inexistent in {date_format_locale}
+    // we receive (due to inconsistency of core api) an array of all (other)
+    // formats available for $langcode in locale table.
+    // However there's no guarantee that the key $format_type exists.
+    // See http://drupal.org/node/1302358.
+    if (!is_string($format)) {
+      // If the configuration page at admin/config/regional/date-time was
+      // never saved, the default core date format variables
+      // ('date_format_short', 'date_format_medium', and 'date_format_long')
+      // will not be stored in the database, so we have to define their
+      // expected defaults here.
+      switch ($format_type) {
+        case 'short':
+          $default = 'm/d/Y - H:i';
+          break;
+        case 'long':
+          $default = 'l, F j, Y - H:i';
+          break;
+        // If it's not one of the core date types and isn't stored in the
+        // database, we'll fall back on using the same default format as the
+        // 'medium' type.
+        case 'medium':
+        default:
+          // @todo: If a non-core module provides a date type and does not
+          //   variable_set() a default for it, the default assumed here may
+          //   not be correct (since the default format used by 'medium' may
+          //   not even be one of the allowed formats for the date type in
+          //   question). To fix this properly, we should really call
+          //   system_get_date_formats($format_type) and take the first
+          //   format from that list as the default. However, this function
+          //   is called often (on many different page requests), so calling
+          //   system_get_date_formats() from here would be a performance hit
+          //   since that function writes several records to the database
+          //   during each page request that calls it.
+          $default = 'D, m/d/Y - H:i';
+          break;
+      }
+      $format = variable_get('date_format_' . $format_type, $default);
+    }
+    $static[$langcode][$format_type] = $format;
+  }
+  return $static[$langcode][$format_type];
+}
+
+/**
+ * Helper function to adapt entity date fields to formatter settings.
+ */
+function date_prepare_entity($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display) {
+  // If there are options to limit multiple values,
+  // alter the entity values to match.
+  $field_name = $field['field_name'];
+  $options = $display['settings'];
+  $max_count = $options['multiple_number'];
+
+  // If no results should be shown, empty the values and return.
+  if (is_numeric($max_count) && $max_count == 0) {
+    $entity->{$field_name} = array();
+    return $entity;
+  }
+
+  // Otherwise removed values that should not be displayed.
+  if (!empty($options['multiple_from']) || !empty($options['multiple_to']) || !empty($max_count)) {
+    $format = date_type_format($field['type']);
+    include_once drupal_get_path('module', 'date_api') . '/date_api_sql.inc';
+    $date_handler = new date_sql_handler($field);
+    $arg0 = !empty($options['multiple_from']) ? $date_handler->arg_replace($options['multiple_from']) : variable_get('date_min_year', 100) . '-01-01T00:00:00';
+    $arg1 = !empty($options['multiple_to']) ? $date_handler->arg_replace($options['multiple_to']) : variable_get('date_max_year', 4000) . '-12-31T23:59:59';
+    if (!empty($arg0) && !empty($arg1)) {
+      $arg = $arg0 . '--' . $arg1;
+    }
+    elseif (!empty($arg0)) {
+      $arg = $arg0;
+    }
+    elseif (!empty($arg1)) {
+      $arg = $arg1;
+    }
+    if (!empty($arg)) {
+      $range = $date_handler->arg_range($arg);
+      $start = date_format($range[0], $format);
+      $end = date_format($range[1], $format);
+      // Empty out values we don't want to see.
+      $count = 0;
+      foreach ($entity->{$field_name}[$langcode] as $delta => $value) {
+        if (!empty($entity->date_repeat_show_all)) {
+          break;
+        }
+        elseif ((!empty($max_count) && is_numeric($max_count) && $count >= $max_count) ||
+          (!empty($value['value'])  && $value['value'] < $start) ||
+          (!empty($value['value2']) && $value['value2'] > $end)) {
+            unset($entity->{$field_name}[$langcode][$delta]);
+        }
+        else {
+          $count++;
+        }
+      }
+    }
+  }
+
+  return $entity;
+}
+
+/**
+ * Callback to alter the property info of date fields.
+ *
+ * @see date_field_info()
+ */
+function date_entity_metadata_property_info_alter(&$info, $entity_type, $field, $instance, $field_type) {
+  $name = $field['field_name'];
+  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
+
+  if ($field['type'] != 'datestamp' || $field['settings']['timezone_db'] != 'UTC') {
+    // Add a getter callback to convert the date into the right format.
+    $property['getter callback'] = 'date_entity_metadata_field_getter';
+    $property['setter callback'] = 'date_entity_metadata_field_setter';
+    unset($property['query callback']);
+  }
+  if (!empty($field['settings']['todate'])) {
+    // Define a simple data structure containing both dates.
+    $property['type'] = ($field['cardinality'] != 1) ? 'list<struct>' : 'struct';
+    $property['getter callback'] = 'entity_metadata_field_verbatim_get';
+    $property['setter callback'] = 'entity_metadata_field_verbatim_set';
+    $property['property info'] = array(
+      'value' => array(
+        'type' => 'date',
+        'label' => t('Start date'),
+        'getter callback' => 'date_entity_metadata_struct_getter',
+        'setter callback' => 'date_entity_metadata_struct_setter',
+        // The getter and setter callbacks for 'value' and 'value2'
+        // will not provide the field name as $name, we'll add it to $info.
+        'field_name' => $field['field_name'],
+      ),
+      'value2' => array(
+        'type' => 'date',
+        'label' => t('End date'),
+        'getter callback' => 'date_entity_metadata_struct_getter',
+        'setter callback' => 'date_entity_metadata_struct_setter',
+        // The getter and setter callbacks for 'value' and 'value2'
+        // will not provide the field name as $name, we'll add it to $info.
+        'field_name' => $field['field_name'],
+      ),
+      'duration' => array(
+        'type' => 'duration',
+        'label' => t('Duration'),
+        'desription' => t('The duration of the time period given by the dates.'),
+        'getter callback' => 'date_entity_metadata_duration_getter',
+        // No setter callback for duration.
+        // The getter callback for duration will not provide the field name
+        // as $name, we'll add it to $info.
+        'field_name' => $field['field_name'],
+      ),
+    );
+    unset($property['query callback']);
+  }
+}
+
+/**
+ * Getter callback to return date values as datestamp in UTC from the field.
+ */
+function date_entity_metadata_field_getter($entity, array $options, $name, $entity_type, &$context) {
+  $return = entity_metadata_field_verbatim_get($entity, $options, $name, $entity_type, $context);
+  $items = ($context['field']['cardinality'] == 1) ? array($return) : $return;
+  foreach ($items as $key => $item) {
+    $items[$key] = date_entity_metadata_struct_getter($item, $options, 'value', 'struct', $context);
+  }
+  return ($context['field']['cardinality'] == 1) ? $items[0] : $items;
+}
+
+/**
+ * Getter callback to return date values as datestamp in UTC.
+ */
+function date_entity_metadata_struct_getter($item, array $options, $name, $type, $info) {
+  $value = trim($item[$name]);
+  if (empty($value)) {
+    return NULL;
+  }
+
+  $timezone_db = !empty($item['timezone_db']) ? $item['timezone_db'] : 'UTC';
+  $date = new DateObject($value, $timezone_db);
+  return !empty($date) ? date_format_date($date, 'custom', 'U') : NULL;
+}
+
+/**
+ * Getter callback to return the duration of the time period given by the dates.
+ */
+function date_entity_metadata_duration_getter($item, array $options, $name, $type, $info) {
+  $value = date_entity_metadata_struct_getter($item, $options, 'value', 'struct', $info);
+  $value2 = date_entity_metadata_struct_getter($item, $options, 'value2', 'struct', $info);
+  if ($value && $value2) {
+    return $value2 - $value;
+  }
+}
+
+/**
+ * Callback for setting field property values.
+ *
+ * Based on entity_metadata_field_property_set(), the original property setter,
+ * adapted to transform non-timestamp date values to timestamps.
+ */
+function date_entity_metadata_field_setter(&$entity, $name, $value, $langcode, $entity_type, $info) {
+  $field = field_info_field($name);
+  if (!isset($langcode)) {
+    // Try to figure out the default language used by the entity.
+    // @todo: Update once http://drupal.org/node/1260640 has been fixed.
+    $langcode = isset($entity->language) ? $entity->language : LANGUAGE_NONE;
+  }
+  $values = $field['cardinality'] == 1 ? array($value) : (array) $value;
+
+  $items = array();
+  foreach ($values as $delta => $value) {
+    // Make use of the struct setter to convert the date back to a timestamp.
+    $info['field_name'] = $name;
+    date_entity_metadata_struct_setter($items[$delta], 'value', $value, $langcode, 'struct', $info);
+  }
+  $entity->{$name}[$langcode] = $items;
+  // Empty the static field language cache, so the field system picks up any
+  // possible new languages.
+  drupal_static_reset('field_language');
+}
+
+/**
+ * Callback for setting an individual field value if a to-date may be there too.
+ * Based on entity_property_verbatim_set().
+ *
+ * The passed in unix timestamp (UTC) is converted to the right value and
+ * format dependent on the field.
+ *
+ * $name is either 'value' or 'value2'.
+ */
+function date_entity_metadata_struct_setter(&$item, $name, $value, $langcode, $type, $info) {
+  if (!isset($value)) {
+    $item[$name] = NULL;
+  }
+  else {
+    $field = field_info_field($info['field_name']);
+    $format = date_type_format($field['type']);
+    $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
+
+    $date = new DateObject($value, 'UTC');
+    if ($timezone_db != 'UTC') {
+      date_timezone_set($date, timezone_open($timezone_db));
+    }
+    $item[$name] = $date->format($format);
+  }
+}
+
+/**
+ * Duplicate functionality of what is now date_all_day_field() in
+ * the Date All Day module. Copy left here to avoid breaking other
+ * modules that use this function.
+ *
+ * DEPRECATED!, will be removed at some time in the future.
+ */
+function date_field_all_day($field, $instance, $date1, $date2 = NULL) {
+  if (empty($date1) || !is_object($date1)) {
+    return FALSE;
+  }
+  elseif (!date_has_time($field['settings']['granularity'])) {
+    return TRUE;
+  }
+  if (empty($date2)) {
+    $date2 = $date1;
+  }
+
+  $granularity = date_granularity_precision($field['settings']['granularity']);
+  $increment = isset($instance['widget']['settings']['increment']) ? $instance['widget']['settings']['increment'] : 1;
+  return date_is_all_day(date_format($date1, DATE_FORMAT_DATETIME), date_format($date2, DATE_FORMAT_DATETIME), $granularity, $increment);
+}
+
+/**
+ * Generates a Date API SQL handler for the given date field.
+ *
+ * The handler will be set up to make the correct timezone adjustments
+ * for the field settings.
+ *
+ * @param array $field
+ *   The $field array.
+ * @param string $compare_tz
+ *   The timezone used for comparison values in the SQL.
+ *
+ * DEPRECATED!, will be removed at some time in the future.
+ */
+function date_field_get_sql_handler($field, $compare_tz = NULL) {
+  module_load_include('inc', 'date_api', 'date_api_sql');
+
+  $db_info = date_api_database_info($field);
+
+  // Create a DateAPI SQL handler class for this field type.
+  $handler = new date_sql_handler($field['type']);
+
+  // If this date field stores a timezone in the DB, tell the handler about it.
+  if ($field['settings']['tz_handling'] == 'date') {
+    $handler->db_timezone_field = $db_info['columns']['timezone']['column'];
+  }
+  else {
+    $handler->db_timezone = date_get_timezone_db($field['settings']['tz_handling']);
+  }
+
+  if (empty($compare_tz)) {
+    $compare_tz = date_get_timezone($field['settings']['tz_handling']);
+  }
+  $handler->local_timezone = $compare_tz;
+
+  // Now that the handler is properly initialized, force the DB
+  // to use UTC so no timezone conversions get added to things like
+  // NOW() or FROM_UNIXTIME().
+  $handler->set_db_timezone();
+
+  return $handler;
+}
+
+/**
+ * Implements hook_field_widget_properties_alter().
+ *
+ * Alters the widget properties of a field instance before it gets displayed.
+ * Used here to flag new entities so we can later tell if they need default values.
+ */
+function date_field_widget_properties_alter(&$widget, $context) {
+  if (in_array($widget['type'], array('date_select', 'date_text', 'date_popup'))) {
+    $entity_type = $context['entity_type'];
+    $entity = $context['entity'];
+    $info = entity_get_info($entity_type);
+    $id = $info['entity keys']['id'];
+    $widget['is_new']= FALSE;
+    if (empty($entity->$id)) {
+      $widget['is_new'] = TRUE;
+    }
+  }
+}
diff --git a/sites/all/modules/date/date.theme b/sites/all/modules/date/date.theme
new file mode 100644
index 0000000000000000000000000000000000000000..0d28be021f238fbffc34d4b6cb7340403d13c0ba
--- /dev/null
+++ b/sites/all/modules/date/date.theme
@@ -0,0 +1,349 @@
+<?php
+
+/**
+ * @file
+ * Theme functions.
+ */
+
+/**
+ * @addtogroup themeable
+ * @{
+ *
+ * Formatter themes
+ */
+
+/**
+ * Returns HTML for a date element formatted as a Start/End combination.
+ *
+ *  $entity->date_id
+ *    If set, this will show only an individual date on a field with
+ *    multiple dates. The value should be a string that contains
+ *    the following values, separated with periods:
+ *    - module name of the module adding the item
+ *    - node nid
+ *    - field name
+ *    - delta value of the field to be displayed
+ *    - other information the module's custom theme might need
+ *
+ *    Used by the calendar module and available for other uses.
+ *    example: 'date.217.field_date.3.test'
+ *
+ *  $entity->date_repeat_show
+ *    If true, tells the theme to show all the computed values of a repeating
+ *    date. If not true or not set, only the start date and the repeat rule
+ *    will be displayed.
+ *
+ *  $dates['format']
+ *    The format string used on these dates
+ *  $dates['value']['local']['object']
+ *    The local date object for the Start date
+ *  $dates['value2']['local']['object']
+ *    The local date object for the End date
+ *  $dates['value']['local']['datetime']
+ *    The datetime value of the Start date database (GMT) value
+ *  $dates['value2']['local']['datetime']
+ *    The datetime value of the End date database (GMT) value
+ *  $dates['value']['formatted']
+ *    Formatted Start date, i.e. 'February 15, 2007 2:00 pm';
+ *  $dates['value']['formatted_date']
+ *    Only the date part of the formatted Start date
+ *  $dates['value']['formatted_time']
+ *    Only the time part of the formatted Start date
+ *  $dates['value2']['formatted']
+ *    Formatted End date, i.e. 'February 15, 2007 6:00 pm';
+ *  $dates['value2']['formatted_date']
+ *    Only the date part of the formatted End date
+ *  $dates['value2']['formatted_time']
+ *    Only the time part of the formatted End date
+ */
+function theme_date_display_combination($variables) {
+  static $repeating_ids = array();
+
+  $entity_type = $variables['entity_type'];
+  $entity      = $variables['entity'];
+  $field       = $variables['field'];
+  $instance    = $variables['instance'];
+  $langcode    = $variables['langcode'];
+  $item        = $variables['item'];
+  $delta       = $variables['delta'];
+  $display     = $variables['display'];
+  $field_name  = $field['field_name'];
+  $formatter   = $display['type'];
+  $options     = $display['settings'];
+  $dates       = $variables['dates'];
+  $attributes  = $variables['attributes'];
+  $rdf_mapping = $variables['rdf_mapping'];
+  $add_rdf     = $variables['add_rdf'];
+  $precision   = date_granularity_precision($field['settings']['granularity']);
+
+  $output = '';
+
+  // If date_id is set for this field and delta doesn't match, don't display it.
+  if (!empty($entity->date_id)) {
+    foreach ((array) $entity->date_id as $key => $id) {
+      list($module, $nid, $field_name, $item_delta, $other) = explode('.', $id . '.');
+      if ($field_name == $field['field_name'] && isset($delta) && $item_delta != $delta) {
+        return $output;
+      }
+    }
+  }
+
+  // Check the formatter settings to see if the repeat rule should be displayed.
+  // Show it only with the first multiple value date.
+  list($id) = entity_extract_ids($entity_type, $entity);
+  if (!in_array($id, $repeating_ids) && module_exists('date_repeat_field') && !empty($item['rrule']) && $options['show_repeat_rule'] == 'show') {
+    $repeat_vars = array(
+      'field' => $field,
+      'item' => $item,
+      'entity_type' => $entity_type,
+      'entity' => $entity,
+    );
+    $output .= theme('date_repeat_display', $repeat_vars);
+    $repeating_ids[] = $id;
+  }
+
+  // If this is a full node or a pseudo node created by grouping multiple
+  // values, see exactly which values are supposed to be visible.
+  if (isset($entity->$field_name)) {
+    $entity = date_prepare_entity($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display);
+    // Did the current value get removed by formatter settings?
+    if (empty($entity->{$field_name}[$langcode][$delta])) {
+      return $output;
+    }
+    // Adjust the $element values to match the changes.
+    $element['#entity'] = $entity;
+  }
+
+  switch ($options['fromto']) {
+    case 'value':
+      $date1 = $dates['value']['formatted'];
+      $date2 = $date1;
+      break;
+    case 'value2':
+      $date2 = $dates['value2']['formatted'];
+      $date1 = $date2;
+      break;
+    default:
+      $date1 = $dates['value']['formatted'];
+      $date2 = $dates['value2']['formatted'];
+      break;
+  }
+
+  // Pull the timezone, if any, out of the formatted result and tack it back on
+  // at the end, if it is in the current formatted date.
+  $timezone = $dates['value']['formatted_timezone'];
+  if ($timezone) {
+    $timezone = ' ' . $timezone;
+  }
+  $date1 = str_replace($timezone, '', $date1);
+  $date2 = str_replace($timezone, '', $date2);
+  $time1 = preg_replace('`^([\(\[])`', '', $dates['value']['formatted_time']);
+  $time1 = preg_replace('([\)\]]$)', '', $time1);
+  $time2 = preg_replace('`^([\(\[])`', '', $dates['value2']['formatted_time']);
+  $time2 = preg_replace('([\)\]]$)', '', $time2);
+
+  // A date with a granularity of 'hour' has a time string that is an integer
+  // value. We can't use that to replace time strings in formatted dates.
+  $has_time_string = date_has_time($field['settings']['granularity']);
+  if ($precision == 'hour') {
+    $has_time_string = FALSE;
+  }
+
+  // No date values, display nothing.
+  if (empty($date1) && empty($date2)) {
+    $output .= '';
+  }
+  // Start and End dates match or there is no End date, display a complete
+  // single date.
+  elseif ($date1 == $date2 || empty($date2)) {
+    $output .= theme('date_display_single', array(
+      'date' => $date1,
+      'timezone' => $timezone,
+      'attributes' => $attributes,
+      'rdf_mapping' => $rdf_mapping,
+      'add_rdf' => $add_rdf,
+      'dates' => $dates,
+    ));
+  }
+  // Same day, different times, don't repeat the date but show both Start and
+  // End times. We can NOT do this if the replacement value is an integer
+  // instead of a time string.
+  elseif ($has_time_string && $dates['value']['formatted_date'] == $dates['value2']['formatted_date']) {
+    // Replace the original time with the start/end time in the formatted start
+    // date. Make sure that parentheses or brackets wrapping the time will be
+    // retained in the final result.
+    $time = theme('date_display_range', array(
+      'date1' => $time1,
+      'date2' => $time2,
+      'timezone' => $timezone,
+      'attributes' => $attributes,
+      'rdf_mapping' => $rdf_mapping,
+      'add_rdf' => $add_rdf,
+      'dates' => $dates,
+    ));
+    $replaced = str_replace($time1, $time, $date1);
+    $output .= theme('date_display_single', array(
+      'date' => $replaced,
+      'timezone' => $timezone,
+      'attributes' => array(),
+      'rdf_mapping' => array(),
+      'add_rdf' => FALSE,
+      'dates' => $dates,
+    ));
+  }
+  // Different days, display both in their entirety.
+  else {
+    $output .= theme('date_display_range', array(
+      'date1' => $date1,
+      'date2' => $date2,
+      'timezone' => $timezone,
+      'attributes' => $attributes,
+      'rdf_mapping' => $rdf_mapping,
+      'add_rdf' => $add_rdf,
+      'dates' => $dates,
+    ));
+  }
+
+  return $output;
+}
+
+/**
+ * Template preprocess function for displaying a single date.
+ */
+function template_preprocess_date_display_single(&$variables) {
+  if ($variables['add_rdf']) {
+    // Pass along the rdf mapping for this field, if any. Add some default rdf
+    // attributes that will be used if not overridden by attributes passed in.
+    $rdf_mapping = $variables['rdf_mapping'];
+    $base_attributes = array(
+      'property' => array('dc:date'),
+      'datatype' => 'xsd:dateTime',
+      'content' => $variables['dates']['value']['formatted_iso'],
+    );
+    $variables['attributes'] = $variables['attributes'] + $base_attributes;
+  }
+}
+
+/**
+ * Returns HTML for a date element formatted as a single date.
+ */
+function theme_date_display_single($variables) {
+  $date = $variables['date'];
+  $timezone = $variables['timezone'];
+  $attributes = $variables['attributes'];
+
+  // Wrap the result with the attributes.
+  return '<span class="date-display-single"' . drupal_attributes($attributes) . '>' . $date . $timezone . '</span>';
+}
+
+/**
+ * Template preprocess function for displaying a range of dates.
+ */
+function template_preprocess_date_display_range(&$variables) {
+  // Merge in the shared attributes for themes to use.
+  $variables['attributes_start'] += $variables['attributes'];
+  $variables['attributes_end'] += $variables['attributes'];
+
+  if ($variables['add_rdf']) {
+    // Pass along the rdf mapping for this field, if any. Add some default rdf
+    // attributes that will be used if not overridden by attributes passed in.
+    $rdf_mapping = $variables['rdf_mapping'];
+    $dates = $variables['dates'];
+    $base_attributes = array(
+      'property' => array('dc:date'),
+      'datatype' => 'xsd:dateTime',
+      'content' => $dates['value']['formatted_iso'],
+    );
+    $variables['attributes_start'] += $base_attributes;
+    $variables['attributes_end'] += $base_attributes;
+    $variables['attributes_end']['content'] = $dates['value2']['formatted_iso'];
+    foreach ($variables['attributes_end']['property'] as $delta => $property) {
+      $variables['attributes_end']['property'][$delta] = str_replace('start', 'end', $property);
+    }
+  }
+}
+
+/**
+ * Returns HTML for a date element formatted as a range.
+ */
+function theme_date_display_range($variables) {
+  $date1 = $variables['date1'];
+  $date2 = $variables['date2'];
+  $timezone = $variables['timezone'];
+  $attributes_start = $variables['attributes_start'];
+  $attributes_end = $variables['attributes_end'];
+
+  // Wrap the result with the attributes.
+  return t('!start-date to !end-date', array(
+    '!start-date' => '<span class="date-display-start"' . drupal_attributes($attributes_start) . '>' . $date1 . '</span>',
+    '!end-date' => '<span class="date-display-end"' . drupal_attributes($attributes_end) . '>' . $date2 . $timezone . '</span>',
+  ));
+}
+
+/**
+ * Returns HTML for a date element formatted as an interval.
+ */
+function theme_date_display_interval($variables) {
+  $entity = $variables['entity'];
+  $options = $variables['display']['settings'];
+  $dates = $variables['dates'];
+  $attributes = $variables['attributes'];
+
+  // Get the formatter settings, either the default settings for this node type
+  // or the View settings stored in $entity->date_info.
+  if (!empty($entity->date_info) && !empty($entity->date_info->formatter_settings)) {
+    $options = $entity->date_info->formatter_settings;
+  }
+
+  $time_ago_vars = array(
+    'start_date' => $dates['value']['local']['object'],
+    'end_date' => $dates['value2']['local']['object'],
+    'interval' => $options['interval'],
+    'interval_display' => $options['interval_display'],
+  );
+  return '<span class="date-display-interval"' . drupal_attributes($attributes) . '>' . theme('date_time_ago', $time_ago_vars) . '</span>';
+}
+
+/**
+ * Returns HTML for a start/end date combination on form.
+ */
+function theme_date_combo($variables) {
+  $element = $variables['element'];
+  $field = field_info_field($element['#field_name']);
+  $instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
+
+  // Group start/end items together in fieldset.
+  $fieldset = array(
+    '#title' => t($element['#title']) . ' ' . ($element['#delta'] > 0 ? intval($element['#delta'] + 1) : ''),
+    '#value' => '',
+    '#description' => !empty($element['#fieldset_description']) ? $element['#fieldset_description'] : '',
+    '#attributes' => array(),
+    '#children' => $element['#children'],
+  );
+  return theme('fieldset', array('element' => $fieldset));
+}
+
+/**
+ * Returns HTML for the text/select options for date parts in a table.
+ */
+function theme_date_text_parts($variables) {
+  $element = $variables['element'];
+  $rows = array();
+  foreach (date_granularity_names() as $key => $part) {
+    if ($element[$key]['#type'] == 'hidden') {
+      $rows[] = drupal_render($element[$key]);
+    }
+    else {
+      $rows[] = array($part, drupal_render($element[$key][0]), drupal_render($element[$key][1]));
+    }
+  }
+  if ($element['year']['#type'] == 'hidden') {
+    return implode($rows) . drupal_render_children($element);
+  }
+  else {
+    $header = array(t('Date part'), t('Select list'), t('Text field'));
+    return theme('table', array('header' => $header, 'rows' => $rows)) . drupal_render_children($element);
+  }
+}
+
+/** @} End of addtogroup themeable */
diff --git a/sites/all/modules/date/date.tokens.inc b/sites/all/modules/date/date.tokens.inc
new file mode 100644
index 0000000000000000000000000000000000000000..5caab14bc535b59f6eb36c02baaa431223d376d8
--- /dev/null
+++ b/sites/all/modules/date/date.tokens.inc
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Token module integration.
+ */
+
+/**
+ * Implements hook_token_info().
+ */
+function date_token_info() {
+  // All date types can share the same date value type.
+  $info['types']['date-field-value'] = array(
+    'name' => t('Date field values'),
+    'description' => t('Tokens related to date field values.'),
+    'needs-data' => 'date-field-value',
+    'field-value' => TRUE,
+  );
+  // Provide two tokens: 'date' (the date or start-date), and 'end-date'.
+  $info['tokens']['date-field-value']['date'] = array(
+    'name' => t('Date'),
+    'description' => t('The date value.'),
+    'type' => 'date',
+  );
+  $info['tokens']['date-field-value']['to-date'] = array(
+    'name' => t('End Date'),
+    'description' => t('The End date value.'),
+    'type' => 'date',
+  );
+
+  return $info;
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function date_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  $replacements = array();
+  $language_code = isset($options['language']) ? $options['language']->language : NULL;
+
+  if (($type == 'date-field-value') && !empty($data['item'])) {
+    $item = $data['item'];
+
+    // Create tokens for the field "Date" or "Start date".
+    if (($date_tokens = token_find_with_prefix($tokens, 'date')) && !empty($item['value'])) {
+      // Load the Start date and convert to a unix timestamp.
+      $date = new DateObject($item['value'], $item['timezone_db'], date_type_format($item['date_type']));
+      if (!empty($date) && $item['timezone_db'] != $item['timezone']) {
+        date_timezone_set($date, timezone_open($item['timezone']));
+      }
+      $timestamp = !empty($date) ? date_format_date($date, 'custom', 'U') : '';
+      // Generate the token replacements, using the date token type provided
+      // by system.module.
+      $replacements += token_generate('date', $date_tokens, array('date' => $timestamp), $options);
+    }
+
+    // Create tokens for the field "End date".
+    if (($date_tokens = token_find_with_prefix($tokens, 'end-date')) && !empty($item['value2'])) {
+      // Load the to date and convert to a unix timestamp.
+      $date = new DateObject($item['value2'], $item['timezone_db'], date_type_format($item['date_type']));
+      if (!empty($date) && $item['timezone_db'] != $item['timezone']) {
+        date_timezone_set($date, timezone_open($item['timezone']));
+      }
+      $timestamp = !empty($date) ? date_format_date($date, 'custom', 'U') : '';
+      // Generate the token replacements, using the date token type provided
+      // by system.module.
+      $replacements += token_generate('date', $date_tokens, array('date' => $timestamp), $options);
+    }
+  }
+
+  return $replacements;
+}
diff --git a/sites/all/modules/date/date_admin.inc b/sites/all/modules/date/date_admin.inc
new file mode 100644
index 0000000000000000000000000000000000000000..f5a345b4e1bfb5f5f05e9e364fb858eb3bf38349
--- /dev/null
+++ b/sites/all/modules/date/date_admin.inc
@@ -0,0 +1,597 @@
+<?php
+
+/**
+ * @file
+ * Date administration code.
+ */
+
+/**
+ * Settings for the default formatter.
+ */
+function date_default_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $formatter = $display['type'];
+  $form = array();
+
+  $form['format_type'] = array(
+    '#title' => t('Choose how users view dates and times:'),
+    '#type' => 'select',
+    '#options' => date_format_type_options(),
+    '#default_value' => $settings['format_type'],
+    '#description' => t('To add or edit options, visit <a href="@date-time-page">Date and time settings</a>.', array('@date-time-page' => url('admin/config/regional/date-time'))),
+    '#weight' => 0,
+  );
+
+  $form['fromto'] = array(
+    '#title' => t('Display:'),
+    '#type' => 'select',
+    '#options' => array(
+      'both' => t('Both Start and End dates'),
+      'value' => t('Start date only'),
+      'value2' => t('End date only'),
+    ),
+    '#access' => $field['settings']['todate'],
+    '#default_value' => $settings['fromto'],
+    '#weight' => 1,
+  );
+
+  // Make the string translatable by keeping it as a whole rather than
+  // translating prefix and suffix separately.
+  list($prefix, $suffix) = explode('@count', t('Show @count value(s)'));
+  $form['multiple_number'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Multiple values:'),
+    '#size' => 5,
+    '#field_prefix' => $prefix,
+    '#field_suffix' => $suffix,
+    '#default_value' => $settings['multiple_number'],
+    '#weight' => 2,
+    '#access' => ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) || ($field['cardinality'] > 1),
+    '#description' => t('Identify a specific number of values to display, or leave blank to show all values.'),
+  );
+
+  list($prefix, $suffix) = explode('@isodate', t('starting from @isodate'));
+  $form['multiple_from'] = array(
+    '#type' => 'textfield',
+    '#size' => 15,
+    '#field_prefix' => $prefix,
+    '#field_suffix' => $suffix,
+    '#default_value' => $settings['multiple_from'],
+    '#weight' => 3,
+    '#access' => ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) || ($field['cardinality'] > 1),
+  );
+
+  list($prefix, $suffix) = explode('@isodate', t('ending with @isodate'));
+  $form['multiple_to'] = array(
+    '#type' => 'textfield',
+    '#size' => 15,
+    '#field_prefix' => $prefix,
+    '#field_suffix' => $suffix,
+    '#default_value' => $settings['multiple_to'],
+    '#weight' => 4,
+    '#access' => ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) || ($field['cardinality'] > 1),
+    '#description' => t('Identify specific start and/or end dates in the format YYYY-MM-DDTHH:MM:SS, or leave blank for all available dates.'),
+  );
+
+  return $form;
+}
+
+/**
+ * Settings for the interval formatter.
+ */
+function date_interval_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $form = array();
+  $form['interval'] = array(
+    '#title' => t('Interval'),
+    '#description' => t("How many time units should be shown in the 'time ago' string."),
+    '#type' => 'select',
+    '#options' => drupal_map_assoc(range(1, 6)),
+    '#default_value' => $settings['interval'],
+    '#weight' => 0,
+  );
+  // Uses the same options used by Views format_interval.
+  $options = array(
+    'raw time ago' => t('Time ago'),
+    'time ago' => t('Time ago (with "ago" appended)'),
+    'raw time hence' => t('Time hence'),
+    'time hence' => t('Time hence (with "hence" appended)'),
+    'raw time span' => t('Time span (future dates have "-" prepended)'),
+    'inverse time span' => t('Time span (past dates have "-" prepended)'),
+    'time span' => t('Time span (with "ago/hence" appended)'),
+  );
+  $form['interval_display'] = array(
+    '#title' => t('Display'),
+    '#description' => t("How to display the time ago or time hence for this field."),
+    '#type' => 'select',
+    '#options' => $options,
+    '#default_value' => $settings['interval_display'],
+    '#weight' => 0,
+  );
+  return $form;
+}
+
+/**
+ * Settings summary for the default formatter.
+ */
+function date_default_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $formatter = $display['type'];
+  $format_types = date_format_type_options();
+  $summary = array();
+  switch ($formatter) {
+    case 'date_plain':
+      $format = t('Plain');
+      break;
+    case 'format_interval':
+      $format = t('Interval');
+      break;
+    default:
+      $format = $format_types[$settings['format_type']];
+  }
+  $summary[] = t('Display dates using the @format format', array('@format' => $format));
+
+  if (array_key_exists('fromto', $settings) && $field['settings']['todate']) {
+    $options = array(
+      'both' => t('Display both Start and End dates'),
+      'value' => t('Display Start date only'),
+      'value2' => t('Display End date only'),
+    );
+    $summary[] = $options[$settings['fromto']];
+  }
+
+  if (array_key_exists('multiple_number', $settings) && !empty($field['cardinality'])) {
+    $summary[] = t('Show @count value(s) starting with @date1, ending with @date2', array(
+      '@count' => !empty($settings['multiple_number']) ? $settings['multiple_number'] : t('all'),
+      '@date1' => !empty($settings['multiple_from']) ? $settings['multiple_from'] : t('earliest'),
+      '@date2' => !empty($settings['multiple_to']) ? $settings['multiple_to'] : t('latest'),
+    ));
+  }
+
+  return $summary;
+}
+
+/**
+ * Settings summary for the interval formatter.
+ *
+ * @TODO Add settings later.
+ */
+function date_interval_formatter_settings_summary($field, $instance, $view_mode) {
+  $summary = array();
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $formatter = $display['type'];
+  $summary[] = t('Display time ago, showing @interval units.', array('@interval' => $settings['interval']));
+
+  return $summary;
+}
+
+/**
+ * Helper function for date_field_instance_settings_form().
+ *
+ * @see date_field_instance_settings_form_validate()
+ */
+function _date_field_instance_settings_form($field, $instance) {
+  $widget = $instance['widget'];
+  $settings = $instance['settings'];
+  $widget_settings = $instance['widget']['settings'];
+
+  $form['default_value'] = array(
+    '#type' => 'select',
+    '#title' => t('Default date'),
+    '#default_value' => $settings['default_value'],
+    '#options' => array('blank' => t('No default value'), 'now' => t('Now'), 'strtotime' => t('Relative')),
+    '#weight' => 1,
+    '#fieldset' => 'default_values',
+  );
+
+  $description = t("Describe a time by reference to the current day, like '+90 days' (90 days from the day the field is created) or '+1 Saturday' (the next Saturday). See !strtotime for more details.", array('!strtotime' => l(t('strtotime'), 'http://www.php.net/manual/en/function.strtotime.php')));
+  $form['default_value_code'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Relative default value'),
+    '#description' => $description,
+    '#default_value' => $settings['default_value_code'],
+    '#states' => array(
+      'visible' => array(
+        ':input[name="instance[settings][default_value]"]' => array('value' => 'strtotime')),
+      ),
+    '#weight' => 1.1,
+    '#fieldset' => 'default_values',
+  );
+  $form['default_value2'] = array(
+    '#type' => !empty($field['settings']['todate']) ? 'select' : 'hidden',
+    '#title' => t('Default end date'),
+    '#default_value' => $settings['default_value2'],
+    '#options' => array('same' => t('Same as Default date'), 'blank' => t('No default value'), 'now' => t('Now'), 'strtotime' => t('Relative')),
+    '#weight' => 2,
+    '#fieldset' => 'default_values',
+  );
+  $form['default_value_code2'] = array(
+    '#type' => !empty($field['settings']['todate']) ? 'textfield' : 'hidden',
+    '#title' => t('Relative default value for end date'),
+    '#description' => $description,
+    '#default_value' => $settings['default_value_code2'],
+    '#states' => array(
+      'visible' => array(
+        ':input[name="instance[settings][default_value2]"]' => array('value' => 'strtotime')),
+      ),
+    '#weight' => 2.1,
+    '#fieldset' => 'default_values',
+  );
+
+  $form['#element_validate'] = array('date_field_instance_settings_form_validate');
+
+  $context = array(
+    'field' => $field,
+    'instance' => $instance,
+  );
+  drupal_alter('date_field_instance_settings_form', $form, $context);
+
+  return $form;
+}
+
+/**
+ * Form validation handler for _date_field_instance_settings_form().
+ */
+function date_field_instance_settings_form_validate(&$form, &$form_state) {
+  $settings = $form_state['values']['instance']['settings'];
+
+  if ($settings['default_value'] == 'strtotime') {
+    $is_strtotime = @strtotime($settings['default_value_code']);
+    if (!$is_strtotime) {
+      form_set_error('instance][settings][default_value_code', t('The Strtotime default value is invalid.'));
+    }
+  }
+  if (isset($settings['default_value2']) && $settings['default_value2'] == 'strtotime') {
+    $is_strtotime = @strtotime($settings['default_value_code2']);
+    if (!$is_strtotime) {
+      form_set_error('instance][settings][default_value_code2', t('The Strtotime default value for the End Date is invalid.'));
+    }
+  }
+}
+
+/**
+ * Helper function for date_field_widget_settings_form().
+ *
+ * @see date_field_widget_settings_form_validate()
+ */
+function _date_field_widget_settings_form($field, $instance) {
+  $widget = $instance['widget'];
+  $settings = $widget['settings'];
+
+  $form = array(
+    '#element_validate' => array('date_field_widget_settings_form_validate'),
+  );
+
+  $options = array();
+  if ($widget['type'] == 'date_popup' && module_exists('date_popup')) {
+    $formats = date_popup_formats();
+  }
+  else {
+    // Example input formats must show all possible date parts, so add seconds.
+    $formats = str_replace('i', 'i:s', array_keys(system_get_date_formats('short')));
+    $formats = drupal_map_assoc($formats);
+  }
+  $now = date_example_date();
+  foreach ($formats as $f) {
+    $options[$f] = date_format_date($now, 'custom', $f);
+  }
+  $form['input_format'] = array(
+    '#type' => 'select',
+    '#title' => t('Date entry options'),
+    '#default_value' => $settings['input_format'],
+    '#options' => $options,
+    '#description' => t('Control the order and format of the options users see.'),
+    '#weight' => 3,
+    '#fieldset' => 'date_format',
+  );
+  // Only a limited set of formats is available for the Date Popup module.
+  if ($widget['type'] != 'date_popup') {
+    $form['input_format']['#options']['custom'] = t('Custom format');
+    $form['input_format_custom'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Custom input format'),
+      '#default_value' => $settings['input_format_custom'],
+      '#description' => t("Override the input format selected above. Define a php date format string like 'm-d-Y H:i' (see <a href=\"@link\">http://php.net/date</a> for more details).", array('@link' => 'http://php.net/date')),
+      '#weight' => 5,
+      '#fieldset' => 'date_format',
+      '#attributes' => array('class' => array('indent')),
+      '#states' => array(
+        'visible' => array(
+          ':input[name="instance[widget][settings][input_format]"]' => array('value' => 'custom'),
+        ),
+      ),
+    );
+  }
+  else {
+    $form['input_format_custom'] = array(
+      '#type' => 'hidden',
+      '#value' => '',
+    );
+  }
+
+  if (in_array($widget['type'], array('date_select', 'date_popup'))) {
+    $form['year_range'] = array(
+      '#type' => 'date_year_range',
+      '#default_value' => $settings['year_range'],
+      '#fieldset' => 'date_format',
+      '#weight' => 6,
+    );
+    $form['increment'] = array(
+      '#type' => 'select', '#title' => t('Time increments'),
+      '#default_value' => $settings['increment'],
+      '#options' => array(
+        1 => t('1 minute'),
+        5 => t('5 minute'),
+        10 => t('10 minute'),
+        15 => t('15 minute'),
+        30 => t('30 minute')),
+      '#weight' => 7,
+      '#fieldset' => 'date_format',
+    );
+  }
+  else {
+    $form['year_range'] = array(
+      '#type' => 'hidden',
+      '#value' => $settings['year_range'],
+    );
+    $form['increment'] = array(
+      '#type' => 'hidden',
+      '#value' => $settings['increment'],
+    );
+  }
+
+  $form['label_position'] = array(
+    '#type' => 'value',
+    '#value' => $settings['label_position'],
+  );
+  $form['text_parts'] = array(
+    '#type' => 'value',
+    '#value' => $settings['text_parts'],
+  );
+  $form['advanced'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Advanced settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#fieldset' => 'date_format',
+    '#weight' => 9,
+  );
+  if (in_array($widget['type'], array('date_select'))) {
+    $options = array('above' => t('Above'), 'within' => t('Within'), 'none' => t('None'));
+    $description = t("The location of date part labels, like 'Year', 'Month', or 'Day' . 'Above' displays the label as titles above each date part. 'Within' inserts the label as the first option in the select list and in blank textfields. 'None' doesn't label any of the date parts. Theme functions like 'date_part_label_year' and 'date_part_label_month' control label text.");
+  }
+  else {
+    $options = array('above' => t('Above'), 'none' => t('None'));
+    $description = t("The location of date part labels, like 'Year', 'Month', or 'Day' . 'Above' displays the label as titles above each date part. 'None' doesn't label any of the date parts. Theme functions like 'date_part_label_year' and 'date_part_label_month' control label text.");
+  }
+  $form['advanced']['label_position'] = array(
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => $settings['label_position'],
+    '#title' => t('Position of date part labels'),
+    '#description' => $description,
+  );
+  $form['advanced']['text_parts'] = array(
+    '#theme' => $widget['type'] == 'date_select' ? 'date_text_parts' : '',
+  );
+  $text_parts = (array) $settings['text_parts'];
+  foreach (date_granularity_names() as $key => $value) {
+    if ($widget['type'] == 'date_select') {
+      $form['advanced']['text_parts'][$key] = array(
+        '#type' => 'radios',
+        '#default_value' => in_array($key, $text_parts) ? 1 : 0,
+        '#options' => array(0 => '', 1 => ''),
+      );
+    }
+    else {
+      $form['advanced']['text_parts'][$key] = array(
+        '#type' => 'value',
+        '#value' => (int) in_array($key, (array) $settings['text_parts']),
+      );
+    }
+  }
+
+  $context = array(
+    'field' => $field,
+    'instance' => $instance,
+  );
+  drupal_alter('date_field_widget_settings_form', $form, $context);
+
+  return $form;
+}
+
+/**
+ * Form validation handler for _date_field_widget_settings_form().
+ */
+function date_field_widget_settings_form_validate(&$form, &$form_state) {
+  // The widget settings are in the wrong place in the form because of #tree on
+  // the top level.
+  $settings = $form_state['values']['instance']['widget']['settings'];
+  $settings = array_merge($settings, $settings['advanced']);
+  unset($settings['advanced']);
+  form_set_value(array('#parents' => array('instance', 'widget', 'settings')), $settings, $form_state);
+
+  $widget = &$form_state['values']['instance']['widget'];
+  // Munge the table display for text parts back into an array of text parts.
+  if (is_array($widget['settings']['text_parts'])) {
+    form_set_value($form['text_parts'], array_keys(array_filter($widget['settings']['text_parts'])), $form_state);
+  }
+
+  if ($widget['settings']['input_format'] === 'custom' && empty($widget['settings']['input_format_custom'])) {
+    form_set_error('instance][widget][settings][input_format_custom', t('Please enter a custom date format, or choose one of the preset formats.'));
+  }
+}
+
+/**
+ * Helper function for date_field_settings_form().
+ *
+ * @see date_field_settings_validate()
+ */
+function _date_field_settings_form($field, $instance, $has_data) {
+  $settings = $field['settings'];
+
+  $form = array(
+    '#element_validate' => array('date_field_settings_validate'),
+  );
+
+  // Make sure granularity is in the right format and has no empty values.
+  if (!empty($settings['granularity']) && is_array($settings['granularity'])) {
+    $granularity = array_filter($settings['granularity']);
+  }
+  $tz_handling = $settings['tz_handling'];
+
+  $description = t('Select the date attributes to collect and store.');
+  $options = date_granularity_names();
+  $checkbox_year = array(
+    '#type' => 'checkbox',
+    '#title' => check_plain($options['year']),
+    '#value' => 'year',
+    '#return_value' => 'year',
+    '#disabled' => TRUE,
+  );
+  unset($options['year']);
+  $form['granularity'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Date attributes to collect'),
+    '#default_value' => $granularity,
+    '#options' => $options,
+    '#attributes' => array('class' => array('container-inline')),
+    '#description' => $description,
+    '#disabled' => $has_data,
+    'year' => $checkbox_year,
+  );
+
+  $description = t('End dates are used to collect duration. E.g., allow an event to start on September 15, and end on September 16.');
+  $form['enddate_get'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Collect an end date'),
+    '#description' => $description,
+    '#default_value' => (empty($settings['todate']) ? FALSE : TRUE),
+    '#disabled' => $has_data,
+  );
+  $form['enddate_required'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Required'),
+    '#default_value' => ((isset($settings['todate']) && $settings['todate'] === 'required') ? TRUE : FALSE),
+    '#disabled' => $has_data,
+    '#states' => array(
+      'invisible' => array(
+        'input[name="field[settings][enddate_get]"]' => array('checked' => FALSE),
+      ),
+    ),
+  );
+  $description = t('Select the timezone handling method for this date field.');
+  $form['tz_handling'] = array(
+    '#type' => 'select',
+    '#title' => t('Time zone handling'),
+    '#default_value' => $tz_handling,
+    '#options' => date_timezone_handling_options(),
+    '#description' => $description,
+    '#disabled' => $has_data,
+    '#attached' => array(
+      'js' => array(drupal_get_path('module', 'date') . '/date_admin.js'),
+    ),
+  );
+  // Force this value to hidden because we don't want to allow it to be changed
+  // right now, but allow it to be a variable if needed.
+  $form['timezone_db'] = array(
+    '#type' => 'hidden',
+    '#value' => date_get_timezone_db($tz_handling),
+  );
+
+  $form['cache_enabled'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Cache dates'),
+    '#description' => t('Date objects can be created and cached as date fields are loaded rather than when they are displayed to improve performance.'),
+    '#default_value' => !empty($settings['cache_enabled']),
+    '#weight' => 10,
+  );
+  $form['cache_count'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Maximum dates per field'),
+    '#default_value' => (isset($settings['cache_count'])) ? $settings['cache_count'] : 4,
+    '#description' => t("If set to '0', all date values on every entity will be cached. Note that caching every date on fields that may have a large number of multiple or repeating values may create a significant performance penalty when the cache is cleared. The suggested setting for multiple value and repeating fields is no more than 4 values per field."),
+    '#size' => 3,
+    '#weight' => 11,
+    '#states' => array(
+      'visible' => array(
+        'input[name="field[settings][cache_enabled]"]' => array('checked' => TRUE),
+      ),
+    ),
+  );
+
+  $context = array(
+    'field' => $field,
+    'instance' => $instance,
+    'has_data' => $has_data,
+  );
+  drupal_alter('date_field_settings_form', $form, $context);
+
+  return $form;
+}
+
+/**
+ * Form validation handler for _date_field_settings_form().
+ */
+function date_field_settings_validate(&$form, &$form_state) {
+  $field = &$form_state['values']['field'];
+
+  if ($field['settings']['tz_handling'] == 'none') {
+    form_set_value($form['timezone_db'], '', $form_state);
+  }
+  else {
+    form_set_value($form['timezone_db'], date_get_timezone_db($field['settings']['tz_handling']), $form_state);
+  }
+
+  if ($field['settings']['tz_handling'] != 'none' && !in_array('hour', array_filter($field['settings']['granularity']))) {
+    form_set_error('field[settings][tz_handling]', t('Dates without hours granularity must not use any timezone handling.'));
+  }
+
+  // Extract the correct 'todate' value out of the two end date checkboxes.
+  if ($field['settings']['enddate_get']) {
+    if ($field['settings']['enddate_required']) {
+      $field['settings']['todate'] = 'required';
+    }
+    else {
+      $field['settings']['todate'] = 'optional';
+    }
+  }
+  else {
+    $field['settings']['todate'] = '';
+  }
+
+  // Don't save the pseudo values created in the UI.
+  unset($field['settings']['enddate_get'], $field['settings']['enddate_required']);
+
+  if (!empty($field['settings']['cache_enabled'])) {
+    if (!is_numeric($field['settings']['cache_count'])) {
+      form_set_error('field[settings][cache_count]', t('The number of cache values must be a number.'));
+    }
+    elseif ($field['settings']['cache_count'] < 0) {
+      form_set_error('field[settings][cache_count]', t('The number of cache values must be a number 0 or greater.'));
+    }
+  }
+}
+
+/**
+ * Timezone handling options.
+ *
+ * The 'none' option will do no timezone conversions and will store and display
+ * dates exactly as entered useful in locales or situations where timezone
+ * conversions are not working reliably, for dates with no times, for historical
+ * dates where timezones are irrelevant, or anytime conversion is unnecessary or
+ * undesirable.
+ */
+function date_timezone_handling_options() {
+  return array(
+    'site' => t("Site's time zone"),
+    'date' => t("Date's time zone"),
+    'user' => t("User's time zone"),
+    'utc' => 'UTC',
+    'none' => t('No time zone conversion'),
+  );
+}
diff --git a/sites/all/modules/date/date_admin.js b/sites/all/modules/date/date_admin.js
new file mode 100644
index 0000000000000000000000000000000000000000..e3cde3fc35c17dad61c696b0df753545c7632506
--- /dev/null
+++ b/sites/all/modules/date/date_admin.js
@@ -0,0 +1,81 @@
+(function ($) {
+
+Drupal.behaviors.dateAdmin = {};
+
+Drupal.behaviors.dateAdmin.attach = function (context, settings) {
+  // Remove timezone handling options for fields without hours granularity.
+  var $hour = $('#edit-field-settings-granularity-hour').once('date-admin');
+  if ($hour.length) {
+    new Drupal.dateAdmin.TimezoneHandler($hour);
+  }
+};
+
+
+Drupal.dateAdmin = {};
+
+/**
+ * Constructor for the TimezoneHandler object.
+ *
+ * This object is responsible for showing the timezone handling options dropdown
+ * when the user has chosen to collect hours as part of the date field, and
+ * hiding it otherwise.
+ */
+Drupal.dateAdmin.TimezoneHandler = function ($checkbox) {
+  this.$checkbox = $checkbox;
+  this.$dropdown = $('#edit-field-settings-tz-handling');
+  this.$timezoneDiv = $('.form-item-field-settings-tz-handling');
+  // Store the initial value of the timezone handling dropdown.
+  this.storeTimezoneHandling();
+  // Toggle the timezone handling section when the user clicks the "Hour"
+  // checkbox.
+  this.$checkbox.bind('click', $.proxy(this.clickHandler, this));
+  // Trigger the click handler so that if the checkbox is unchecked on initial
+  // page load, the timezone handling section will be hidden.
+  this.clickHandler();
+};
+
+/**
+ * Event handler triggered when the user clicks the "Hour" checkbox.
+ */
+Drupal.dateAdmin.TimezoneHandler.prototype.clickHandler = function () {
+  if (this.$checkbox.is(':checked')) {
+    this.restoreTimezoneHandlingOptions();
+  }
+  else {
+    this.hideTimezoneHandlingOptions();
+  }
+};
+
+/**
+ * Hide the timezone handling options section of the form.
+ */
+Drupal.dateAdmin.TimezoneHandler.prototype.hideTimezoneHandlingOptions = function () {
+  this.storeTimezoneHandling();
+  this.$dropdown.val('none');
+  this.$timezoneDiv.hide();
+};
+
+/**
+ * Show the timezone handling options section of the form.
+ */
+Drupal.dateAdmin.TimezoneHandler.prototype.restoreTimezoneHandlingOptions = function () {
+  var val = this.getTimezoneHandling();
+  this.$dropdown.val(val);
+  this.$timezoneDiv.show();
+};
+
+/**
+ * Store the current value of the timezone handling dropdown.
+ */
+Drupal.dateAdmin.TimezoneHandler.prototype.storeTimezoneHandling = function () {
+  this._timezoneHandling = this.$dropdown.val();
+};
+
+/**
+ * Return the stored value of the timezone handling dropdown.
+ */
+Drupal.dateAdmin.TimezoneHandler.prototype.getTimezoneHandling = function () {
+  return this._timezoneHandling;
+};
+
+})(jQuery);
diff --git a/sites/all/modules/date/date_all_day/README.txt b/sites/all/modules/date/date_all_day/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d65a6d99e4e1a8c1a7b37153c2d8832e4fd641dd
--- /dev/null
+++ b/sites/all/modules/date/date_all_day/README.txt
@@ -0,0 +1,9 @@
+Date All Day
+
+This module provides the option to add an 'All Day' checkbox to toggle time on 
+and off for date fields. It also contains the theme that displays the 'All Day' 
+text on fields that have no time. 
+
+Additionally, this module serves as an example of how other modules can inject 
+new functionality into date fields using various hooks provided by Date and by 
+the Field API.
\ No newline at end of file
diff --git a/sites/all/modules/date/date_all_day/date_all_day.info b/sites/all/modules/date/date_all_day/date_all_day.info
new file mode 100644
index 0000000000000000000000000000000000000000..ba5d0f185e26f1f8b8a7177db83c447a2be6ad06
--- /dev/null
+++ b/sites/all/modules/date/date_all_day/date_all_day.info
@@ -0,0 +1,13 @@
+name = Date All Day
+description = Adds 'All Day' functionality to date fields, including an 'All Day' theme and 'All Day' checkboxes for the Date select and Date popup widgets.
+dependencies[] = date_api
+dependencies[] = date
+package = Date/Time
+core = 7.x
+
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date_all_day/date_all_day.module b/sites/all/modules/date/date_all_day/date_all_day.module
new file mode 100644
index 0000000000000000000000000000000000000000..93fc61badb7bdb12ad1ad41cff523088fa69c2df
--- /dev/null
+++ b/sites/all/modules/date/date_all_day/date_all_day.module
@@ -0,0 +1,419 @@
+<?php
+
+/**
+ * @file
+ * Adds All Day functionality to the Date field.
+ *
+ * This module implements a number of hooks in the Date field and
+ * Date api element processing and to add an All Day checkbox to
+ * date widgets, and also adds an All Day theme and
+ * All Day information to the formatting.
+ *
+ * Keep in mind that the process hooks are fired from the top down,
+ * first date_combo, then the date_select or date_popup.
+ *
+ * Validation fires from the bottom up, first date_select and
+ * date_popup, then date_combo.
+ */
+
+/**
+ * Implements hook_theme().
+ */
+function date_all_day_theme() {
+  $themes = array(
+    'date_all_day' => array(
+      'variables' => array(
+        'field' => NULL,
+        'instance' => NULL,
+        'which' => NULL,
+        'date1' => NULL,
+        'date2' => NULL,
+        'format' => NULL,
+        'entity_type' => NULL,
+        'entity' => NULL,
+        'view' => NULL
+      )
+    ),
+    'date_all_day_label' => array(
+       'variables' => array()
+    ),
+  );
+
+  return $themes;
+}
+
+/**
+ * Implements hook_date_formatter_dates_alter().
+ *
+ * This allows us to alter the $dates array created
+ * by date_formatter_process.
+ */
+function date_all_day_date_formatter_dates_alter(&$dates, $context) {
+
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $format = $context['format'];
+  $entity_type = $context['entity_type'];
+  $entity = $context['entity'];
+  $date1 = $dates['value']['local']['object'];
+  $date2 = $dates['value2']['local']['object'];
+
+  $is_all_day = date_all_day_field($field, $instance, $date1, $date2);
+
+  $all_day1 = '';
+  $all_day2 = '';
+  if ($format != 'format_interval' && $is_all_day) {
+    $all_day1 = theme('date_all_day', array(
+      'field' => $field,
+      'instance' => $instance,
+      'which' => 'date1',
+      'date1' => $date1,
+      'date2' => $date2,
+      'format' => $format,
+      'entity_type' => $entity_type,
+      'entity' => $entity));
+    $all_day2 = theme('date_all_day', array(
+      'field' => $field,
+      'instance' => $instance,
+      'which' => 'date2',
+      'date1' => $date1,
+      'date2' => $date2,
+      'format' => $format,
+      'entity_type' => $entity_type,
+      'entity' => $entity));
+    $dates['value']['formatted_time'] = theme('date_all_day_label');
+    $dates['value2']['formatted_time'] = theme('date_all_day_label');
+    $dates['value']['formatted'] = $all_day1;
+    $dates['value2']['formatted'] = $all_day2;
+  }
+}
+
+/**
+ * Adjust start/end date format to account for 'all day' .
+ *
+ * @param array $field, the field definition for this date field.
+ * @param string $which, which value to return, 'date1' or 'date2' .
+ * @param object $date1, a date/time object for the 'start' date.
+ * @param object $date2, a date/time object for the 'end' date.
+ * @param string $format
+ * @param object $entity, the node this date comes from (may be incomplete, always contains nid).
+ * @param object $view, the view this node comes from, if applicable.
+ * @return formatted date.
+ */
+function theme_date_all_day($vars) {
+  $field    = $vars['field'];
+  $instance = $vars['instance'];
+  $which    = $vars['which'];
+  $date1    = $vars['date1'];
+  $date2    = $vars['date2'];
+  $format   = $vars['format'];
+  $entity   = $vars['entity'];
+  $view     = !empty($vars['view']) ? $vars['view'] : NULL;
+
+  if (empty($date1) || !is_object($date1) || $format == 'format_interval') {
+    return;
+  }
+  if (empty($date2)) {
+    $date2 = $date1;
+  }
+
+  $suffix = '';
+  if (!date_has_time($field['settings']['granularity'])) {
+    $format = date_limit_format($format, array('year', 'month', 'day'));
+  }
+  else {
+    $format_granularity = date_format_order($format);
+    $format_has_time = FALSE;
+    if (in_array('hour', $format_granularity)) {
+      $format_has_time = TRUE;
+    }
+    $all_day = date_all_day_field($field, $instance, $date1, $date2);
+    if ($all_day && $format_has_time) {
+      $format = date_limit_format($format, array('year', 'month', 'day'));
+      $suffix = ' ' . theme('date_all_day_label');
+    }
+  }
+
+  return trim(date_format_date($$which, 'custom', $format) . $suffix);
+
+}
+
+/**
+ * Theme the way an 'all day' label will look.
+ */
+function theme_date_all_day_label() {
+  return '(' . t('All day', array(), array('context' => 'datetime')) .')';
+}
+
+/**
+ * Determine if a Start/End date combination qualify as 'All day'.
+ *
+ * @param array $field, the field definition for this date field.
+ * @param object $date1, a date/time object for the 'Start' date.
+ * @param object $date2, a date/time object for the 'End' date.
+ * @return TRUE or FALSE.
+ */
+function date_all_day_field($field, $instance, $date1, $date2 = NULL) {
+  if (empty($date1) || !is_object($date1)) {
+    return FALSE;
+  }
+  elseif (!date_has_time($field['settings']['granularity'])) {
+    return TRUE;
+  }
+  if (empty($date2)) {
+    $date2 = $date1;
+  }
+
+  $granularity = date_granularity_precision($field['settings']['granularity']);
+  $increment = isset($instance['widget']['settings']['increment']) ? $instance['widget']['settings']['increment'] : 1;
+  return date_is_all_day(date_format($date1, DATE_FORMAT_DATETIME), date_format($date2, DATE_FORMAT_DATETIME), $granularity, $increment);
+
+}
+
+/**
+ * Implements hook_date_combo_process_alter().
+ *
+ * This hook lets us make changes to the date_combo element.
+ */
+function date_all_day_date_combo_process_alter(&$element, &$form_state, $context) {
+
+  $field = $context['field'];
+  $instance = $context['instance'];
+
+  // Add the all_day checkbox to the combo element.
+  if (!empty($instance['widget']['settings']['display_all_day'])) {
+
+    $parents = $element['#parents'];
+    $first_parent = array_shift($parents);
+    $all_day_id = $first_parent . '[' . implode('][', $parents) . '][all_day]';;
+    foreach (array('value', 'value2') as $key) {
+      if (array_key_exists($key, $element)) {
+        $element[$key]['#date_all_day_id']  = $all_day_id;
+      }
+    }
+
+    $from = $element['#default_value']['value'];
+    $to = !empty($element['#default_value']['value2']) ? $element['#default_value']['value2'] : $element['#default_value']['value'];
+    $date_is_all_day = date_is_all_day($from, $to);
+    $all_day = !empty($form_state['values']['all_day']) || $date_is_all_day;
+    $element['all_day'] = array(
+      '#title' => t('All Day'),
+      '#type' => 'checkbox',
+      '#default_value' => $all_day,
+      '#weight' => -21,
+      '#prefix' => '<div class="date-float">',
+      '#suffix' => '</div>',
+    );
+  }
+
+  // Set all_day to 0 for all other date fields.
+  else {
+    $form['all_day']['#type'] = 'hidden';
+    $form['all_day']['#value'] = 0;
+  }
+}
+
+
+/**
+ * Implements hook_date_text_process_alter().
+ *
+ * This hook lets us make changes to the date_select widget.
+ */
+function date_all_day_date_text_process_alter(&$element, &$form_state, $context) {
+  $all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
+  if ($all_day_id != '') {
+    // All Day handling on text dates works only if the user leaves the time out of the input value.
+    // There is no element to hide or show.
+  }
+}
+
+/**
+ * Implements hook_date_select_process_alter().
+ *
+ * This hook lets us make changes to the date_select widget.
+ */
+function date_all_day_date_select_process_alter(&$element, &$form_state, $context) {
+
+  // Hide or show this element in reaction to the all_day status for this element.
+  $all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
+  if ($all_day_id != '') {
+    foreach(array('hour', 'minute', 'second', 'ampm') as $field) {
+      if (array_key_exists($field, $element)) {
+        $element[$field]['#states'] = array(
+          'visible' => array(
+            'input[name="' . $all_day_id . '"]' => array('checked' => FALSE),
+          ));
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_date_popup_process_alter().
+ *
+ * This hook lets us make changes to the date_popup element.
+ */
+function date_all_day_date_popup_process_alter(&$element, &$form_state, $context) {
+
+  // Hide or show this element in reaction to the all_day status for this element.
+  $all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
+  if ($all_day_id != '' && array_key_exists('time', $element)) {
+    $element['time']['#states'] = array(
+      'visible' => array(
+        'input[name="' . $all_day_id . '"]' => array('checked' => FALSE),
+      ));
+  }
+}
+
+/**
+ * Implements hook_date_select_pre_validate_alter().
+ *
+ * This hook lets us alter the element or the form_state before the rest
+ * of the date_select validation gets fired.
+ */
+function date_all_day_date_text_pre_validate_alter(&$element, &$form_state, &$input) {
+  // Let Date module massage the format for all day values so they will pass validation.
+  // The All day flag, if used, actually exists on the parent element.
+  date_all_day_value($element, $form_state);
+}
+
+/**
+ * Implements hook_date_select_pre_validate_alter().
+ *
+ * This hook lets us alter the element or the form_state before the rest
+ * of the date_select validation gets fired.
+ */
+function date_all_day_date_select_pre_validate_alter(&$element, &$form_state, &$input) {
+  // Let Date module massage the format for all day values so they will pass validation.
+  // The All day flag, if used, actually exists on the parent element.
+  date_all_day_value($element, $form_state);
+}
+
+/**
+ * Implements hook_date_select_pre_validate_alter().
+ *
+ * This hook lets us alter the element or the form_state before the rest
+ * of the date_popup validation gets fired.
+ */
+function date_all_day_date_popup_pre_validate_alter(&$element, &$form_state, &$input) {
+  // Let Date module massage the format for all day values so they will pass validation.
+  // The All day flag, if used, actually exists on the parent element.
+  date_all_day_value($element, $form_state);
+}
+
+/**
+ * A helper function to check if the all day flag is set on the parent of an
+ * element, and adjust the date_format accordingly so the missing time will
+ * not cause validation errors.
+ */
+function date_all_day_value(&$element, $form_state) {
+  if (!empty($element['#date_all_day_id'])) {
+    $parents = $element['#parents'];
+    array_pop($parents);
+    $parent_element = drupal_array_get_nested_value($form_state['values'], $parents);
+    if (!empty($parent_element) && !empty($parent_element['all_day'])) {
+      $element['#date_format'] = date_part_format('date', $element['#date_format']);
+      return $parent_element['all_day'];
+    }
+  }
+  return FALSE;
+}
+
+/**
+ * Implements hook_date_combo_pre_validate_alter().
+ *
+ * This hook lets us alter the element or the form_state before the rest
+ * of the date_combo validation gets fired.
+ */
+function date_all_day_date_combo_pre_validate_alter(&$element, &$form_state, $context) {
+
+  if (!empty($context['item']['all_day'])) {
+
+    $field = $context['field'];
+
+    // If we have an all day flag on this date and the time is empty,
+    // change the format to match the input value so we don't get validation errors.
+    $element['#date_is_all_day'] = TRUE;
+    $element['value']['#date_format'] = date_part_format('date', $element['value']['#date_format']);
+    if (!empty($field['settings']['todate'])) {
+      $element['value2']['#date_format'] = date_part_format('date', $element['value2']['#date_format']);
+    }
+  }
+}
+
+/**
+ * Implements hook_date_combo_validate_date_start_alter().
+ *
+ * This hook lets us alter the local date objects created by the date_combo validation
+ * before they are converted back to the database timezone and stored.
+ */
+function date_all_day_date_combo_validate_date_start_alter(&$date, &$form_state, $context) {
+
+   // If this is an 'All day' value, set the time to midnight.
+   if (!empty($context['element']['#date_is_all_day'])) {
+     $date->setTime(0, 0, 0);
+   }
+}
+
+/**
+ * Implements hook_date_combo_validate_date_end_alter().
+ *
+ * This hook lets us alter the local date objects created by the date_combo validation
+ * before they are converted back to the database timezone and stored.
+ */
+function date_all_day_date_combo_validate_date_end_alter(&$date, &$form_state, $context) {
+
+   // If this is an 'All day' value, set the time to midnight.
+   if (!empty($context['element']['#date_is_all_day'])) {
+     $date->setTime(0, 0, 0);
+   }
+}
+
+/**
+ * Implements hook_field_widget_info_alter().
+ *
+ * This Field API hook lets us add a new setting to the widgets.
+ */
+function date_all_day_field_widget_info_alter(&$info) {
+  // Add a setting to a widget type.
+  $info['date_select']['settings'] += array(
+    'display_all_day' => 0,
+  );
+  $info['date_text']['settings'] += array(
+    'display_all_day' => 0,
+  );
+  if (module_exists('date_popup')) {
+    $info['date_popup']['settings'] += array(
+      'display_all_day' => 0,
+    );
+  }
+}
+
+/**
+ * Implements hook_date_field_widget_settings_form_alter().
+ *
+ * This hook lets us alter the field settings form by adding a place
+ * to set the value added above.
+ */
+function date_all_day_date_field_widget_settings_form_alter(&$form, $context) {
+
+  $field = $context['field'];
+  $instance = $context['instance'];
+
+  $settings = $instance['widget']['settings'];
+
+  $form['display_all_day'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Display all day checkbox'),
+    '#default_value' => $settings['display_all_day'],
+    '#description' => t("Determines whether to display the 'All Day' checkbox to the user."),
+    '#weight' => 8,
+    '#fieldset' => 'date_format',
+  );
+
+  // Hide the option to use the all day checkbox for dates with no time.
+  if (!date_has_time($field['settings']['granularity'])) {
+    $form['display_all_day']['#type'] = 'hidden';
+    $form['display_all_day']['#value'] = 0;
+  }
+}
diff --git a/sites/all/modules/date/date_api/date-rtl.css b/sites/all/modules/date/date_api/date-rtl.css
new file mode 100644
index 0000000000000000000000000000000000000000..deaa9a1ca524ef2ce3ec228128530d737accc38c
--- /dev/null
+++ b/sites/all/modules/date/date_api/date-rtl.css
@@ -0,0 +1,27 @@
+.container-inline-date > .form-item {
+  margin-left: 0.5em;
+  margin-right: 0;
+}
+.container-inline-date .form-item .form-item {
+  float: right;
+}
+
+.container-inline-date .form-item input,
+.container-inline-date .form-item select,
+.container-inline-date .form-item option {
+  margin-left: 5px;
+  margin-right: 0;
+}
+
+.container-inline-date .date-spacer {
+  margin-left: 0;
+  margin-right: -5px;
+}
+
+.form-type-date-select .form-type-select[class$=hour] {
+  margin-right: .75em;
+}
+
+#edit-field-settings-granularity .form-type-checkbox {
+  margin-left: .6em;
+}
diff --git a/sites/all/modules/date/date_api/date.css b/sites/all/modules/date/date_api/date.css
new file mode 100644
index 0000000000000000000000000000000000000000..9b72ecdb7b9c519139bbcf9350f22433a74b925e
--- /dev/null
+++ b/sites/all/modules/date/date_api/date.css
@@ -0,0 +1,188 @@
+/**
+ * @file
+ * Main stylesheet for Date module.
+ */
+
+/* Force start/end dates to float using inline-block, where it works, otherwise inline. */
+.container-inline-date {
+  clear: both;
+}
+.container-inline-date .form-item {
+  float: none;
+  margin: 0;
+  padding: 0;
+}
+.container-inline-date > .form-item {
+  display: inline-block;
+  margin-right: 0.5em; /* LTR */
+  margin-bottom: 10px;
+  vertical-align: top;
+}
+.container-inline-date .form-item .form-item {
+  float: left; /* LTR */
+}
+.container-inline-date .form-item,
+.container-inline-date .form-item input {
+  width: auto;
+}
+.container-inline-date .description {
+  clear: both;
+}
+
+.container-inline-date .form-item input,
+.container-inline-date .form-item select,
+.container-inline-date .form-item option {
+  margin-right: 5px; /* LTR */
+}
+
+.container-inline-date .date-spacer {
+  margin-left: -5px; /* LTR */
+}
+
+.views-right-60 .container-inline-date div {
+  margin: 0;
+  padding: 0;
+}
+
+.container-inline-date .date-timezone .form-item {
+  clear: both;
+  float: none;
+  width: auto;
+}
+
+/* The exposed Views form doesn't need some of these styles */
+.container-inline-date .date-padding {
+  padding: 10px;
+  float: left;
+}
+.views-exposed-form .container-inline-date .date-padding {
+  padding: 0;
+}
+
+/* Fixes for date popup css so it will behave in Drupal */
+#calendar_div,
+#calendar_div td,
+#calendar_div th {
+  margin: 0;
+  padding: 0;
+}
+#calendar_div,
+.calendar_control,
+.calendar_links,
+.calendar_header,
+.calendar {
+  border-collapse: separate;
+  margin: 0;
+  width: 185px;
+}
+
+.calendar td {
+  padding: 0;
+}
+
+/* formatting for start/end dates in nodes and views */
+span.date-display-single {
+}
+span.date-display-start {
+}
+span.date-display-end {
+}
+
+.date-prefix-inline {
+  display: inline-block;
+}
+
+.date-clear {
+  clear: both;
+  display: block;
+  float: none;
+}
+
+.date-no-float {
+  clear: both;
+  float: none;
+  width: 98%;
+}
+
+.date-float {
+  clear: none;
+  float: left;
+  width: auto;
+}
+
+/* Add space between date option checkboxes ('All day' & 'Collect End Date') */
+.date-float .form-type-checkbox{
+  padding-right: 1em;
+}
+
+/* Add space between the date and time portions of the date_select widget. */
+.form-type-date-select .form-type-select[class$=hour] {
+  margin-left: .75em; /* LTR */
+}
+
+.date-container .date-format-delete {
+  float: left;
+  margin-top: 1.8em;
+  margin-left: 1.5em;
+}
+.date-container .date-format-name {
+  float: left;
+}
+.date-container .date-format-type {
+  float: left;
+  padding-left: 10px;
+}
+
+.date-container .select-container {
+  clear: left;
+  float: left;
+}
+
+/* Calendar day css */
+div.date-calendar-day {
+  background: #F3F3F3;
+  border-top: 1px solid #EEE;
+  border-left: 1px solid #EEE;
+  border-right: 1px solid #BBB;
+  border-bottom: 1px solid #BBB;
+  color: #999;
+  float: left;
+  line-height: 1;
+  margin: 6px 10px 0 0;
+  text-align: center;
+  width: 40px;
+}
+
+div.date-calendar-day span {
+  display: block;
+  text-align: center;
+}
+div.date-calendar-day span.month {
+  background-color: #B5BEBE;
+  color: white;
+  font-size: .9em;
+  padding: 2px;
+  text-transform: uppercase;
+}
+div.date-calendar-day span.day {
+  font-size: 2em;
+  font-weight: bold;
+}
+div.date-calendar-day span.year {
+  font-size: .9em;
+  padding: 2px;
+}
+
+/* Admin styling */
+.form-item.form-item-instance-widget-settings-input-format-custom,
+.form-item.form-item-field-settings-enddate-required {
+  margin-left: 1.3em;
+}
+
+#edit-field-settings-granularity .form-type-checkbox {
+  margin-right: .6em; /* LTR */
+}
+
+.date-year-range-select {
+  margin-right: 1em;
+}
diff --git a/sites/all/modules/date/date_api/date_api.admin.inc b/sites/all/modules/date/date_api/date_api.admin.inc
new file mode 100644
index 0000000000000000000000000000000000000000..966b1a4232025ef2fa8e5f6d789f6d13953b2653
--- /dev/null
+++ b/sites/all/modules/date/date_api/date_api.admin.inc
@@ -0,0 +1,126 @@
+<?php
+
+/**
+ * @file
+ * Administrative page callbacks for the date_api module.
+ */
+
+/**
+ * Create replacement values for deprecated timezone names.
+ */
+function _date_timezone_replacement($old) {
+  $replace = array(
+  'Brazil/Acre' => 'America/Rio_Branco',
+  'Brazil/DeNoronha' => 'America/Noronha',
+  'Brazil/East' => 'America/Recife',
+  'Brazil/West' => 'America/Manaus',
+  'Canada/Atlantic' => 'America/Halifax',
+  'Canada/Central' => 'America/Winnipeg',
+  'Canada/East-Saskatchewan' => 'America/Regina',
+  'Canada/Eastern' => 'America/Toronto',
+  'Canada/Mountain' => 'America/Edmonton',
+  'Canada/Newfoundland' => 'America/St_Johns',
+  'Canada/Pacific' => 'America/Vancouver',
+  'Canada/Saskatchewan' => 'America/Regina',
+  'Canada/Yukon' => 'America/Whitehorse',
+  'CET' => 'Europe/Berlin',
+  'Chile/Continental' => 'America/Santiago',
+  'Chile/EasterIsland' => 'Pacific/Easter',
+  'CST6CDT' => 'America/Chicago',
+  'Cuba' => 'America/Havana',
+  'EET' => 'Europe/Bucharest',
+  'Egypt' => 'Africa/Cairo',
+  'Eire' => 'Europe/Belfast',
+  'EST' => 'America/New_York',
+  'EST5EDT' => 'America/New_York',
+  'GB' => 'Europe/London',
+  'GB-Eire' => 'Europe/Belfast',
+  'Etc/GMT' => 'UTC',
+  'Etc/GMT+0' => 'UTC',
+  'Etc/GMT+1' => 'UTC',
+  'Etc/GMT+10' => 'UTC',
+  'Etc/GMT+11' => 'UTC',
+  'Etc/GMT+12' => 'UTC',
+  'Etc/GMT+2' => 'UTC',
+  'Etc/GMT+3' => 'UTC',
+  'Etc/GMT+4' => 'UTC',
+  'Etc/GMT+5' => 'UTC',
+  'Etc/GMT+6' => 'UTC',
+  'Etc/GMT+7' => 'UTC',
+  'Etc/GMT+8' => 'UTC',
+  'Etc/GMT+9' => 'UTC',
+  'Etc/GMT-0' => 'UTC',
+  'Etc/GMT-1' => 'UTC',
+  'Etc/GMT-10' => 'UTC',
+  'Etc/GMT-11' => 'UTC',
+  'Etc/GMT-12' => 'UTC',
+  'Etc/GMT-13' => 'UTC',
+  'Etc/GMT-14' => 'UTC',
+  'Etc/GMT-2' => 'UTC',
+  'Etc/GMT-3' => 'UTC',
+  'Etc/GMT-4' => 'UTC',
+  'Etc/GMT-5' => 'UTC',
+  'Etc/GMT-6' => 'UTC',
+  'Etc/GMT-7' => 'UTC',
+  'Etc/GMT-8' => 'UTC',
+  'Etc/GMT-9' => 'UTC',
+  'Etc/GMT0' => 'UTC',
+  'Etc/Greenwich' => 'UTC',
+  'Etc/UCT' => 'UTC',
+  'Etc/Universal' => 'UTC',
+  'Etc/UTC' => 'UTC',
+  'Etc/Zulu' => 'UTC',
+  'Factory' => 'UTC',
+  'GMT' => 'UTC',
+  'GMT+0' => 'UTC',
+  'GMT-0' => 'UTC',
+  'GMT0' => 'UTC',
+  'Hongkong' => 'Asia/Hong_Kong',
+  'HST' => 'Pacific/Honolulu',
+  'Iceland' => 'Atlantic/Reykjavik',
+  'Iran' => 'Asia/Tehran',
+  'Israel' => 'Asia/Tel_Aviv',
+  'Jamaica' => 'America/Jamaica',
+  'Japan' => 'Asia/Tokyo',
+  'Kwajalein' => 'Pacific/Kwajalein',
+  'Libya' => 'Africa/Tunis',
+  'MET' => 'Europe/Budapest',
+  'Mexico/BajaNorte' => 'America/Tijuana',
+  'Mexico/BajaSur' => 'America/Mazatlan',
+  'Mexico/General' => 'America/Mexico_City',
+  'MST' => 'America/Boise',
+  'MST7MDT' => 'America/Boise',
+  'Navajo' => 'America/Phoenix',
+  'NZ' => 'Pacific/Auckland',
+  'NZ-CHAT' => 'Pacific/Chatham',
+  'Poland' => 'Europe/Warsaw',
+  'Portugal' => 'Europe/Lisbon',
+  'PRC' => 'Asia/Chongqing',
+  'PST8PDT' => 'America/Los_Angeles',
+  'ROC' => 'Asia/Taipei',
+  'ROK' => 'Asia/Seoul',
+  'Singapore' => 'Asia/Singapore',
+  'Turkey' => 'Europe/Istanbul',
+  'US/Alaska' => 'America/Anchorage',
+  'US/Aleutian' => 'America/Adak',
+  'US/Arizona' => 'America/Phoenix',
+  'US/Central' => 'America/Chicago',
+  'US/East-Indiana' => 'America/Indianapolis',
+  'US/Eastern' => 'America/New_York',
+  'US/Hawaii' => 'Pacific/Honolulu',
+  'US/Indiana-Starke' => 'America/Indiana/Knox',
+  'US/Michigan' => 'America/Detroit',
+  'US/Mountain' => 'America/Boise',
+  'US/Pacific' => 'America/Los_Angeles',
+  'US/Pacific-New' => 'America/Los_Angeles',
+  'US/Samoa' => 'Pacific/Samoa',
+  'W-SU' => 'Europe/Moscow',
+  'WET' => 'Europe/Paris',
+  );
+  if (array_key_exists($old, $replace)) {
+    return $replace[$old];
+  }
+  else {
+    return $old;
+  }
+}
diff --git a/sites/all/modules/date/date_api/date_api.info b/sites/all/modules/date/date_api/date_api.info
new file mode 100644
index 0000000000000000000000000000000000000000..09c0983ba95656b9ecbe8dd35240987f2e393db0
--- /dev/null
+++ b/sites/all/modules/date/date_api/date_api.info
@@ -0,0 +1,17 @@
+name = Date API
+description = A Date API that can be used by other modules.
+package = Date/Time
+core = 7.x
+php = 5.2
+
+stylesheets[all][] = date.css
+
+files[] = date_api.module
+files[] = date_api_sql.inc
+
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date_api/date_api.install b/sites/all/modules/date/date_api/date_api.install
new file mode 100644
index 0000000000000000000000000000000000000000..d2bfbb36794f2c1d00565a4a017f68a24ea51c20
--- /dev/null
+++ b/sites/all/modules/date/date_api/date_api.install
@@ -0,0 +1,239 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the date_api module.
+ */
+
+/**
+ * Helper function for setting Date variables.
+ */
+function date_api_set_variables() {
+  // Set absolute minimum and maximum year for dates on this site.
+  // There is actually no maximum and minimum year in PHP 5, but a date with
+  // a year less than 0 would result in negative ISO and DATETIME dates,
+  // like -1250-01-01T00:00:00, which probably won't make sense or work
+  // correctly anywhere.
+  // The odd construct of using variable_get() instead of variable_set()
+  // is so we don't accidentally write over an existing value. If
+  // no value is set, variable_get() will set it.
+  variable_get('date_max_year', 4000);
+  variable_get('date_min_year', 1);
+  variable_get('date_php_min_year', 1901);
+
+  // Set an API version in a way that other modules can test for compatibility.
+  variable_set('date_api_version', '7.2');
+}
+
+/**
+ * Implements hook_requirements().
+ */
+function date_api_requirements($phase) {
+  $requirements = array();
+
+  if ($phase == 'runtime') {
+    $t = get_t();
+    module_load_include('module', 'date_api');
+    $messages = date_api_status();
+    $error_messages = !empty($messages['errors']) ? $messages['errors'] : array();
+    $success_messages = !empty($messages['success']) ? $messages['success'] : array();
+
+    if (!empty($error_messages)) {
+      $requirements['date'] = array(
+        'title' => $t('Date API'),
+        'value' => $t('Missing system date settings'),
+        'description' => implode(' ', array_merge($error_messages, $success_messages)),
+        'severity' => REQUIREMENT_ERROR,
+      );
+    }
+    else {
+      $requirements['date'] = array(
+        'title' => $t('Date API'),
+        'value' => $t('System date settings'),
+        'description' => implode(' ', $success_messages),
+      );
+    }
+  }
+  return $requirements;
+}
+
+/**
+ * Implements hook_install().
+ */
+function date_api_install() {
+  // Ensure translations don't break at install time.
+  $t = get_t();
+
+  // date_api_set_variables can install date_timezone. The
+  // date_timezone_install() function does a module_enable('date_api'). This
+  // means that date_api_enable() can be called before date_api_install()
+  // finishes! So the date_api schema needs to be installed before this line!
+  date_api_set_variables();
+
+  $message = $t('The Date API requires that you set up the !timezone_link and the !format_link to function correctly.', array('!timezone_link' => l($t('site timezone and first day of week settings'), 'admin/config/regional/settings'), '!format_link' => l($t('date format settings'), 'admin/config/regional/date-time')));
+  drupal_set_message(filter_xss_admin($message), 'warning');
+}
+
+/**
+ * Implements hook_enable().
+ */
+function date_api_enable() {
+  date_api_set_variables();
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function date_api_uninstall() {
+  cache_clear_all('date_timezone_identifiers_list', 'cache');
+  $variables = array(
+    'date_api_version',
+    'date_min_year',
+    'date_max_year',
+    'date_php_min_year',
+    'date_db_tz_support',
+    'date_api_use_iso8601',
+    );
+  foreach ($variables as $variable) {
+    variable_del($variable);
+  }
+
+  if (db_table_exists('views_display')) {
+    $displays = array(
+      'date_nav',
+    );
+    db_query("DELETE FROM {views_display} WHERE display_plugin IN ('" . implode("','", $displays) . "')");
+    db_query("DELETE FROM {cache_views}");
+  }
+}
+
+/**
+ * Implements hook_update_last_removed().
+ */
+function date_api_update_last_removed() {
+  return 6005;
+}
+
+/**
+ * Move old date format data to new date format tables, and delete the old
+ * tables. Insert only values that don't already exist in the new tables, in
+ * case new version of those custom values have already been created.
+ */
+function date_api_update_7000() {
+  // Move format data from the old 'date_format_types' table to the new
+  // 'date_format_type' table.
+  if (db_table_exists('date_format_types')) {
+    // Find all the custom entries in the D6 table.
+    $result = db_select('date_format_types', 'old')
+      ->fields('old', array('type', 'title', 'locked'))
+      ->condition('locked', 0)
+      ->execute()
+      ->fetchAll(PDO::FETCH_ASSOC);
+
+    // Iterate over all the old values.
+    foreach ($result as $row) {
+      // See if this value already exists in the new table
+      // (it might have been added manually before this update got run).
+      $count = db_select('date_format_type', 'new')
+        ->condition('type', $row['type'])
+        ->countQuery()
+        ->execute()
+        ->fetchField();
+
+      // If the value is missing, insert it.
+      // Do nothing if it already exists, assume the value in the
+      // new table trumps the old values.
+      if (empty($count)) {
+        db_insert('date_format_type')
+          ->fields(array(
+            'type' => $row['type'],
+            'title' => $row['title'],
+            'locked' => $row['locked'],
+          ))
+          ->execute();
+      }
+    }
+
+    // Drop the old table.
+    db_drop_table('date_format_types');
+
+  }
+
+  // Move format data from the old 'date_formats' table (which was renamed to
+  // 'd6_date_formats') to the new 'date_formats' table.
+  if (db_table_exists('d6_date_formats')) {
+    // Find all the custom entries in the D6 table.
+    $result = db_select('d6_date_formats', 'old')
+      ->fields('old', array('format', 'type', 'locked'))
+      ->condition('type', 'custom')
+      ->execute()
+      ->fetchAll(PDO::FETCH_ASSOC);
+
+    // Iterate over all the old values.
+    foreach ($result as $row) {
+      // See if this value already exists in the new table (it might have been
+      // added manually before this update got run).
+      $count = db_select('date_formats', 'new')
+        ->condition('format', $row['format'])
+        ->condition('type', $row['type'])
+        ->countQuery()
+        ->execute()
+        ->fetchField();
+
+      // If the value is missing, insert it. Do nothing if it already exists,
+      // assume the value in the new table trumps the old values.
+      if (empty($count)) {
+        db_insert('date_formats')
+          ->fields(array(
+            'format' => $row['format'],
+            'type' => $row['type'],
+            'locked' => $row['locked'],
+          ))
+          ->execute();
+      }
+    }
+
+    // Drop the old table.
+    db_drop_table('d6_date_formats');
+  }
+
+  // Move format data from the old 'date_format_locale' table (which was renamed
+  // to 'd6_date_format_locale') to the new 'date_format_locale' table.
+  if (db_table_exists('d6_date_format_locale')) {
+    // Find all the custom entries in the D6 table.
+    $result = db_select('d6_date_format_locale', 'old')
+      ->fields('old', array('format', 'type', 'language'))
+      ->condition('type', 'custom')
+      ->execute()
+      ->fetchAll(PDO::FETCH_ASSOC);
+
+    // Iterate over all the old values.
+    foreach ($result as $row) {
+      // See if this value already exists in the new table (it might have been
+      // added manually before this update got run).
+      $count = db_select('date_format_locale', 'new')
+        ->condition('format', $row['format'])
+        ->condition('type', $row['type'])
+        ->condition('language', $row['language'])
+        ->countQuery()
+        ->execute()
+        ->fetchField();
+
+      // If the value is missing, insert it.
+      // Do nothing if it already exists, assume the value in the
+      // new table trumps the old values.
+      if (empty($count)) {
+        db_insert('date_format_locale')
+          ->fields(array(
+            'format' => $row['format'],
+            'type' => $row['type'],
+            'language' => $row['language'],
+          ))
+          ->execute();
+      }
+    }
+
+    // Drop the old table.
+    db_drop_table('d6_date_format_locale');
+  }
+}
diff --git a/sites/all/modules/date/date_api/date_api.module b/sites/all/modules/date/date_api/date_api.module
new file mode 100644
index 0000000000000000000000000000000000000000..b8c95f775fb68ed1d58dde4a191e73b886ce8c9d
--- /dev/null
+++ b/sites/all/modules/date/date_api/date_api.module
@@ -0,0 +1,2669 @@
+<?php
+
+/**
+ * @file
+ * This module will make the date API available to other modules.
+ * Designed to provide a light but flexible assortment of functions
+ * and constants, with more functionality in additional files that
+ * are not loaded unless other modules specifically include them.
+ */
+
+/**
+ * Set up some constants.
+ *
+ * Includes standard date types, format strings, strict regex strings for ISO
+ * and DATETIME formats (seconds are optional).
+ *
+ * The loose regex will find any variety of ISO date and time, with or
+ * without time, with or without dashes and colons separating the elements,
+ * and with either a 'T' or a space separating date and time.
+ */
+define('DATE_ISO', 'date');
+define('DATE_UNIX', 'datestamp');
+define('DATE_DATETIME', 'datetime');
+define('DATE_ARRAY', 'array');
+define('DATE_OBJECT', 'object');
+define('DATE_ICAL', 'ical');
+
+define('DATE_FORMAT_ISO', "Y-m-d\TH:i:s");
+define('DATE_FORMAT_UNIX', "U");
+define('DATE_FORMAT_DATETIME', "Y-m-d H:i:s");
+define('DATE_FORMAT_ICAL', "Ymd\THis");
+define('DATE_FORMAT_ICAL_DATE', "Ymd");
+define('DATE_FORMAT_DATE', 'Y-m-d');
+
+define('DATE_REGEX_ISO', '/(\d{4})?(-(\d{2}))?(-(\d{2}))?([T\s](\d{2}))?(:(\d{2}))?(:(\d{2}))?/');
+define('DATE_REGEX_DATETIME', '/(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):?(\d{2})?/');
+define('DATE_REGEX_LOOSE', '/(\d{4})-?(\d{1,2})-?(\d{1,2})([T\s]?(\d{2}):?(\d{2}):?(\d{2})?(\.\d+)?(Z|[\+\-]\d{2}:?\d{2})?)?/');
+define('DATE_REGEX_ICAL_DATE', '/(\d{4})(\d{2})(\d{2})/');
+define('DATE_REGEX_ICAL_DATETIME', '/(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(Z)?/');
+
+/**
+ * Core DateTime extension module used for as many date operations as possible.
+ */
+
+/**
+ * Implements hook_help().
+ */
+function date_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#date':
+      $output = '';
+      $messages = date_api_status();
+      $output = '<h2>Date API Status</h2>';
+      if (!empty($messages['success'])) {
+        $output .= '<ul><li>' . implode('</li><li>', $messages['success']) . '</li></ul>';
+      }
+      if (!empty($messages['errors'])) {
+        $output .= '<h3>Errors</h3><ul class="error"><li>' . implode('</li><li>', $messages['errors']) . '</li></ul>';
+      }
+
+      if (module_exists('date_tools')) {
+        $output .= '<h3>Date Tools</h3>' . t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and with a date field. ', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
+      }
+      else {
+        $output .= '<h3>Date Tools</h3>' . t('Dates and calendars can be complicated to set up. If you enable the Date Tools module, it provides a Date Wizard that makes it easy to create a simple date content type with a date field. ');
+      }
+
+      $output .= '<h2>More Information</h2><p>' . t('Complete documentation for the Date and Date API modules is available at <a href="@link">http://drupal.org/node/92460</a>.', array('@link' => 'http://drupal.org/node/262062')) . '</p>';
+
+      return $output;
+      break;
+  }
+}
+
+/**
+ * Helper function to retun the status of required date variables.
+ */
+function date_api_status() {
+  $t = get_t();
+
+  $error_messages = array();
+  $success_messages = array();
+
+  $value = variable_get('date_default_timezone');
+  if (isset($value)) {
+    $success_messages[] = $t('The timezone has been set to !value_link.', array('!value_link' => l($value, 'admin/config/regional/settings')));
+  }
+  else {
+    $error_messages[] = $t('The Date API requires that you set up the !timezone_link to function correctly.', array('!timezone_link' => l($t('site timezone'), 'admin/config/regional/settings')));
+  }
+
+  $value = variable_get('date_first_day');
+  if (isset($value)) {
+    $days = date_week_days();
+    $success_messages[] = $t('The first day of the week has been set to !value_link.', array('!value_link' => l($days[$value], 'admin/config/regional/settings')));
+  }
+  else {
+    $error_messages[] = $t('The Date API requires that you set up the !first_day_link to function correctly.', array('!first_day_link' => l($t('site first day of week settings'), 'admin/config/regional/settings')));
+  }
+
+  $value = variable_get('date_format_medium');
+  if (isset($value)) {
+    $now = date_now();
+    $success_messages[] = $t('The medium date format type has been set to to @value. You may find it helpful to add new format types like Date, Time, Month, or Year, with appropriate formats, at !value_link.', array('@value' => $now->format($value), '!value_link' => l(t('Date and time'), 'admin/config/regional/date-time')));
+  }
+  else {
+    $error_messages[] = $t('The Date API requires that you set up the !format_link to function correctly.', array('!format_link' => l($t('system date formats'), 'admin/config/regional/date-time')));
+  }
+
+  return array('errors', $error_messages, 'success' => $success_messages);
+
+}
+
+/**
+ * Implements hook_menu().
+ *
+ * Creates a 'Date API' section on the administration page for Date
+ * modules to use for their configuration and settings.
+ */
+function date_api_menu() {
+  $items['admin/config/date'] = array(
+    'title' => 'Date API',
+    'description' => 'Settings for modules the use the Date API.',
+    'position' => 'left',
+    'weight' => -10,
+    'page callback' => 'system_admin_menu_block_page',
+    'access arguments' => array('administer site configuration'),
+    'file' => 'system.admin.inc',
+    'file path' => drupal_get_path('module', 'system'),
+  );
+  return $items;
+}
+
+/**
+ * Extend PHP DateTime class with granularity handling, merge functionality and
+ * slightly more flexible initialization parameters.
+ *
+ * This class is a Drupal independent extension of the >= PHP 5.2 DateTime
+ * class.
+ *
+ * @see FeedsDateTimeElement class
+ */
+class DateObject extends DateTime {
+  public $granularity = array();
+  public $errors = array();
+  protected static $allgranularity = array('year', 'month', 'day', 'hour', 'minute', 'second', 'timezone');
+  private $serializedTime;
+  private $serializedTimezone;
+
+  /**
+   * Prepares the object during serialization.
+   *
+   * We are extending a core class and core classes cannot be serialized.
+   *
+   * @return array
+   *   Returns an array with the names of the variables that were serialized.
+   *
+   * @see http://bugs.php.net/41334
+   * @see http://bugs.php.net/39821
+   */
+  public function __sleep() {
+    $this->serializedTime = $this->format('c');
+    $this->serializedTimezone = $this->getTimezone()->getName();
+    return array('serializedTime', 'serializedTimezone');
+  }
+
+  /**
+   * Re-builds the object using local variables.
+   */
+  public function __wakeup() {
+    $this->__construct($this->serializedTime, new DateTimeZone($this->serializedTimezone));
+  }
+
+  /**
+   * Returns the date object as a string.
+   *
+   * @return string
+   *   The date object formatted as a string.
+   */
+  public function __toString() {
+    return $this->format(DATE_FORMAT_DATETIME) . ' ' . $this->getTimeZone()->getName();
+  }
+
+  /**
+   * Constructs a date object.
+   *
+   * @param string $time
+   *   A date/time string. Defaults to 'now'.
+   * @param object|string|null $tz
+   *   PHP DateTimeZone object, string or NULL allowed. Defaults to NULL.
+   * @param string $format
+   *   PHP date() type format for parsing. Doesn't support timezones; if you
+   *   have a timezone, send NULL and the default constructor method will
+   *   hopefully parse it. $format is recommended in order to use negative or
+   *   large years, which php's parser fails on.
+   */
+  public function __construct($time = 'now', $tz = NULL, $format = NULL) {
+    $this->timeOnly = FALSE;
+    $this->dateOnly = FALSE;
+
+    // Allow string timezones.
+    if (!empty($tz) && !is_object($tz)) {
+      $tz = new DateTimeZone($tz);
+    }
+
+    // Default to the site timezone when not explicitly provided.
+    elseif (empty($tz)) {
+      $tz = date_default_timezone_object();
+    }
+    // Special handling for Unix timestamps expressed in the local timezone.
+    // Create a date object in UTC and convert it to the local timezone. Don't
+    // try to turn things like '2010' with a format of 'Y' into a timestamp.
+    if (is_numeric($time) && (empty($format) || $format == 'U')) {
+      // Assume timestamp.
+      $time = "@" . $time;
+      $date = new DateObject($time, 'UTC');
+      if ($tz->getName() != 'UTC') {
+        $date->setTimezone($tz);
+      }
+      $time = $date->format(DATE_FORMAT_DATETIME);
+      $format = DATE_FORMAT_DATETIME;
+      $this->addGranularity('timezone');
+    }
+
+    if (is_array($time)) {
+      // Assume we were passed an indexed array.
+      if (empty($time['year']) && empty($time['month']) && empty($time['day'])) {
+        $this->timeOnly = TRUE;
+      }
+      if (empty($time['hour']) && empty($time['minute']) && empty($time['second'])) {
+        $this->dateOnly = TRUE;
+      }
+      $this->errors = $this->arrayErrors($time);
+      // Make this into an ISO date, forcing a full ISO date even if some values
+      // are missing.
+      $time = $this->toISO($time, TRUE);
+      // We checked for errors already, skip parsing the input values.
+      $format = NULL;
+    }
+
+    // The parse function will also set errors on the date parts.
+    if (!empty($format)) {
+      $arg = self::$allgranularity;
+      $element = array_pop($arg);
+      while (!$this->parse($time, $tz, $format) && $element != 'year') {
+        $element = array_pop($arg);
+        $format = date_limit_format($format, $arg);
+      }
+      if ($element == 'year') {
+        return FALSE;
+      }
+    }
+    elseif (is_string($time)) {
+      // PHP < 5.3 doesn't like the GMT- notation for parsing timezones.
+      $time = str_replace("GMT-", "-", $time);
+      $time = str_replace("GMT+", "+", $time);
+      // We are going to let the parent dateObject do a best effort attempt to
+      // turn this string into a valid date. It might fail and we want to
+      // control the error messages.
+      try {
+        @parent::__construct($time, $tz);
+      }
+      catch (Exception $e) {
+        $this->errors['date'] = $e;
+        return;
+      }
+      if (empty($this->granularity)) {
+        $this->setGranularityFromTime($time, $tz);
+      }
+    }
+    // If this tz was given as just an offset or the timezone
+    // was invalid, we need to do some tweaking.
+    if (!$this->getTimezone() || !preg_match('/[a-zA-Z]/', $this->getTimezone()->getName())) {
+
+      // If the timezone name is an offset and the original
+      // $tz has a name, use it. This happens if you pass in
+      // a date string with an offset along with a specific timezone name.
+      if (!preg_match('/[a-zA-Z]/', $this->getTimezone()->getName()) && preg_match('/[a-zA-Z]/', $tz->getName())) {
+        $this->setTimezone($tz);
+      }
+      // If we get this far, we have no information about the timezone name,
+      // but we will get undefined index errors without any name.
+      else {
+        $this->setTimezone(new DateTimeZone("UTC"));
+        $this->errors['timezone'] = t('No valid timezone name was provided.');
+      }
+    }
+  }
+
+  /**
+   * Merges two date objects together using the current date values as defaults.
+   *
+   * @param object $other
+   *   Another date object to merge with.
+   *
+   * @return object
+   *   A merged date object.
+   */
+  public function merge(FeedsDateTime $other) {
+    $other_tz = $other->getTimezone();
+    $this_tz = $this->getTimezone();
+    // Figure out which timezone to use for combination.
+    $use_tz = ($this->hasGranularity('timezone') || !$other->hasGranularity('timezone')) ? $this_tz : $other_tz;
+
+    $this2 = clone $this;
+    $this2->setTimezone($use_tz);
+    $other->setTimezone($use_tz);
+    $val = $this2->toArray(TRUE);
+    $otherval = $other->toArray();
+    foreach (self::$allgranularity as $g) {
+      if ($other->hasGranularity($g) && !$this2->hasGranularity($g)) {
+        // The other class has a property we don't; steal it.
+        $this2->addGranularity($g);
+        $val[$g] = $otherval[$g];
+      }
+    }
+    $other->setTimezone($other_tz);
+
+    $this2->setDate($val['year'], $val['month'], $val['day']);
+    $this2->setTime($val['hour'], $val['minute'], $val['second']);
+    return $this2;
+  }
+
+  /**
+   * Sets the time zone for the current date.
+   *
+   * Overrides default DateTime function. Only changes output values if
+   * actually had time granularity. This should be used as a "converter" for
+   * output, to switch tzs.
+   *
+   * In order to set a timezone for a datetime that doesn't have such
+   * granularity, merge() it with one that does.
+   *
+   * @param object $tz
+   *   A timezone object.
+   * @param bool $force
+   *   Whether or not to skip a date with no time. Defaults to FALSE.
+   */
+  public function setTimezone($tz, $force = FALSE) {
+    // PHP 5.2.6 has a fatal error when setting a date's timezone to itself.
+    // http://bugs.php.net/bug.php?id=45038
+    if (version_compare(PHP_VERSION, '5.2.7', '<') && $tz == $this->getTimezone()) {
+      $tz = new DateTimeZone($tz->getName());
+    }
+
+    if (!$this->hasTime() || !$this->hasGranularity('timezone') || $force) {
+      // This has no time or timezone granularity, so timezone doesn't mean
+      // much. We set the timezone using the method, which will change the
+      // day/hour, but then we switch back.
+      $arr = $this->toArray(TRUE);
+      parent::setTimezone($tz);
+      $this->setDate($arr['year'], $arr['month'], $arr['day']);
+      $this->setTime($arr['hour'], $arr['minute'], $arr['second']);
+      $this->addGranularity('timezone');
+      return;
+    }
+    return parent::setTimezone($tz);
+  }
+
+  /**
+   * Returns date formatted according to given format.
+   *
+   * Overrides base format function, formats this date according to its
+   * available granularity, unless $force'ed not to limit to granularity.
+   *
+   * @TODO Add translation into this so translated names will be provided.
+   *
+   * @param string $format
+   *   A date format string.
+   * @param bool $force
+   *   Whether or not to limit the granularity. Defaults to FALSE.
+   *
+   * @return string|false
+   *   Returns the formatted date string on success or FALSE on failure.
+   */
+  public function format($format, $force = FALSE) {
+    return parent::format($force ? $format : date_limit_format($format, $this->granularity));
+  }
+
+  /**
+   * Adds a granularity entry to the array.
+   *
+   * @param string $g
+   *   A single date part.
+   */
+  public function addGranularity($g) {
+    $this->granularity[] = $g;
+    $this->granularity = array_unique($this->granularity);
+  }
+
+  /**
+   * Removes a granularity entry from the array.
+   *
+   * @param string $g
+   *   A single date part.
+   */
+  public function removeGranularity($g) {
+    if ($key = array_search($g, $this->granularity)) {
+      unset($this->granularity[$key]);
+    }
+  }
+
+  /**
+   * Checks granularity array for a given entry.
+   *
+   * @param array|null $g
+   *   An array of date parts. Defaults to NULL.
+   *
+   * @returns bool
+   *   TRUE if the date part is present in the date's granularity.
+   */
+  public function hasGranularity($g = NULL) {
+    if ($g === NULL) {
+      // Just want to know if it has something valid means no lower
+      // granularities without higher ones.
+      $last = TRUE;
+      foreach (self::$allgranularity as $arg) {
+        if ($arg == 'timezone') {
+          continue;
+        }
+        if (in_array($arg, $this->granularity) && !$last) {
+          return FALSE;
+        }
+        $last = in_array($arg, $this->granularity);
+      }
+      return in_array('year', $this->granularity);
+    }
+    if (is_array($g)) {
+      foreach ($g as $gran) {
+        if (!in_array($gran, $this->granularity)) {
+          return FALSE;
+        }
+      }
+      return TRUE;
+    }
+    return in_array($g, $this->granularity);
+  }
+
+  /**
+   * Determines if a a date is valid for a given granularity.
+   *
+   * @param array|null $granularity
+   *   An array of date parts. Defaults to NULL.
+   * @param bool $flexible
+   *   TRUE if the granuliarty is flexible, FALSE otherwise. Defaults to FALSE.
+   *
+   * @return bool
+   *   Whether a date is valid for a given granularity.
+   */
+  public function validGranularity($granularity = NULL, $flexible = FALSE) {
+    $true = $this->hasGranularity() && (!$granularity || $flexible || $this->hasGranularity($granularity));
+    if (!$true && $granularity) {
+      foreach ((array) $granularity as $part) {
+        if (!$this->hasGranularity($part)) {
+          $this->errors[$part] = t("The @part is missing.", array('@part' => $part));
+        }
+      }
+    }
+    return $true;
+  }
+
+  /**
+   * Returns whether this object has time set.
+   *
+   * Used primarily for timezone conversion and formatting.
+   *
+   * @return bool
+   *   TRUE if the date contains time parts, FALSE otherwise.
+   */
+  public function hasTime() {
+    return $this->hasGranularity('hour');
+  }
+
+  /**
+   * Returns whether the input values included a year.
+   *
+   * Useful to use pseudo date objects when we only are interested in the time.
+   *
+   * @todo $this->completeDate does not actually exist?
+   */
+  public function completeDate() {
+    return $this->completeDate;
+  }
+
+  /**
+   * Removes unwanted date parts from a date.
+   *
+   * In common usage we should not unset timezone through this.
+   *
+   * @param array $granularity
+   *   An array of date parts.
+   */
+  public function limitGranularity($granularity) {
+    foreach ($this->granularity as $key => $val) {
+      if ($val != 'timezone' && !in_array($val, $granularity)) {
+        unset($this->granularity[$key]);
+      }
+    }
+  }
+
+  /**
+   * Determines the granularity of a date based on the constructor's arguments.
+   *
+   * @param string $time
+   *   A date string.
+   * @param bool $tz
+   *   TRUE if the date has a timezone, FALSE otherwise.
+   */
+  protected function setGranularityFromTime($time, $tz) {
+    $this->granularity = array();
+    $temp = date_parse($time);
+    // Special case for 'now'.
+    if ($time == 'now') {
+      $this->granularity = array('year', 'month', 'day', 'hour', 'minute', 'second');
+    }
+    else {
+      // This PHP date_parse() method currently doesn't have resolution down to
+      // seconds, so if there is some time, all will be set.
+      foreach (self::$allgranularity as $g) {
+        if ((isset($temp[$g]) && is_numeric($temp[$g])) || ($g == 'timezone' && (isset($temp['zone_type']) && $temp['zone_type'] > 0))) {
+          $this->granularity[] = $g;
+        }
+      }
+    }
+    if ($tz) {
+      $this->addGranularity('timezone');
+    }
+  }
+
+  /**
+   * Converts a date string into a date object.
+   *
+   * @param string $date
+   *   The date string to parse.
+   * @param object $tz
+   *   A timezone object.
+   * @param string $format
+   *   The date format string.
+   *
+   * @return object
+   *   Returns the date object.
+   */
+  protected function parse($date, $tz, $format) {
+    $array = date_format_patterns();
+    foreach ($array as $key => $value) {
+      // The letter with no preceding '\'.
+      $patterns[] = "`(^|[^\\\\\\\\])" . $key . "`";
+      // A single character.
+      $repl1[] = '${1}(.)';
+      // The.
+      $repl2[] = '${1}(' . $value . ')';
+    }
+    $patterns[] = "`\\\\\\\\([" . implode(array_keys($array)) . "])`";
+    $repl1[] = '${1}';
+    $repl2[] = '${1}';
+
+    $format_regexp = preg_quote($format);
+
+    // Extract letters.
+    $regex1 = preg_replace($patterns, $repl1, $format_regexp, 1);
+    $regex1 = str_replace('A', '(.)', $regex1);
+    $regex1 = str_replace('a', '(.)', $regex1);
+    preg_match('`^' . $regex1 . '$`', stripslashes($format), $letters);
+    array_shift($letters);
+    // Extract values.
+    $regex2 = preg_replace($patterns, $repl2, $format_regexp, 1);
+    $regex2 = str_replace('A', '(AM|PM)', $regex2);
+    $regex2 = str_replace('a', '(am|pm)', $regex2);
+    preg_match('`^' . $regex2 . '$`', $date, $values);
+    array_shift($values);
+    // If we did not find all the values for the patterns in the format, abort.
+    if (count($letters) != count($values)) {
+      $this->errors['invalid'] = t('The value @date does not match the expected format.', array('@date' => $date));
+      return FALSE;
+    }
+    $this->granularity = array();
+    $final_date = array('hour' => 0, 'minute' => 0, 'second' => 0, 'month' => 1, 'day' => 1, 'year' => 0);
+    foreach ($letters as $i => $letter) {
+      $value = $values[$i];
+      switch ($letter) {
+        case 'd':
+        case 'j':
+          $final_date['day'] = intval($value);
+          $this->addGranularity('day');
+          break;
+        case 'n':
+        case 'm':
+          $final_date['month'] = intval($value);
+          $this->addGranularity('month');
+          break;
+        case 'F':
+          $array_month_long = array_flip(date_month_names());
+          $final_date['month'] = array_key_exists($value, $array_month_long) ? $array_month_long[$value] : '';
+          $this->addGranularity('month');
+          break;
+        case 'M':
+          $array_month = array_flip(date_month_names_abbr());
+          $final_date['month'] = array_key_exists($value, $array_month) ? $array_month[$value] : '';
+          $this->addGranularity('month');
+          break;
+        case 'Y':
+          $final_date['year'] = $value;
+          $this->addGranularity('year');
+          if (strlen($value) < 4) {
+            $this->errors['year'] = t('The year is invalid. Please check that entry includes four digits.');
+          }
+          break;
+        case 'y':
+          $year = $value;
+          // If no century, we add the current one ("06" => "2006").
+          $final_date['year'] = str_pad($year, 4, substr(date("Y"), 0, 2), STR_PAD_LEFT);
+          $this->addGranularity('year');
+          break;
+        case 'a':
+        case 'A':
+          $ampm = strtolower($value);
+          break;
+        case 'g':
+        case 'h':
+        case 'G':
+        case 'H':
+          $final_date['hour'] = intval($value);
+          $this->addGranularity('hour');
+          break;
+        case 'i':
+          $final_date['minute'] = intval($value);
+          $this->addGranularity('minute');
+          break;
+        case 's':
+          $final_date['second'] = intval($value);
+          $this->addGranularity('second');
+          break;
+        case 'U':
+          parent::__construct($value, $tz ? $tz : new DateTimeZone("UTC"));
+          $this->addGranularity('year');
+          $this->addGranularity('month');
+          $this->addGranularity('day');
+          $this->addGranularity('hour');
+          $this->addGranularity('minute');
+          $this->addGranularity('second');
+          return $this;
+          break;
+      }
+    }
+    if (isset($ampm) && $ampm == 'pm' && $final_date['hour'] < 12) {
+      $final_date['hour'] += 12;
+    }
+    elseif (isset($ampm) && $ampm == 'am' && $final_date['hour'] == 12) {
+      $final_date['hour'] -= 12;
+    }
+
+    // Blank becomes current time, given TZ.
+    parent::__construct('', $tz ? $tz : new DateTimeZone("UTC"));
+    if ($tz) {
+      $this->addGranularity('timezone');
+    }
+
+    // SetDate expects an integer value for the year, results can be unexpected
+    // if we feed it something like '0100' or '0000'.
+    $final_date['year'] = intval($final_date['year']);
+
+    $this->errors += $this->arrayErrors($final_date);
+    $granularity = drupal_map_assoc($this->granularity);
+
+    // If the input value is '0000-00-00', PHP's date class will later
+    // incorrectly convert it to something like '-0001-11-30' if we do setDate()
+    // here. If we don't do setDate() here, it will default to the current date
+    // and we will lose any way to tell that there was no date in the orignal
+    // input values. So set a flag we can use later to tell that this date
+    // object was created using only time values, and that the date values are
+    // artifical.
+    if (empty($final_date['year']) && empty($final_date['month']) && empty($final_date['day'])) {
+      $this->timeOnly = TRUE;
+    }
+    elseif (empty($this->errors)) {
+      // setDate() expects a valid year, month, and day.
+      // Set some defaults for dates that don't use this to
+      // keep PHP from interpreting it as the last day of
+      // the previous month or last month of the previous year.
+      if (empty($granularity['month'])) {
+        $final_date['month'] = 1;
+      }
+      if (empty($granularity['day'])) {
+        $final_date['day'] = 1;
+      }
+      $this->setDate($final_date['year'], $final_date['month'], $final_date['day']);
+    }
+
+    if (!isset($final_date['hour']) && !isset($final_date['minute']) && !isset($final_date['second'])) {
+      $this->dateOnly = TRUE;
+    }
+    elseif (empty($this->errors)) {
+      $this->setTime($final_date['hour'], $final_date['minute'], $final_date['second']);
+    }
+    return $this;
+  }
+
+  /**
+   * Returns all standard date parts in an array.
+   *
+   * Will return '' for parts in which it lacks granularity.
+   *
+   * @param bool $force
+   *   Whether or not to limit the granularity. Defaults to FALSE.
+   *
+   * @return array
+   *   An array of formatted date part values, keyed by date parts.
+   */
+  public function toArray($force = FALSE) {
+    return array(
+      'year' => $this->format('Y', $force),
+      'month' => $this->format('n', $force),
+      'day' => $this->format('j', $force),
+      'hour' => intval($this->format('H', $force)),
+      'minute' => intval($this->format('i', $force)),
+      'second' => intval($this->format('s', $force)),
+      'timezone' => $this->format('e', $force),
+    );
+  }
+
+  /**
+   * Creates an ISO date from an array of values.
+   *
+   * @param array $arr
+   *   An array of date values keyed by date part.
+   * @param bool $full
+   *   (optional) Whether to force a full date by filling in missing values.
+   *   Defaults to FALSE.
+   */
+  public function toISO($arr, $full = FALSE) {
+    // Add empty values to avoid errors. The empty values must create a valid
+    // date or we will get date slippage, i.e. a value of 2011-00-00 will get
+    // interpreted as November of 2010 by PHP.
+    if ($full) {
+      $arr += array('year' => 0, 'month' => 1, 'day' => 1, 'hour' => 0, 'minute' => 0, 'second' => 0);
+    }
+    else {
+      $arr += array('year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '');
+    }
+    $datetime = '';
+    if ($arr['year'] !== '') {
+      $datetime = date_pad(intval($arr['year']), 4);
+      if ($full || $arr['month'] !== '') {
+        $datetime .= '-' . date_pad(intval($arr['month']));
+        if ($full || $arr['day'] !== '') {
+          $datetime .= '-' . date_pad(intval($arr['day']));
+        }
+      }
+    }
+    if ($arr['hour'] !== '') {
+      $datetime .= $datetime ? 'T' : '';
+      $datetime .= date_pad(intval($arr['hour']));
+      if ($full || $arr['minute'] !== '') {
+        $datetime .= ':' . date_pad(intval($arr['minute']));
+        if ($full || $arr['second'] !== '') {
+          $datetime .= ':' . date_pad(intval($arr['second']));
+        }
+      }
+    }
+    return $datetime;
+  }
+
+  /**
+   * Forces an incomplete date to be valid.
+   *
+   * E.g., add a valid year, month, and day if only the time has been defined.
+   *
+   * @param array|string $date
+   *   An array of date parts or a datetime string with values to be massaged
+   *   into a valid date object.
+   * @param string $format
+   *   (optional) The format of the date. Defaults to NULL.
+   * @param string $default
+   *   (optional) If the fallback should use the first value of the date part,
+   *   or the current value of the date part. Defaults to 'first'.
+   */
+  public function setFuzzyDate($date, $format = NULL, $default = 'first') {
+    $timezone = $this->getTimeZone() ? $this->getTimeZone()->getName() : NULL;
+    $comp = new DateObject($date, $timezone, $format);
+    $arr = $comp->toArray(TRUE);
+    foreach ($arr as $key => $value) {
+      // Set to intval here and then test that it is still an integer.
+      // Needed because sometimes valid integers come through as strings.
+      $arr[$key] = $this->forceValid($key, intval($value), $default, $arr['month'], $arr['year']);
+    }
+    $this->setDate($arr['year'], $arr['month'], $arr['day']);
+    $this->setTime($arr['hour'], $arr['minute'], $arr['second']);
+  }
+
+  /**
+   * Converts a date part into something that will produce a valid date.
+   *
+   * @param string $part
+   *   The date part.
+   * @param int $value
+   *   The date value for this part.
+   * @param string $default
+   *   (optional) If the fallback should use the first value of the date part,
+   *   or the current value of the date part. Defaults to 'first'.
+   * @param int $month
+   *   (optional) Used when the date part is less than 'month' to specify the
+   *   date. Defaults to NULL.
+   * @param int $year
+   *   (optional) Used when the date part is less than 'year' to specify the
+   *   date. Defaults to NULL.
+   *
+   * @return int
+   *   A valid date value.
+   */
+  protected function forceValid($part, $value, $default = 'first', $month = NULL, $year = NULL) {
+    $now = date_now();
+    switch ($part) {
+      case 'year':
+        $fallback = $now->format('Y');
+        return !is_int($value) || empty($value) || $value < variable_get('date_min_year', 1) || $value > variable_get('date_max_year', 4000) ? $fallback : $value;
+        break;
+      case 'month':
+        $fallback = $default == 'first' ? 1 : $now->format('n');
+        return !is_int($value) || empty($value) || $value <= 0 || $value > 12 ? $fallback : $value;
+        break;
+      case 'day':
+        $fallback = $default == 'first' ? 1 : $now->format('j');
+        $max_day = isset($year) && isset($month) ? date_days_in_month($year, $month) : 31;
+        return !is_int($value) || empty($value) || $value <= 0 || $value > $max_day ? $fallback : $value;
+        break;
+      case 'hour':
+        $fallback = $default == 'first' ? 0 : $now->format('G');
+        return !is_int($value) || $value < 0 || $value > 23 ? $fallback : $value;
+        break;
+      case 'minute':
+        $fallback = $default == 'first' ? 0 : $now->format('i');
+        return !is_int($value) || $value < 0 || $value > 59 ? $fallback : $value;
+        break;
+      case 'second':
+        $fallback = $default == 'first' ? 0 : $now->format('s');
+        return !is_int($value) || $value < 0 || $value > 59 ? $fallback : $value;
+        break;
+    }
+  }
+
+  /**
+   * Finds possible errors in an array of date part values.
+   *
+   * The forceValid() function will change an invalid value to a valid one, so
+   * we just need to see if the value got altered.
+   *
+   * @param array $arr
+   *   An array of date values, keyed by date part.
+   *
+   * @return array
+   *   An array of error messages, keyed by date part.
+   */
+  public function arrayErrors($arr) {
+    $errors = array();
+    $now = date_now();
+    $default_month = !empty($arr['month']) ? $arr['month'] : $now->format('n');
+    $default_year = !empty($arr['year']) ? $arr['year'] : $now->format('Y');
+
+    $this->granularity = array();
+    foreach ($arr as $part => $value) {
+      // Explicitly set the granularity to the values in the input array.
+      if (is_numeric($value)) {
+        $this->addGranularity($part);
+      }
+      // Avoid false errors when a numeric value is input as a string by casting
+      // as an integer.
+      $value = intval($value);
+      if (!empty($value) && $this->forceValid($part, $value, 'now', $default_month, $default_year) != $value) {
+        // Use a switch/case to make translation easier by providing a different
+        // message for each part.
+        switch ($part) {
+          case 'year':
+            $errors['year'] = t('The year is invalid.');
+            break;
+          case 'month':
+            $errors['month'] = t('The month is invalid.');
+            break;
+          case 'day':
+            $errors['day'] = t('The day is invalid.');
+            break;
+          case 'hour':
+            $errors['hour'] = t('The hour is invalid.');
+            break;
+          case 'minute':
+            $errors['minute'] = t('The minute is invalid.');
+            break;
+          case 'second':
+            $errors['second'] = t('The second is invalid.');
+            break;
+        }
+      }
+    }
+    if ($this->hasTime()) {
+      $this->addGranularity('timezone');
+    }
+    return $errors;
+  }
+
+  /**
+   * Computes difference between two days using a given measure.
+   *
+   * @param object $date2_in
+   *   The stop date.
+   * @param string $measure
+   *   (optional) A granularity date part. Defaults to 'seconds'.
+   * @param boolean $absolute
+   *   (optional) Indicate whether the absolute value of the difference should
+   *   be returned or if the sign should be retained. Defaults to TRUE.
+   */
+  public function difference($date2_in, $measure = 'seconds', $absolute = TRUE) {
+    // Create cloned objects or original dates will be impacted by the
+    // date_modify() operations done in this code.
+    $date1 = clone($this);
+    $date2 = clone($date2_in);
+    if (is_object($date1) && is_object($date2)) {
+      $diff = date_format($date2, 'U') - date_format($date1, 'U');
+      if ($diff == 0) {
+        return 0;
+      }
+      elseif ($diff < 0 && $absolute) {
+        // Make sure $date1 is the smaller date.
+        $temp = $date2;
+        $date2 = $date1;
+        $date1 = $temp;
+        $diff = date_format($date2, 'U') - date_format($date1, 'U');
+      }
+      $year_diff = intval(date_format($date2, 'Y') - date_format($date1, 'Y'));
+      switch ($measure) {
+        // The easy cases first.
+        case 'seconds':
+          return $diff;
+        case 'minutes':
+          return $diff / 60;
+        case 'hours':
+          return $diff / 3600;
+        case 'years':
+          return $year_diff;
+
+        case 'months':
+          $format = 'n';
+          $item1 = date_format($date1, $format);
+          $item2 = date_format($date2, $format);
+          if ($year_diff == 0) {
+            return intval($item2 - $item1);
+          }
+          else {
+            $item_diff = 12 - $item1;
+            $item_diff += intval(($year_diff - 1) * 12);
+            return $item_diff + $item2;
+          }
+          break;
+
+        case 'days':
+          $format = 'z';
+          $item1 = date_format($date1, $format);
+          $item2 = date_format($date2, $format);
+          if ($year_diff == 0) {
+            return intval($item2 - $item1);
+          }
+          else {
+            $item_diff = date_days_in_year($date1) - $item1;
+            for ($i = 1; $i < $year_diff; $i++) {
+              date_modify($date1, '+1 year');
+              $item_diff += date_days_in_year($date1);
+            }
+            return $item_diff + $item2;
+          }
+          break;
+
+        case 'weeks':
+          $week_diff = date_format($date2, 'W') - date_format($date1, 'W');
+          $year_diff = date_format($date2, 'o') - date_format($date1, 'o');
+          for ($i = 1; $i <= $year_diff; $i++) {
+            date_modify($date1, '+1 year');
+            $week_diff += date_iso_weeks_in_year($date1);
+          }
+          return $week_diff;
+      }
+    }
+    return NULL;
+  }
+}
+
+/**
+ * Determines if the date element needs to be processed.
+ *
+ * Helper function to see if date element has been hidden by FAPI to see if it
+ * needs to be processed or just pass the value through. This is needed since
+ * normal date processing explands the date element into parts and then
+ * reconstructs it, which is not needed or desirable if the field is hidden.
+ *
+ * @param array $element
+ *   The date element to check.
+ *
+ * @return bool
+ *   TRUE if the element is effectively hidden, FALSE otherwise.
+ */
+function date_hidden_element($element) {
+  // @TODO What else needs to be tested to see if dates are hidden or disabled?
+  if ((isset($element['#access']) && empty($element['#access']))
+    || !empty($element['#programmed'])
+    || in_array($element['#type'], array('hidden', 'value'))) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Helper function for getting the format string for a date type.
+ *
+ * @param string $type
+ *   A date type format name.
+ *
+ * @return string
+ *   A date type format, like 'Y-m-d H:i:s'.
+ */
+function date_type_format($type) {
+  switch ($type) {
+    case DATE_ISO:
+      return DATE_FORMAT_ISO;
+    case DATE_UNIX:
+      return DATE_FORMAT_UNIX;
+    case DATE_DATETIME:
+      return DATE_FORMAT_DATETIME;
+    case DATE_ICAL:
+      return DATE_FORMAT_ICAL;
+  }
+}
+
+/**
+ * Constructs an untranslated array of month names.
+ *
+ * Needed for CSS, translation functions, strtotime(), and other places
+ * that use the English versions of these words.
+ *
+ * @return array
+ *   An array of month names.
+ */
+function date_month_names_untranslated() {
+  static $month_names;
+  if (empty($month_names)) {
+    $month_names = array(
+      1 => 'January',
+      2 => 'February',
+      3 => 'March',
+      4 => 'April',
+      5 => 'May',
+      6 => 'June',
+      7 => 'July',
+      8 => 'August',
+      9 => 'September',
+      10 => 'October',
+      11 => 'November',
+      12 => 'December',
+    );
+  }
+  return $month_names;
+}
+
+/**
+ * Returns a translated array of month names.
+ *
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ *
+ * @return array
+ *   An array of month names.
+ */
+function date_month_names($required = FALSE) {
+  $month_names = array();
+  foreach (date_month_names_untranslated() as $key => $month) {
+    $month_names[$key] = t($month, array(), array('context' => 'Long month name'));
+  }
+  $none = array('' => '');
+  return !$required ? $none + $month_names : $month_names;
+}
+
+/**
+ * Constructs a translated array of month name abbreviations
+ *
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ * @param int $length
+ *   (optional) The length of the abbreviation. Defaults to 3.
+ *
+ * @return array
+ *   An array of month abbreviations.
+ */
+function date_month_names_abbr($required = FALSE, $length = 3) {
+  $month_names = array();
+  foreach (date_month_names_untranslated() as $key => $month) {
+    if ($length == 3) {
+      $month_names[$key] = t(substr($month, 0, $length), array());
+    }
+    else {
+      $month_names[$key] = t(substr($month, 0, $length), array(), array('context' => 'month_abbr'));
+    }
+  }
+  $none = array('' => '');
+  return !$required ? $none + $month_names : $month_names;
+}
+
+/**
+ * Constructs an untranslated array of week days.
+ *
+ * Needed for CSS, translation functions, strtotime(), and other places
+ * that use the English versions of these words.
+ *
+ * @param bool $refresh
+ *   (optional) Whether to refresh the list. Defaults to TRUE.
+ *
+ * @return array
+ *   An array of week day names
+ */
+function date_week_days_untranslated($refresh = TRUE) {
+  static $weekdays;
+  if ($refresh || empty($weekdays)) {
+    $weekdays = array(
+      'Sunday',
+      'Monday',
+      'Tuesday',
+      'Wednesday',
+      'Thursday',
+      'Friday',
+      'Saturday',
+    );
+  }
+  return $weekdays;
+}
+
+/**
+ * Returns a translated array of week names.
+ *
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ *
+ * @return array
+ *   An array of week day names
+ */
+function date_week_days($required = FALSE, $refresh = TRUE) {
+  $weekdays = array();
+  foreach (date_week_days_untranslated() as $key => $day) {
+    $weekdays[$key] = t($day, array(), array('context' => ''));
+  }
+  $none = array('' => '');
+  return !$required ? $none + $weekdays : $weekdays;
+}
+
+/**
+ * Constructs a translated array of week day abbreviations.
+ *
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ * @param bool $refresh
+ *   (optional) Whether to refresh the list. Defaults to TRUE.
+ * @param int $length
+ *   (optional) The length of the abbreviation. Defaults to 3.
+ *
+ * @return array
+ *   An array of week day abbreviations
+ */
+function date_week_days_abbr($required = FALSE, $refresh = TRUE, $length = 3) {
+  $weekdays = array();
+  switch ($length) {
+    case 1:
+      $context = 'day_abbr1';
+      break;
+    case 2:
+      $context = 'day_abbr2';
+      break;
+    default:
+      $context = '';
+      break;
+  }
+  foreach (date_week_days_untranslated() as $key => $day) {
+    $weekdays[$key] = t(substr($day, 0, $length), array(), array('context' => $context));
+  }
+  $none = array('' => '');
+  return !$required ? $none + $weekdays : $weekdays;
+}
+
+/**
+ * Reorders weekdays to match the first day of the week.
+ *
+ * @param array $weekdays
+ *   An array of weekdays.
+ *
+ * @return array
+ *   An array of weekdays reordered to match the first day of the week.
+ */
+function date_week_days_ordered($weekdays) {
+  $first_day = variable_get('date_first_day', 0);
+  if ($first_day > 0) {
+    for ($i = 1; $i <= $first_day; $i++) {
+      $last = array_shift($weekdays);
+      array_push($weekdays, $last);
+    }
+  }
+  return $weekdays;
+}
+
+/**
+ * Constructs an array of years.
+ *
+ * @param int $min
+ *   The minimum year in the array.
+ * @param int $max
+ *   The maximum year in the array.
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ *
+ * @return array
+ *   An array of years in the selected range.
+ */
+function date_years($min = 0, $max = 0, $required = FALSE) {
+  // Ensure $min and $max are valid values.
+  if (empty($min)) {
+    $min = intval(date('Y', REQUEST_TIME) - 3);
+  }
+  if (empty($max)) {
+    $max = intval(date('Y', REQUEST_TIME) + 3);
+  }
+  $none = array(0 => '');
+  return !$required ? $none + drupal_map_assoc(range($min, $max)) : drupal_map_assoc(range($min, $max));
+}
+
+/**
+ * Constructs an array of days in a month.
+ *
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ * @param int $month
+ *   (optional) The month in which to find the number of days.
+ * @param int $year
+ *   (optional) The year in which to find the number of days.
+ *
+ * @return array
+ *   An array of days for the selected month.
+ */
+function date_days($required = FALSE, $month = NULL, $year = NULL) {
+  // If we have a month and year, find the right last day of the month.
+  if (!empty($month) && !empty($year)) {
+    $date = new DateObject($year . '-' . $month . '-01 00:00:00', 'UTC');
+    $max = $date->format('t');
+  }
+  // If there is no month and year given, default to 31.
+  if (empty($max)) {
+    $max = 31;
+  }
+  $none = array(0 => '');
+  return !$required ? $none + drupal_map_assoc(range(1, $max)) : drupal_map_assoc(range(1, $max));
+}
+
+/**
+ * Constructs an array of hours.
+ *
+ * @param string $format
+ *   A date format string.
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ *
+ * @return array
+ *   An array of hours in the selected format.
+ */
+function date_hours($format = 'H', $required = FALSE) {
+  $hours = array();
+  if ($format == 'h' || $format == 'g') {
+    $min = 1;
+    $max = 12;
+  }
+  else {
+    $min = 0;
+    $max = 23;
+  }
+  for ($i = $min; $i <= $max; $i++) {
+    $hours[$i] = $i < 10 && ($format == 'H' || $format == 'h') ? "0$i" : $i;
+  }
+  $none = array('' => '');
+  return !$required ? $none + $hours : $hours;
+}
+
+/**
+ * Constructs an array of minutes.
+ *
+ * @param string $format
+ *   A date format string.
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ *
+ * @return array
+ *   An array of minutes in the selected format.
+ */
+function date_minutes($format = 'i', $required = FALSE, $increment = 1) {
+  $minutes = array();
+  // Ensure $increment has a value so we don't loop endlessly.
+  if (empty($increment)) {
+    $increment = 1;
+  }
+  for ($i = 0; $i < 60; $i += $increment) {
+    $minutes[$i] = $i < 10 && $format == 'i' ? "0$i" : $i;
+  }
+  $none = array('' => '');
+  return !$required ? $none + $minutes : $minutes;
+}
+
+/**
+ * Constructs an array of seconds.
+ *
+ * @param string $format
+ *   A date format string.
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ *
+ * @return array
+ *   An array of seconds in the selected format.
+ */
+function date_seconds($format = 's', $required = FALSE, $increment = 1) {
+  $seconds = array();
+  // Ensure $increment has a value so we don't loop endlessly.
+  if (empty($increment)) {
+    $increment = 1;
+  }
+  for ($i = 0; $i < 60; $i += $increment) {
+    $seconds[$i] = $i < 10 && $format == 's' ? "0$i" : $i;
+  }
+  $none = array('' => '');
+  return !$required ? $none + $seconds : $seconds;
+}
+
+/**
+ * Constructs an array of AM and PM options.
+ *
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ *
+ * @return array
+ *   An array of AM and PM options.
+ */
+function date_ampm($required = FALSE) {
+  $none = array('' => '');
+  $ampm = array(
+    'am' => t('am', array(), array('context' => 'ampm')),
+    'pm' => t('pm', array(), array('context' => 'ampm')),
+  );
+  return !$required ? $none + $ampm : $ampm;
+}
+
+/**
+ * Constructs an array of regex replacement strings for date format elements.
+ *
+ * @param bool $strict
+ *   Whether or not to force 2 digits for elements that sometimes allow either
+ *   1 or 2 digits.
+ *
+ * @return array
+ *   An array of date() format letters and their regex equivalents.
+ */
+function date_format_patterns($strict = FALSE) {
+  return array(
+    'd' => '\d{' . ($strict ? '2' : '1,2') . '}',
+    'm' => '\d{' . ($strict ? '2' : '1,2') . '}',
+    'h' => '\d{' . ($strict ? '2' : '1,2') . '}',
+    'H' => '\d{' . ($strict ? '2' : '1,2') . '}',
+    'i' => '\d{' . ($strict ? '2' : '1,2') . '}',
+    's' => '\d{' . ($strict ? '2' : '1,2') . '}',
+    'j' => '\d{1,2}',
+    'N' => '\d',
+    'S' => '\w{2}',
+    'w' => '\d',
+    'z' => '\d{1,3}',
+    'W' => '\d{1,2}',
+    'n' => '\d{1,2}',
+    't' => '\d{2}',
+    'L' => '\d',
+    'o' => '\d{4}',
+    'Y' => '-?\d{1,6}',
+    'y' => '\d{2}',
+    'B' => '\d{3}',
+    'g' => '\d{1,2}',
+    'G' => '\d{1,2}',
+    'e' => '\w*',
+    'I' => '\d',
+    'T' => '\w*',
+    'U' => '\d*',
+    'z' => '[+-]?\d*',
+    'O' => '[+-]?\d{4}',
+    // Using S instead of w and 3 as well as 4 to pick up non-ASCII chars like
+    // German umlaut. Per http://drupal.org/node/1101284, we may need as little
+    // as 2 and as many as 5 characters in some languages.
+    'D' => '\S{2,5}',
+    'l' => '\S*',
+    'M' => '\S{2,5}',
+    'F' => '\S*',
+    'P' => '[+-]?\d{2}\:\d{2}',
+    'O' => '[+-]\d{4}',
+    'c' => '(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})([+-]?\d{2}\:\d{2})',
+    'r' => '(\w{3}), (\d{2})\s(\w{3})\s(\d{2,4})\s(\d{2}):(\d{2}):(\d{2})([+-]?\d{4})?',
+  );
+}
+
+/**
+ * Constructs an array of granularity options and their labels.
+ *
+ * @return array
+ *   An array of translated date parts, keyed by their machine name.
+ */
+function date_granularity_names() {
+  return array(
+    'year' => t('Year', array(), array('context' => 'datetime')),
+    'month' => t('Month', array(), array('context' => 'datetime')),
+    'day' => t('Day', array(), array('context' => 'datetime')),
+    'hour' => t('Hour', array(), array('context' => 'datetime')),
+    'minute' => t('Minute', array(), array('context' => 'datetime')),
+    'second' => t('Second', array(), array('context' => 'datetime')),
+  );
+}
+
+/**
+ * Sorts a granularity array.
+ *
+ * @param array $granularity
+ *   An array of date parts.
+ */
+function date_granularity_sorted($granularity) {
+  return array_intersect(array('year', 'month', 'day', 'hour', 'minute', 'second'), $granularity);
+}
+
+/**
+ * Constructs an array of granularity based on a given precision.
+ *
+ * @param string $precision
+ *   A granularity item.
+ *
+ * @return array
+ *   A granularity array containing the given precision and all those above it.
+ *   For example, passing in 'month' will return array('year', 'month').
+ */
+function date_granularity_array_from_precision($precision) {
+  $granularity_array = array('year', 'month', 'day', 'hour', 'minute', 'second');
+  switch ($precision) {
+    case 'year':
+      return array_slice($granularity_array, -6, 1);
+    case 'month':
+      return array_slice($granularity_array, -6, 2);
+    case 'day':
+      return array_slice($granularity_array, -6, 3);
+    case 'hour':
+      return array_slice($granularity_array, -6, 4);
+    case 'minute':
+      return array_slice($granularity_array, -6, 5);
+    default:
+      return $granularity_array;
+  }
+}
+
+/**
+ * Give a granularity array, return the highest precision.
+ *
+ * @param array $granularity_array
+ *   An array of date parts.
+ *
+ * @return string
+ *   The most precise element in a granularity array.
+ */
+function date_granularity_precision($granularity_array) {
+  $input = date_granularity_sorted($granularity_array);
+  return array_pop($input);
+}
+
+/**
+ * Constructs a valid DATETIME format string for the granularity of an item.
+ *
+ * @todo This function is no longer used as of
+ * http://drupalcode.org/project/date.git/commit/07efbb5.
+ */
+function date_granularity_format($granularity) {
+  if (is_array($granularity)) {
+    $granularity = date_granularity_precision($granularity);
+  }
+  $format = 'Y-m-d H:i:s';
+  switch ($granularity) {
+    case 'year':
+      return substr($format, 0, 1);
+    case 'month':
+      return substr($format, 0, 3);
+    case 'day':
+      return substr($format, 0, 5);
+    case 'hour';
+      return substr($format, 0, 7);
+    case 'minute':
+      return substr($format, 0, 9);
+    default:
+      return $format;
+  }
+}
+
+/**
+ * Returns a translated array of timezone names.
+ *
+ * Cache the untranslated array, make the translated array a static variable.
+ *
+ * @param bool $required
+ *   (optional) If FALSE, the returned array will include a blank value.
+ *   Defaults to FALSE.
+ * @param bool $refresh
+ *   (optional) Whether to refresh the list. Defaults to TRUE.
+ *
+ * @return array
+ *   An array of timezone names.
+ */
+function date_timezone_names($required = FALSE, $refresh = FALSE) {
+  static $zonenames;
+  if (empty($zonenames) || $refresh) {
+    $cached = cache_get('date_timezone_identifiers_list');
+    $zonenames = !empty($cached) ? $cached->data : array();
+    if ($refresh || empty($cached) || empty($zonenames)) {
+      $data = timezone_identifiers_list();
+      asort($data);
+      foreach ($data as $delta => $zone) {
+        // Because many timezones exist in PHP only for backward compatibility
+        // reasons and should not be used, the list is filtered by a regular
+        // expression.
+        if (preg_match('!^((Africa|America|Antarctica|Arctic|Asia|Atlantic|Australia|Europe|Indian|Pacific)/|UTC$)!', $zone)) {
+          $zonenames[$zone] = $zone;
+        }
+      }
+
+      if (!empty($zonenames)) {
+        cache_set('date_timezone_identifiers_list', $zonenames);
+      }
+    }
+    foreach ($zonenames as $zone) {
+      $zonenames[$zone] = t('!timezone', array('!timezone' => t($zone)));
+    }
+  }
+  $none = array('' => '');
+  return !$required ? $none + $zonenames : $zonenames;
+}
+
+/**
+ * Returns an array of system-allowed timezone abbreviations.
+ *
+ * Cache an array of just the abbreviation names because the whole
+ * timezone_abbreviations_list() is huge, so we don't want to retrieve it more
+ * than necessary.
+ *
+ * @param bool $refresh
+ *   (optional) Whether to refresh the list. Defaults to TRUE.
+ *
+ * @return array
+ *   An array of allowed timezone abbreviations.
+ */
+function date_timezone_abbr($refresh = FALSE) {
+  $cached = cache_get('date_timezone_abbreviations');
+  $data = isset($cached->data) ? $cached->data : array();
+  if (empty($data) || $refresh) {
+    $data = array_keys(timezone_abbreviations_list());
+    cache_set('date_timezone_abbreviations', $data);
+  }
+  return $data;
+}
+
+/**
+ * Formats a date, using a date type or a custom date format string.
+ *
+ * Reworked from Drupal's format_date function to handle pre-1970 and
+ * post-2038 dates and accept a date object instead of a timestamp as input.
+ * Translates formatted date results, unlike PHP function date_format().
+ * Should only be used for display, not input, because it can't be parsed.
+ *
+ * @param object $date
+ *   A date object.
+ * @param string $type
+ *   (optional) The date format to use. Can be 'small', 'medium' or 'large' for
+ *   the preconfigured date formats. If 'custom' is specified, then $format is
+ *   required as well. Defaults to 'medium'.
+ * @param string $format
+ *   (optional) A PHP date format string as required by date(). A backslash
+ *   should be used before a character to avoid interpreting the character as
+ *   part of a date format. Defaults to an empty string.
+ * @param string $langcode
+ *   (optional) Language code to translate to. Defaults to NULL.
+ *
+ * @return string
+ *   A translated date string in the requested format.
+ *
+ * @see format_date()
+ */
+function date_format_date($date, $type = 'medium', $format = '', $langcode = NULL) {
+  if (empty($date)) {
+    return '';
+  }
+  if ($type != 'custom') {
+    $format = variable_get('date_format_' . $type);
+  }
+  if ($type != 'custom' && empty($format)) {
+    $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
+  }
+  $format = date_limit_format($format, $date->granularity);
+  $max = strlen($format);
+  $datestring = '';
+  for ($i = 0; $i < $max; $i++) {
+    $c = $format[$i];
+    switch ($c) {
+      case 'l':
+        $datestring .= t($date->format('l'), array(), array('context' => '', 'langcode' => $langcode));
+        break;
+      case 'D':
+        $datestring .= t($date->format('D'), array(), array('context' => '', 'langcode' => $langcode));
+        break;
+      case 'F':
+        $datestring .= t($date->format('F'), array(), array('context' => 'Long month name', 'langcode' => $langcode));
+        break;
+      case 'M':
+        $datestring .= t($date->format('M'), array(), array('langcode' => $langcode));
+        break;
+      case 'A':
+      case 'a':
+        $datestring .= t($date->format($c), array(), array('context' => 'ampm', 'langcode' => $langcode));
+        break;
+      // The timezone name translations can use t().
+      case 'e':
+      case 'T':
+        $datestring .= t($date->format($c));
+        break;
+      // Remaining date parts need no translation.
+      case 'O':
+        $datestring .= sprintf('%s%02d%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
+        break;
+      case 'P':
+        $datestring .= sprintf('%s%02d:%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
+        break;
+      case 'Z':
+        $datestring .= date_offset_get($date);
+        break;
+      case '\\':
+        $datestring .= $format[++$i];
+        break;
+      case 'r':
+        $datestring .= date_format_date($date, 'custom', 'D, d M Y H:i:s O', $langcode);
+        break;
+      default:
+        if (strpos('BdcgGhHiIjLmnNosStTuUwWYyz', $c) !== FALSE) {
+          $datestring .= $date->format($c);
+        }
+        else {
+          $datestring .= $c;
+        }
+    }
+  }
+  return $datestring;
+}
+
+/**
+ * Formats a time interval with granularity, including past and future context.
+ *
+ * @param object $date
+ *   The current date object.
+ * @param int $granularity
+ *   (optional) Number of units to display in the string. Defaults to 2.
+ *
+ * @return string
+ *   A translated string representation of the interval.
+ *
+ * @see format_interval()
+ */
+function date_format_interval($date, $granularity = 2, $display_ago = TRUE) {
+  // If no date is sent, then return nothing.
+  if (empty($date)) {
+    return NULL;
+  }
+
+  $interval = REQUEST_TIME - $date->format('U');
+  if ($interval > 0) {
+    return $display_ago ? t('!time ago', array('!time' => format_interval($interval, $granularity))) :
+      t('!time', array('!time' => format_interval($interval, $granularity)));
+  }
+  else {
+    return format_interval(abs($interval), $granularity);
+  }
+}
+
+/**
+ * A date object for the current time.
+ *
+ * @param object $timezone
+ *   (optional) Optionally force time to a specific timezone, defaults to user
+ *   timezone, if set, otherwise site timezone. Defaults to NULL.
+ *
+ * @return object
+ *   The current time as a date object.
+ */
+function date_now($timezone = NULL) {
+  return new DateObject('now', $timezone);
+}
+
+/**
+ * Determines if a timezone string is valid.
+ *
+ * @param string $timezone
+ *   A potentially invalid timezone string.
+ *
+ * @return bool
+ *   TRUE if the timezone is valid, FALSE otherwise.
+ */
+function date_timezone_is_valid($timezone) {
+  static $timezone_names;
+  if (empty($timezone_names)) {
+    $timezone_names = array_keys(date_timezone_names(TRUE));
+  }
+  return in_array($timezone, $timezone_names);
+}
+
+/**
+ * Returns a timezone name to use as a default.
+ *
+ * @param bool $check_user
+ *   (optional) Whether or not to check for a user-configured timezone.
+ *   Defaults to TRUE.
+ *
+ * @return string
+ *   The default timezone for a user, if available, otherwise the site.
+ */
+function date_default_timezone($check_user = TRUE) {
+  global $user;
+  if ($check_user && variable_get('configurable_timezones', 1) && !empty($user->timezone)) {
+    return $user->timezone;
+  }
+  else {
+    $default = variable_get('date_default_timezone', '');
+    return empty($default) ? 'UTC' : $default;
+  }
+}
+
+/**
+ * Returns a timezone object for the default timezone.
+ *
+ * @param bool $check_user
+ *   (optional) Whether or not to check for a user-configured timezone.
+ *   Defaults to TRUE.
+ *
+ * @return object
+ *   The default timezone for a user, if available, otherwise the site.
+ */
+function date_default_timezone_object($check_user = TRUE) {
+  return timezone_open(date_default_timezone($check_user));
+}
+
+/**
+ * Identifies the number of days in a month for a date.
+ */
+function date_days_in_month($year, $month) {
+  // Pick a day in the middle of the month to avoid timezone shifts.
+  $datetime = date_pad($year, 4) . '-' . date_pad($month) . '-15 00:00:00';
+  $date = new DateObject($datetime);
+  return $date->format('t');
+}
+
+/**
+ * Identifies the number of days in a year for a date.
+ *
+ * @param mixed $date
+ *   (optional) The current date object, or a date string. Defaults to NULL.
+ *
+ * @return integer
+ *   The number of days in the year.
+ */
+function date_days_in_year($date = NULL) {
+  if (empty($date)) {
+    $date = date_now();
+  }
+  elseif (!is_object($date)) {
+    $date = new DateObject($date);
+  }
+  if (is_object($date)) {
+    if ($date->format('L')) {
+      return 366;
+    }
+    else {
+      return 365;
+    }
+  }
+  return NULL;
+}
+
+/**
+ * Identifies the number of ISO weeks in a year for a date.
+ *
+ * December 28 is always in the last ISO week of the year.
+ *
+ * @param mixed $date
+ *   (optional) The current date object, or a date string. Defaults to NULL.
+ *
+ * @return integer
+ *   The number of ISO weeks in a year.
+ */
+function date_iso_weeks_in_year($date = NULL) {
+  if (empty($date)) {
+    $date = date_now();
+  }
+  elseif (!is_object($date)) {
+    $date = new DateObject($date);
+  }
+
+  if (is_object($date)) {
+    date_date_set($date, $date->format('Y'), 12, 28);
+    return $date->format('W');
+  }
+  return NULL;
+}
+
+/**
+ * Returns day of week for a given date (0 = Sunday).
+ *
+ * @param mixed $date
+ *   (optional) A date, default is current local day. Defaults to NULL.
+ *
+ * @return int
+ *   The number of the day in the week.
+ */
+function date_day_of_week($date = NULL) {
+  if (empty($date)) {
+    $date = date_now();
+  }
+  elseif (!is_object($date)) {
+    $date = new DateObject($date);
+  }
+
+  if (is_object($date)) {
+    return $date->format('w');
+  }
+  return NULL;
+}
+
+/**
+ * Returns translated name of the day of week for a given date.
+ *
+ * @param mixed $date
+ *   (optional) A date, default is current local day. Defaults to NULL.
+ * @param string $abbr
+ *   (optional) Whether to return the abbreviated name for that day.
+ *   Defaults to TRUE.
+ *
+ * @return string
+ *   The name of the day in the week for that date.
+ */
+function date_day_of_week_name($date = NULL, $abbr = TRUE) {
+  if (!is_object($date)) {
+    $date = new DateObject($date);
+  }
+  $dow = date_day_of_week($date);
+  $days = $abbr ? date_week_days_abbr() : date_week_days();
+  return $days[$dow];
+}
+
+/**
+ * Calculates the start and end dates for a calendar week.
+ *
+ * The dates are adjusted to use the chosen first day of week for this site.
+ *
+ * @param int $week
+ *   The week value.
+ * @param int $year
+ *   The year value.
+ *
+ * @return array
+ *   A numeric array containing the start and end dates of a week.
+ */
+function date_week_range($week, $year) {
+  if (variable_get('date_api_use_iso8601', FALSE)) {
+    return date_iso_week_range($week, $year);
+  }
+  $min_date = new DateObject($year . '-01-01 00:00:00');
+  $min_date->setTimezone(date_default_timezone_object());
+
+  // Move to the right week.
+  date_modify($min_date, '+' . strval(7 * ($week - 1)) . ' days');
+
+  // Move backwards to the first day of the week.
+  $first_day = variable_get('date_first_day', 0);
+  $day_wday = date_format($min_date, 'w');
+  date_modify($min_date, '-' . strval((7 + $day_wday - $first_day) % 7) . ' days');
+
+  // Move forwards to the last day of the week.
+  $max_date = clone($min_date);
+  date_modify($max_date, '+7 days');
+
+  if (date_format($min_date, 'Y') != $year) {
+    $min_date = new DateObject($year . '-01-01 00:00:00');
+  }
+  return array($min_date, $max_date);
+}
+
+/**
+ * Calculates the start and end dates for an ISO week.
+ *
+ * @param int $week
+ *   The week value.
+ * @param int $year
+ *   The year value.
+ *
+ * @return array
+ *   A numeric array containing the start and end dates of an ISO week.
+ */
+function date_iso_week_range($week, $year) {
+  // Get to the last ISO week of the previous year.
+  $min_date = new DateObject(($year - 1) . '-12-28 00:00:00');
+  date_timezone_set($min_date, date_default_timezone_object());
+
+  // Find the first day of the first ISO week in the year.
+  date_modify($min_date, '+1 Monday');
+
+  // Jump ahead to the desired week for the beginning of the week range.
+  if ($week > 1) {
+    date_modify($min_date, '+ ' . ($week - 1) . ' weeks');
+  }
+
+  // Move forwards to the last day of the week.
+  $max_date = clone($min_date);
+  date_modify($max_date, '+7 days');
+  return array($min_date, $max_date);
+}
+
+/**
+ * The number of calendar weeks in a year.
+ *
+ * PHP week functions return the ISO week, not the calendar week.
+ *
+ * @param int $year
+ *   A year value.
+ *
+ * @return int
+ *   Number of calendar weeks in selected year.
+ */
+function date_weeks_in_year($year) {
+  $date = new DateObject(($year + 1) . '-01-01 12:00:00', 'UTC');
+  date_modify($date, '-1 day');
+  return date_week($date->format('Y-m-d'));
+}
+
+/**
+ * The calendar week number for a date.
+ *
+ * PHP week functions return the ISO week, not the calendar week.
+ *
+ * @param string $date
+ *   A date string in the format Y-m-d.
+ *
+ * @return int
+ *   The calendar week number.
+ */
+function date_week($date) {
+  $date = substr($date, 0, 10);
+  $parts = explode('-', $date);
+
+  $date = new DateObject($date . ' 12:00:00', 'UTC');
+
+  // If we are using ISO weeks, this is easy.
+  if (variable_get('date_api_use_iso8601', FALSE)) {
+    return intval($date->format('W'));
+  }
+
+  $year_date = new DateObject($parts[0] . '-01-01 12:00:00', 'UTC');
+  $week = intval($date->format('W'));
+  $year_week = intval(date_format($year_date, 'W'));
+  $date_year = intval($date->format('o'));
+
+  // Remove the leap week if it's present.
+  if ($date_year > intval($parts[0])) {
+    $last_date = clone($date);
+    date_modify($last_date, '-7 days');
+    $week = date_format($last_date, 'W') + 1;
+  }
+  elseif ($date_year < intval($parts[0])) {
+    $week = 0;
+  }
+
+  if ($year_week != 1) {
+    $week++;
+  }
+
+  // Convert to ISO-8601 day number, to match weeks calculated above.
+  $iso_first_day = 1 + (variable_get('date_first_day', 0) + 6) % 7;
+
+  // If it's before the starting day, it's the previous week.
+  if (intval($date->format('N')) < $iso_first_day) {
+    $week--;
+  }
+
+  // If the year starts before, it's an extra week at the beginning.
+  if (intval(date_format($year_date, 'N')) < $iso_first_day) {
+    $week++;
+  }
+
+  return $week;
+}
+
+/**
+ * Helper function to left pad date parts with zeros.
+ *
+ * Provided because this is needed so often with dates.
+ *
+ * @param int $value
+ *   The value to pad.
+ * @param int $size
+ *   (optional) Total size expected, usually 2 or 4. Defaults to 2.
+ *
+ * @return string
+ *   The padded value.
+ */
+function date_pad($value, $size = 2) {
+  return sprintf("%0" . $size . "d", $value);
+}
+
+/**
+ * Determines if the granularity contains a time portion.
+ *
+ * @param array $granularity
+ *   An array of allowed date parts, all others will be removed.
+ *
+ * @return bool
+ *   TRUE if the granularity contains a time portion, FALSE otherwise.
+ */
+function date_has_time($granularity) {
+  if (!is_array($granularity)) {
+    $granularity = array();
+  }
+  return (bool) count(array_intersect($granularity, array('hour', 'minute', 'second')));
+}
+
+/**
+ * Determines if the granularity contains a date portion.
+ *
+ * @param array $granularity
+ *   An array of allowed date parts, all others will be removed.
+ *
+ * @return bool
+ *   TRUE if the granularity contains a date portion, FALSE otherwise.
+ */
+function date_has_date($granularity) {
+  if (!is_array($granularity)) {
+    $granularity = array();
+  }
+  return (bool) count(array_intersect($granularity, array('year', 'month', 'day')));
+}
+
+/**
+ * Helper function to get a format for a specific part of a date field.
+ *
+ * @param string $part
+ *   The date field part, either 'time' or 'date'.
+ * @param string $format
+ *   A date format string.
+ *
+ * @return string
+ *   The date format for the given part.
+ */
+function date_part_format($part, $format) {
+  switch ($part) {
+    case 'date':
+      return date_limit_format($format, array('year', 'month', 'day'));
+    case 'time':
+      return date_limit_format($format, array('hour', 'minute', 'second'));
+    default:
+      return date_limit_format($format, array($part));
+  }
+}
+
+/**
+ * Limits a date format to include only elements from a given granularity array.
+ *
+ * Example:
+ *   date_limit_format('F j, Y - H:i', array('year', 'month', 'day'));
+ *   returns 'F j, Y'
+ *
+ * @param string $format
+ *   A date format string.
+ * @param array $granularity
+ *   An array of allowed date parts, all others will be removed.
+ *
+ * @return string
+ *   The format string with all other elements removed.
+ */
+function date_limit_format($format, $granularity) {
+  // If punctuation has been escaped, remove the escaping. Done using strtr()
+  // because it is easier than getting the escape character extracted using
+  // preg_replace().
+  $replace = array(
+    '\-' => '-',
+    '\:' => ':',
+    "\'" => "'",
+    '\. ' => ' . ',
+    '\,' => ',',
+  );
+  $format = strtr($format, $replace);
+
+  // Get the 'T' out of ISO date formats that don't have both date and time.
+  if (!date_has_time($granularity) || !date_has_date($granularity)) {
+    $format = str_replace('\T', ' ', $format);
+    $format = str_replace('T', ' ', $format);
+  }
+
+  $regex = array();
+  if (!date_has_time($granularity)) {
+    $regex[] = '((?<!\\\\)[a|A])';
+  }
+  // Create regular expressions to remove selected values from string.
+  // Use (?<!\\\\) to keep escaped letters from being removed.
+  foreach (date_nongranularity($granularity) as $element) {
+    switch ($element) {
+      case 'year':
+        $regex[] = '([\-/\.,:]?\s?(?<!\\\\)[Yy])';
+        break;
+      case 'day':
+        $regex[] = '([\-/\.,:]?\s?(?<!\\\\)[l|D|d|dS|j|jS|N|w|W|z]{1,2})';
+        break;
+      case 'month':
+        $regex[] = '([\-/\.,:]?\s?(?<!\\\\)[FMmn])';
+        break;
+      case 'hour':
+        $regex[] = '([\-/\.,:]?\s?(?<!\\\\)[HhGg])';
+        break;
+      case 'minute':
+        $regex[] = '([\-/\.,:]?\s?(?<!\\\\)[i])';
+        break;
+      case 'second':
+        $regex[] = '([\-/\.,:]?\s?(?<!\\\\)[s])';
+        break;
+      case 'timezone':
+        $regex[] = '([\-/\.,:]?\s?(?<!\\\\)[TOZPe])';
+        break;
+
+    }
+  }
+  // Remove empty parentheses, brackets, pipes.
+  $regex[] = '(\(\))';
+  $regex[] = '(\[\])';
+  $regex[] = '(\|\|)';
+
+  // Remove selected values from string.
+  $format = trim(preg_replace($regex, array(), $format));
+  // Remove orphaned punctuation at the beginning of the string.
+  $format = preg_replace('`^([\-/\.,:\'])`', '', $format);
+  // Remove orphaned punctuation at the end of the string.
+  $format = preg_replace('([\-/,:\']$)', '', $format);
+  $format = preg_replace('(\\$)', '', $format);
+
+  // Trim any whitespace from the result.
+  $format = trim($format);
+
+  // After removing the non-desired parts of the format, test if the only things
+  // left are escaped, non-date, characters. If so, return nothing.
+  // Using S instead of w to pick up non-ASCII characters.
+  $test = trim(preg_replace('(\\\\\S{1,3})', '', $format));
+  if (empty($test)) {
+    $format = '';
+  }
+
+  return $format;
+}
+
+/**
+ * Converts a format to an ordered array of granularity parts.
+ *
+ * Example:
+ *   date_format_order('m/d/Y H:i')
+ *   returns
+ *     array(
+ *       0 => 'month',
+ *       1 => 'day',
+ *       2 => 'year',
+ *       3 => 'hour',
+ *       4 => 'minute',
+ *     );
+ *
+ * @param string $format
+ *   A date format string.
+ *
+ * @return array
+ *   An array of ordered granularity elements from the given format string.
+ */
+function date_format_order($format) {
+  $order = array();
+  if (empty($format)) {
+    return $order;
+  }
+
+  $max = strlen($format);
+  for ($i = 0; $i <= $max; $i++) {
+    if (!isset($format[$i])) {
+      break;
+    }
+    switch ($format[$i]) {
+      case 'd':
+      case 'j':
+        $order[] = 'day';
+        break;
+      case 'F':
+      case 'M':
+      case 'm':
+      case 'n':
+        $order[] = 'month';
+        break;
+      case 'Y':
+      case 'y':
+        $order[] = 'year';
+        break;
+      case 'g':
+      case 'G':
+      case 'h':
+      case 'H':
+        $order[] = 'hour';
+        break;
+      case 'i':
+        $order[] = 'minute';
+        break;
+      case 's':
+        $order[] = 'second';
+        break;
+    }
+  }
+  return $order;
+}
+
+/**
+ * Strips out unwanted granularity elements.
+ *
+ * @param array $granularity
+ *   An array like ('year', 'month', 'day', 'hour', 'minute', 'second');
+ *
+ * @return array
+ *   A reduced set of granularitiy elements.
+ */
+function date_nongranularity($granularity) {
+  return array_diff(array('year', 'month', 'day', 'hour', 'minute', 'second', 'timezone'), (array) $granularity);
+}
+
+/**
+ * Implements hook_element_info().
+ */
+function date_api_element_info() {
+  module_load_include('inc', 'date_api', 'date_api_elements');
+  return _date_api_element_info();
+}
+
+/**
+ * Implements hook_theme().
+ */
+function date_api_theme($existing, $type, $theme, $path) {
+  $base = array(
+    'file' => 'theme.inc',
+    'path' => "$path/theme",
+  );
+  return array(
+    'date_nav_title' => $base + array('variables' => array('granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL)),
+    'date_timezone' => $base + array('render element' => 'element'),
+    'date_select' => $base + array('render element' => 'element'),
+    'date_text' => $base + array('render element' => 'element'),
+    'date_select_element' => $base + array('render element' => 'element'),
+    'date_textfield_element' => $base + array('render element' => 'element'),
+    'date_part_hour_prefix' => $base + array('render element' => 'element'),
+    'date_part_minsec_prefix' => $base + array('render element' => 'element'),
+    'date_part_label_year' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
+    'date_part_label_month' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
+    'date_part_label_day' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
+    'date_part_label_hour' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
+    'date_part_label_minute' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
+    'date_part_label_second' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
+    'date_part_label_ampm' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
+    'date_part_label_timezone' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
+    'date_part_label_date' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
+    'date_part_label_time' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
+    'date_views_filter_form' => $base + array('template' => 'date-views-filter-form', 'render element' => 'form'),
+    'date_calendar_day' => $base + array('variables' => array('date' => NULL)),
+    'date_time_ago' => $base + array('variables' => array('start_date' => NULL, 'end_date' => NULL, 'interval' => NULL)),
+  );
+}
+
+/**
+ * Function to figure out which local timezone applies to a date and select it.
+ *
+ * @param string $handling
+ *   The timezone handling.
+ * @param string $timezone
+ *   (optional) A timezone string. Defaults to an empty string.
+ *
+ * @return string
+ *   The timezone string.
+ */
+function date_get_timezone($handling, $timezone = '') {
+  switch ($handling) {
+    case 'date':
+      $timezone = !empty($timezone) ? $timezone : date_default_timezone();
+      break;
+    case 'utc':
+      $timezone = 'UTC';
+      break;
+    default:
+      $timezone = date_default_timezone();
+  }
+  return $timezone > '' ? $timezone : date_default_timezone();
+}
+
+/**
+ * Function to figure out which db timezone applies to a date and select it.
+ *
+ * @param string $handling
+ *   The timezone handling.
+ * @param string $timezone
+ *   (optional) A timezone string. Defaults to an empty string.
+ *
+ * @return string
+ *   The timezone string.
+ */
+function date_get_timezone_db($handling, $timezone = '') {
+  switch ($handling) {
+    case 'none':
+      $timezone = date_default_timezone();
+      break;
+    default:
+      $timezone = 'UTC';
+      break;
+  }
+  return $timezone > '' ? $timezone : 'UTC';
+}
+
+/**
+ * Helper function for converting back and forth from '+1' to 'First'.
+ */
+function date_order_translated() {
+  return array(
+    '+1' => t('First', array(), array('context' => 'date_order')),
+    '+2' => t('Second', array(), array('context' => 'date_order')),
+    '+3' => t('Third', array(), array('context' => 'date_order')),
+    '+4' => t('Fourth', array(), array('context' => 'date_order')),
+    '+5' => t('Fifth', array(), array('context' => 'date_order')),
+    '-1' => t('Last', array(), array('context' => 'date_order_reverse')),
+    '-2' => t('Next to last', array(), array('context' => 'date_order_reverse')),
+    '-3' => t('Third from last', array(), array('context' => 'date_order_reverse')),
+    '-4' => t('Fourth from last', array(), array('context' => 'date_order_reverse')),
+    '-5' => t('Fifth from last', array(), array('context' => 'date_order_reverse')),
+  );
+}
+
+/**
+ * Creates an array of ordered strings, using English text when possible.
+ */
+function date_order() {
+  return array(
+    '+1' => 'First',
+    '+2' => 'Second',
+    '+3' => 'Third',
+    '+4' => 'Fourth',
+    '+5' => 'Fifth',
+    '-1' => 'Last',
+    '-2' => '-2',
+    '-3' => '-3',
+    '-4' => '-4',
+    '-5' => '-5',
+  );
+}
+
+/**
+ * Tests validity of a date range string.
+ *
+ * @param string $string
+ *   A min and max year string like '-3:+1'a.
+ *
+ * @return bool
+ *   TRUE if the date range is valid, FALSE otherwise.
+ */
+function date_range_valid($string) {
+  $matches = preg_match('@^(\-[0-9]+|[0-9]{4}):([\+|\-][0-9]+|[0-9]{4})$@', $string);
+  return $matches < 1 ? FALSE : TRUE;
+}
+
+/**
+ * Splits a string like -3:+3 or 2001:2010 into an array of min and max years.
+ *
+ * Center the range around the current year, if any, but expand it far
+ * enough so it will pick up the year value in the field in case
+ * the value in the field is outside the initial range.
+ *
+ * @param string $string
+ *   A min and max year string like '-3:+1'.
+ * @param object $date
+ *   (optional) A date object. Defaults to NULL.
+ *
+ * @return array
+ *   A numerically indexed array, containing a minimum and maximum year.
+ */
+function date_range_years($string, $date = NULL) {
+  $this_year = date_format(date_now(), 'Y');
+  list($min_year, $max_year) = explode(':', $string);
+
+  // Valid patterns would be -5:+5, 0:+1, 2008:2010.
+  $plus_pattern = '@[\+|\-][0-9]{1,4}@';
+  $year_pattern = '@^[0-9]{4}@';
+  if (!preg_match($year_pattern, $min_year, $matches)) {
+    if (preg_match($plus_pattern, $min_year, $matches)) {
+      $min_year = $this_year + $matches[0];
+    }
+    else {
+      $min_year = $this_year;
+    }
+  }
+  if (!preg_match($year_pattern, $max_year, $matches)) {
+    if (preg_match($plus_pattern, $max_year, $matches)) {
+      $max_year = $this_year + $matches[0];
+    }
+    else {
+      $max_year = $this_year;
+    }
+  }
+  // We expect the $min year to be less than the $max year.
+  // Some custom values for -99:+99 might not obey that.
+  if ($min_year > $max_year) {
+    $temp = $max_year;
+    $max_year = $min_year;
+    $min_year = $temp;
+  }
+  // If there is a current value, stretch the range to include it.
+  $value_year = is_object($date) ? $date->format('Y') : '';
+  if (!empty($value_year)) {
+    $min_year = min($value_year, $min_year);
+    $max_year = max($value_year, $max_year);
+  }
+  return array($min_year, $max_year);
+}
+
+/**
+ * Converts a min and max year into a string like '-3:+1'.
+ *
+ * @param array $years
+ *   A numerically indexed array, containing a minimum and maximum year.
+ *
+ * @return string
+ *   A min and max year string like '-3:+1'.
+ */
+function date_range_string($years) {
+  $this_year = date_format(date_now(), 'Y');
+
+  if ($years[0] < $this_year) {
+    $min = '-' . ($this_year - $years[0]);
+  }
+  else {
+    $min = '+' . ($years[0] - $this_year);
+  }
+
+  if ($years[1] < $this_year) {
+    $max = '-' . ($this_year - $years[1]);
+  }
+  else {
+    $max = '+' . ($years[1] - $this_year);
+  }
+
+  return $min . ':' . $max;
+}
+
+/**
+ * Temporary helper to re-create equivalent of content_database_info().
+ */
+function date_api_database_info($field, $revision = FIELD_LOAD_CURRENT) {
+  return array(
+    'columns' => $field['storage']['details']['sql'][$revision],
+    'table' => _field_sql_storage_tablename($field),
+  );
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for system_regional_settings().
+ *
+ * Add a form element to configure whether or not week numbers are ISO-8601, the
+ * default is FALSE (US/UK/AUS norm).
+ */
+function date_api_form_system_regional_settings_alter(&$form, &$form_state, $form_id) {
+  $form['locale']['date_api_use_iso8601'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use ISO-8601 week numbers'),
+    '#default_value' => variable_get('date_api_use_iso8601', FALSE),
+    '#description' => t('IMPORTANT! If checked, First day of week MUST be set to Monday'),
+  );
+  $form['#validate'][] = 'date_api_form_system_settings_validate';
+}
+
+/**
+ * Validate that the option to use ISO weeks matches first day of week choice.
+ */
+function date_api_form_system_settings_validate(&$form, &$form_state) {
+  $form_values = $form_state['values'];
+  if ($form_values['date_api_use_iso8601'] && $form_values['date_first_day'] != 1) {
+    form_set_error('date_first_day', t('When using ISO-8601 week numbers, the first day of the week must be set to Monday.'));
+  }
+}
+
+/**
+ * Creates an array of date format types for use as an options list.
+ */
+function date_format_type_options() {
+  $options = array();
+  $format_types = system_get_date_types();
+  if (!empty($format_types)) {
+    foreach ($format_types as $type => $type_info) {
+      $options[$type] = $type_info['title'] . ' (' . date_format_date(date_example_date(), $type) . ')';
+    }
+  }
+  return $options;
+}
+
+/**
+ * Creates an example date.
+ *
+ * This ensures a clear difference between month and day, and 12 and 24 hours.
+ */
+function date_example_date() {
+  $now = date_now();
+  if (date_format($now, 'M') == date_format($now, 'F')) {
+    date_modify($now, '+1 month');
+  }
+  if (date_format($now, 'm') == date_format($now, 'd')) {
+    date_modify($now, '+1 day');
+  }
+  if (date_format($now, 'H') == date_format($now, 'h')) {
+    date_modify($now, '+12 hours');
+  }
+  return $now;
+}
+
+/**
+ * Determine if a start/end date combination qualify as 'All day'.
+ *
+ * @param string $string1
+ *   A string date in datetime format for the 'start' date.
+ * @param string $string2
+ *   A string date in datetime format for the 'end' date.
+ * @param string $granularity
+ *   (optional) The granularity of the date. Defaults to 'second'.
+ * @param int $increment
+ *   (optional) The increment of the date. Defaults to 1.
+ *
+ * @return bool
+ *   TRUE if the date is all day, FALSE otherwise.
+ */
+function date_is_all_day($string1, $string2, $granularity = 'second', $increment = 1) {
+  if (empty($string1) || empty($string2)) {
+    return FALSE;
+  }
+  elseif (!in_array($granularity, array('hour', 'minute', 'second'))) {
+    return FALSE;
+  }
+
+  preg_match('/([0-9]{4}-[0-9]{2}-[0-9]{2}) (([0-9]{2}):([0-9]{2}):([0-9]{2}))/', $string1, $matches);
+  $count = count($matches);
+  $date1 = $count > 1 ? $matches[1] : '';
+  $time1 = $count > 2 ? $matches[2] : '';
+  $hour1 = $count > 3 ? intval($matches[3]) : 0;
+  $min1 = $count > 4 ? intval($matches[4]) : 0;
+  $sec1 = $count > 5 ? intval($matches[5]) : 0;
+  preg_match('/([0-9]{4}-[0-9]{2}-[0-9]{2}) (([0-9]{2}):([0-9]{2}):([0-9]{2}))/', $string2, $matches);
+  $count = count($matches);
+  $date2 = $count > 1 ? $matches[1] : '';
+  $time2 = $count > 2 ? $matches[2] : '';
+  $hour2 = $count > 3 ? intval($matches[3]) : 0;
+  $min2 = $count > 4 ? intval($matches[4]) : 0;
+  $sec2 = $count > 5 ? intval($matches[5]) : 0;
+  if (empty($date1) || empty($date2)) {
+    return FALSE;
+  }
+  if (empty($time1) || empty($time2)) {
+    return FALSE;
+  }
+
+  $tmp = date_seconds('s', TRUE, $increment);
+  $max_seconds = intval(array_pop($tmp));
+  $tmp = date_minutes('i', TRUE, $increment);
+  $max_minutes = intval(array_pop($tmp));
+
+  // See if minutes and seconds are the maximum allowed for an increment or the
+  // maximum possible (59), or 0.
+  switch ($granularity) {
+    case 'second':
+      $min_match = $time1 == '00:00:00'
+        || ($hour1 == 0 && $min1 == 0 && $sec1 == 0);
+      $max_match = $time2 == '00:00:00'
+        || ($hour2 == 23 && in_array($min2, array($max_minutes, 59)) && in_array($sec2, array($max_seconds, 59)))
+        || ($hour1 == 0 && $hour2 == 0 && $min1 == 0 && $min2 == 0 && $sec1 == 0 && $sec2 == 0);
+      break;
+    case 'minute':
+      $min_match = $time1 == '00:00:00'
+        || ($hour1 == 0 && $min1 == 0);
+      $max_match = $time2 == '00:00:00'
+        || ($hour2 == 23 && in_array($min2, array($max_minutes, 59)))
+        || ($hour1 == 0 && $hour2 == 0 && $min1 == 0 && $min2 == 0);
+      break;
+    case 'hour':
+      $min_match = $time1 == '00:00:00'
+        || ($hour1 == 0);
+      $max_match = $time2 == '00:00:00'
+        || ($hour2 == 23)
+        || ($hour1 == 0 && $hour2 == 0);
+      break;
+    default:
+      $min_match = TRUE;
+      $max_match = FALSE;
+  }
+
+  if ($min_match && $max_match) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+ * Helper function to round minutes and seconds to requested value.
+ */
+function date_increment_round(&$date, $increment) {
+  // Round minutes and seconds, if necessary.
+  if (is_object($date) && $increment > 1) {
+    $day = intval(date_format($date, 'j'));
+    $hour = intval(date_format($date, 'H'));
+    $second = intval(round(intval(date_format($date, 's')) / $increment) * $increment);
+    $minute = intval(date_format($date, 'i'));
+    if ($second == 60) {
+      $minute += 1;
+      $second = 0;
+    }
+    $minute = intval(round($minute / $increment) * $increment);
+    if ($minute == 60) {
+      $hour += 1;
+      $minute = 0;
+    }
+    date_time_set($date, $hour, $minute, $second);
+    if ($hour == 24) {
+      $day += 1;
+      $hour = 0;
+      $year = date_format($date, 'Y');
+      $month = date_format($date, 'n');
+      date_date_set($date, $year, $month, $day);
+    }
+  }
+  return $date;
+}
+
+/**
+ * Determines if a date object is valid.
+ *
+ * @param object $date
+ *   The date object to check.
+ *
+ * @return bool
+ *   TRUE if the date is a valid date object, FALSE otherwise.
+ */
+function date_is_date($date) {
+  if (empty($date) || !is_object($date) || !empty($date->errors)) {
+    return FALSE;
+  }
+  return TRUE;
+}
diff --git a/sites/all/modules/date/date_api/date_api_elements.inc b/sites/all/modules/date/date_api/date_api_elements.inc
new file mode 100644
index 0000000000000000000000000000000000000000..b5a90a0e8a9e37c8e39b637b6c5c1446a86aac8a
--- /dev/null
+++ b/sites/all/modules/date/date_api/date_api_elements.inc
@@ -0,0 +1,752 @@
+<?php
+
+/**
+ * @file
+ * Date API elements themes and validation.
+ * This file is only included during the edit process to reduce memory usage.
+ */
+
+/**
+ * Implements hook_element_info().
+ *
+ * Parameters for date form elements, designed to have sane defaults so any
+ * or all can be omitted.
+ *
+ * Fill the element #default_value with a date in datetime format,
+ * (YYYY-MM-DD HH:MM:SS), adjusted to the proper local timezone.
+ *
+ * NOTE - Converting a date stored in the database from UTC to the local zone
+ * and converting it back to UTC before storing it is not handled by this
+ * element and must be done in pre-form and post-form processing!!
+ *
+ * The date_select element will create a collection of form elements, with a
+ * separate select or textfield for each date part. The whole collection will
+ * get reformatted back to a date value of the requested type during validation.
+ *
+ * The date_text element will create a textfield that can contain a whole
+ * date or any part of a date as text. The user input value will be re-formatted
+ * back into a date value of the requested type during validation.
+ *
+ * The date_timezone element will create a drop-down selector to pick a
+ * timezone name.
+ *
+ * The date_year_range element will create two textfields (for users with
+ * JavaScript enabled they will appear as drop-down selectors with an option
+ * for custom text entry) to pick a range of years that will be passed to form
+ * submit handlers as a single string (e.g., -3:+3).
+ *
+ * #date_timezone
+ *   The local timezone to be used to create this date.
+ *
+ * #date_format
+ *   A format string that describes the format and order of date parts to
+ *   display in the edit form for this element. This makes it possible
+ *   to show date parts in a custom order, or to leave some of them out.
+ *   Be sure to add 'A' or 'a' to get an am/pm selector. Defaults to the
+ *   short site default format.
+ *
+ * #date_label_position
+ *   Handling option for date part labels, like 'Year', 'Month', and 'Day',
+ *   can be 'above' the date part, 'within' it, or 'none', default is 'above' .
+ *   The 'within' option shows the label as the first option in a select list
+ *   or the default value for an empty textfield, taking up less screen space.
+ *
+ * #date_increment
+ *   Increment minutes and seconds by this amount, default is 1.
+ *
+ * #date_year_range
+ *   The number of years to go back and forward in a year selector,
+ *   default is -3:+3 (3 back and 3 forward).
+ *
+ * #date_text_parts
+ *   Array of date parts that should use textfields instead of selects
+ *   i.e. array('year') will format the year as a textfield and other
+ *   date parts as drop-down selects.
+ */
+function _date_api_element_info() {
+  $date_base = array(
+    '#input' => TRUE, '#tree' => TRUE,
+    '#date_timezone' => date_default_timezone(),
+    '#date_flexible' => 0,
+    '#date_format' => variable_get('date_format_short', 'm/d/Y - H:i'),
+    '#date_text_parts' => array(),
+    '#date_increment' => 1,
+    '#date_year_range' => '-3:+3',
+    '#date_label_position' => 'above',
+  );
+  if (module_exists('ctools')) {
+    $date_base['#pre_render'] = array('ctools_dependent_pre_render');
+  }
+  $type['date_select'] = array_merge($date_base, array(
+    '#process' => array('date_select_element_process'),
+    '#theme_wrappers' => array('date_select'),
+    '#value_callback' => 'date_select_element_value_callback',
+  ));
+  $type['date_text'] = array_merge($date_base, array(
+    '#process' => array('date_text_element_process'),
+    '#theme_wrappers' => array('date_text'),
+    '#value_callback' => 'date_text_element_value_callback',
+  ));
+  $type['date_timezone'] = array(
+    '#input' => TRUE, '#tree' => TRUE,
+    '#process' => array('date_timezone_element_process'),
+    '#theme_wrappers' => array('date_text'),
+    '#value_callback' => 'date_timezone_element_value_callback',
+  );
+  $type['date_year_range'] = array(
+    '#input' => TRUE,
+    '#process' => array('date_year_range_element_process'),
+    '#value_callback' => 'date_year_range_element_value_callback',
+    '#element_validate' => array('date_year_range_validate'),
+  );
+  return $type;
+}
+
+/**
+ * Create a date object from a datetime string value.
+ */
+function date_default_date($element) {
+  $granularity = date_format_order($element['#date_format']);
+  $default_value = $element['#default_value'];
+  $format = DATE_FORMAT_DATETIME;
+
+  // The text and popup widgets might return less than a full datetime string.
+  if (strlen($element['#default_value']) < 19) {
+    switch (strlen($element['#default_value'])) {
+      case 16:
+        $format = 'Y-m-d H:i';
+        break;
+      case 13:
+        $format = 'Y-m-d H';
+        break;
+      case 10:
+        $format = 'Y-m-d';
+        break;
+      case 7:
+        $format = 'Y-m';
+        break;
+      case 4:
+        $format = 'Y';
+        break;
+    }
+  }
+  $date = new DateObject($default_value, $element['#date_timezone'], $format);
+  if (is_object($date)) {
+    $date->limitGranularity($granularity);
+    if ($date->validGranularity($granularity, $element['#date_flexible'])) {
+      date_increment_round($date, $element['#date_increment']);
+    }
+    return $date;
+  }
+  return NULL;
+}
+
+/**
+ * Process callback which creates a date_year_range form element.
+ */
+function date_year_range_element_process($element, &$form_state, $form) {
+  // Year range is stored in the -3:+3 format, but collected as two separate
+  // textfields.
+  $element['years_back'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Starting year'),
+    '#default_value' => $element['#value']['years_back'],
+    '#size' => 10,
+    '#maxsize' => 10,
+    '#attributes' => array('class' => array('select-list-with-custom-option', 'back')),
+    '#description' => t('Enter a relative value (-9, +9) or an absolute year such as 2015.'),
+  );
+  $element['years_forward'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Ending year'),
+    '#default_value' => $element['#value']['years_forward'],
+    '#size' => 10,
+    '#maxsize' => 10,
+    '#attributes' => array('class' => array('select-list-with-custom-option', 'forward')),
+    '#description' => t('Enter a relative value (-9, +9) or an absolute year such as 2015.'),
+  );
+
+  $element['#tree'] = TRUE;
+  $element['#attached']['js'][] = drupal_get_path('module', 'date_api') . '/date_year_range.js';
+
+  $context = array(
+   'form' => $form,
+  );
+  drupal_alter('date_year_range_process', $element, $form_state, $context);
+
+  return $element;
+}
+
+/**
+ * Element value callback for the date_year_range form element.
+ */
+function date_year_range_element_value_callback($element, $input = FALSE, &$form_state = array()) {
+  // Convert the element's default value from a string to an array (to match
+  // what we will get from the two textfields when the form is submitted).
+  if ($input === FALSE) {
+    list($years_back, $years_forward) = explode(':', $element['#default_value']);
+    return array(
+      'years_back' => $years_back,
+      'years_forward' => $years_forward,
+    );
+  }
+}
+
+/**
+ * Element validation function for the date_year_range form element.
+ */
+function date_year_range_validate(&$element, &$form_state) {
+  // Recombine the two submitted form values into the -3:+3 format we will
+  // validate and save.
+  $year_range_submitted = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
+  $year_range = $year_range_submitted['years_back'] . ':' . $year_range_submitted['years_forward'];
+  drupal_array_set_nested_value($form_state['values'], $element['#parents'], $year_range);
+  if (!date_range_valid($year_range)) {
+    form_error($element['years_back'], t('Starting year must be in the format -9, or an absolute year such as 1980.'));
+    form_error($element['years_forward'], t('Ending year must be in the format +9, or an absolute year such as 2030.'));
+  }
+}
+
+/**
+ * Element value callback for date_timezone element.
+ */
+function date_timezone_element_value_callback($element, $input = FALSE, &$form_state = array()) {
+  $return = '';
+  if ($input !== FALSE) {
+    $return = $input;
+  }
+  elseif (!empty($element['#default_value'])) {
+    $return = array('timezone' => $element['#default_value']);
+  }
+  return $return;
+}
+
+/**
+ * Creates a timezone form element.
+ *
+ * @param array $element
+ *   The timezone form element.
+ *
+ * @return array
+ *   the timezone form element
+ */
+function date_timezone_element_process($element, &$form_state, $form) {
+  if (date_hidden_element($element)) {
+    return $element;
+  }
+
+  $element['#tree'] = TRUE;
+  $label = theme('date_part_label_timezone', array('part_type' => 'select', 'element' => $element));
+  $element['timezone'] = array(
+    '#type' => 'select',
+    '#title' => $element['#date_label_position'] == 'above' ? $label : '',
+    '#options' => date_timezone_names($element['#required']),
+    '#value' => $element['#value'],
+    '#weight' => $element['#weight'],
+    '#required' => $element['#required'],
+    '#theme' => 'date_select_element',
+    '#theme_wrappers' => array('form_element'),
+  );
+  if (isset($element['#element_validate'])) {
+    array_push($element['#element_validate'], 'date_timezone_validate');
+  }
+  else {
+    $element['#element_validate'] = array('date_timezone_validate');
+  }
+
+  $context = array(
+   'form' => $form,
+  );
+  drupal_alter('date_timezone_process', $element, $form_state, $context);
+
+  return $element;
+}
+
+/**
+ *  Validation for timezone input
+ *
+ *  Move the timezone value from the nested field back to the original field.
+ */
+function date_timezone_validate($element, &$form_state) {
+  if (date_hidden_element($element)) {
+    return;
+  }
+
+  form_set_value($element, $element['#value']['timezone'], $form_state);
+}
+
+/**
+ * Element value callback for date_text element.
+ */
+function date_text_element_value_callback($element, $input = FALSE, &$form_state = array()) {
+  $return = array('date' => '');
+  $date = NULL;
+
+  // Normal input from submitting the form element.
+  // Check is_array() to skip the string input values created by Views pagers.
+  // Those string values, if present, should be interpreted as empty input.
+  if ($input != FALSE && is_array($input)) {
+    $return = $input;
+    $date = date_text_input_date($element, $input);
+  }
+  // No input? Try the default value.
+  elseif (!empty($element['#default_value'])) {
+    $date = date_default_date($element);
+  }
+  if (date_is_date($date)) {
+    $return['date'] = $date->format($element['#date_format']);
+  }
+  return $return;
+}
+
+/**
+ * Text date input form.
+ *
+ * Display all or part of a date in a single textfield.
+ *
+ * The exact parts displayed in the field are those in #date_granularity.
+ * The display of each part comes from #date_format.
+ *
+ */
+function date_text_element_process($element, &$form_state, $form) {
+  if (date_hidden_element($element)) {
+    return $element;
+  }
+
+  $element['#tree'] = TRUE;
+  $element['#theme_wrappers'] = array('date_text');
+  $element['date']['#value'] = $element['#value']['date'];
+  $element['date']['#type'] = 'textfield';
+  $element['date']['#weight'] = !empty($element['date']['#weight']) ? $element['date']['#weight'] : $element['#weight'];
+  $element['date']['#attributes'] = array('class' => isset($element['#attributes']['class']) ? $element['#attributes']['class'] += array('date-date') : array('date-date'));
+  $now = date_example_date();
+  $element['date']['#description'] = ' ' . t('Format: @date', array('@date' => date_now()->format($element['#date_format'])));
+  $element['date']['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
+
+  // Keep the system from creating an error message for the sub-element.
+  // We'll set our own message on the parent element.
+  // $element['date']['#required'] = $element['#required'];
+  $element['date']['#theme'] = 'date_textfield_element';
+  if (isset($element['#element_validate'])) {
+    array_push($element['#element_validate'], 'date_text_validate');
+  }
+  else {
+    $element['#element_validate'] = array('date_text_validate');
+  }
+  if (!empty($element['#force_value'])) {
+    $element['date']['#value'] = $element['date']['#default_value'];
+  }
+
+  $context = array(
+   'form' => $form,
+  );
+  drupal_alter('date_text_process', $element, $form_state, $context);
+
+  return $element;
+}
+
+/**
+ *  Validation for text input.
+ *
+ * When used as a Views widget, the validation step always gets triggered,
+ * even with no form submission. Before form submission $element['#value']
+ * contains a string, after submission it contains an array.
+ *
+ */
+function date_text_validate($element, &$form_state) {
+  if (date_hidden_element($element)) {
+    return;
+  }
+
+  if (is_string($element['#value'])) {
+    return;
+  }
+  $input_exists = NULL;
+  $input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
+
+  drupal_alter('date_text_pre_validate', $element, $form_state, $input);
+
+  $label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
+  $date = date_text_input_date($element, $input);
+
+  // If the field has errors, display them.
+  // If something was input but there is no date, the date is invalid.
+  // If the field is empty and required, set error message and return.
+  $error_field = implode('][', $element['#parents']);
+  if (empty($date) || !empty($date->errors)) {
+    if (is_object($date) && !empty($date->errors)) {
+      $message = t('The value input for field %field is invalid:', array('%field' => $label));
+      $message .= '<br />' . implode('<br />', $date->errors);
+      form_set_error($error_field, $message);
+      return;
+    }
+    if (!empty($element['#required'])) {
+      $message = t('A valid date is required for %title.', array('%title' => $label));
+      form_set_error($error_field, $message);
+      return;
+    }
+    // Fall through, some other error.
+    if (!empty($input['date'])) {
+      form_error($element, t('%title is invalid.', array('%title' => $label)));
+      return;
+    }
+  }
+  $value = !empty($date) ? $date->format(DATE_FORMAT_DATETIME) : NULL;
+  form_set_value($element, $value, $form_state);
+}
+
+/**
+ * Helper function for creating a date object out of user input.
+ */
+function date_text_input_date($element, $input) {
+  if (empty($input) || !is_array($input) || !array_key_exists('date', $input) || empty($input['date'])) {
+    return NULL;
+  }
+  $granularity = date_format_order($element['#date_format']);
+  $date = new DateObject($input['date'], $element['#date_timezone'], $element['#date_format']);
+  if (is_object($date)) {
+    $date->limitGranularity($granularity);
+    if ($date->validGranularity($granularity, $element['#date_flexible'])) {
+      date_increment_round($date, $element['#date_increment']);
+    }
+    return $date;
+  }
+  return NULL;
+}
+
+/**
+ * Element value callback for date_select element.
+ */
+function date_select_element_value_callback($element, $input = FALSE, &$form_state = array()) {
+  $return = array('year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '');
+  $date = NULL;
+  if ($input !== FALSE) {
+    $return = $input;
+    $date = date_select_input_date($element, $input);
+  }
+  elseif (!empty($element['#default_value'])) {
+    $date = date_default_date($element);
+  }
+  $granularity = date_format_order($element['#date_format']);
+  $formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
+  foreach ($granularity as $field) {
+    if ($field != 'timezone') {
+      $return[$field] = date_is_date($date) ? $date->format($formats[$field]) : '';
+    }
+  }
+  return $return;
+}
+
+/**
+ * Flexible date/time drop-down selector.
+ *
+ * Splits date into a collection of date and time sub-elements, one
+ * for each date part. Each sub-element can be either a textfield or a
+ * select, based on the value of ['#date_settings']['text_fields'].
+ *
+ * The exact parts displayed in the field are those in #date_granularity.
+ * The display of each part comes from ['#date_settings']['format'].
+ *
+ */
+function date_select_element_process($element, &$form_state, $form) {
+  if (date_hidden_element($element)) {
+    return $element;
+  }
+
+  $date = NULL;
+  $granularity = date_format_order($element['#date_format']);
+
+  if (is_array($element['#default_value'])) {
+    $date = date_select_input_date($element, $element['#default_value']);
+  }
+  elseif (!empty($element['#default_value'])) {
+    $date = date_default_date($element);
+  }
+
+  $element['#tree'] = TRUE;
+  $element['#theme_wrappers'] = array('date_select');
+
+  $element += (array) date_parts_element($element, $date, $element['#date_format']);
+
+  // Store a hidden value for all date parts not in the current display.
+  $granularity = date_format_order($element['#date_format']);
+  $formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
+  foreach (date_nongranularity($granularity) as $field) {
+    if ($field != 'timezone') {
+      $element[$field] = array(
+        '#type' => 'value',
+        '#value' => 0,
+      );
+    }
+  }
+  if (isset($element['#element_validate'])) {
+    array_push($element['#element_validate'], 'date_select_validate');
+  }
+  else {
+    $element['#element_validate'] = array('date_select_validate');
+  }
+
+  $context = array(
+   'form' => $form,
+  );
+  drupal_alter('date_select_process', $element, $form_state, $context);
+
+  return $element;
+}
+
+/**
+ * Creates form elements for one or more date parts.
+ *
+ * Get the order of date elements from the provided format.
+ * If the format order omits any date parts in the granularity, alter the
+ * granularity array to match the format, then flip the $order array
+ * to get the position for each element. Then iterate through the
+ * elements and create a sub-form for each part.
+ *
+ * @param array $element
+ *   The date element.
+ * @param object $date
+ *   The date object.
+ * @param string $format
+ *   A date format string.
+ *
+ * @return array
+ *   The form array for the submitted date parts.
+ */
+function date_parts_element($element, $date, $format) {
+  $granularity = date_format_order($format);
+  $sub_element = array('#granularity' => $granularity);
+  $order = array_flip($granularity);
+
+  $hours_format  = strpos(strtolower($element['#date_format']), 'a') ? 'g': 'G';
+  $month_function  = strpos($element['#date_format'], 'F') !== FALSE ? 'date_month_names' : 'date_month_names_abbr';
+  $count = 0;
+  $increment = min(intval($element['#date_increment']), 1);
+
+  // Allow empty value as option if date is not required or there is no date.
+  $part_required = (bool) $element['#required'] && is_object($date);
+  foreach ($granularity as $field) {
+    $part_type = in_array($field, $element['#date_text_parts']) ? 'textfield' : 'select';
+    $sub_element[$field] = array(
+      '#weight' => $order[$field],
+      '#required' => $part_required,
+      '#attributes' => array('class' => isset($element['#attributes']['class']) ? $element['#attributes']['class'] += array('date-' . $field) : array('date-' . $field)),
+      '#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
+    );
+    switch ($field) {
+      case 'year':
+        $range = date_range_years($element['#date_year_range'], $date);
+        $min_year = $range[0];
+        $max_year = $range[1];
+
+        $sub_element[$field]['#default_value'] = is_object($date) ? $date->format('Y') : '';
+        if ($part_type == 'select') {
+          $sub_element[$field]['#options'] = drupal_map_assoc(date_years($min_year, $max_year, $part_required));
+        }
+        break;
+      case 'month':
+        $sub_element[$field]['#default_value'] = is_object($date) ? $date->format('n') : '';
+        if ($part_type == 'select') {
+          $sub_element[$field]['#options'] = $month_function($part_required);
+        }
+        break;
+      case 'day':
+        $sub_element[$field]['#default_value'] = is_object($date) ? $date->format('j') : '';
+        if ($part_type == 'select') {
+          $sub_element[$field]['#options'] = drupal_map_assoc(date_days($part_required));
+        }
+        break;
+      case 'hour':
+        $sub_element[$field]['#default_value'] = is_object($date) ? $date->format($hours_format) : '';
+        if ($part_type == 'select') {
+          $sub_element[$field]['#options'] = drupal_map_assoc(date_hours($hours_format, $part_required));
+        }
+        $sub_element[$field]['#prefix'] = theme('date_part_hour_prefix', $element);
+        break;
+      case 'minute':
+        $sub_element[$field]['#default_value'] = is_object($date) ? $date->format('i') : '';
+        if ($part_type == 'select') {
+          $sub_element[$field]['#options'] = drupal_map_assoc(date_minutes('i', $part_required, $element['#date_increment']));
+        }
+        $sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
+        break;
+      case 'second':
+        $sub_element[$field]['#default_value'] = is_object($date) ? $date->format('s') : '';
+        if ($part_type == 'select') {
+          $sub_element[$field]['#options'] = drupal_map_assoc(date_seconds('s', $part_required, $element['#date_increment']));
+        }
+        $sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
+        break;
+    }
+
+    // Add handling for the date part label.
+    $label = theme('date_part_label_' . $field, array('part_type' => $part_type, 'element' => $element));
+    if (in_array($field, $element['#date_text_parts'])) {
+      $sub_element[$field]['#type'] = 'textfield';
+      $sub_element[$field]['#theme'] = 'date_textfield_element';
+      $sub_element[$field]['#size'] = 7;
+      if ($element['#date_label_position'] == 'within') {
+        if (!empty($sub_element[$field]['#options']) && is_array($sub_element[$field]['#options'])) {
+          $sub_element[$field]['#options'] = array(
+            '-' . $label => '-' . $label) + $sub_element[$field]['#options'];
+        }
+        if (empty($sub_element[$field]['#default_value'])) {
+          $sub_element[$field]['#default_value'] = '-' . $label;
+        }
+      }
+      elseif ($element['#date_label_position'] != 'none') {
+        $sub_element[$field]['#title'] = $label;
+      }
+    }
+    else {
+      $sub_element[$field]['#type'] = 'select';
+      $sub_element[$field]['#theme'] = 'date_select_element';
+      if ($element['#date_label_position'] == 'within') {
+        $sub_element[$field]['#options'] = array(
+          '' => '-' . $label) + $sub_element[$field]['#options'];
+      }
+      elseif ($element['#date_label_position'] != 'none') {
+        $sub_element[$field]['#title'] = $label;
+      }
+    }
+  }
+
+  // Views exposed filters are treated as submitted even if not,
+  // so force the #default value in that case. Make sure we set
+  // a default that is in the option list.
+  if (!empty($element['#force_value'])) {
+    $options = $sub_element[$field]['#options'];
+    $default = !empty($sub_element[$field]['#default_value']) ? $sub_element[$field]['#default_value'] : array_shift($options);
+    $sub_element[$field]['#value'] = $default;
+  }
+
+  if (($hours_format == 'g' || $hours_format == 'h') && date_has_time($granularity)) {
+    $sub_element['ampm'] = array(
+      '#type' => 'select',
+      '#theme' => 'date_select_element',
+      '#default_value' => is_object($date) ? (date_format($date, 'G') >= 12 ? 'pm' : 'am') : '',
+      '#options' => drupal_map_assoc(date_ampm($part_required)),
+      '#required' => $part_required,
+      '#weight' => 8,
+      '#attributes' => array('class' => array('date-ampm')),
+    );
+    if ($element['#date_label_position'] == 'within') {
+      $sub_element['ampm']['#options'] = array('' => '-' . theme('date_part_label_ampm', array('part_type' => 'ampm', 'eleement' => $element))) + $sub_element['ampm']['#options'];
+    }
+    elseif ($element['#date_label_position'] != 'none') {
+      $sub_element['ampm']['#title'] = theme('date_part_label_ampm', array('part_type' => 'ampm', 'element' => $element));
+    }
+  }
+
+  return $sub_element;
+}
+
+/**
+ * Validation function for date selector.
+ *
+ * When used as a Views widget, the validation step always gets triggered,
+ * even with no form submission. Before form submission $element['#value']
+ * contains a string, after submission it contains an array.
+ */
+function date_select_validate($element, &$form_state) {
+  if (date_hidden_element($element)) {
+    return;
+  }
+
+  if (is_string($element['#value'])) {
+    return;
+  }
+
+  $input_exists = NULL;
+  $input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
+
+  // Strip field labels out of the results.
+  foreach ($element['#value'] as $field => $field_value) {
+    if (substr($field_value, 0, 1) == '-') {
+      $input[$field] = '';
+    }
+  }
+
+  drupal_alter('date_select_pre_validate', $element, $form_state, $input);
+
+  $label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
+  if (isset($input['ampm'])) {
+    if ($input['ampm'] == 'pm' && $input['hour'] < 12) {
+      $input['hour'] += 12;
+    }
+    elseif ($input['ampm'] == 'am' && $input['hour'] == 12) {
+      $input['hour'] -= 12;
+    }
+  }
+  unset($input['ampm']);
+  $date = date_select_input_date($element, $input);
+
+  // If the field has errors, display them.
+  $error_field = implode('][', $element['#parents']);
+  $entered = array_values(array_filter($input));
+  if (empty($date) || !empty($date->errors)) {
+    // The input created a date but it has errors.
+    if (is_object($date) && !empty($date->errors)) {
+      $message = t('The value input for field %field is invalid:', array('%field' => $label));
+      $message .= '<br />' . implode('<br />', $date->errors);
+      form_set_error($error_field, $message);
+      return;
+    }
+    // Nothing was entered but the date is required.
+    elseif (empty($entered) && $element['#required']) {
+      $message = t('A valid date is required for %title.', array('%title' => $label));
+      form_set_error($error_field, $message);
+      return;
+    }
+    // Something was input but it wasn't enough to create a valid date.
+    elseif (!empty($entered)) {
+      $message = t('The value input for field %field is invalid.', array('%field' => $label));
+      form_set_error($error_field, $message);
+      return;
+    }
+  }
+  $value = !empty($date) ? $date->format(DATE_FORMAT_DATETIME) : NULL;
+  form_set_value($element, $value, $form_state);
+}
+
+/**
+ * Helper function for creating a date object out of user input.
+ */
+function date_select_input_date($element, $input) {
+
+  // Was anything entered? If not, we have no date.
+  if (!is_array($input)) {
+    return NULL;
+  }
+  else {
+    $entered = array_values(array_filter($input));
+    if (empty($entered)) {
+      return NULL;
+    }
+  }
+  $granularity = date_format_order($element['#date_format']);
+  if (isset($input['ampm'])) {
+    if ($input['ampm'] == 'pm' && $input['hour'] < 12) {
+      $input['hour'] += 12;
+    }
+    elseif ($input['ampm'] == 'am' && $input['hour'] == 12) {
+      $input['hour'] -= 12;
+    }
+  }
+  unset($input['ampm']);
+
+  // Make the input match the granularity.
+  foreach (date_nongranularity($granularity) as $part) {
+    unset($input[$part]);
+  }
+
+  $date = new DateObject($input, $element['#date_timezone']);
+  if (is_object($date)) {
+    $date->limitGranularity($granularity);
+    if ($date->validGranularity($granularity, $element['#date_flexible'])) {
+      date_increment_round($date, $element['#date_increment']);
+    }
+    return $date;
+  }
+  return NULL;
+}
diff --git a/sites/all/modules/date/date_api/date_api_ical.inc b/sites/all/modules/date/date_api/date_api_ical.inc
new file mode 100644
index 0000000000000000000000000000000000000000..7cb2b957745d9d7ed22459e15c4e7d84484dc0f5
--- /dev/null
+++ b/sites/all/modules/date/date_api/date_api_ical.inc
@@ -0,0 +1,783 @@
+<?php
+
+/**
+ * @file
+ * Parse iCal data.
+ *
+ * This file must be included when these functions are needed.
+ */
+
+/**
+ * Return an array of iCalendar information from an iCalendar file.
+ *
+ *   No timezone adjustment is performed in the import since the timezone
+ *   conversion needed will vary depending on whether the value is being
+ *   imported into the database (when it needs to be converted to UTC), is being
+ *   viewed on a site that has user-configurable timezones (when it needs to be
+ *   converted to the user's timezone), if it needs to be converted to the
+ *   site timezone, or if it is a date without a timezone which should not have
+ *   any timezone conversion applied.
+ *
+ *   Properties that have dates and times are converted to sub-arrays like:
+ *      'datetime'   => date in YYYY-MM-DD HH:MM format, not timezone adjusted
+ *      'all_day'    => whether this is an all-day event
+ *      'tz'         => the timezone of the date, could be blank for absolute
+ *                      times that should get no timezone conversion.
+ *
+ *   Exception dates can have muliple values and are returned as arrays
+ *   like the above for each exception date.
+ *
+ *   Most other properties are returned as PROPERTY => VALUE.
+ *
+ *   Each item in the VCALENDAR will return an array like:
+ *   [0] => Array (
+ *     [TYPE] => VEVENT
+ *     [UID] => 104
+ *     [SUMMARY] => An example event
+ *     [URL] => http://example.com/node/1
+ *     [DTSTART] => Array (
+ *       [datetime] => 1997-09-07 09:00:00
+ *       [all_day] => 0
+ *       [tz] => US/Eastern
+ *     )
+ *     [DTEND] => Array (
+ *       [datetime] => 1997-09-07 11:00:00
+ *       [all_day] => 0
+ *       [tz] => US/Eastern
+ *     )
+ *     [RRULE] => Array (
+ *       [FREQ] => Array (
+ *         [0] => MONTHLY
+ *       )
+ *       [BYDAY] => Array (
+ *         [0] => 1SU
+ *         [1] => -1SU
+ *       )
+ *     )
+ *     [EXDATE] => Array (
+ *       [0] = Array (
+ *         [datetime] => 1997-09-21 09:00:00
+ *         [all_day] => 0
+ *         [tz] => US/Eastern
+ *       )
+ *       [1] = Array (
+ *         [datetime] => 1997-10-05 09:00:00
+ *         [all_day] => 0
+ *         [tz] => US/Eastern
+ *       )
+ *     )
+ *     [RDATE] => Array (
+ *       [0] = Array (
+ *         [datetime] => 1997-09-21 09:00:00
+ *         [all_day] => 0
+ *         [tz] => US/Eastern
+ *       )
+ *       [1] = Array (
+ *         [datetime] => 1997-10-05 09:00:00
+ *         [all_day] => 0
+ *         [tz] => US/Eastern
+ *       )
+ *     )
+ *   )
+ *
+ * @todo
+ *   figure out how to handle this if subgroups are nested,
+ *   like a VALARM nested inside a VEVENT.
+ *
+ * @param string $filename
+ *   Location (local or remote) of a valid iCalendar file.
+ *
+ * @return array
+ *   An array with all the elements from the ical.
+ */
+function date_ical_import($filename) {
+  // Fetch the iCal data. If file is a URL, use drupal_http_request. fopen
+  // isn't always configured to allow network connections.
+  if (substr($filename, 0, 4) == 'http') {
+    // Fetch the ical data from the specified network location.
+    $icaldatafetch = drupal_http_request($filename);
+    // Check the return result.
+    if ($icaldatafetch->error) {
+      watchdog('date ical', 'HTTP Request Error importing %filename: @error', array('%filename' => $filename, '@error' => $icaldatafetch->error));
+      return FALSE;
+    }
+    // Break the return result into one array entry per lines.
+    $icaldatafolded = explode("\n", $icaldatafetch->data);
+  }
+  else {
+    $icaldatafolded = @file($filename, FILE_IGNORE_NEW_LINES);
+    if ($icaldatafolded === FALSE) {
+      watchdog('date ical', 'Failed to open file: %filename', array('%filename' => $filename));
+      return FALSE;
+    }
+  }
+  // Verify this is iCal data.
+  if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') {
+    watchdog('date ical', 'Invalid calendar file: %filename', array('%filename' => $filename));
+    return FALSE;
+  }
+  return date_ical_parse($icaldatafolded);
+}
+
+/**
+ * Returns an array of iCalendar information from an iCalendar file.
+ *
+ * As date_ical_import() but different param.
+ *
+ * @param array $icaldatafolded
+ *   An array of lines from an ical feed.
+ *
+ * @return array
+ *   An array with all the elements from the ical.
+ */
+function date_ical_parse($icaldatafolded = array()) {
+  $items = array();
+
+  // Verify this is iCal data.
+  if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') {
+    watchdog('date ical', 'Invalid calendar file.');
+    return FALSE;
+  }
+
+  // "Unfold" wrapped lines.
+  $icaldata = array();
+  foreach ($icaldatafolded as $line) {
+    $out = array();
+    // See if this looks like the beginning of a new property or value. If not,
+    // it is a continuation of the previous line. The regex is to ensure that
+    // wrapped QUOTED-PRINTABLE data is kept intact.
+    if (!preg_match('/([A-Z]+)[:;](.*)/', $line, $out)) {
+      // Trim up to 1 leading space from wrapped line per iCalendar standard.
+      $line = array_pop($icaldata) . (ltrim(substr($line, 0, 1)) . substr($line, 1));
+    }
+    $icaldata[] = $line;
+  }
+  unset($icaldatafolded);
+
+  // Parse the iCal information.
+  $parents = array();
+  $subgroups = array();
+  $vcal = '';
+  foreach ($icaldata as $line) {
+    $line = trim($line);
+    $vcal .= $line . "\n";
+    // Deal with begin/end tags separately.
+    if (preg_match('/(BEGIN|END):V(\S+)/', $line, $matches)) {
+      $closure = $matches[1];
+      $type = 'V' . $matches[2];
+      if ($closure == 'BEGIN') {
+        array_push($parents, $type);
+        array_push($subgroups, array());
+      }
+      elseif ($closure == 'END') {
+        end($subgroups);
+        $subgroup = &$subgroups[key($subgroups)];
+        switch ($type) {
+          case 'VCALENDAR':
+            if (prev($subgroups) == FALSE) {
+              $items[] = array_pop($subgroups);
+            }
+            else {
+              $parent[array_pop($parents)][] = array_pop($subgroups);
+            }
+            break;
+          // Add the timezones in with their index their TZID.
+          case 'VTIMEZONE':
+            $subgroup = end($subgroups);
+            $id = $subgroup['TZID'];
+            unset($subgroup['TZID']);
+
+            // Append this subgroup onto the one above it.
+            prev($subgroups);
+            $parent = &$subgroups[key($subgroups)];
+
+            $parent[$type][$id] = $subgroup;
+
+            array_pop($subgroups);
+            array_pop($parents);
+            break;
+          // Do some fun stuff with durations and all_day events and then append
+          // to parent.
+          case 'VEVENT':
+          case 'VALARM':
+          case 'VTODO':
+          case 'VJOURNAL':
+          case 'VVENUE':
+          case 'VFREEBUSY':
+          default:
+            // Can't be sure whether DTSTART is before or after DURATION, so
+            // parse DURATION at the end.
+            if (isset($subgroup['DURATION'])) {
+              date_ical_parse_duration($subgroup, 'DURATION');
+            }
+            // Add a top-level indication for the 'All day' condition. Leave it
+            // in the individual date components, too, so it is always available
+            // even when you are working with only a portion of the VEVENT
+            // array, like in Feed API parsers.
+            $subgroup['all_day'] = FALSE;
+            if (!empty($subgroup['DTSTART']) && (!empty($subgroup['DTSTART']['all_day']) ||
+              (empty($subgroup['DTEND']) && empty($subgroup['RRULE']) && empty($subgroup['RRULE']['COUNT'])))) {
+              // Many programs output DTEND for an all day event as the
+              // following day, reset this to the same day for internal use.
+              $subgroup['all_day'] = TRUE;
+              $subgroup['DTEND'] = $subgroup['DTSTART'];
+            }
+            // Add this element to the parent as an array under the component
+            // name.
+            prev($subgroups);
+            $parent = &$subgroups[key($subgroups)];
+
+            $parent[$type][] = $subgroup;
+
+            array_pop($subgroups);
+            array_pop($parents);
+            break;
+        }
+      }
+    }
+    // Handle all other possibilities.
+    else {
+      // Grab current subgroup.
+      end($subgroups);
+      $subgroup = &$subgroups[key($subgroups)];
+
+      // Split up the line into nice pieces for PROPERTYNAME,
+      // PROPERTYATTRIBUTES, and PROPERTYVALUE.
+      preg_match('/([^;:]+)(?:;([^:]*))?:(.+)/', $line, $matches);
+      $name = !empty($matches[1]) ? strtoupper(trim($matches[1])) : '';
+      $field = !empty($matches[2]) ? $matches[2] : '';
+      $data = !empty($matches[3]) ? $matches[3] : '';
+      $parse_result = '';
+      switch ($name) {
+        // Keep blank lines out of the results.
+        case '':
+          break;
+
+          // Lots of properties have date values that must be parsed out.
+        case 'CREATED':
+        case 'LAST-MODIFIED':
+        case 'DTSTART':
+        case 'DTEND':
+        case 'DTSTAMP':
+        case 'FREEBUSY':
+        case 'DUE':
+        case 'COMPLETED':
+          $parse_result = date_ical_parse_date($field, $data);
+          break;
+
+        case 'EXDATE':
+        case 'RDATE':
+          $parse_result = date_ical_parse_exceptions($field, $data);
+          break;
+
+        case 'TRIGGER':
+          // A TRIGGER can either be a date or in the form -PT1H.
+          if (!empty($field)) {
+            $parse_result = date_ical_parse_date($field, $data);
+          }
+          else {
+            $parse_result = array('DATA' => $data);
+          }
+          break;
+
+        case 'DURATION':
+          // Can't be sure whether DTSTART is before or after DURATION in
+          // the VEVENT, so store the data and parse it at the end.
+          $parse_result = array('DATA' => $data);
+          break;
+
+        case 'RRULE':
+        case 'EXRULE':
+          $parse_result = date_ical_parse_rrule($field, $data);
+          break;
+
+        case 'SUMMARY':
+        case 'DESCRIPTION':
+          $parse_result = date_ical_parse_text($field, $data);
+          break;
+
+        case 'LOCATION':
+          $parse_result = date_ical_parse_location($field, $data);
+          break;
+
+          // For all other properties, just store the property and the value.
+          // This can be expanded on in the future if other properties should
+          // be given special treatment.
+        default:
+          $parse_result = $data;
+          break;
+      }
+
+      // Store the result of our parsing.
+      $subgroup[$name] = $parse_result;
+    }
+  }
+  return $items;
+}
+
+/**
+ * Parses a ical date element.
+ *
+ * Possible formats to parse include:
+ *   PROPERTY:YYYYMMDD[T][HH][MM][SS][Z]
+ *   PROPERTY;VALUE=DATE:YYYYMMDD[T][HH][MM][SS][Z]
+ *   PROPERTY;VALUE=DATE-TIME:YYYYMMDD[T][HH][MM][SS][Z]
+ *   PROPERTY;TZID=XXXXXXXX;VALUE=DATE:YYYYMMDD[T][HH][MM][SS]
+ *   PROPERTY;TZID=XXXXXXXX:YYYYMMDD[T][HH][MM][SS]
+ *
+ *   The property and the colon before the date are removed in the import
+ *   process above and we are left with $field and $data.
+ *
+ * @param string $field
+ *   The text before the colon and the date, i.e.
+ *   ';VALUE=DATE:', ';VALUE=DATE-TIME:', ';TZID='
+ * @param string $data
+ *   The date itself, after the colon, in the format YYYYMMDD[T][HH][MM][SS][Z]
+ *   'Z', if supplied, means the date is in UTC.
+ *
+ * @return array
+ *   $items array, consisting of:
+ *      'datetime'   => date in YYYY-MM-DD HH:MM format, not timezone adjusted
+ *      'all_day'    => whether this is an all-day event with no time
+ *      'tz'         => the timezone of the date, could be blank if the ical
+ *                      has no timezone; the ical specs say no timezone
+ *                      conversion should be done if no timezone info is
+ *                      supplied
+ *  @todo
+ *   Another option for dates is the format PROPERTY;VALUE=PERIOD:XXXX. The
+ *   period may include a duration, or a date and a duration, or two dates, so
+ *   would have to be split into parts and run through date_ical_parse_date()
+ *   and date_ical_parse_duration(). This is not commonly used, so ignored for
+ *   now. It will take more work to figure how to support that.
+ */
+function date_ical_parse_date($field, $data) {
+
+  $items = array('datetime' => '', 'all_day' => '', 'tz' => '');
+  if (empty($data)) {
+    return $items;
+  }
+  // Make this a little more whitespace independent.
+  $data = trim($data);
+
+  // Turn the properties into a nice indexed array of
+  // array(PROPERTYNAME => PROPERTYVALUE);
+  $field_parts = preg_split('/[;:]/', $field);
+  $properties = array();
+  foreach ($field_parts as $part) {
+    if (strpos($part, '=') !== FALSE) {
+      $tmp = explode('=', $part);
+      $properties[$tmp[0]] = $tmp[1];
+    }
+  }
+
+  // Make this a little more whitespace independent.
+  $data = trim($data);
+
+  // Record if a time has been found.
+  $has_time = FALSE;
+
+  // If a format is specified, parse it according to that format.
+  if (isset($properties['VALUE'])) {
+    switch ($properties['VALUE']) {
+      case 'DATE':
+        preg_match(DATE_REGEX_ICAL_DATE, $data, $regs);
+        // Date.
+        $datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
+        break;
+      case 'DATE-TIME':
+        preg_match(DATE_REGEX_ICAL_DATETIME, $data, $regs);
+        // Date.
+        $datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
+        // Time.
+        $datetime .= ' ' . date_pad($regs[4]) . ':' . date_pad($regs[5]) . ':' . date_pad($regs[6]);
+        $has_time = TRUE;
+        break;
+    }
+  }
+  // If no format is specified, attempt a loose match.
+  else {
+    preg_match(DATE_REGEX_LOOSE, $data, $regs);
+    if (!empty($regs) && count($regs) > 2) {
+      // Date.
+      $datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
+      if (isset($regs[4])) {
+        $has_time = TRUE;
+        // Time.
+        $datetime .= ' ' . (!empty($regs[5]) ? date_pad($regs[5]) : '00') .
+         ':' . (!empty($regs[6]) ? date_pad($regs[6]) : '00') .
+         ':' . (!empty($regs[7]) ? date_pad($regs[7]) : '00');
+      }
+    }
+  }
+
+  // Use timezone if explicitly declared.
+  if (isset($properties['TZID'])) {
+    $tz = $properties['TZID'];
+    // Fix alternatives like US-Eastern which should be US/Eastern.
+    $tz = str_replace('-', '/', $tz);
+    // Unset invalid timezone names.
+    module_load_include('inc', 'date_api', 'date_api.admin');
+    $tz = _date_timezone_replacement($tz);
+    if (!date_timezone_is_valid($tz)) {
+      $tz = '';
+    }
+  }
+  // If declared as UTC with terminating 'Z', use that timezone.
+  elseif (strpos($data, 'Z') !== FALSE) {
+    $tz = 'UTC';
+  }
+  // Otherwise this date is floating.
+  else {
+    $tz = '';
+  }
+
+  $items['datetime'] = $datetime;
+  $items['all_day'] = $has_time ? FALSE : TRUE;
+  $items['tz'] = $tz;
+  return $items;
+}
+
+/**
+ * Parse an ical repeat rule.
+ *
+ * @return array
+ *   Array in the form of PROPERTY => array(VALUES)
+ *   PROPERTIES include FREQ, INTERVAL, COUNT, BYDAY, BYMONTH, BYYEAR, UNTIL
+ */
+function date_ical_parse_rrule($field, $data) {
+  $data = preg_replace("/RRULE.*:/", '', $data);
+  $items = array('DATA' => $data);
+  $rrule = explode(';', $data);
+  foreach ($rrule as $key => $value) {
+    $param = explode('=', $value);
+    // Must be some kind of invalid data.
+    if (count($param) != 2) {
+      continue;
+    }
+    if ($param[0] == 'UNTIL') {
+      $values = date_ical_parse_date('', $param[1]);
+    }
+    else {
+      $values = explode(',', $param[1]);
+    }
+    // Treat items differently if they have multiple or single values.
+    if (in_array($param[0], array('FREQ', 'INTERVAL', 'COUNT', 'WKST'))) {
+      $items[$param[0]] = $param[1];
+    }
+    else {
+      $items[$param[0]] = $values;
+    }
+  }
+  return $items;
+}
+
+/**
+ * Parse exception dates (can be multiple values).
+ *
+ * @return array
+ *   an array of date value arrays.
+ */
+function date_ical_parse_exceptions($field, $data) {
+  $data = str_replace($field . ':', '', $data);
+  $items = array('DATA' => $data);
+  $ex_dates = explode(',', $data);
+  foreach ($ex_dates as $ex_date) {
+    $items[] = date_ical_parse_date('', $ex_date);
+  }
+  return $items;
+}
+
+/**
+ * Parses the duration of the event.
+ *
+ * Example:
+ *  DURATION:PT1H30M
+ *  DURATION:P1Y2M
+ *
+ * @param array $subgroup
+ *   Array of other values in the vevent so we can check for DTSTART.
+ */
+function date_ical_parse_duration(&$subgroup, $field = 'DURATION') {
+  $items = $subgroup[$field];
+  $data  = $items['DATA'];
+  preg_match('/^P(\d{1,4}[Y])?(\d{1,2}[M])?(\d{1,2}[W])?(\d{1,2}[D])?([T]{0,1})?(\d{1,2}[H])?(\d{1,2}[M])?(\d{1,2}[S])?/', $data, $duration);
+  $items['year'] = isset($duration[1]) ? str_replace('Y', '', $duration[1]) : '';
+  $items['month'] = isset($duration[2]) ?str_replace('M', '', $duration[2]) : '';
+  $items['week'] = isset($duration[3]) ?str_replace('W', '', $duration[3]) : '';
+  $items['day'] = isset($duration[4]) ?str_replace('D', '', $duration[4]) : '';
+  $items['hour'] = isset($duration[6]) ?str_replace('H', '', $duration[6]) : '';
+  $items['minute'] = isset($duration[7]) ?str_replace('M', '', $duration[7]) : '';
+  $items['second'] = isset($duration[8]) ?str_replace('S', '', $duration[8]) : '';
+  $start_date = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['datetime'] : date_format(date_now(), DATE_FORMAT_ISO);
+  $timezone = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['tz'] : variable_get('date_default_timezone');
+  if (empty($timezone)) {
+    $timezone = 'UTC';
+  }
+  $date = new DateObject($start_date, $timezone);
+  $date2 = clone($date);
+  foreach ($items as $item => $count) {
+    if ($count > 0) {
+      date_modify($date2, '+' . $count . ' ' . $item);
+    }
+  }
+  $format = isset($subgroup['DTSTART']['type']) && $subgroup['DTSTART']['type'] == 'DATE' ? 'Y-m-d' : 'Y-m-d H:i:s';
+  $subgroup['DTEND'] = array(
+    'datetime' => date_format($date2, DATE_FORMAT_DATETIME),
+    'all_day' => isset($subgroup['DTSTART']['all_day']) ? $subgroup['DTSTART']['all_day'] : 0,
+    'tz' => $timezone,
+    );
+  $duration = date_format($date2, 'U') - date_format($date, 'U');
+  $subgroup['DURATION'] = array('DATA' => $data, 'DURATION' => $duration);
+}
+
+/**
+ * Parse and clean up ical text elements.
+ */
+function date_ical_parse_text($field, $data) {
+  if (strstr($field, 'QUOTED-PRINTABLE')) {
+    $data = quoted_printable_decode($data);
+  }
+  // Strip line breaks within element.
+  $data = str_replace(array("\r\n ", "\n ", "\r "), '', $data);
+  // Put in line breaks where encoded.
+  $data = str_replace(array("\\n", "\\N"), "\n", $data);
+  // Remove other escaping.
+  $data = stripslashes($data);
+  return $data;
+}
+
+/**
+ * Parse location elements.
+ *
+ * Catch situations like the upcoming.org feed that uses
+ * LOCATION;VENUE-UID="http://upcoming.yahoo.com/venue/104/":111 First Street...
+ * or more normal LOCATION;UID=123:111 First Street...
+ * Upcoming feed would have been improperly broken on the ':' in http://
+ * so we paste the $field and $data back together first.
+ *
+ * Use non-greedy check for ':' in case there are more of them in the address.
+ */
+function date_ical_parse_location($field, $data) {
+  if (preg_match('/UID=[?"](.+)[?"][*?:](.+)/', $field . ':' . $data, $matches)) {
+    $location = array();
+    $location['UID'] = $matches[1];
+    $location['DESCRIPTION'] = stripslashes($matches[2]);
+    return $location;
+  }
+  else {
+    // Remove other escaping.
+    $location = stripslashes($data);
+    return $location;
+  }
+}
+
+/**
+ * Return a date object for the ical date, adjusted to its local timezone.
+ *
+ * @param array $ical_date
+ *   An array of ical date information created in the ical import.
+ * @param string $to_tz
+ *   The timezone to convert the date's value to.
+ *
+ * @return object
+ *   A timezone-adjusted date object.
+ */
+function date_ical_date($ical_date, $to_tz = FALSE) {
+
+  // If the ical date has no timezone, must assume it is stateless
+  // so treat it as a local date.
+  if (empty($ical_date['datetime'])) {
+    return NULL;
+  }
+  elseif (empty($ical_date['tz'])) {
+    $from_tz = date_default_timezone();
+  }
+  else {
+    $from_tz = $ical_date['tz'];
+  }
+  if (strlen($ical_date['datetime']) < 11) {
+    $ical_date['datetime'] .= ' 00:00:00';
+  }
+  $date = new DateObject($ical_date['datetime'], new DateTimeZone($from_tz));
+
+  if ($to_tz && $ical_date['tz'] != '' && $to_tz != $ical_date['tz']) {
+    date_timezone_set($date, timezone_open($to_tz));
+  }
+  return $date;
+}
+
+/**
+ * Escape #text elements for safe iCal use.
+ *
+ * @param string $text
+ *   Text to escape
+ *
+ * @return string
+ *   Escaped text
+ *
+ */
+function date_ical_escape_text($text) {
+  $text = drupal_html_to_text($text);
+  $text = trim($text);
+  // TODO Per #38130 the iCal specs don't want : and " escaped
+  // but there was some reason for adding this in. Need to watch
+  // this and see if anything breaks.
+  // $text = str_replace('"', '\"', $text);
+  // $text = str_replace(":", "\:", $text);
+  $text = preg_replace("/\\\b/", "\\\\", $text);
+  $text = str_replace(",", "\,", $text);
+  $text = str_replace(";", "\;", $text);
+  $text = str_replace("\n", "\\n ", $text);
+  return trim($text);
+}
+
+/**
+ * Build an iCal RULE from $form_values.
+ *
+ * @param array $form_values
+ *   An array constructed like the one created by date_ical_parse_rrule().
+ *     [RRULE] => Array (
+ *       [FREQ] => Array (
+ *         [0] => MONTHLY
+ *       )
+ *       [BYDAY] => Array (
+ *         [0] => 1SU
+ *         [1] => -1SU
+ *       )
+ *       [UNTIL] => Array (
+ *         [datetime] => 1997-21-31 09:00:00
+ *         [all_day] => 0
+ *         [tz] => US/Eastern
+ *       )
+ *     )
+ *     [EXDATE] => Array (
+ *       [0] = Array (
+ *         [datetime] => 1997-09-21 09:00:00
+ *         [all_day] => 0
+ *         [tz] => US/Eastern
+ *       )
+ *       [1] = Array (
+ *         [datetime] => 1997-10-05 09:00:00
+ *         [all_day] => 0
+ *         [tz] => US/Eastern
+ *       )
+ *     )
+ *     [RDATE] => Array (
+ *       [0] = Array (
+ *         [datetime] => 1997-09-21 09:00:00
+ *         [all_day] => 0
+ *         [tz] => US/Eastern
+ *       )
+ *       [1] = Array (
+ *         [datetime] => 1997-10-05 09:00:00
+ *         [all_day] => 0
+ *         [tz] => US/Eastern
+ *       )
+ *     )
+ */
+function date_api_ical_build_rrule($form_values) {
+  $RRULE = '';
+  if (empty($form_values) || !is_array($form_values)) {
+    return $RRULE;
+  }
+
+  // Grab the RRULE data and put them into iCal RRULE format.
+  $RRULE .= 'RRULE:FREQ=' . (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']);
+  $RRULE .= ';INTERVAL=' . (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']);
+
+  // Unset the empty 'All' values.
+  if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) {
+    unset($form_values['BYDAY']['']);
+  }
+  if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH'])) {
+    unset($form_values['BYMONTH']['']);
+  }
+  if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY'])) {
+    unset($form_values['BYMONTHDAY']['']);
+  }
+
+  if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY']) && $BYDAY = implode(",", $form_values['BYDAY'])) {
+    $RRULE .= ';BYDAY=' . $BYDAY;
+  }
+  if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH']) && $BYMONTH = implode(",", $form_values['BYMONTH'])) {
+    $RRULE .= ';BYMONTH=' . $BYMONTH;
+  }
+  if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY']) && $BYMONTHDAY = implode(",", $form_values['BYMONTHDAY'])) {
+    $RRULE .= ';BYMONTHDAY=' . $BYMONTHDAY;
+  }
+  // The UNTIL date is supposed to always be expressed in UTC.
+  // The input date values may already have been converted to a date object on a
+  // previous pass, so check for that.
+  if (array_key_exists('UNTIL', $form_values) && array_key_exists('datetime', $form_values['UNTIL']) && !empty($form_values['UNTIL']['datetime'])) {
+    // We only collect a date for UNTIL, but we need it to be inclusive, so
+    // force it to a full datetime element at the last second of the day.
+    if (!is_object($form_values['UNTIL']['datetime'])) {
+      $form_values['UNTIL']['datetime'] .= ' 23:59:59';
+      $form_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute', 'second')));
+      $form_values['UNTIL']['all_day'] = 0;
+      $until = date_ical_date($form_values['UNTIL'], 'UTC');
+    }
+    else {
+      $until = $form_values['UNTIL']['datetime'];
+    }
+    $RRULE .= ';UNTIL=' . date_format($until, DATE_FORMAT_ICAL) . 'Z';
+  }
+  // Our form doesn't allow a value for COUNT, but it may be needed by
+  // modules using the API, so add it to the rule.
+  if (array_key_exists('COUNT', $form_values)) {
+    $RRULE .= ';COUNT=' . $form_values['COUNT'];
+  }
+
+  // iCal rules presume the week starts on Monday unless otherwise specified,
+  // so we'll specify it.
+  if (array_key_exists('WKST', $form_values)) {
+    $RRULE .= ';WKST=' . $form_values['WKST'];
+  }
+  else {
+    $RRULE .= ';WKST=' . date_repeat_dow2day(variable_get('date_first_day', 0));
+  }
+
+  // Exceptions dates go last, on their own line.
+  // The input date values may already have been converted to a date
+  // object on a previous pass, so check for that.
+  if (isset($form_values['EXDATE']) && is_array($form_values['EXDATE'])) {
+    $ex_dates = array();
+    foreach ($form_values['EXDATE'] as $value) {
+      if (!empty($value['datetime'])) {
+        $date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
+        $ex_date = !empty($date) ? $date->format(DATE_FORMAT_ICAL) . 'Z': '';
+        if (!empty($ex_date)) {
+          $ex_dates[] = $ex_date;
+        }
+      }
+    }
+    if (!empty($ex_dates)) {
+      sort($ex_dates);
+      $RRULE .= chr(13) . chr(10) . 'EXDATE:' . implode(',', $ex_dates);
+    }
+  }
+  elseif (!empty($form_values['EXDATE'])) {
+    $RRULE .= chr(13) . chr(10) . 'EXDATE:' . $form_values['EXDATE'];
+  }
+
+  // Exceptions dates go last, on their own line.
+  if (isset($form_values['RDATE']) && is_array($form_values['RDATE'])) {
+    $ex_dates = array();
+    foreach ($form_values['RDATE'] as $value) {
+      $date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
+      $ex_date = !empty($date) ? $date->format(DATE_FORMAT_ICAL) . 'Z': '';
+      if (!empty($ex_date)) {
+        $ex_dates[] = $ex_date;
+      }
+    }
+    if (!empty($ex_dates)) {
+      sort($ex_dates);
+      $RRULE .= chr(13) . chr(10) . 'RDATE:' . implode(',', $ex_dates);
+    }
+  }
+  elseif (!empty($form_values['RDATE'])) {
+    $RRULE .= chr(13) . chr(10) . 'RDATE:' . $form_values['RDATE'];
+  }
+
+  return $RRULE;
+}
diff --git a/sites/all/modules/date/date_api/date_api_sql.inc b/sites/all/modules/date/date_api/date_api_sql.inc
new file mode 100644
index 0000000000000000000000000000000000000000..ede8b1ef33fbd1071b828de1c863078693b300d9
--- /dev/null
+++ b/sites/all/modules/date/date_api/date_api_sql.inc
@@ -0,0 +1,1156 @@
+<?php
+
+/**
+ * @file
+ * SQL helper for Date API.
+ *
+ * @TODO
+ * Add experimental support for sqlite: http://www.sqlite.org/lang_datefunc.html
+ * and Oracle (http://psoug.org/reference/date_func.html and
+ * http://psoug.org/reference/datatypes.html) date/time functions.
+ */
+
+/**
+ * A helper function to do cross-database concatation of date parts.
+ *
+ * @param array $array
+ *   An array of values to be concatonated in sql.
+ *
+ * @return string
+ *   Correct sql string for database type.
+ */
+function date_sql_concat($array) {
+  switch (db_driver()) {
+    case 'mysql':
+    case 'mysqli':
+      return "CONCAT(" . implode(",", $array) . ")";
+    case 'pgsql':
+      return implode(" || ", $array);
+  }
+}
+
+/**
+ * Helper function to do cross-database NULL replacements
+ *
+ * @param array $array
+ *   An array of values to test for NULL values.
+ *
+ * @return string
+ *   SQL statement to return the first non-NULL value in the list.
+ */
+function date_sql_coalesce($array) {
+  switch (db_driver()) {
+    case 'mysql':
+    case 'mysqli':
+    case 'pgsql':
+      return "COALESCE(" . implode(',', $array) . ")";
+  }
+}
+
+/**
+ * A helper function to do cross-database padding of date parts.
+ *
+ * @param string $str
+ *   A string to apply padding to
+ * @param int $size
+ *   The size the final string should be
+ * @param string $pad
+ *   The value to pad the string with
+ * @param string $side
+ *   The side of the string to pad
+ */
+function date_sql_pad($str, $size = 2, $pad = '0', $side = 'l') {
+  switch ($side) {
+    case 'r':
+      return "RPAD($str, $size, '$pad')";
+    default:
+      return "LPAD($str, $size, '$pad')";
+  }
+}
+
+/**
+ * A class to manipulate date SQL.
+ */
+class date_sql_handler {
+  var $db_type = NULL;
+  var $date_type = DATE_DATETIME;
+  // A string timezone name.
+  var $db_timezone = 'UTC';
+  // A string timezone name.
+  var $local_timezone = NULL;
+  // Use if the db timezone is stored in a field.
+  var $db_timezone_field = NULL;
+  // Use if the local timezone is stored in a field.
+  var $local_timezone_field = NULL;
+  // Use if the offset is stored in a field.
+  var $offset_field = NULL;
+
+  /**
+   * The object constuctor.
+   */
+  function __construct($date_type = DATE_DATETIME, $local_timezone = NULL, $offset = '+00:00') {
+    $this->db_type = db_driver();
+    $this->date_type = $date_type;
+    $this->db_timezone = 'UTC';
+    $this->local_timezone = isset($local_timezone) ? $local_timezone : date_default_timezone();
+    $this->set_db_timezone($offset);
+  }
+
+  /**
+   * See if the db has timezone name support.
+   */
+  function db_tz_support($reset = FALSE) {
+    $has_support = variable_get('date_db_tz_support', -1);
+    if ($has_support == -1 || $reset) {
+      $has_support = FALSE;
+      switch ($this->db_type) {
+        case 'mysql':
+        case 'mysqli':
+          $test = db_query("SELECT CONVERT_TZ('2008-02-15 12:00:00', 'UTC', 'US/Central')")->fetchField();
+          if ($test == '2008-02-15 06:00:00') {
+            $has_support = TRUE;
+          }
+          break;
+        case 'pgsql':
+          $test = db_query("SELECT '2008-02-15 12:00:00 UTC' AT TIME ZONE 'US/Central'")->fetchField();
+          if ($test == '2008-02-15 06:00:00') {
+            $has_support = TRUE;
+          }
+          break;
+      }
+      variable_set('date_db_tz_support', $has_support);
+    }
+    return $has_support;
+  }
+
+  /**
+   * Set the database timzone offset.
+   *
+   * Setting the db timezone to UTC is done to ensure consistency in date
+   * handling whether or not the database can do proper timezone conversion.
+   *
+   * Views filters that not exposed are cached and won't set the timezone
+   * so views date filters should add 'cacheable' => 'no' to their
+   * definitions to ensure that the database timezone gets set properly
+   * when the query is executed.
+   *
+   * @param string $offset
+   *   An offset value to set the database timezone to. This will only
+   *   set a fixed offset, not a timezone, so any value other than
+   *   '+00:00' should be used with caution.
+   */
+  function set_db_timezone($offset = '+00:00') {
+    static $already_set = FALSE;
+    $type = db_driver();
+    if (!$already_set) {
+      switch ($type) {
+        case 'mysql':
+        case 'mysqli':
+          db_query("SET @@session.time_zone = '$offset'");
+          break;
+        case 'pgsql':
+          db_query("SET TIME ZONE INTERVAL '$offset' HOUR TO MINUTE");
+          break;
+        case 'sqlsrv':
+          // Issue #1201342, This is the wrong way to set the timezone, this
+          // still needs to be fixed. In the meantime, commenting this out makes
+          // SQLSRV functional.
+          // db_query('TimeZone.setDefault(TimeZone.getTimeZone("GMT"))');
+          break;
+      }
+      $already_set = TRUE;
+    }
+  }
+
+  /**
+   * Return timezone offset for the date being processed.
+   */
+  function get_offset($comp_date = NULL) {
+    if (!empty($this->db_timezone) && !empty($this->local_timezone)) {
+      if ($this->db_timezone != $this->local_timezone) {
+        if (empty($comp_date)) {
+          $comp_date = date_now($this->db_timezone);
+        }
+        $comp_date->setTimezone(timezone_open($this->local_timezone));
+        return date_offset_get($comp_date);
+      }
+    }
+    return 0;
+  }
+
+  /**
+   * Helper function to create cross-database SQL dates.
+   *
+   * @param string $field
+   *   The real table and field name, like 'tablename.fieldname' .
+   * @param string $offset
+   *   The name of a field that holds the timezone offset or an
+   *   offset value. If NULL, the normal Drupal timezone handling
+   *   will be used, if $offset = 0 no adjustment will be made.
+   *
+   * @return string
+   *   An appropriate SQL string for the db type and field type.
+   */
+  function sql_field($field, $offset = NULL, $comp_date = NULL) {
+    if (strtoupper($field) == 'NOW') {
+      // NOW() will be in UTC since that is what we set the db timezone to.
+      $this->local_timezone = 'UTC';
+      return $this->sql_offset('NOW()', $offset);
+    }
+    switch ($this->db_type) {
+      case 'mysql':
+      case 'mysqli':
+        switch ($this->date_type) {
+          case DATE_UNIX:
+            $field = "FROM_UNIXTIME($field)";
+            break;
+          case DATE_ISO:
+            $field = "STR_TO_DATE($field, '%Y-%m-%dT%T')";
+            break;
+          case DATE_DATETIME:
+            break;
+        }
+        break;
+      case 'pgsql':
+        switch ($this->date_type) {
+          case DATE_UNIX:
+            $field = "$field::ABSTIME";
+            break;
+          case DATE_ISO:
+            $field = "TO_DATE($field, 'FMYYYY-FMMM-FMDDTFMHH24:FMMI:FMSS')";
+            break;
+          case DATE_DATETIME:
+            break;
+        }
+        break;
+      case 'sqlite':
+        switch ($this->date_type) {
+          case DATE_UNIX:
+            $field = "datetime($field, 'unixepoch')";
+            break;
+          case DATE_ISO:
+          case DATE_DATETIME:
+            $field = "datetime($field)";
+            break;
+        }
+        break;
+      case 'sqlsrv':
+        switch ($this->date_type) {
+          case DATE_UNIX:
+            $field = "DATEADD(s, $field, '19700101 00:00:00:000')";
+            break;
+          case DATE_ISO:
+          case DATE_DATETIME:
+            $field = "CAST($field as smalldatetime)";
+            break;
+        }
+        break;
+      break;
+    }
+    // Adjust the resulting value to the right timezone/offset.
+    return $this->sql_tz($field, $offset, $comp_date);
+  }
+
+  /**
+   * Adjust a field value by an offset in seconds.
+   */
+  function sql_offset($field, $offset = NULL) {
+    if (!empty($offset)) {
+      switch ($this->db_type) {
+        case 'mysql':
+        case 'mysqli':
+          return "ADDTIME($field, SEC_TO_TIME($offset))";
+        case 'pgsql':
+          return "($field + INTERVAL '$offset SECONDS')";;
+        case 'sqlite':
+          return "datetime($field, '$offset seconds')";
+        case 'sqlsrv':
+          return "DATEADD(second, $offset, $field)";
+      }
+    }
+    return $field;
+  }
+
+  /**
+   * Adjusts a field value by time interval.
+   *
+   * @param string $field
+   *   The field to be adjusted.
+   * @param string $direction
+   *   Either ADD or SUB.
+   * @param int $count
+   *   The number of values to adjust.
+   * @param string $granularity
+   *   The granularity of the adjustment, should be singular,
+   *   like SECOND, MINUTE, DAY, HOUR.
+   */
+  function sql_date_math($field, $direction, $count, $granularity) {
+    $granularity = strtoupper($granularity);
+    switch ($this->db_type) {
+      case 'mysql':
+      case 'mysqli':
+        switch ($direction) {
+          case 'ADD':
+            return "DATE_ADD($field, INTERVAL $count $granularity)";
+          case 'SUB':
+            return "DATE_SUB($field, INTERVAL $count $granularity)";
+        }
+
+      case 'pgsql':
+        $granularity .= 'S';
+        switch ($direction) {
+          case 'ADD':
+            return "($field + INTERVAL '$count $granularity')";
+          case 'SUB':
+            return "($field - INTERVAL '$count $granularity')";
+        }
+      case 'sqlite':
+        $granularity .= 'S';
+        switch ($direction) {
+          case 'ADD':
+            return "datetime($field, '+$count $granularity')";
+          case 'SUB':
+            return "datetime($field, '-$count $granularity')";
+        }
+    }
+    return $field;
+  }
+
+  /**
+   * Select a date value from the database, adjusting the value
+   * for the timezone.
+   *
+   * Check whether database timezone conversion is supported in
+   * this system and use it if possible, otherwise use an
+   * offset.
+   *
+   * @param string $field
+   *   The field to be adjusted.
+   * @param bool $offset
+   *   Set a fixed offset or offset field to use for the date.
+   *   If set, no timezone conversion will be done and the
+   *   offset will be used.
+   */
+  function sql_tz($field, $offset = NULL, $comp_date = NULL) {
+    // If the timezones are values they need to be quoted, but
+    // if they are field names they do not.
+    $db_zone   = !empty($this->db_timezone_field) ? $this->db_timezone_field : "'{$this->db_timezone}'";
+    $localzone = !empty($this->local_timezone_field) ? $this->local_timezone_field : "'{$this->local_timezone}'";
+    // If a fixed offset is required, use it.
+    if ($offset !== NULL) {
+      return $this->sql_offset($field, $offset);
+    }
+    // If the db and local timezones are the same, make no adjustment.
+    elseif ($db_zone == $localzone) {
+      return $this->sql_offset($field, 0);
+    }
+    // If the db has no timezone support, adjust by the offset,
+    // could be either a field name or a value.
+    elseif (!$this->db_tz_support() || empty($localzone)) {
+      if (!empty($this->offset_field)) {
+        return $this->sql_offset($field, $this->offset_field);
+      }
+      else {
+        return $this->sql_offset($field, $this->get_offset($comp_date));
+      }
+    }
+    // Otherwise make a database timezone adjustment to the field.
+    else {
+      switch ($this->db_type) {
+        case 'mysql':
+        case 'mysqli':
+          return "CONVERT_TZ($field, $db_zone, $localzone)";
+        case 'pgsql':
+          // WITH TIME ZONE assumes the date is using the system
+          // timezone, which should have been set to UTC.
+          return "$field::timestamp with time zone AT TIME ZONE $localzone";
+      }
+    }
+  }
+
+  /**
+   * Helper function to create cross-database SQL date formatting.
+   *
+   * @param string $format
+   *   A format string for the result, like 'Y-m-d H:i:s' .
+   * @param string $field
+   *   The real table and field name, like 'tablename.fieldname' .
+   *
+   * @return string
+   *   An appropriate SQL string for the db type and field type.
+   */
+  function sql_format($format, $field) {
+    switch ($this->db_type) {
+      case 'mysql':
+      case 'mysqli':
+        $replace = array(
+          'Y' => '%Y',
+          'y' => '%y',
+          'M' => '%b',
+          'm' => '%m',
+          'n' => '%c',
+          'F' => '%M',
+          'D' => '%a',
+          'd' => '%d',
+          'l' => '%W',
+          'j' => '%e',
+          'W' => '%v',
+          'H' => '%H',
+          'h' => '%h',
+          'i' => '%i',
+          's' => '%s',
+          'A' => '%p',
+          '\WW' => 'W%U',
+        );
+        $format = strtr($format, $replace);
+        return "DATE_FORMAT($field, '$format')";
+      case 'pgsql':
+        $replace = array(
+          'Y' => 'YYYY',
+          'y' => 'YY',
+          'M' => 'Mon',
+          'm' => 'MM',
+          // No format for Numeric representation of a month, without leading
+          // zeros.
+          'n' => 'MM',
+          'F' => 'Month',
+          'D' => 'Dy',
+          'd' => 'DD',
+          'l' => 'Day',
+          // No format for Day of the month without leading zeros.
+          'j' => 'DD',
+          'W' => 'WW',
+          'H' => 'HH24',
+          'h' => 'HH12',
+          'i' => 'MI',
+          's' => 'SS',
+          'A' => 'AM',
+          '\T' => '"T"',
+          // '\W' => // TODO, what should this be?
+        );
+        $format = strtr($format, $replace);
+        return "TO_CHAR($field, '$format')";
+      case 'sqlite':
+        $replace = array(
+          // 4 digit year number.
+          'Y' => '%Y',
+          // No format for 2 digit year number.
+          'y' => '%Y',
+          // No format for 3 letter month name.
+          'M' => '%m',
+          // Month number with leading zeros.
+          'm' => '%m',
+          // No format for month number without leading zeros.
+          'n' => '%m',
+          // No format for full month name.
+          'F' => '%m',
+          // No format for 3 letter day name.
+          'D' => '%d',
+          // Day of month number with leading zeros.
+          'd' => '%d',
+          // No format for full day name.
+          'l' => '%d',
+          // No format for day of month number without leading zeros.
+          'j' => '%d',
+          // ISO week number.
+          'W' => '%W',
+          // 24 hour hour with leading zeros.
+          'H' => '%H',
+          // No format for 12 hour hour with leading zeros.
+          'h' => '%H',
+          // Minutes with leading zeros.
+          'i' => '%M',
+          // Seconds with leading zeros.
+          's' => '%S',
+          // No format for AM/PM.
+          'A' => '',
+          // Week number.
+          '\WW' => '',
+        );
+        $format = strtr($format, $replace);
+        return "strftime('$format', $field)";
+      case 'sqlsrv':
+        $replace = array(
+          // 4 digit year number.
+          'Y' => "' + CAST(DATEPART(year, $field) AS nvarchar) + '",
+          // 2 digit year number.
+          'y' => "' + RIGHT(DATEPART(year, $field), 2) + '",
+          // 3 letter month name.
+          'M' => "' + LEFT(DATENAME(month, $field), 3) + '",
+          // Month number with leading zeros.
+          'm' => "' + RIGHT('0' + CAST(DATEPART(month, $field) AS nvarchar), 2) + '",
+          // Month number without leading zeros.
+          'n' => "' + CAST(DATEPART(month, $field) AS nvarchar) + '",
+          // Full month name.
+          'F' => "' + DATENAME(month, $field) + '",
+          // 3 letter day name.
+          'D' => "' + LEFT(DATENAME(day, $field), 3) + '",
+          // Day of month number with leading zeros.
+          'd' => "' + RIGHT('0' + CAST(DATEPART(day, $field) AS nvarchar), 2) + '",
+          // Full day name.
+          'l' => "' + DATENAME(day, $field) + '",
+          // Day of month number without leading zeros.
+          'j' => "' + CAST(DATEPART(day, $field) AS nvarchar) + '",
+          // ISO week number.
+          'W' => "' + CAST(DATEPART(iso_week, $field) AS nvarchar) + '",
+          // 24 hour with leading zeros.
+          'H' => "' + RIGHT('0' + CAST(DATEPART(hour, $field) AS nvarchar), 2) + '",
+          // 12 hour with leading zeros.
+          // Conversion to 'mon dd yyyy hh:miAM/PM' format (corresponds to style
+          // 100 in MSSQL).
+          // Hour position is fixed, so we use SUBSTRING to extract it.
+          'h' => "' + RIGHT('0' + LTRIM(SUBSTRING(CONVERT(nvarchar, $field, 100), 13, 2)), 2) + '",
+          // Minutes with leading zeros.
+          'i' => "' + RIGHT('0' + CAST(DATEPART(minute, $field) AS nvarchar), 2) + '",
+          // Seconds with leading zeros.
+          's' => "' + RIGHT('0' + CAST(DATEPART(second, $field) AS nvarchar), 2) + '",
+          // AM/PM.
+          // Conversion to 'mon dd yyyy hh:miAM/PM' format (corresponds to style
+          // 100 in MSSQL).
+          'A' => "' + RIGHT(CONVERT(nvarchar, $field, 100), 2) + '",
+          // Week number.
+          '\WW' => "' + CAST(DATEPART(week, $field) AS nvarchar) + '",
+          '\T' => 'T',
+          // MS SQL uses single quote as escape symbol.
+          '\'' => '\'\'',
+        );
+        $format = strtr($format, $replace);
+        $format = "'$format'";
+        return $format;
+    }
+  }
+
+  /**
+   * Helper function to create cross-database SQL date extraction.
+   *
+   * @param string $extract_type
+   *   The type of value to extract from the date, like 'MONTH'.
+   * @param string $field
+   *   The real table and field name, like 'tablename.fieldname'.
+   *
+   * @return string
+   *   An appropriate SQL string for the db type and field type.
+   */
+  function sql_extract($extract_type, $field) {
+    // Note there is no space after FROM to avoid db_rewrite problems
+    // see http://drupal.org/node/79904.
+    switch (strtoupper($extract_type)) {
+      case 'DATE':
+        return $field;
+      case 'YEAR':
+        return "EXTRACT(YEAR FROM($field))";
+      case 'MONTH':
+        return "EXTRACT(MONTH FROM($field))";
+      case 'DAY':
+        return "EXTRACT(DAY FROM($field))";
+      case 'HOUR':
+        return "EXTRACT(HOUR FROM($field))";
+      case 'MINUTE':
+        return "EXTRACT(MINUTE FROM($field))";
+      case 'SECOND':
+        return "EXTRACT(SECOND FROM($field))";
+      // ISO week number for date.
+      case 'WEEK':
+        switch ($this->db_type) {
+          case 'mysql':
+          case 'mysqli':
+            // WEEK using arg 3 in MySQl should return the same value as
+            // Postgres EXTRACT.
+            return "WEEK($field, 3)";
+          case 'pgsql':
+            return "EXTRACT(WEEK FROM($field))";
+        }
+      case 'DOW':
+        switch ($this->db_type) {
+          case 'mysql':
+          case 'mysqli':
+            // MySQL returns 1 for Sunday through 7 for Saturday, PHP date
+            // functions and Postgres use 0 for Sunday and 6 for Saturday.
+            return "INTEGER(DAYOFWEEK($field) - 1)";
+          case 'pgsql':
+            return "EXTRACT(DOW FROM($field))";
+        }
+      case 'DOY':
+        switch ($this->db_type) {
+          case 'mysql':
+          case 'mysqli':
+            return "DAYOFYEAR($field)";
+          case 'pgsql':
+            return "EXTRACT(DOY FROM($field))";
+        }
+    }
+  }
+
+  /**
+   * Creates a where clause to compare a complete date field to a date value.
+   *
+   * @param string $type
+   *   The type of value we're comparing to, could be another field
+   *   or a date value.
+   * @param string $field
+   *   The db table and field name, like "$table.$field".
+   * @param string $operator
+   *   The db comparison operator to use, like '='.
+   * @param int $value
+   *   The value to compare the extracted date part to, could be a field name or
+   *   a date string or NOW().
+   *
+   * @return string
+   *   SQL for the where clause for this operation.
+   */
+  function sql_where_date($type, $field, $operator, $value, $adjustment = 0) {
+    $type = strtoupper($type);
+    if (strtoupper($value) == 'NOW') {
+      $value = $this->sql_field('NOW', $adjustment);
+    }
+    elseif ($type == 'FIELD') {
+      $value = $this->sql_field($value, $adjustment);
+    }
+    elseif ($type == 'DATE') {
+      $date = new DateObject($value, date_default_timezone(), DATE_FORMAT_DATETIME);
+      if (!empty($adjustment)) {
+        date_modify($date, $adjustment . ' seconds');
+      }
+      // When comparing a field to a date we can avoid doing timezone
+      // conversion by altering the comparison date to the db timezone.
+      // This won't work if the timezone is a field instead of a value.
+      if (empty($this->db_timezone_field) && empty($this->local_timezone_field) && $this->db_timezone_field != $this->local_timezone_field) {
+        $date->setTimezone(timezone_open($this->db_timezone));
+        $this->local_timezone = $this->db_timezone;
+      }
+      $value = "'" . $date->format(DATE_FORMAT_DATETIME, TRUE) . "'";
+    }
+    if ($this->local_timezone != $this->db_timezone) {
+      $field = $this->sql_field($field);
+    }
+    else {
+      $field = $this->sql_field($field, 0);
+    }
+    return "$field $operator $value";
+  }
+
+  /**
+   * Creates a where clause comparing an extracted date part to an integer.
+   *
+   * @param string $part
+   *   The part to extract, YEAR, MONTH, DAY, etc.
+   * @param string $field
+   *   The db table and field name, like "$table.$field".
+   * @param string $operator
+   *   The db comparison operator to use, like '=' .
+   * @param int $value
+   *   The integer value to compare the extracted date part to.
+   *
+   * @return string
+   *   SQL for the where clause for this operation.
+   */
+  function sql_where_extract($part, $field, $operator, $value) {
+    if ($this->local_timezone != $this->db_timezone) {
+      $field = $this->sql_field($field);
+    }
+    else {
+      $field = $this->sql_field($field, 0);
+    }
+    return $this->sql_extract($part, $field) . " $operator $value";
+  }
+
+  /**
+   * Create a where clause to compare a formated field to a formated value.
+   *
+   * @param string $format
+   *   The format to use on the date and the value when comparing them.
+   * @param string $field
+   *   The db table and field name, like "$table.$field".
+   * @param string $operator
+   *   The db comparison operator to use, like '=' .
+   * @param string $value
+   *   The value to compare the extracted date part to, could be a
+   *   field name or a date string or NOW().
+   *
+   * @return string
+   *   SQL for the where clause for this operation.
+   */
+  function sql_where_format($format, $field, $operator, $value) {
+    if ($this->local_timezone != $this->db_timezone) {
+      $field = $this->sql_field($field);
+    }
+    else {
+      $field = $this->sql_field($field, 0);
+    }
+    return $this->sql_format($format, $field) . " $operator '$value'";
+  }
+
+  /**
+   * An array of all date parts,
+   * optionally limited to an array of allowed parts.
+   */
+  function date_parts($limit = NULL) {
+    $parts = array(
+      'year' => t('Year', array(), array('context' => 'datetime')),
+      'month' => t('Month', array(), array('context' => 'datetime')),
+      'day' => t('Day', array(), array('context' => 'datetime')),
+      'hour' => t('Hour', array(), array('context' => 'datetime')),
+      'minute' => t('Minute', array(), array('context' => 'datetime')),
+      'second' => t('Second', array(), array('context' => 'datetime')),
+    );
+    if (!empty($limit)) {
+      $last = FALSE;
+      foreach ($parts as $key => $part) {
+        if ($last) {
+          unset($parts[$key]);
+        }
+        if ($key == $limit) {
+          $last = TRUE;
+        }
+      }
+    }
+    return $parts;
+  }
+
+  /**
+   * Part information.
+   *
+   * @param string $op
+   *   'min', 'max', 'format', 'sep', 'empty_now', 'empty_min', 'empty_max' .
+   *   Returns all info if empty.
+   * @param string $part
+   *   'year', 'month', 'day', 'hour', 'minute', or 'second.
+   *   returns info for all parts if empty.
+   */
+  function part_info($op = NULL, $part = NULL) {
+    $info = array();
+    $info['min'] = array(
+      'year' => 100,
+      'month' => 1,
+      'day' => 1,
+      'hour' => 0,
+      'minute' => 0,
+      'second' => 0,
+    );
+    $info['max'] = array(
+      'year' => 4000,
+      'month' => 12,
+      'day' => 31,
+      'hour' => 23,
+      'minute' => 59,
+      'second' => 59,
+    );
+    $info['format'] = array(
+      'year' => 'Y',
+      'month' => 'm',
+      'day' => 'd',
+      'hour' => 'H',
+      'minute' => 'i',
+      'second' => 's',
+    );
+    $info['sep'] = array(
+      'year' => '',
+      'month' => '-',
+      'day' => '-',
+      'hour' => ' ',
+      'minute' => ':',
+      'second' => ':',
+    );
+    $info['empty_now'] = array(
+      'year' => date('Y'),
+      'month' => date('m'),
+      'day' => min('28', date('d')),
+      'hour' => date('H'),
+      'minute' => date('i'),
+      'second' => date('s'),
+    );
+    $info['empty_min'] = array(
+      'year' => '1000',
+      'month' => '01',
+      'day' => '01',
+      'hour' => '00',
+      'minute' => '00',
+      'second' => '00',
+    );
+    $info['empty_max'] = array(
+      'year' => '9999',
+      'month' => '12',
+      'day' => '31',
+      'hour' => '23',
+      'minute' => '59',
+      'second' => '59',
+    );
+    if (!empty($op)) {
+      if (!empty($part)) {
+        return $info[$op][$part];
+      }
+      else {
+        return $info[$op];
+      }
+    }
+    return $info;
+  }
+
+  /**
+   * Create a complete datetime value out of an
+   * incomplete array of selected values.
+   *
+   * For example, array('year' => 2008, 'month' => 05) will fill
+   * in the day, hour, minute and second with the earliest possible
+   * values if type = 'min', the latest possible values if type = 'max',
+   * and the current values if type = 'now' .
+   */
+  function complete_date($selected, $type = 'now') {
+    if (empty($selected)) {
+      return '';
+    }
+    // Special case for weeks.
+    if (array_key_exists('week', $selected)) {
+      $dates = date_week_range($selected['week'], $selected['year']);
+      switch ($type) {
+        case 'empty_now':
+        case 'empty_min':
+        case 'min':
+          return date_format($dates[0], 'Y-m-d H:i:s');
+        case 'empty_max':
+        case 'max':
+          return date_format($dates[1], 'Y-m-d H:i:s');
+        default:
+          return;
+      }
+    }
+
+    $compare = array_merge($this->part_info('empty_' . $type), $selected);
+    // If this is a max date, make sure the last day of
+    // the month is the right one for this date.
+    if ($type == 'max') {
+      $compare['day'] = date_days_in_month($compare['year'], $compare['month']);
+    }
+    $value = '';
+    $separators = $this->part_info('sep');
+    foreach ($this->date_parts() as $key => $name) {
+      $value .= $separators[$key] . (!empty($selected[$key]) ? $selected[$key] : $compare[$key]);
+    }
+    return $value;
+  }
+
+  /**
+   * Converts a format string into help text, i.e. 'Y-m-d' becomes 'YYYY-MM-DD'.
+   *
+   * @param string $format
+   *   A date format string.
+   *
+   * @return string
+   *   The conveted help text.
+   */
+  function format_help($format) {
+    $replace = array(
+      'Y' => 'YYYY',
+      'm' => 'MM',
+      'd' => 'DD',
+      'H' => 'HH',
+      'i' => 'MM',
+      's' => 'SS',
+      '\T' => 'T',
+    );
+    return strtr($format, $replace);
+  }
+
+  /**
+   *  A function to test the validity of various date parts
+   */
+  function part_is_valid($value, $type) {
+    if (!preg_match('/^[0-9]*$/', $value)) {
+      return FALSE;
+    }
+    $value = intval($value);
+    if ($value <= 0) {
+      return FALSE;
+    }
+    switch ($type) {
+      case 'year':
+        if ($value < DATE_MIN_YEAR) {
+          return FALSE;
+        }
+        break;
+      case 'month':
+        if ($value < 0 || $value > 12) {
+          return FALSE;
+        }
+        break;
+      case 'day':
+        if ($value < 0 || $value > 31) {
+          return FALSE;
+        }
+        break;
+      case 'week':
+        if ($value < 0 || $value > 53) {
+          return FALSE;
+        }
+        break;
+    }
+    return TRUE;
+  }
+
+  /**
+   * @todo.
+   */
+  function views_formats($granularity, $type = 'sql') {
+    if (empty($granularity)) {
+      return DATE_FORMAT_ISO;
+    }
+    $formats = array('display', 'sql');
+    // Start with the site long date format and add seconds to it.
+    $long = str_replace(':i', ':i:s', variable_get('date_format_long', 'l, F j, Y - H:i'));
+    switch ($granularity) {
+      case 'year':
+        $formats['display'] = 'Y';
+        $formats['sql'] = 'Y';
+        break;
+      case 'month':
+        $formats['display'] = date_limit_format($long, array('year', 'month'));
+        $formats['sql'] = 'Y-m';
+        break;
+      case 'day':
+        $formats['display'] = date_limit_format($long, array('year', 'month', 'day'));
+        $formats['sql'] = 'Y-m-d';
+        break;
+      case 'hour':
+        $formats['display'] = date_limit_format($long, array('year', 'month', 'day', 'hour'));
+        $formats['sql'] = 'Y-m-d\TH';
+        break;
+      case 'minute':
+        $formats['display'] = date_limit_format($long, array('year', 'month', 'day', 'hour', 'minute'));
+        $formats['sql'] = 'Y-m-d\TH:i';
+        break;
+      case 'second':
+        $formats['display'] = date_limit_format($long, array('year', 'month', 'day', 'hour', 'minute', 'second'));
+        $formats['sql'] = 'Y-m-d\TH:i:s';
+        break;
+      case 'week':
+        $formats['display'] = 'F j Y (W)';
+        $formats['sql'] = 'Y-\WW';
+        break;
+    }
+    return $formats[$type];
+  }
+
+  /**
+   * @todo.
+   */
+  function granularity_form($granularity) {
+    $form = array(
+      '#title' => t('Granularity'),
+      '#type' => 'radios',
+      '#default_value' => $granularity,
+      '#options' => $this->date_parts(),
+      );
+    return $form;
+  }
+
+  /**
+   * Parse date parts from an ISO date argument.
+   *
+   * Based on ISO 8601 date duration and time interval standards.
+   *
+   * Parses a value like 2006-01-01--2006-01-15, or 2006-W24, or @P1W.
+   * Separate start and end dates or date and period with a double hyphen (--).
+   *
+   * The 'end' portion of the argument can be eliminated if it is the same as
+   * the 'start' portion. Use @ instead of a date to substitute in the current
+   * date and time.
+   *
+   * Use periods (P1H, P1D, P1W, P1M, P1Y) to get next hour/day/week/month/year
+   * from now. Use date before P sign to get next hour/day/week/month/year from
+   * that date. Use period then date to get a period that ends on the date.
+   *
+   * @see http://en.wikipedia.org/wiki/ISO_8601#Week_dates
+   * @see http://en.wikipedia.org/wiki/ISO_8601#Duration
+   */
+  function arg_parts($argument) {
+    $values = array();
+    // Keep mal-formed arguments from creating errors.
+    if (empty($argument) || is_array($argument)) {
+      return array('date' => array(), 'period' => array());
+    }
+    $fromto = explode('--', $argument);
+    foreach ($fromto as $arg) {
+      $parts = array();
+      if ($arg == '@') {
+        $date = date_now();
+        $parts['date'] = $date->toArray();
+      }
+      elseif (preg_match('/(\d{4})?-?(W)?(\d{1,2})?-?(\d{1,2})?[T\s]?(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?/', $arg, $matches)) {
+        $date = array();
+        if (!empty($matches[1])) {
+          $date['year'] = $matches[1];
+        }
+        if (!empty($matches[3])) {
+          if (empty($matches[2])) {
+            $date['month'] = $matches[3];
+          }
+          else {
+            $date['week'] = $matches[3];
+          }
+        }
+        if (!empty($matches[4])) {
+          $date['day'] = $matches[4];
+        }
+        if (!empty($matches[5])) {
+          $date['hour'] = $matches[5];
+        }
+        if (!empty($matches[6])) {
+          $date['minute'] = $matches[6];
+        }
+        if (!empty($matches[7])) {
+          $date['second'] = $matches[7];
+        }
+        $parts['date'] = $date;
+      }
+      if (preg_match('/^P(\d{1,4}[Y])?(\d{1,2}[M])?(\d{1,2}[W])?(\d{1,2}[D])?([T]{0,1})?(\d{1,2}[H])?(\d{1,2}[M])?(\d{1,2}[S])?/', $arg, $matches)) {
+        $period = array();
+        if (!empty($matches[1])) {
+          $period['year'] = str_replace('Y', '', $matches[1]);
+        }
+        if (!empty($matches[2])) {
+          $period['month'] = str_replace('M', '', $matches[2]);
+        }
+        if (!empty($matches[3])) {
+          $period['week'] = str_replace('W', '', $matches[3]);
+        }
+        if (!empty($matches[4])) {
+          $period['day'] = str_replace('D', '', $matches[4]);
+        }
+        if (!empty($matches[6])) {
+          $period['hour'] = str_replace('H', '', $matches[6]);
+        }
+        if (!empty($matches[7])) {
+          $period['minute'] = str_replace('M', '', $matches[7]);
+        }
+        if (!empty($matches[8])) {
+          $period['second'] = str_replace('S', '', $matches[8]);
+        }
+        $parts['period'] = $period;
+      }
+      $values[] = $parts;
+    }
+    return $values;
+  }
+
+  /**
+   * Convert strings like '+1 day' to the ISO equivalent, like 'P1D' .
+   */
+  function arg_replace($arg) {
+    if (!preg_match('/([+|-])\s?([0-9]{1,32})\s?([day(s)?|week(s)?|month(s)?|year(s)?|hour(s)?|minute(s)?|second(s)?]{1,10})/', $arg, $results)) {
+      return str_replace('now', '@', $arg);
+    }
+    $direction = $results[1];
+    $count = $results[2];
+    $item = $results[3];
+
+    $replace = array(
+      'now' => '@',
+      '+' => 'P',
+      '-' => 'P-',
+      'years' => 'Y',
+      'year' => 'Y',
+      'months' => 'M',
+      'month' => 'M',
+      'weeks' => 'W',
+      'week' => 'W',
+      'days' => 'D',
+      'day' => 'D',
+      'hours' => 'H',
+      'hour' => 'H',
+      'minutes' => 'M',
+      'minute' => 'M',
+      'seconds' => 'S',
+      'second' => 'S',
+      '  ' => '',
+      ' ' => '',
+      );
+    $prefix = in_array($item, array('hours', 'hour', 'minutes', 'minute', 'seconds', 'second')) ? 'T' : '';
+    return $prefix . strtr($direction, $replace) . $count . strtr($item, $replace);
+  }
+
+  /**
+   * Use the parsed values from the ISO argument to determine the
+   * granularity of this period.
+   */
+  function arg_granularity($arg) {
+    $granularity = '';
+    $parts = $this->arg_parts($arg);
+    $date = !empty($parts[0]['date']) ? $parts[0]['date'] : (!empty($parts[1]['date']) ? $parts[1]['date'] : array());
+    foreach ($date as $key => $part) {
+      $granularity = $key;
+    }
+    return $granularity;
+  }
+
+  /**
+   * Use the parsed values from the ISO argument to determine the
+   * min and max date for this period.
+   */
+  function arg_range($arg) {
+    // Parse the argument to get its parts.
+    $parts = $this->arg_parts($arg);
+
+    // Build a range from a period-only argument (assumes the min date is now.)
+    if (empty($parts[0]['date']) && !empty($parts[0]['period']) && (empty($parts[1]))) {
+      $min_date = date_now();
+      $max_date = clone($min_date);
+      foreach ($parts[0]['period'] as $part => $value) {
+        date_modify($max_date, "+$value $part");
+      }
+      date_modify($max_date, '-1 second');
+      return array($min_date, $max_date);
+    }
+    // Build a range from a period to period argument.
+    if (empty($parts[0]['date']) && !empty($parts[0]['period']) && !empty($parts[1]['period'])) {
+      $min_date = date_now();
+      $max_date = clone($min_date);
+      foreach ($parts[0]['period'] as $part => $value) {
+        date_modify($min_date, "+$value $part");
+      }
+      date_modify($min_date, '-1 second');
+      foreach ($parts[1]['period'] as $part => $value) {
+        date_modify($max_date, "+$value $part");
+      }
+      date_modify($max_date, '-1 second');
+      return array($min_date, $max_date);
+    }
+    if (!empty($parts[0]['date'])) {
+      $value = $this->complete_date($parts[0]['date'], 'min');
+      $min_date = new DateObject($value, date_default_timezone(), DATE_FORMAT_DATETIME);
+      // Build a range from a single date-only argument.
+      if (empty($parts[1]) || (empty($parts[1]['date']) && empty($parts[1]['period']))) {
+        $value = $this->complete_date($parts[0]['date'], 'max');
+        $max_date = new DateObject($value, date_default_timezone(), DATE_FORMAT_DATETIME);
+        return array($min_date, $max_date);
+      }
+      // Build a range from start date + period.
+      elseif (!empty($parts[1]['period'])) {
+        foreach ($parts[1]['period'] as $part => $value) {
+          $max_date = clone($min_date);
+          date_modify($max_date, "+$value $part");
+        }
+        date_modify($max_date, '-1 second');
+        return array($min_date, $max_date);
+      }
+    }
+    // Build a range from start date and end date.
+    if (!empty($parts[1]['date'])) {
+      $value = $this->complete_date($parts[1]['date'], 'max');
+      $max_date = new DateObject($value, date_default_timezone(), DATE_FORMAT_DATETIME);
+      if (isset($min_date)) {
+        return array($min_date, $max_date);
+      }
+    }
+    // Build a range from period + end date.
+    if (!empty($parts[0]['period'])) {
+      $min_date = date_now();
+      foreach ($parts[0]['period'] as $part => $value) {
+        date_modify($min_date, "$value $part");
+      }
+      return array($min_date, $max_date);
+    }
+     // Intercept invalid info and fall back to the current date.
+    $now = date_now();
+    return array($now, $now);
+  }
+}
diff --git a/sites/all/modules/date/date_api/date_year_range.js b/sites/all/modules/date/date_api/date_year_range.js
new file mode 100644
index 0000000000000000000000000000000000000000..f301b991cf7662c0288e3eb295a5ebd1f29163d2
--- /dev/null
+++ b/sites/all/modules/date/date_api/date_year_range.js
@@ -0,0 +1,223 @@
+(function ($) {
+
+Drupal.behaviors.dateYearRange = {};
+
+Drupal.behaviors.dateYearRange.attach = function (context, settings) {
+  var $textfield, $textfields, i;
+
+  // Turn the years back and forward fieldsets into dropdowns.
+  $textfields = $('input.select-list-with-custom-option', context).once('date-year-range');
+  for (i = 0; i < $textfields.length; i++) {
+    $textfield = $($textfields[i]);
+    new Drupal.dateYearRange.SelectListWithCustomOption($textfield);
+  }
+};
+
+
+Drupal.dateYearRange = {};
+
+/**
+ * Constructor for the SelectListWithCustomOption object.
+ *
+ * This object is responsible for turning the years back and forward textfields
+ * into dropdowns with an 'other' option that lets the user enter a custom
+ * value.
+ */
+Drupal.dateYearRange.SelectListWithCustomOption = function ($textfield) {
+  this.$textfield = $textfield;
+  this.$description = $textfield.next('div.description');
+  this.defaultValue = $textfield.val();
+  this.$dropdown = this.createDropdown();
+  this.$dropdown.insertBefore($textfield);
+};
+
+/**
+ * Get the value of the textfield as it existed on page load.
+ *
+ * @param {String} type
+ *   The type of the variable to be returned. Defaults to string.
+ * @return
+ *   The original value of the textfield. Returned as an integer, if the type
+ *   parameter was 'int'.
+ */
+Drupal.dateYearRange.SelectListWithCustomOption.prototype.getOriginal = function (type) {
+  var original;
+  if (type === 'int') {
+    original = parseInt(this.defaultValue, 10);
+    if (window.isNaN(original)) {
+      original = 0;
+    }
+  }
+  else {
+    original = this.defaultValue;
+  }
+  return original;
+};
+
+/**
+ * Get the correct first value for the dropdown.
+ */
+Drupal.dateYearRange.SelectListWithCustomOption.prototype.getStartValue = function () {
+  var direction = this.getDirection();
+  var start;
+  switch (direction) {
+    case 'back':
+      // For the 'years back' dropdown, the first option should be -10, unless
+      // the default value of the textfield is even smaller than that.
+      start = Math.min(this.getOriginal('int'), -10);
+      break;
+    case 'forward':
+      start = 0;
+      break;
+  }
+  return start;
+};
+
+/**
+ * Get the correct last value for the dropdown.
+ */
+Drupal.dateYearRange.SelectListWithCustomOption.prototype.getEndValue = function () {
+  var direction = this.getDirection();
+  var end;
+  var originalString = this.getOriginal();
+  switch (direction) {
+    case 'back':
+      end = 0;
+      break;
+    case 'forward':
+      // If the original value of the textfield is an absolute year such as
+      // 2020, don't try to include it in the dropdown.
+      if (originalString.indexOf('+') === -1) {
+        end = 10;
+      }
+      // If the original value is a relative value (+x), we want it to be
+      // included in the possible dropdown values.
+      else {
+        end = Math.max(this.getOriginal('int'), 10);
+      }
+      break;
+  }
+  return end;
+};
+
+/**
+ * Create a dropdown select list with the correct options for this textfield.
+ */
+Drupal.dateYearRange.SelectListWithCustomOption.prototype.createDropdown = function () {
+  var $dropdown = $('<select>').addClass('form-select date-year-range-select');
+  var $option, i, value;
+  var start = this.getStartValue();
+  var end = this.getEndValue();
+  var direction = this.getDirection();
+  for (i = start; i <= end; i++) {
+    // Make sure we include the +/- sign in the option value.
+    value = i;
+    if (i > 0) {
+      value = '+' + i;
+    }
+    // Zero values must have a + or - in front.
+    if (i === 0) {
+      if (direction === 'back') {
+        value = '-' + i;
+      }
+      else {
+        value = '+' + i;
+      }
+    }
+    $option = $('<option>' + Drupal.formatPlural(value, '@count year from now', '@count years from now') + '</option>').val(value);
+    $dropdown.append($option);
+  }
+  // Create an 'Other' option.
+  $option = $('<option class="custom-option">' + Drupal.t('Other') + '</option>').val('');
+  $dropdown.append($option);
+
+  // When the user changes the selected option in the dropdown, perform
+  // appropriate actions (such as showing or hiding the textfield).
+  $dropdown.bind('change', $.proxy(this.handleDropdownChange, this));
+
+  // Set the initial value of the dropdown.
+  this._setInitialDropdownValue($dropdown);
+  return $dropdown;
+};
+
+Drupal.dateYearRange.SelectListWithCustomOption.prototype._setInitialDropdownValue = function ($dropdown) {
+  var textfieldValue = this.getOriginal();
+  // Determine whether the original textfield value exists in the dropdown.
+  var possible = $dropdown.find('option[value="' + textfieldValue + '"]');
+  // If the original textfield value is one of the dropdown options, preselect
+  // it and hide the 'other' textfield.
+  if (possible.length) {
+    $dropdown.val(textfieldValue);
+    this.hideTextfield();
+  }
+  // If the original textfield value isn't one of the dropdown options, choose
+  // the 'Other' option in the dropdown.
+  else {
+    $dropdown.val('');
+  }
+};
+
+/**
+ * Determine whether this is the "years back" or "years forward" textfield.
+ */
+Drupal.dateYearRange.SelectListWithCustomOption.prototype.getDirection = function () {
+  if (this.direction) {
+    return this.direction;
+  }
+  var direction;
+  if (this.$textfield.hasClass('back')) {
+    direction = 'back';
+  }
+  else if (this.$textfield.hasClass('forward')) {
+    direction = 'forward';
+  }
+  this.direction = direction;
+  return direction;
+};
+
+/**
+ * Change handler for the dropdown, to modify the textfield as appropriate.
+ */
+Drupal.dateYearRange.SelectListWithCustomOption.prototype.handleDropdownChange = function () {
+  // Since the dropdown changed, we need to make the content of the textfield
+  // match the (new) selected option.
+  this.syncTextfield();
+
+  // Show the textfield if the 'Other' option was selected, and hide it if one
+  // of the preset options was selected.
+  if ($(':selected', this.$dropdown).hasClass('custom-option')) {
+    this.revealTextfield();
+  }
+  else {
+    this.hideTextfield();
+  }
+};
+
+/**
+ * Display the textfield and its description.
+ */
+Drupal.dateYearRange.SelectListWithCustomOption.prototype.revealTextfield = function () {
+  this.$textfield.show();
+  this.$description.show();
+};
+
+/**
+ * Hide the textfield and its description.
+ */
+Drupal.dateYearRange.SelectListWithCustomOption.prototype.hideTextfield = function () {
+  this.$textfield.hide();
+  this.$description.hide();
+};
+
+/**
+ * Copy the selected value of the dropdown to the textfield.
+ *
+ * FAPI doesn't know about the JS-only dropdown, so the textfield needs to
+ * reflect the value of the dropdown.
+ */
+Drupal.dateYearRange.SelectListWithCustomOption.prototype.syncTextfield = function () {
+  var value = this.$dropdown.val();
+  this.$textfield.val(value);
+};
+
+})(jQuery);
diff --git a/sites/all/modules/date/date_api/images/calendar.png b/sites/all/modules/date/date_api/images/calendar.png
new file mode 100644
index 0000000000000000000000000000000000000000..9d40d4c6faf2b3831919865cf6bc20bee7d3d705
Binary files /dev/null and b/sites/all/modules/date/date_api/images/calendar.png differ
diff --git a/sites/all/modules/date/date_api/images/ical16x16.gif b/sites/all/modules/date/date_api/images/ical16x16.gif
new file mode 100644
index 0000000000000000000000000000000000000000..e61bc41a29500bfbe9a87e6e7422a10c4365f397
Binary files /dev/null and b/sites/all/modules/date/date_api/images/ical16x16.gif differ
diff --git a/sites/all/modules/date/date_api/theme/theme.inc b/sites/all/modules/date/date_api/theme/theme.inc
new file mode 100644
index 0000000000000000000000000000000000000000..032e3e9335621072e3e541b402efc1d7b5c7c989
--- /dev/null
+++ b/sites/all/modules/date/date_api/theme/theme.inc
@@ -0,0 +1,229 @@
+<?php
+
+/**
+ * @file
+ * Theme files for Date API.
+ */
+
+/**
+ * Returns HTML for a date timezone element.
+ */
+function theme_date_timezone($variables) {
+  $element = $variables['element'];
+  $attributes = $element['#attributes'];
+  $wrapper_attributes = array();
+  // Add an wrapper to mimic the way a single value field works, for ease in
+  // using #states.
+  if (isset($element['#children'])) {
+    $element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) . '>' . $element['#children'] . '</div>';
+  }
+  return '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
+}
+
+/**
+ * Returns HTML for a date select element.
+ */
+function theme_date_select($variables) {
+  $element = $variables['element'];
+  $attributes = !empty($element['#wrapper_attributes']) ? $element['#wrapper_attributes'] : array('class' => array());
+  $attributes['class'][] = 'container-inline-date';
+  $wrapper_attributes = array('class' => array('date-padding'));
+  $wrapper_attributes['class'][] = 'clearfix';
+  // Add an wrapper to mimic the way a single value field works, for ease in
+  // using #states.
+  if (isset($element['#children'])) {
+    $element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) . '>' . $element['#children'] . '</div>';
+  }
+  return '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
+}
+
+/**
+ * Returns HTML for a date text element.
+ */
+function theme_date_text($variables) {
+  $element = $variables['element'];
+  $attributes = !empty($element['#wrapper_attributes']) ? $element['#wrapper_attributes'] : array('class' => array());
+  $attributes['class'][] = 'container-inline-date';
+  // If there is no description, the floating date elements need some extra
+  // padding below them.
+  $wrapper_attributes = array('class' => array('date-padding'));
+  if (empty($element['date']['#description'])) {
+    $wrapper_attributes['class'][] = 'clearfix';
+  }
+  // Add an wrapper to mimic the way a single value field works, for ease in
+  // using #states.
+  if (isset($element['#children'])) {
+    $element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) . '>' . $element['#children'] . '</div>';
+  }
+  return '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
+}
+
+/**
+ * Returns HTML for a date select input form element.
+ */
+function theme_date_select_element($variables) {
+  $element = $variables['element'];
+  $parents = $element['#parents'];
+  $part = array_pop($parents);
+  return '<div class="date-' . $part . '">' . theme('select', $element) . '</div>';
+}
+
+/**
+ * Returns HTML for a date textfield input form element.
+ */
+function theme_date_textfield_element($variables) {
+  $element = $variables['element'];
+  $parents = $element['#parents'];
+  $part = array_pop($parents);
+  return '<div class="date-' . $part . '">' . theme('textfield', $element) . '</div>';
+}
+
+/**
+ * Returns HTML for a 'hour' date part prefix.
+ */
+function theme_date_part_hour_prefix($variables) {
+  $element = $variables['element'];
+  if ($element['#date_label_position'] != 'above') {
+    return '<span class="form-item date-spacer">&nbsp;-&nbsp;</span>';
+  }
+}
+
+/**
+ * Returns HTML for a 'minutes and seconds' date part prefix.
+ */
+function theme_date_part_minsec_prefix($variables) {
+  $element = $variables['element'];
+  if ($element['#date_label_position'] != 'above') {
+    return '<span class="form-item date-spacer">:</span>';
+  }
+}
+
+/**
+ * Returns HTML for a date_select 'year' label.
+ */
+function theme_date_part_label_year($variables) {
+  return t('Year', array(), array('context' => 'datetime'));
+}
+
+/**
+ * Returns HTML for a date_select 'month' label.
+ */
+function theme_date_part_label_month($variables) {
+  return t('Month', array(), array('context' => 'datetime'));
+}
+
+/**
+ * Returns HTML for a date_select 'day' label.
+ */
+function theme_date_part_label_day($variables) {
+  return t('Day', array(), array('context' => 'datetime'));
+}
+
+/**
+ * Returns HTML for a date_select 'hour' label.
+ */
+function theme_date_part_label_hour($variables) {
+  return t('Hour', array(), array('context' => 'datetime'));
+}
+
+/**
+ * Returns HTML for a date_select 'minute' label.
+ */
+function theme_date_part_label_minute($variables) {
+  return t('Minute', array(), array('context' => 'datetime'));
+}
+
+/**
+ * Returns HTML for a date_select 'second' label.
+ */
+function theme_date_part_label_second($variables) {
+  return t('Second', array(), array('context' => 'datetime'));
+}
+
+/**
+ * Returns HTML for a date_select 'ampm' label.
+ */
+function theme_date_part_label_ampm($variables) {
+  return '&nbsp;';
+}
+
+/**
+ * Returns HTML for a date_select 'timezone' label.
+ */
+function theme_date_part_label_timezone($variables) {
+  return t('Timezone');
+}
+
+/**
+ * Returns HTML for a date_select 'date' label.
+ */
+function theme_date_part_label_date($variables) {
+  return t('Date', array(), array('context' => 'datetime'));
+}
+
+/**
+ * Returns HTML for a date_select 'time' label.
+ */
+function theme_date_part_label_time($variables) {
+  return t('Time', array(), array('context' => 'datetime'));
+}
+
+
+/**
+ * Returns HTML for a date block that looks like a mini calendar day.
+ *
+ * Pass in a date object already set to the right timezone, format as a calendar
+ * page date. The calendar styling is created in CSS.
+ */
+function theme_date_calendar_day($variables) {
+  $output = '';
+  $date = $variables['date'];
+  if (!empty($date)) {
+    $output .= '<div class="date-calendar-day">';
+    $output .= '<span class="month">' . date_format_date($date, 'custom', 'M') . '</span>';
+    $output .= '<span class="day">' . date_format_date($date, 'custom', 'j') . '</span>';
+    $output .= '<span class="year">' . date_format_date($date, 'custom', 'Y') . '</span>';
+    $output .= '</div>';
+  }
+  return $output;
+}
+
+/**
+ * Returns HTML for a date in the format 'time ago'.
+ */
+function theme_date_time_ago($variables) {
+  $start_date = $variables['start_date'];
+  $end_date = $variables['end_date'];
+  $interval = !empty($variables['interval']) ? $variables['interval'] : 2;
+  $display = isset($variables['interval_display']) ? $variables['interval_display'] : 'time ago';
+
+  // If no date is sent, then return nothing.
+  if (empty($start_date) || empty($end_date)) {
+    return;
+  }
+
+  // Time to compare dates to.
+  $now = date_format(date_now(), DATE_FORMAT_UNIX);
+  $start = date_format($start_date, DATE_FORMAT_UNIX);
+
+  // will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence)
+  $time_diff = $now - $start;
+
+  // Uses the same options used by Views format_interval.
+  switch ($display) {
+    case 'raw time ago':
+      return format_interval($time_diff, $interval);
+    case 'time ago':
+      return t('%time ago', array('%time' => format_interval($time_diff, $interval)));
+    case 'raw time hence':
+      return format_interval(-$time_diff, $interval);
+    case 'time hence':
+      return t('%time hence', array('%time' => format_interval(-$time_diff, $interval)));
+    case 'raw time span':
+      return ($time_diff < 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
+    case 'inverse time span':
+      return ($time_diff > 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
+    case 'time span':
+      return t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => format_interval(abs($time_diff), $interval)));
+  }
+}
diff --git a/sites/all/modules/date/date_context/date_context.info b/sites/all/modules/date/date_context/date_context.info
new file mode 100644
index 0000000000000000000000000000000000000000..63f012901831d930e3b9a4f374a3673df64143c4
--- /dev/null
+++ b/sites/all/modules/date/date_context/date_context.info
@@ -0,0 +1,16 @@
+name = Date Context
+description = Adds an option to the Context module to set a context condition based on the value of a date field.
+package = Date/Time
+core = 7.x
+
+dependencies[] = date
+dependencies[] = context
+
+files[] = date_context.module
+files[] = plugins/date_context_date_condition.inc
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date_context/date_context.module b/sites/all/modules/date/date_context/date_context.module
new file mode 100644
index 0000000000000000000000000000000000000000..a5d265084083123a4a40fe63b5f55121f3a84037
--- /dev/null
+++ b/sites/all/modules/date/date_context/date_context.module
@@ -0,0 +1,52 @@
+<?php
+/**
+ * @TODO
+ *
+ * Currently only implemented for nodes. Need to add $plugin->execute()
+ * for any other entities that might be supported.
+ *
+ * Cache the date processing, perhaps cache the formatted, timezone-adjusted
+ * date strings for each entity (would have to be cached differently for each
+ * timezone, based on the tz_handling method for the date).
+ *
+ * Add an option to set/not set the context on forms vs views.
+ */
+
+/**
+ * Implements hook_context_node_condition_alter().
+ */
+function date_context_context_node_condition_alter($node, $op) {
+  if ($plugin = context_get_plugin('condition', 'date_context_date_condition')) {
+    $plugin->execute($node, $op);
+  }
+}
+
+/**
+ * Implements hook_context_plugins()
+ */
+function date_context_context_plugins() {
+  $plugins = array();
+  $plugins['date_context_date_condition'] = array(
+    'handler' => array(
+      'class' => 'date_context_date_condition',
+      'parent' => 'context_condition_node',
+    ),
+  );
+  return $plugins;
+}
+
+/**
+ * Implements hook_context_registry()
+ */
+function date_context_context_registry() {
+  return array(
+    'conditions' => array(
+      'date_context_date_condition' => array(
+        'title' => t('Date'),
+        'description' => t('Set a condition based on the value of a date field'),
+        'plugin' => 'date_context_date_condition',
+      ),
+    ),
+  );
+}
+
diff --git a/sites/all/modules/date/date_context/plugins/date_context_date_condition.inc b/sites/all/modules/date/date_context/plugins/date_context_date_condition.inc
new file mode 100644
index 0000000000000000000000000000000000000000..3fcb042857105e04007ad75afb0ff4b1a3dce4e6
--- /dev/null
+++ b/sites/all/modules/date/date_context/plugins/date_context_date_condition.inc
@@ -0,0 +1,129 @@
+<?php
+
+/**
+ * Expose term views/term forms by vocabulary as a context condition.
+ */
+class date_context_date_condition extends context_condition_node {
+  function condition_values() {
+    $values = array();
+    $fields = field_info_fields();
+    foreach ($fields as $field_name => $field) {
+      if (in_array($field['type'], array('date', 'datetime', 'datestamp'))) {
+        $values[$field_name] = $field_name;
+      }
+    }
+    return $values;
+  }
+
+  function options_form($context) {
+    $defaults = $this->fetch_from_context($context, 'options');
+    $options = array(
+      '<' =>  t('Is less than'),
+      '<=' => t('Is less than or equal to'),
+      '>=' => t('Is greater than or equal to'),
+      '>' => t('Is greater than'),
+      '=' => t('Is equal to'),
+      '!=' => t('Is not equal to'),
+      'empty' => t('Is empty'),
+      'not empty' => t('Is not Empty'),
+    );
+    $form['operation'] = array(
+      '#title' => t('Operation'),
+      '#type' => 'select',
+      '#options' => $options,
+      '#description' => t('The comparison to perform to determine if the date field meets the condition. For multiple value date fields, all values will be checked to see if any meet the condition.'),
+      '#default_value' => isset($defaults['operation']) ? $defaults['operation'] : '',
+      '#required' => TRUE,
+    );
+    $form['value'] = array(
+      '#title' => t('Value'),
+      '#type' => 'textfield',
+      '#description' => t("The value the field should contain to meet the condition. This can either be an absolute date in ISO format (YYYY-MM-DDTHH:MM:SS) or a relative string like '12AM today'. Examples: 2011-12-31T00:00:00, now, now +1 day, 12AM today, Monday next week. <a href=\"@relative_format\">More examples of relative date formats in the PHP documentation</a>.", array('@relative_format' => 'http://www.php.net/manual/en/datetime.formats.relative.php')),
+      '#default_value' => isset($defaults['value']) ? $defaults['value'] : '',
+      '#process' => array('ctools_dependent_process'),
+      '#dependency' => array(':input[name="conditions[plugins][date_context_date_condition][options][operation]"]' => array('<', '<=', '>', '>=', '=', '!=')),
+    );
+    return $form;
+  }
+
+  function execute($entity, $op) {
+    if (in_array($op, array('view', 'form'))) {
+      foreach ($this->get_contexts() as $context) {
+        $options = $this->fetch_from_context($context, 'options');
+        $fields = $this->fetch_from_context($context, 'values');
+
+        foreach ($fields as $field_name => $label) {
+
+          // If this field does not exist on this entity, just move along.
+          if (empty($entity->{$field_name})) {
+            continue;
+          }
+
+          $items = field_get_items('node', $entity, $field_name);
+
+          // If there are no values, nothing to do unless we were looking for 'empty' or '!='.
+          if (empty($items)) {
+            if ($options['operation'] == '!=' || $options['operation'] == 'empty') {
+              $this->condition_met($context, $field_name);
+            }
+          }
+
+          // We don't have to construct the date values if we're just testing for 'not empty'.
+          elseif ($options['operation'] == 'not empty') {
+            $this->condition_met($context, $field_name);
+          }
+
+          // All other operations need to retrieve the date values for comparision.
+          else {
+            $field = field_info_field($field_name);
+            $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
+            foreach ($items as $delta => $item) {
+              $timezone = date_get_timezone($field['settings']['tz_handling'], $item['timezone']);
+              $date = new DateObject($item['value'], $timezone_db);
+              date_timezone_set($date, timezone_open($timezone));
+              $date1 = $date->format(DATE_FORMAT_DATETIME);
+              $date = new DateObject($item['value2'], $timezone_db);
+              date_timezone_set($date, timezone_open($timezone));
+              $date2 = $date->format(DATE_FORMAT_DATETIME);
+              str_replace('now', 'today', $options['value']);
+              $date = date_create($options['value'], date_default_timezone_object());
+              $compdate = $date->format(DATE_FORMAT_DATETIME);
+              switch($options['operation']) {
+                case '=':
+                  if ($date2 >= $compdate && $date1 <= $compdate) {
+                    $this->condition_met($context, $field_name);
+                  }
+                  break;
+                case '>':
+                  if ($date1 > $compdate) {
+                    $this->condition_met($context, $field_name);
+                  }
+                  break;
+                case '>=':
+                  if ($date1 >= $compdate) {
+                    $this->condition_met($context, $field_name);
+                  }
+                  break;
+                case '<':
+                  if ($date2 < $compdate) {
+                    $this->condition_met($context, $field_name);
+                  }
+                  break;
+                case '<=':
+                  if ($date2 <= $compdate) {
+                    $this->condition_met($context, $field_name);
+                  }
+                  break;
+                case '!=':
+                  if ($date1 < $compdate || $date2 > $compdate) {
+                    $this->condition_met($context, $field_name);
+                  }
+                  break;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/sites/all/modules/date/date_elements.inc b/sites/all/modules/date/date_elements.inc
new file mode 100644
index 0000000000000000000000000000000000000000..20620edffacf4ea27a0b9863183398677be6a85e
--- /dev/null
+++ b/sites/all/modules/date/date_elements.inc
@@ -0,0 +1,660 @@
+<?php
+/**
+ * @file
+ * Date forms and form themes and validation.
+ *
+ * All code used in form editing and processing is in this file,
+ * included only during form editing.
+ */
+
+/**
+ * Private implementation of hook_widget().
+ *
+ * The widget builds out a complex date element in the following way:
+ *
+ * - A field is pulled out of the database which is comprised of one or
+ *   more collections of start/end dates.
+ *
+ * - The dates in this field are all converted from the UTC values stored
+ *   in the database back to the local time. This is done in #process
+ *   to avoid making this change to dates that are not being processed,
+ *   like those hidden with #access.
+ *
+ * - If values are empty, the field settings rules are used to determine
+ *   if the default_values should be empty, now, the same, or use strtotime.
+ *
+ * - Each start/end combination is created using the date_combo element type
+ *   defined by the date module. If the timezone is date-specific, a
+ *   timezone selector is added to the first combo element.
+ *
+ * - The date combo element creates two individual date elements, one each
+ *   for the start and end field, using the appropriate individual Date API
+ *   date elements, like selects, textfields, or popups.
+ *
+ * - In the individual element validation, the data supplied by the user is
+ *   used to update the individual date values.
+ *
+ * - In the combo date validation, the timezone is updated, if necessary,
+ *   then the user input date values are used with that timezone to create
+ *   date objects, which are used update combo date timezone and offset values.
+ *
+ * - In the field's submission processing, the new date values, which are in
+ *   the local timezone, are converted back to their UTC values and stored.
+ *
+ */
+function date_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $base) {
+
+  $element = $base;
+  $field_name = $field['field_name'];
+  $entity_type = $instance['entity_type'];
+
+  // If this is a new entity, populate the field with the right default values.
+  // This happens early so even fields later hidden with #access get those values.
+  // We should only add default values to new entities, to avoid over-writing
+  // a value that has already been set. This means we can't just check to see
+  // if $items is empty, because it might have been set that way on purpose.
+  // @see date_field_widget_properties_alter() where we flagged if this is a new entity.
+
+  // We check !isset($items[$delta]['value']) because entity translation may create
+  // a new translation entity for an existing entity and we don't want to clobber
+  // values that were already set in that case.
+  // @see http://drupal.org/node/1478848.
+
+  $is_default = FALSE;
+  if (!empty($instance['widget']['is_new']) && !isset($items[$delta]['value'])) {
+    $items = date_default_value($field, $instance, $langcode);
+    $is_default = TRUE;
+  }
+
+  // @TODO Repeating dates should probably be made into their own field type and completely separated out.
+  // That will have to wait for a new branch since it may break other things, including other modules
+  // that have an expectation of what the date field types are.
+
+  // Since repeating dates cannot use the default Add more button, we have to handle our own behaviors here.
+  // Return only the first multiple value for repeating dates, then clean up the 'Add more' bits in #after_build.
+  // The repeating values will be re-generated when the repeat widget form is validated.
+  // At this point we can't tell if this form element is going to be hidden by #access, and we're going to
+  // lose all but the first value by doing this, so store the original values in case we need to replace them later.
+  if (!empty($field['settings']['repeat'])) {
+    if ($delta == 0) {
+      $form['#after_build'] = array('date_repeat_after_build');
+      $form_state['storage']['repeat_fields'][$field_name] = array_merge($form['#parents'], array($field_name));
+      $form_state['storage']['date_items'][$field_name][$langcode] = $items;
+    }
+    else {
+      return;
+    }
+  }
+
+  module_load_include('inc', 'date_api', 'date_api_elements');
+  $timezone = date_get_timezone($field['settings']['tz_handling'], isset($items[0]['timezone']) ? $items[0]['timezone'] : date_default_timezone());
+
+  // TODO see if there's a way to keep the timezone element from ever being
+  // nested as array('timezone' => 'timezone' => value)). After struggling
+  // with this a while, I can find no way to get it displayed in the form
+  // correctly and get it to use the timezone element without ending up
+  // with nesting.
+  if (is_array($timezone)) {
+    $timezone = $timezone['timezone'];
+  }
+
+  $element += array(
+    '#type' => 'date_combo',
+    '#theme_wrappers' => array('date_combo'),
+    '#weight' => $delta,
+    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
+    '#date_timezone' => $timezone,
+    '#element_validate' => array('date_combo_validate'),
+    '#date_is_default' => $is_default,
+
+    // Store the original values, for use with disabled and hidden fields.
+    '#date_items' => isset($items[$delta]) ? $items[$delta] : '',
+  );
+
+  $element['#title'] = $instance['label'];
+
+  if ($field['settings']['tz_handling'] == 'date') {
+    $element['timezone'] = array(
+      '#type' => 'date_timezone',
+      '#theme_wrappers' => array('date_timezone'),
+      '#delta' => $delta,
+      '#default_value' => $timezone,
+      '#weight' => $instance['widget']['weight'] + 1,
+      '#attributes' => array('class' => array('date-no-float')),
+      '#date_label_position' => $instance['widget']['settings']['label_position'],
+      );
+  }
+
+  return $element;
+}
+
+/**
+ * Create local date object.
+ *
+ * Create a date object set to local time from the field and
+ * widget settings and item values. Default values for new entities
+ * are set by the default value callback, so don't need to be accounted for here.
+ */
+function date_local_date($item, $timezone, $field, $instance, $part = 'value') {
+
+  $value = $item[$part];
+
+  // If the value is empty, don't try to create a date object because it will
+  // end up being the current day.
+  if (empty($value)) {
+    return NULL;
+  }
+
+  // @TODO Figure out how to replace date_fuzzy_datetime() function.
+  // Special case for ISO dates to create a valid date object for formatting.
+  // Is this still needed?
+  /*
+  if ($field['type'] == DATE_ISO) {
+    $value = date_fuzzy_datetime($value);
+  }
+  else {
+    $db_timezone = date_get_timezone_db($field['settings']['tz_handling']);
+    $value = date_convert($value, $field['type'], DATE_DATETIME, $db_timezone);
+  }
+  */
+
+  $date = new DateObject($value, date_get_timezone_db($field['settings']['tz_handling']));
+  $date->limitGranularity($field['settings']['granularity']);
+  if (empty($date)) {
+    return NULL;
+  }
+  date_timezone_set($date, timezone_open($timezone));
+
+  return $date;
+}
+
+/**
+ * The callback for setting a default value for an empty date field.
+ */
+function date_default_value($field, $instance, $langcode) {
+  $item = array();
+  $db_format = date_type_format($field['type']);
+  $date = date_default_value_part($item, $field, $instance, $langcode, 'value');
+  $item[0]['value'] = is_object($date) ? date_format($date, $db_format) : '';
+  if (!empty($field['settings']['todate'])) {
+    $date = date_default_value_part($item, $field, $instance, $langcode, 'value2');
+    $item[0]['value2'] = is_object($date) ? date_format($date, $db_format) : '';
+  }
+
+  // Make sure the default value has the same construct as a loaded field value
+  // to avoid errors if the default value is used on a hidden element.
+  $item[0]['timezone'] = date_get_timezone($field['settings']['tz_handling']);
+  $item[0]['timezone_db'] = date_get_timezone_db($field['settings']['tz_handling']);
+  $item[0]['date_type'] = $field['type'];
+  if (!isset($item[0]['value2'])) {
+    $item[0]['value2'] = $item[0]['value'];
+  }
+  return $item;
+}
+
+/**
+ * Helper function for the date default value callback to set
+ * either 'value' or 'value2' to its default value.
+ */
+function date_default_value_part($item, $field, $instance, $langcode, $part = 'value') {
+  $timezone = date_get_timezone($field['settings']['tz_handling']);
+  $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
+  $date = NULL;
+  if ($part == 'value') {
+    $default_value = $instance['settings']['default_value'];
+    $default_value_code = $instance['settings']['default_value_code'];
+  }
+  else {
+    $default_value = $instance['settings']['default_value2'];
+    $default_value_code = $instance['settings']['default_value_code2'];
+  }
+  if (empty($default_value) || $default_value == 'blank') {
+    return NULL;
+  }
+  elseif ($default_value == 'strtotime' && !empty($default_value_code)) {
+    $date = new DateObject($default_value_code, date_default_timezone());
+  }
+  elseif ($part == 'value2' && $default_value == 'same') {
+    if ($instance['settings']['default_value'] == 'blank' || empty($item[0]['value'])) {
+      return NULL;
+    }
+    else {
+      // The date stored in 'value' has already been switched to the db timezone.
+      $date = new DateObject($item[0]['value'], $timezone_db, DATE_FORMAT_DATETIME);
+    }
+  }
+  // Special case for 'now' when using dates with no timezone,
+  // make sure 'now' isn't adjusted to UTC value of 'now' .
+  elseif ($field['settings']['tz_handling'] == 'none') {
+    $date = date_now();
+  }
+  else {
+    $date = date_now($timezone);
+  }
+  // The default value needs to be in the database timezone.
+  date_timezone_set($date, timezone_open($timezone_db));
+  $date->limitGranularity($field['settings']['granularity']);
+  return $date;
+}
+
+/**
+ * Process an individual date element.
+ */
+function date_combo_element_process($element, &$form_state, $form) {
+    
+  if (date_hidden_element($element)) {
+    // A hidden value for a new entity that had its end date set to blank
+    // will not get processed later to populate the end date, so set it here.
+    if (isset($element['#value']['value2']) && empty($element['#value']['value2'])) {
+      $element['#value']['value2'] = $element['#value']['value'];
+    }
+    return $element;
+  }
+
+  $field_name = $element['#field_name'];
+  $delta = $element['#delta'];
+  $bundle = $element['#bundle'];
+  $entity_type = $element['#entity_type'];
+  $langcode = $element['#language'];
+  $date_is_default = $element['#date_is_default'];
+
+  $field = field_widget_field($element, $form_state);
+  $instance = field_widget_instance($element, $form_state);
+
+  // Figure out how many items are in the form, including new ones added by ajax.
+  $field_state = field_form_get_state($element['#field_parents'], $field_name, $element['#language'], $form_state);
+  $items_count = $field_state['items_count'];
+
+  $columns = $element['#columns'];
+  if (isset($columns['rrule'])) {
+    unset($columns['rrule']);
+  }
+  $from_field = 'value';
+  $to_field = 'value2';
+  $tz_field = 'timezone';
+  $offset_field = 'offset';
+  $offset_field2 = 'offset2';
+
+  // Convert UTC dates to their local values in DATETIME format,
+  // and adjust the default values as specified in the field settings.
+
+  // It would seem to make sense to do this conversion when the data
+  // is loaded instead of when the form is created, but the loaded
+  // field data is cached and we can't cache dates that have been converted
+  // to the timezone of an individual user, so we cache the UTC values
+  // instead and do our conversion to local dates in the form and
+  // in the formatters.
+  $process = date_process_values($field, $instance);
+  foreach ($process as $processed) {
+    if (!isset($element['#default_value'][$processed])) {
+      $element['#default_value'][$processed] = '';
+    }
+    $date = date_local_date($element['#default_value'], $element['#date_timezone'], $field, $instance, $processed);
+    $element['#default_value'][$processed] = is_object($date) ? date_format($date, DATE_FORMAT_DATETIME) : '';
+  }
+
+  // Blank out the end date for optional end dates that match the start date,
+  // except when this is a new node that has default values that should be honored.
+  if (!$date_is_default && $field['settings']['todate'] != 'required'
+  && !empty($element['#default_value'][$to_field])
+  && $element['#default_value'][$to_field] == $element['#default_value'][$from_field]) {
+    unset($element['#default_value'][$to_field]);
+  }
+
+  $show_todate = !empty($form_state['values']['show_todate']) || !empty($element['#default_value'][$to_field]) || $field['settings']['todate'] == 'required';
+  $element['show_todate'] = array(
+    '#title' => t('Show End Date'),
+    '#type' => 'checkbox',
+    '#default_value' => $show_todate,
+    '#weight' => -20,
+    '#access' => $field['settings']['todate'] == 'optional',
+    '#prefix' => '<div class="date-float">',
+    '#suffix' => '</div>',
+  );
+
+  $parents = $element['#parents'];
+  $first_parent = array_shift($parents);
+  $show_id = $first_parent . '[' . implode('][', $parents) . '][show_todate]';
+
+  $element[$from_field] = array(
+    '#field'         => $field,
+    '#instance'      => $instance,
+    '#weight'        => $instance['widget']['weight'],
+    '#required'      => ($instance['required'] && $delta == 0) ? 1 : 0,
+    '#default_value' => isset($element['#default_value'][$from_field]) ? $element['#default_value'][$from_field] : '',
+    '#delta'         => $delta,
+    '#date_timezone' => $element['#date_timezone'],
+    '#date_format'      => date_limit_format(date_input_format($element, $field, $instance), $field['settings']['granularity']),
+    '#date_text_parts'  => (array) $instance['widget']['settings']['text_parts'],
+    '#date_increment'   => $instance['widget']['settings']['increment'],
+    '#date_year_range'  => $instance['widget']['settings']['year_range'],
+    '#date_label_position' => $instance['widget']['settings']['label_position'],
+    );
+
+  $description =  !empty($instance['description']) ? t($instance['description']) : '';
+
+  // Give this element the right type, using a Date API
+  // or a Date Popup element type.
+  $element[$from_field]['#attributes'] = array('class' => array('date-clear'));
+  $element[$from_field]['#wrapper_attributes'] = array('class' => array());
+  $element[$from_field]['#wrapper_attributes']['class'][] = 'date-no-float';
+
+  switch ($instance['widget']['type']) {
+    case 'date_select':
+      $element[$from_field]['#type'] = 'date_select';
+      $element[$from_field]['#theme_wrappers'] = array('date_select');
+      $element['#attached']['js'][] = drupal_get_path('module', 'date') . '/date.js';
+      $element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
+      break;
+    case 'date_popup':
+      $element[$from_field]['#type'] = 'date_popup';
+      $element[$from_field]['#theme_wrappers'] = array('date_popup');
+      $element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
+      break;
+    default:
+      $element[$from_field]['#type'] = 'date_text';
+      $element[$from_field]['#theme_wrappers'] = array('date_text');
+      $element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
+      break;
+  }
+
+  // If this field uses the 'End', add matching element
+  // for the 'End' date, and adapt titles to make it clear which
+  // is the 'Start' and which is the 'End' .
+
+  if (!empty($field['settings']['todate'])) {
+    $element[$from_field]['#title'] = '';
+    $element[$to_field] = $element[$from_field];
+    $element[$to_field]['#title'] = t('to:');
+    $element[$from_field]['#wrapper_attributes']['class'][] = 'start-date-wrapper';
+    $element[$to_field]['#wrapper_attributes']['class'][] = 'end-date-wrapper';
+    $element[$to_field]['#default_value'] = isset($element['#default_value'][$to_field]) ? $element['#default_value'][$to_field] : '';
+    $element[$to_field]['#required'] = ($element[$from_field]['#required'] && $field['settings']['todate'] == 'required');
+    $element[$to_field]['#weight'] += .2;
+    $element[$to_field]['#prefix'] = '';
+    // Users with JS enabled will never see initially blank values for the end
+    // date (see Drupal.date.EndDateHandler()), so hide the message for them.
+    $description .= '<span class="js-hide"> ' . t("Empty 'End date' values will use the 'Start date' values.") . '</span>';
+    $element['#fieldset_description'] = $description;
+    if ($field['settings']['todate'] == 'optional') {
+      $element[$to_field]['#states'] = array(
+        'visible' => array(
+          'input[name="' . $show_id . '"]' => array('checked' => TRUE),
+      ));
+    }
+  }
+  else {
+    $element[$from_field]['#description'] = $description;
+  }
+
+  // Create label for error messages that make sense in multiple values
+  // and when the title field is left blank.
+  if ($field['cardinality'] <> 1 && empty($field['settings']['repeat'])) {
+    $element[$from_field]['#date_title'] = t('@field_name Start date value #@delta', array('@field_name' => $instance['label'], '@delta' => $delta + 1));
+    if (!empty($field['settings']['todate'])) {
+      $element[$to_field]['#date_title'] = t('@field_name End date value #@delta', array('@field_name' => $instance['label'], '@delta' => $delta + 1));
+    }
+  }
+  elseif (!empty($field['settings']['todate'])) {
+    $element[$from_field]['#date_title'] = t('@field_name Start date', array('@field_name' => $instance['label']));
+    $element[$to_field]['#date_title'] = t('@field_name End date', array('@field_name' => $instance['label']));
+  }
+  else {
+    $element[$from_field]['#date_title'] = $instance['label'];
+  }
+
+  $context = array(
+   'field' => $field,
+   'instance' => $instance,
+   'form' => $form,
+  );
+  drupal_alter('date_combo_process', $element, $form_state, $context);
+
+  return $element;
+}
+
+function date_element_empty($element, &$form_state) {
+  $item = array();
+  $item['value'] = NULL;
+  $item['value2']   = NULL;
+  $item['timezone']   = NULL;
+  $item['offset'] = NULL;
+  $item['offset2'] = NULL;
+  $item['rrule'] = NULL;
+  form_set_value($element, $item, $form_state);
+  return $item;
+}
+
+/**
+ * Validate and update a combo element.
+ * Don't try this if there were errors before reaching this point.
+ */
+function date_combo_validate($element, &$form_state) {
+
+  // Disabled and hidden elements won't have any input and don't need validation,
+  // we just need to re-save the original values, from before they were processed into
+  // widget arrays and timezone-adjusted.
+  if (date_hidden_element($element) || !empty($element['#disabled'])) {
+    form_set_value($element, $element['#date_items'], $form_state);
+    return;
+  }
+
+  $field_name = $element['#field_name'];
+  $delta = $element['#delta'];
+  $langcode = $element['#language'];
+
+  $form_values = drupal_array_get_nested_value($form_state['values'], $element['#field_parents']);
+  $form_input = drupal_array_get_nested_value($form_state['input'], $element['#field_parents']);
+
+  // If the whole field is empty and that's OK, stop now.
+  if (empty($form_input[$field_name]) && !$element['#required']) {
+    return;
+  }
+
+  $item = $form_values[$field_name][$langcode][$delta];
+  $posted = $form_input[$field_name][$langcode][$delta];
+
+  $field = field_widget_field($element, $form_state);
+  $instance = field_widget_instance($element, $form_state);
+
+  $context = array(
+    'field' => $field,
+    'instance' => $instance,
+    'item' => $item,
+  );
+
+  drupal_alter('date_combo_pre_validate', $element, $form_state, $context);
+
+  $from_field = 'value';
+  $to_field = 'value2';
+  $tz_field = 'timezone';
+  $offset_field = 'offset';
+  $offset_field2 = 'offset2';
+
+  // Check for empty 'Start date', which could either be an empty
+  // value or an array of empty values, depending on the widget.
+  $empty = TRUE;
+  if (!empty($item[$from_field])) {
+    if (!is_array($item[$from_field])) {
+      $empty = FALSE;
+    }
+    else {
+      foreach ($item[$from_field] as $key => $value) {
+        if (!empty($value)) {
+          $empty = FALSE;
+          break;
+        }
+      }
+    }
+  }
+
+  // An 'End' date without a 'Start' date is a validation error.
+  if ($empty && !empty($item[$to_field])) {
+    if (!is_array($item[$to_field])) {
+      form_error($element, t("A 'Start date' date is required if an 'end date' is supplied for field %field #%delta.", array('%delta' => $field['cardinality'] ? intval($delta + 1) : '', '%field' => $instance['label'])));
+      $empty = FALSE;
+    }
+    else {
+      foreach ($item[$to_field] as $key => $value) {
+        if (!empty($value)) {
+          form_error($element, t("A 'Start date' date is required if an 'End date' is supplied for field %field #%delta.", array('%delta' => $field['cardinality'] ? intval($delta + 1) : '', '%field' => $instance['label'])));
+          $empty = FALSE;
+          break;
+        }
+      }
+    }
+  }
+
+  // If the user chose the option to not show the end date, just swap in the
+  // start date as that value so the start and end dates are the same.
+  if ($field['settings']['todate'] == 'optional' && empty($item['show_todate'])) {
+    $item[$to_field] = $item[$from_field];
+    $posted[$to_field] = $posted[$from_field];
+  }
+
+  if ($empty) {
+    $item = date_element_empty($element, $form_state);
+    if (!$element['#required']) {
+      return;
+    }
+  }
+  // Don't look for further errors if errors are already flagged
+  // because otherwise we'll show errors on the nested elements
+  // more than once.
+  elseif (!form_get_errors()) {
+
+    $timezone = !empty($item[$tz_field]) ? $item[$tz_field] : $element['#date_timezone'];
+    $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
+    $element[$from_field]['#date_timezone'] = $timezone;
+    $from_date = date_input_date($field, $instance, $element[$from_field], $posted[$from_field]);
+
+    if (!empty($field['settings']['todate'])) {
+      $element[$to_field]['#date_timezone'] = $timezone;
+      $to_date = date_input_date($field, $instance, $element[$to_field], $posted[$to_field]);
+    }
+    else {
+      $to_date = $from_date;
+    }
+
+    // Neither the start date nor the end date should be empty at this point
+    // unless they held values that couldn't be evaluated.
+
+    if (!$instance['required'] && (!date_is_date($from_date) || !date_is_date($to_date))) {
+      $item = date_element_empty($element, $form_state);
+      $errors[] = t('The dates are invalid.');
+    }
+    elseif (!empty($field['settings']['todate']) && $from_date > $to_date) {
+      form_set_value($element[$to_field], $to_date, $form_state);
+      $errors[] = t('The End date must be greater than the Start date.');
+    }
+    else {
+      // Convert input dates back to their UTC values and re-format to ISO
+      // or UNIX instead of the DATETIME format used in element processing.
+      $item[$tz_field] = $timezone;
+
+      // Update the context for changes in the $item, and allow other modules to
+      // alter the computed local dates.
+      $context['item'] = $item;
+      // We can only pass two additional values to drupal_alter, so $element
+      // needs to be included in $context.
+      $context['element'] = $element;
+      drupal_alter('date_combo_validate_date_start', $from_date, $form_state, $context);
+      drupal_alter('date_combo_validate_date_end', $to_date, $form_state, $context);
+
+      $item[$offset_field] = date_offset_get($from_date);
+
+      $test_from = date_format($from_date, 'r');
+      $test_to = date_format($to_date, 'r');
+
+      $item[$offset_field2] = date_offset_get($to_date);
+      date_timezone_set($from_date, timezone_open($timezone_db));
+      date_timezone_set($to_date, timezone_open($timezone_db));
+      $item[$from_field] = date_format($from_date, date_type_format($field['type']));
+      $item[$to_field] = date_format($to_date, date_type_format($field['type']));
+      if (isset($form_values[$field_name]['rrule'])) {
+        $item['rrule'] = $form_values[$field['field_name']]['rrule'];
+      }
+
+      // If the db timezone is not the same as the display timezone
+      // and we are using a date with time granularity,
+      // test a roundtrip back to the original timezone to catch
+      // invalid dates, like 2AM on the day that spring daylight savings
+      // time begins in the US.
+      $granularity = date_format_order($element[$from_field]['#date_format']);
+      if ($timezone != $timezone_db && date_has_time($granularity)) {
+        date_timezone_set($from_date, timezone_open($timezone));
+        date_timezone_set($to_date, timezone_open($timezone));
+
+        if ($test_from != date_format($from_date, 'r')) {
+          $errors[] = t('The Start date is invalid.');
+        }
+        if ($test_to != date_format($to_date, 'r')) {
+          $errors[] = t('The End date is invalid.');
+        }
+      }
+      if (empty($errors)) {
+        form_set_value($element, $item, $form_state);
+      }
+    }
+  }
+  if (!empty($errors)) {
+    if ($field['cardinality']) {
+      form_error($element, t('There are errors in @field_name value #@delta:', array('@field_name' => $instance['label'], '@delta' => $delta + 1)) . theme('item_list', array('items' => $errors)));
+    }
+    else {
+      form_error($element, t('There are errors in @field_name:', array('@field_name' => $instance['label'])) . theme('item_list', array('items' => $errors)));
+    }
+  }
+}
+
+/**
+ * Determine the input format for this element.
+ */
+function date_input_format($element, $field, $instance) {
+  if (!empty($instance['widget']['settings']['input_format_custom'])) {
+    return $instance['widget']['settings']['input_format_custom'];
+  }
+  elseif (!empty($instance['widget']['settings']['input_format']) && $instance['widget']['settings']['input_format'] != 'site-wide') {
+    return $instance['widget']['settings']['input_format'];
+  }
+  return variable_get('date_format_short', 'm/d/Y - H:i');
+}
+
+
+/**
+ * Implements hook_date_select_pre_validate_alter().
+ */
+function date_date_select_pre_validate_alter(&$element, &$form_state, &$input) {
+  date_empty_end_date($element, $form_state, $input);
+}
+
+/**
+ * Implements hook_date_text_pre_validate_alter().
+ */
+function date_date_text_pre_validate_alter(&$element, &$form_state, &$input) {
+  date_empty_end_date($element, $form_state, $input);
+}
+
+/**
+ * Implements hook_date_popup_pre_validate_alter().
+ */
+function date_date_popup_pre_validate_alter(&$element, &$form_state, &$input) {
+  date_empty_end_date($element, $form_state, $input);
+}
+
+/**
+ * Helper function to clear out end date when not being used.
+ */
+function date_empty_end_date(&$element, &$form_state, &$input) {
+  // If this is the end date and the option to show an end date has not been selected,
+  // empty the end date to surpress validation errors and stop further processing.
+  $parents = $element['#parents'];
+  $parent = array_pop($parents);
+  if ($parent == 'value2') {
+    $parent_values = drupal_array_get_nested_value($form_state['values'], $parents);
+    if (isset($parent_values['show_todate']) && $parent_values['show_todate'] != 1) {
+      $input = array();
+      form_set_value($element, NULL, $form_state);
+    }
+  }
+}
diff --git a/sites/all/modules/date/date_migrate/date.migrate.inc b/sites/all/modules/date/date_migrate/date.migrate.inc
new file mode 100644
index 0000000000000000000000000000000000000000..637a626bbb8127a93f9699e51d128c2b673cf2c5
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date.migrate.inc
@@ -0,0 +1,175 @@
+<?php
+
+/**
+ * @file
+ * Support for migration into Date fields.
+ */
+
+class DateMigrateFieldHandler extends MigrateFieldHandler {
+
+  /**
+   * Declares the types of fields used.
+   */
+  public function __construct() {
+    $this->registerTypes(array('date', 'datestamp', 'datetime'));
+  }
+
+  /**
+   * Arguments for a date field migration.
+   *
+   * @param string $timezone
+   *   Timezone (such as UTC, America/New_York, etc.) to apply.
+   * @param string $timezone_db
+   *   Timezone_db value for the field.
+   * @param string $rrule
+   *   Rule string for a repeating date field.
+   * @param string $language
+   *   Language of the text (defaults to destination language)
+   *
+   * @return array
+   *   An array of the defined variables in this scope.
+   */
+  static function arguments($timezone = 'UTC', $timezone_db = 'UTC', $rrule = NULL, $language = NULL) {
+    return get_defined_vars();
+  }
+
+  /**
+   * Converts incoming data into the proper field arrays for Date fields.
+   *
+   * @param object $entity
+   *   The destination entity which will hold the field arrays.
+   * @param array $field_info
+   *   Metadata for the date field being populated.
+   * @param array $instance
+   *   Metadata for this instance of the date field being populated.
+   * @param array $values
+   *   Array of date values to be fielded.
+   *
+   * @return array|null
+   *   An array of date fields.
+   */
+  public function prepare($entity, array $field_info, array $instance, array $values) {
+    if (isset($values['arguments'])) {
+      $arguments = $values['arguments'];
+      unset($values['arguments']);
+    }
+    else {
+      $arguments = array();
+    }
+
+    if (isset($arguments['timezone'])) {
+      $default_timezone = $arguments['timezone'];
+    }
+    else {
+      $default_timezone = 'UTC';
+    }
+    if (isset($arguments['timezone_db'])) {
+      $default_timezone_db = $arguments['timezone_db'];
+    }
+    else {
+      $default_timezone_db = NULL;
+    }
+    if (isset($arguments['rrule'])) {
+      $default_rrule = $arguments['rrule'];
+    }
+    else {
+      $default_rrule = NULL;
+    }
+    $language = $this->getFieldLanguage($entity, $field_info, $arguments);
+
+    // Setup the standard Field API array for saving.
+    $delta = 0;
+    foreach ($values as $from) {
+      // Set defaults.
+      $to = NULL;
+      $timezone = $default_timezone;
+      $timezone_db = $default_timezone_db;
+      $rrule = $default_rrule;
+
+      // Is the value a straight datetime value, or JSON containing a set of
+      // properties?
+      if (!empty($from) && $from{0} == '{') {
+        $properties = drupal_json_decode($from);
+        $from = $properties['from'];
+        // Properties passed in with the date override any set via arguments.
+        if (!empty($properties['to'])) {
+          $to = $properties['to'];
+        }
+        if (!empty($properties['timezone'])) {
+          $timezone = $properties['timezone'];
+        }
+        if (!empty($properties['timezone_db'])) {
+          $timezone_db = $properties['timezone_db'];
+        }
+        if (!empty($properties['rrule'])) {
+          $rrule = $properties['rrule'];
+        }
+      }
+
+      // Missing data? Create an empty value and return;
+      // Don't try to turn the empty value into a bogus
+      // timestamp for 'now'.
+      if (empty($from)) {
+        $return[$language][$delta]['value'] = NULL;
+        if (!empty($field_info['settings']['todate'])) {
+          $return[$language][$delta]['value2'] = NULL;
+        }
+        return $return;
+      }
+
+      // If there is no 'to' date, just use the 'from' date.
+      if (!empty($field_info['settings']['todate']) && empty($to)) {
+        $to = $from;
+      }
+
+      // If we have a value, work from a timestamp.
+      $from = MigrationBase::timestamp($from);
+      if ($to) {
+        $to = MigrationBase::timestamp($to);
+      }
+
+      // What does the destination field expect?
+      switch ($field_info['type']) {
+        case 'datestamp':
+          // Already done.
+          break;
+        case 'datetime':
+          // YYYY-MM-DD HH:MM:SS.
+          $from = format_date($from, 'custom', 'Y-m-d H:i:s', $timezone);
+          if ($to) {
+            $to = format_date($to, 'custom', 'Y-m-d H:i:s', $timezone);
+          }
+          break;
+        case 'date':
+          // ISO date: YYYY-MM-DDTHH:MM:SS.
+          $from = format_date($from, 'custom', 'Y-m-d\TH:i:s', $timezone);
+          if ($to) {
+            $to = format_date($to, 'custom', 'Y-m-d\TH:i:s', $timezone);
+          }
+          break;
+        default:
+          break;
+      }
+
+      // Handle repeats, coming in as RRULEs. Many field instances may be
+      // created.
+      if (function_exists('date_repeat_build_dates') && !empty($field_info['settings']['repeat']) && $rrule) {
+        include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'date_api') . '/date_api_ical.inc';
+        $item = array('value' => $from, 'value2' => $to, 'timezone' => $timezone);
+        // Can be de-uglified when http://drupal.org/node/1159404 is committed.
+        $return[$language] = date_repeat_build_dates(NULL, date_ical_parse_rrule($field_info, $rrule), $field_info, $item);
+      }
+      else {
+        $return[$language][$delta]['value'] = $from;
+        if (!empty($to)) {
+          $return[$language][$delta]['value2'] = $to;
+        }
+      }
+      $delta++;
+    }
+    if (!isset($return)) {
+      $return = NULL;
+    }
+    return $return;
+  }
+}
diff --git a/sites/all/modules/date/date_migrate/date_migrate.info b/sites/all/modules/date/date_migrate/date_migrate.info
new file mode 100644
index 0000000000000000000000000000000000000000..487fec8446743635a0395b76d7e667b6d545a47d
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date_migrate.info
@@ -0,0 +1,16 @@
+name = Date Migration
+description = Provides support for importing into date fields with the Migrate module.
+core = 7.x
+package = Date/Time
+
+dependencies[] = migrate
+dependencies[] = date
+files[] = date.migrate.inc
+files[] = date_migrate.test
+
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date_migrate/date_migrate.module b/sites/all/modules/date/date_migrate/date_migrate.module
new file mode 100644
index 0000000000000000000000000000000000000000..accdcf84e156c30786f7b5fd4b3012b498d44a4d
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date_migrate.module
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Migration integration for Date Migrate.
+ */
+
+/**
+ * Implements hook_migrate_api().
+ */
+function date_migrate_migrate_api() {
+  $api = array(
+    'api' => 2,
+  );
+  return $api;
+}
diff --git a/sites/all/modules/date/date_migrate/date_migrate.test b/sites/all/modules/date/date_migrate/date_migrate.test
new file mode 100644
index 0000000000000000000000000000000000000000..400b2d2bcabb81d60028571d8354f3f0f40a91c9
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date_migrate.test
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Test for using date fields with Migrate module.
+ */
+
+/**
+ * Test date migration.
+ */
+class DateMigrateExampleUnitTest extends DrupalWebTestCase {
+
+  /**
+   * Provides information about this test.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Date2 migration',
+      'description' => 'Testing migration of date fields',
+      'group' => 'Migrate',
+    );
+  }
+
+  /**
+   * Declars the module dependencies for the test.
+   */
+  function setUp() {
+    parent::setUp('migrate', 'features', 'date', 'date_repeat', 'date_repeat_field', 'date_migrate_example');
+  }
+
+  /**
+   * Verify that date fields are imported correctly. When no timezone is
+   * explicitly provided with the source data, we want the displayed time on the
+   * Drupal site to match that in the source data. To validate that, we make
+   * sure we have set a consistent timezone at the PHP and Drupal levels, and
+   * that the format used on the page is not locale-dependent (no day or month
+   * names). Then, we can just look for the desired date/time strings in the
+   * node page.
+   */
+  function testDateImport() {
+    date_default_timezone_set('America/Los_Angeles');
+    variable_set('date_default_timezone', 'America/Los_Angeles');
+    variable_set('date_format_medium', 'Y-m-d H:i');
+    $migration = Migration::getInstance('DateExample');
+    $result = $migration->processImport();
+    $this->assertEqual($result, Migration::RESULT_COMPLETED, t('Variety term import returned RESULT_COMPLETED'));
+    $rawnodes = node_load_multiple(FALSE, array('type' => 'date_migrate_example'), TRUE);
+    $this->assertEqual(count($rawnodes), 2, t('Two sample nodes created'));
+    $node = reset($rawnodes);
+    $this->drupalGet('/node/' . $node->nid);
+    $this->assertText('2011-05-12 19:43', t('Simple date field found'));
+    $this->assertText('2011-06-13 18:32 to 2011-07-23 10:32', t('Date range field found'));
+    $this->assertText('2011-07-22 12:13', t('Datestamp field found'));
+    $this->assertText('2011-08-01 00:00 to 2011-09-01 00:00', t('Datestamp range field found'));
+    $this->assertText('2011-11-18 15:00', t('Datetime field with +9 timezone found'));
+    $this->assertText('2011-10-30 14:43 to 2011-12-31 17:59', t('Datetime range field with -5 timezone found'));
+    $this->assertText('2011-11-25 09:01', t('First date repeat instance found'));
+    $this->assertText('2011-12-09 09:01', t('Second date repeat instance found'));
+    $this->assertNoText('2011-12-23 09:01', t('Skipped date repeat instance not found'));
+    $this->assertText('2012-05-11 09:01', t('Last date repeat instance found'));
+    $node = next($rawnodes);
+    $this->drupalGet('/node/' . $node->nid);
+    $this->assertText('2012-06-21 15:32', t('First date value found'));
+    $this->assertText('2012-12-02 11:08', t('Second date value found'));
+    $this->assertText('2004-02-03 01:15', t('Start for first date range found'));
+    $this->assertText('2005-03-04 22:11', t('End for first date range found'));
+    $this->assertText('2014-09-01 17:21', t('Start for second date range found'));
+    $this->assertText('2015-12-23 00:01', t('End for first second range found'));
+  }
+}
diff --git a/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.features.field.inc b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.features.field.inc
new file mode 100644
index 0000000000000000000000000000000000000000..4d979812b1475481421985951cfacdaf2c07f8b3
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.features.field.inc
@@ -0,0 +1,680 @@
+<?php
+
+/**
+ * @file
+ * Examples and test folder for migration into date fields.
+ */
+
+/**
+ * Implements hook_field_default_fields().
+ */
+function date_migrate_example_field_default_fields() {
+  $fields = array();
+
+  // Exported field: 'node-date_migrate_example-body'
+  $fields['node-date_migrate_example-body'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(
+        '0' => 'node',
+      ),
+      'field_name' => 'body',
+      'foreign keys' => array(
+        'format' => array(
+          'columns' => array(
+            'format' => 'format',
+          ),
+          'table' => 'filter_format',
+        ),
+      ),
+      'indexes' => array(
+        'format' => array(
+          '0' => 'format',
+        ),
+      ),
+      'module' => 'text',
+      'settings' => array(),
+      'translatable' => '1',
+      'type' => 'text_with_summary',
+    ),
+    'field_instance' => array(
+      'bundle' => 'date_migrate_example',
+      'default_value' => NULL,
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'hidden',
+          'module' => 'text',
+          'settings' => array(),
+          'type' => 'text_default',
+          'weight' => '0',
+        ),
+        'teaser' => array(
+          'label' => 'hidden',
+          'module' => 'text',
+          'settings' => array(
+            'trim_length' => 600,
+          ),
+          'type' => 'text_summary_or_trimmed',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'body',
+      'label' => 'Body',
+      'required' => FALSE,
+      'settings' => array(
+        'display_summary' => TRUE,
+        'text_processing' => 1,
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'module' => 'text',
+        'settings' => array(
+          'rows' => 20,
+          'summary_rows' => 5,
+        ),
+        'type' => 'text_textarea_with_summary',
+        'weight' => '1',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-date_migrate_example-field_date'
+  $fields['node-date_migrate_example-field_date'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '-1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_date',
+      'foreign keys' => array(),
+      'indexes' => array(),
+      'module' => 'date',
+      'settings' => array(
+        'granularity' => array(
+          'day' => 'day',
+          'hour' => 'hour',
+          'minute' => 'minute',
+          'month' => 'month',
+          'year' => 'year',
+        ),
+        'repeat' => 0,
+        'timezone_db' => 'UTC',
+        'todate' => '',
+        'tz_handling' => 'site',
+      ),
+      'translatable' => '1',
+      'type' => 'date',
+    ),
+    'field_instance' => array(
+      'bundle' => 'date_migrate_example',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'date',
+          'settings' => array(
+            'format_type' => 'medium',
+            'fromto' => 'both',
+            'multiple_from' => '',
+            'multiple_number' => '',
+            'multiple_to' => '',
+            'show_repeat_rule' => 'show',
+          ),
+          'type' => 'date_default',
+          'weight' => '1',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_date',
+      'label' => 'Date',
+      'required' => 0,
+      'settings' => array(
+        'default_format' => 'medium',
+        'default_value' => 'now',
+        'default_value2' => 'blank',
+        'default_value_code' => '',
+        'default_value_code2' => '',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'date',
+        'settings' => array(
+          'increment' => 1,
+          'input_format' => 'm/d/Y - H:i:s',
+          'input_format_custom' => '',
+          'label_position' => 'above',
+          'repeat_collapsed' => 0,
+          'text_parts' => array(),
+          'year_range' => '-3:+3',
+        ),
+        'type' => 'date_text',
+        'weight' => '2',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-date_migrate_example-field_date_range'
+  $fields['node-date_migrate_example-field_date_range'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '-1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_date_range',
+      'foreign keys' => array(),
+      'indexes' => array(),
+      'module' => 'date',
+      'settings' => array(
+        'granularity' => array(
+          'day' => 'day',
+          'hour' => 'hour',
+          'minute' => 'minute',
+          'month' => 'month',
+          'year' => 'year',
+        ),
+        'repeat' => 0,
+        'timezone_db' => 'UTC',
+        'todate' => 'required',
+        'tz_handling' => 'site',
+      ),
+      'translatable' => '1',
+      'type' => 'date',
+    ),
+    'field_instance' => array(
+      'bundle' => 'date_migrate_example',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'date',
+          'settings' => array(
+            'format_type' => 'medium',
+            'fromto' => 'both',
+            'multiple_from' => '',
+            'multiple_number' => '',
+            'multiple_to' => '',
+            'show_repeat_rule' => 'show',
+          ),
+          'type' => 'date_default',
+          'weight' => '2',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_date_range',
+      'label' => 'Date range',
+      'required' => 0,
+      'settings' => array(
+        'default_format' => 'medium',
+        'default_value' => 'now',
+        'default_value2' => 'strtotime',
+        'default_value_code' => '',
+        'default_value_code2' => '+7 days',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'date',
+        'settings' => array(
+          'increment' => 1,
+          'input_format' => 'm/d/Y - H:i:s',
+          'input_format_custom' => '',
+          'label_position' => 'above',
+          'repeat_collapsed' => 0,
+          'text_parts' => array(),
+          'year_range' => '-3:+3',
+        ),
+        'type' => 'date_text',
+        'weight' => '3',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-date_migrate_example-field_date_repeat'
+  $fields['node-date_migrate_example-field_date_repeat'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '-1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_date_repeat',
+      'foreign keys' => array(),
+      'indexes' => array(),
+      'module' => 'date',
+      'settings' => array(
+        'granularity' => array(
+          'day' => 'day',
+          'hour' => 'hour',
+          'minute' => 'minute',
+          'month' => 'month',
+          'year' => 'year',
+        ),
+        'repeat' => 1,
+        'timezone_db' => 'UTC',
+        'todate' => '',
+        'tz_handling' => 'site',
+      ),
+      'translatable' => '1',
+      'type' => 'date',
+    ),
+    'field_instance' => array(
+      'bundle' => 'date_migrate_example',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'date',
+          'settings' => array(
+            'format_type' => 'medium',
+            'fromto' => 'both',
+            'multiple_from' => '',
+            'multiple_number' => '',
+            'multiple_to' => '',
+            'show_repeat_rule' => 'show',
+          ),
+          'type' => 'date_default',
+          'weight' => '7',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_date_repeat',
+      'label' => 'Date with repeat',
+      'required' => 0,
+      'settings' => array(
+        'default_format' => 'medium',
+        'default_value' => 'now',
+        'default_value2' => 'blank',
+        'default_value_code' => '',
+        'default_value_code2' => '',
+        'repeat_collapsed' => '0',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'date',
+        'settings' => array(
+          'increment' => 1,
+          'input_format' => 'm/d/Y - H:i:s',
+          'input_format_custom' => '',
+          'label_position' => 'above',
+          'repeat_collapsed' => 0,
+          'text_parts' => array(),
+          'year_range' => '-3:+3',
+        ),
+        'type' => 'date_text_repeat',
+        'weight' => '8',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-date_migrate_example-field_datestamp'
+  $fields['node-date_migrate_example-field_datestamp'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_datestamp',
+      'foreign keys' => array(),
+      'indexes' => array(),
+      'module' => 'date',
+      'settings' => array(
+        'granularity' => array(
+          'day' => 'day',
+          'hour' => 'hour',
+          'minute' => 'minute',
+          'month' => 'month',
+          'year' => 'year',
+        ),
+        'repeat' => 0,
+        'timezone_db' => 'UTC',
+        'todate' => '',
+        'tz_handling' => 'site',
+      ),
+      'translatable' => '1',
+      'type' => 'datestamp',
+    ),
+    'field_instance' => array(
+      'bundle' => 'date_migrate_example',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'date',
+          'settings' => array(
+            'format_type' => 'medium',
+            'fromto' => 'both',
+            'multiple_from' => '',
+            'multiple_number' => '',
+            'multiple_to' => '',
+            'show_repeat_rule' => 'show',
+          ),
+          'type' => 'date_default',
+          'weight' => '3',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_datestamp',
+      'label' => 'Datestamp',
+      'required' => 0,
+      'settings' => array(
+        'default_format' => 'medium',
+        'default_value' => 'now',
+        'default_value2' => 'blank',
+        'default_value_code' => '',
+        'default_value_code2' => '',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'date',
+        'settings' => array(
+          'increment' => 1,
+          'input_format' => 'm/d/Y - H:i:s',
+          'input_format_custom' => '',
+          'label_position' => 'above',
+          'repeat_collapsed' => 0,
+          'text_parts' => array(),
+          'year_range' => '-3:+3',
+        ),
+        'type' => 'date_text',
+        'weight' => '4',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-migrate_example_date-field_datestamp_range'
+  $fields['node-date_migrate_example-field_datestamp_range'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_datestamp_range',
+      'foreign keys' => array(),
+      'indexes' => array(),
+      'module' => 'date',
+      'settings' => array(
+        'granularity' => array(
+          'day' => 'day',
+          'hour' => 'hour',
+          'minute' => 'minute',
+          'month' => 'month',
+          'year' => 'year',
+        ),
+        'repeat' => 0,
+        'timezone_db' => 'UTC',
+        'todate' => 'optional',
+        'tz_handling' => 'site',
+      ),
+      'translatable' => '1',
+      'type' => 'datestamp',
+    ),
+    'field_instance' => array(
+      'bundle' => 'date_migrate_example',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'date',
+          'settings' => array(
+            'format_type' => 'medium',
+            'fromto' => 'both',
+            'multiple_from' => '',
+            'multiple_number' => '',
+            'multiple_to' => '',
+            'show_repeat_rule' => 'show',
+          ),
+          'type' => 'date_default',
+          'weight' => '4',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_datestamp_range',
+      'label' => 'Datestamp range',
+      'required' => 0,
+      'settings' => array(
+        'default_format' => 'medium',
+        'default_value' => 'now',
+        'default_value2' => 'strtotime',
+        'default_value_code' => '',
+        'default_value_code2' => '+3 months',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'date',
+        'settings' => array(
+          'increment' => '1',
+          'input_format' => 'm/d/Y - H:i:s',
+          'input_format_custom' => '',
+          'label_position' => 'above',
+          'repeat_collapsed' => 0,
+          'text_parts' => array(),
+          'year_range' => '-3:+3',
+        ),
+        'type' => 'date_select',
+        'weight' => '5',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-date_migrate_example-field_datetime'
+  $fields['node-date_migrate_example-field_datetime'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_datetime',
+      'foreign keys' => array(),
+      'indexes' => array(),
+      'module' => 'date',
+      'settings' => array(
+        'granularity' => array(
+          'day' => 'day',
+          'hour' => 'hour',
+          'minute' => 'minute',
+          'month' => 'month',
+          'year' => 'year',
+        ),
+        'repeat' => 0,
+        'timezone_db' => 'UTC',
+        'todate' => '',
+        'tz_handling' => 'site',
+      ),
+      'translatable' => '1',
+      'type' => 'datetime',
+    ),
+    'field_instance' => array(
+      'bundle' => 'date_migrate_example',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'date',
+          'settings' => array(
+            'format_type' => 'medium',
+            'fromto' => 'both',
+            'multiple_from' => '',
+            'multiple_number' => '',
+            'multiple_to' => '',
+            'show_repeat_rule' => 'show',
+          ),
+          'type' => 'date_default',
+          'weight' => '5',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_datetime',
+      'label' => 'Datetime',
+      'required' => 0,
+      'settings' => array(
+        'default_format' => 'medium',
+        'default_value' => 'now',
+        'default_value2' => 'blank',
+        'default_value_code' => '',
+        'default_value_code2' => '',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'date',
+        'settings' => array(
+          'increment' => 1,
+          'input_format' => 'm/d/Y - H:i:s',
+          'input_format_custom' => '',
+          'label_position' => 'above',
+          'repeat_collapsed' => 0,
+          'text_parts' => array(),
+          'year_range' => '-3:+3',
+        ),
+        'type' => 'date_text',
+        'weight' => '6',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-date_migrate_example-field_datetime_range'
+  $fields['node-date_migrate_example-field_datetime_range'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_datetime_range',
+      'foreign keys' => array(),
+      'indexes' => array(),
+      'module' => 'date',
+      'settings' => array(
+        'granularity' => array(
+          'day' => 'day',
+          'hour' => 'hour',
+          'minute' => 'minute',
+          'month' => 'month',
+          'year' => 'year',
+        ),
+        'repeat' => 0,
+        'timezone_db' => 'UTC',
+        'todate' => 'required',
+        'tz_handling' => 'site',
+      ),
+      'translatable' => '1',
+      'type' => 'datetime',
+    ),
+    'field_instance' => array(
+      'bundle' => 'date_migrate_example',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'date',
+          'settings' => array(
+            'format_type' => 'medium',
+            'fromto' => 'both',
+            'multiple_from' => '',
+            'multiple_number' => '',
+            'multiple_to' => '',
+            'show_repeat_rule' => 'show',
+          ),
+          'type' => 'date_default',
+          'weight' => '6',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_datetime_range',
+      'label' => 'Datetime range',
+      'required' => 0,
+      'settings' => array(
+        'default_format' => 'medium',
+        'default_value' => 'now',
+        'default_value2' => 'blank',
+        'default_value_code' => '',
+        'default_value_code2' => '+1 year',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'date',
+        'settings' => array(
+          'increment' => 1,
+          'input_format' => 'm/d/Y - H:i:s',
+          'input_format_custom' => '',
+          'label_position' => 'above',
+          'repeat_collapsed' => 0,
+          'text_parts' => array(),
+          'year_range' => '-3:+3',
+        ),
+        'type' => 'date_text',
+        'weight' => '7',
+      ),
+    ),
+  );
+
+  // Translatables
+  // Included for use with string extractors like potx.
+  t('Body');
+  t('Date');
+  t('Date range');
+  t('Date with repeat');
+  t('Datestamp');
+  t('Datestamp range');
+  t('Datetime');
+  t('Datetime range');
+
+  return $fields;
+}
diff --git a/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.features.inc b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.features.inc
new file mode 100644
index 0000000000000000000000000000000000000000..34b15d2c3cdfc19dc99699a88bfec8c621461385
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.features.inc
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @file
+ * Examples and test folder for migration into date fields.
+ */
+
+/**
+ * Implements hook_node_info().
+ */
+function date_migrate_example_node_info() {
+  $items = array(
+    'date_migrate_example' => array(
+      'name' => t('Migrate example - dates'),
+      'base' => 'node_content',
+      'description' => t('This content type is used for demonstrating and testing migration into Date fields.'),
+      'has_title' => '1',
+      'title_label' => t('Title'),
+      'help' => '',
+    ),
+  );
+  return $items;
+}
diff --git a/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.info b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.info
new file mode 100644
index 0000000000000000000000000000000000000000..ad43d983fa49cd94ecf8f245e24e2b002bb2f496
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.info
@@ -0,0 +1,29 @@
+core = "7.x"
+dependencies[] = "date"
+dependencies[] = "date_repeat"
+dependencies[] = "date_repeat_field"
+dependencies[] = "date_migrate"
+dependencies[] = "features"
+dependencies[] = "migrate"
+description = "Examples of migrating with the Date module"
+features[field][] = "node-date_migrate_example-body"
+features[field][] = "node-date_migrate_example-field_date"
+features[field][] = "node-date_migrate_example-field_date_range"
+features[field][] = "node-date_migrate_example-field_date_repeat"
+features[field][] = "node-date_migrate_example-field_datestamp"
+features[field][] = "node-date_migrate_example-field_datestamp_range"
+features[field][] = "node-date_migrate_example-field_datetime"
+features[field][] = "node-date_migrate_example-field_datetime_range"
+features[node][] = "date_migrate_example"
+files[] = date_migrate_example.migrate.inc
+name = "Date Migration Example"
+package = "Features"
+project = "date_migrate_example"
+version = "7.x-2.0"
+
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.install b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.install
new file mode 100644
index 0000000000000000000000000000000000000000..7a35cec9b5b06917f55b02348dee7d3314f26e43
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.install
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the Date Migrate Example module.
+ */
+
+/**
+ * Implements hook_disable().
+ */
+function date_migrate_example_disable() {
+  Migration::deregisterMigration('DateExample');
+}
+
diff --git a/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc
new file mode 100644
index 0000000000000000000000000000000000000000..491c27f37ee41889d4a195fe52627ae645a6ffb0
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc
@@ -0,0 +1,130 @@
+<?php
+
+/**
+ * @file
+ * Examples and test folder for migration into date fields.
+ */
+
+/**
+ * Migration class to test import of various date fields.
+ */
+class DateExampleMigration extends XMLMigration {
+
+  /**
+   * Sets up the migration.
+   */
+  public function __construct() {
+    parent::__construct();
+    $this->description = t('Example migration into date fields');
+
+    $this->map = new MigrateSQLMap($this->machineName,
+      array(
+        'id' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'description' => 'Date ID',
+        ),
+      ),
+      MigrateDestinationNode::getKeySchema()
+    );
+
+    // Source fields available in the XML file.
+    $fields = array(
+      'id' => t('Source id'),
+      'title' => t('Title'),
+      'body' => t('Description'),
+      'date' => t('A simple date'),
+      'date_range_from' => t('Start value for a date range'),
+      'datestamp' => t('Simple datestamp'),
+      'datestamp_range_from' => t('Start value for a datestamp range'),
+      'datetime' => t('Simple datetime'),
+      'datetime_range_from' => t('Start value for a datetime range'),
+      'date_repeat' => t('Sample of a repeating date field'),
+    );
+
+    // Our test data is in an XML file.
+    $xml_folder = drupal_get_path('module', 'date_migrate_example');
+    $items_url = $xml_folder . '/date_migrate_example.xml';
+    $item_xpath = '/source_data/item';
+    $item_ID_xpath = 'id';
+    $items_class = new MigrateItemsXML($items_url, $item_xpath, $item_ID_xpath);
+    $this->source = new MigrateSourceMultiItems($items_class, $fields);
+    $this->destination = new MigrateDestinationNode('date_migrate_example');
+
+    // Basic fields.
+    $this->addFieldMapping('title', 'title')
+      ->xpath('title');
+    $this->addFieldMapping('uid')
+      ->defaultValue(1);
+    $this->addFieldMapping('body', 'body')
+      ->xpath('body');
+
+    // For simple date fields, we just need the xpath.
+    $this->addFieldMapping('field_date', 'date')
+      ->xpath('date');
+
+    // For date ranges, we add the "end" value in prepareRow() below.
+    $this->addFieldMapping('field_date_range', 'date_range_from');
+
+    // RRULEs on repeat fields are also done in prepareRow().
+    $this->addFieldMapping('field_date_repeat', 'date_repeat');
+
+    $this->addFieldMapping('field_datestamp', 'datestamp')
+      ->xpath('datestamp');
+    $this->addFieldMapping('field_datestamp_range', 'datestamp_range_from');
+
+    // You can specify a timezone to be applied to all values going into the
+    // field (Tokyo is UTC+9, no DST)
+    $arguments = DateMigrateFieldHandler::arguments('Asia/Tokyo');
+    $this->addFieldMapping('field_datetime', 'datetime')
+      ->xpath('datetime')
+      ->arguments($arguments);
+
+    // You can also get the timezone from the source data - it can be different
+    // for each instance of the field. Like To and RRULE values, it is added
+    // in prepareRow().
+    $this->addFieldMapping('field_datetime_range', 'datetime_range_from');
+
+    // Unmapped destination fields.
+    $this->addUnmigratedDestinations(array('is_new', 'status', 'promote', 'revision', 'language', 'sticky', 'created', 'changed', 'revision_uid'));
+  }
+
+  /**
+   * Transforms the raw migration data into the expected date formats.
+   *
+   * An advanced feature of the date field handler is that in addition to the
+   * basic (Start) date itself, we can add additional properties like timezone,
+   * encapsulating them as JSON.
+   */
+  public function prepareRow($current_row) {
+    // The date range field can have multiple values.
+    $current_row->date_range_from = array();
+    foreach ($current_row->xml->date_range as $range) {
+      $date_data = array(
+        'from' => (string) $range->from[0],
+        'to' => (string) $range->to[0],
+      );
+      $current_row->date_range_from[] = drupal_json_encode($date_data);
+    }
+
+    $date_data = array(
+      'from' => (string) $current_row->xml->datestamp_range->from[0],
+      'to' => (string) $current_row->xml->datestamp_range->to[0],
+    );
+    $current_row->datestamp_range_from = drupal_json_encode($date_data);
+
+    $date_data = array(
+      'from' => (string) $current_row->xml->datetime_range->from[0],
+      'to' => (string) $current_row->xml->datetime_range->to[0],
+      'timezone' => (string) $current_row->xml->datetime_range->timezone[0],
+    );
+    $current_row->datetime_range_from = drupal_json_encode($date_data);
+
+    $date_data = array(
+      'from' => (string) $current_row->xml->date_repeat->date[0],
+      'rrule' => (string) $current_row->xml->date_repeat->rule[0],
+    );
+    $current_row->date_repeat = drupal_json_encode($date_data);
+  }
+}
diff --git a/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.module b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.module
new file mode 100644
index 0000000000000000000000000000000000000000..993bd11818c92a0639e9e0110c3d75fddee227f2
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.module
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * @file
+ * Migration integration for Date Migrate Example.
+ */
+
+include_once 'date_migrate_example.features.inc';
+
+/**
+ * Implements hook_migrate_api().
+ */
+function date_migrate_example_migrate_api() {
+  $api = array(
+    'api' => 2,
+  );
+  return $api;
+}
diff --git a/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.xml b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a893bcf8eb7505d7e6beeea274a090d7fbc74e88
--- /dev/null
+++ b/sites/all/modules/date/date_migrate/date_migrate_example/date_migrate_example.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<source_data>
+  <item>
+    <id>3</id>
+    <title>Simple example</title>
+    <body>This is pretty straight-forward.</body>
+    <date>05/12/2011 19:43</date>
+    <date_range>
+      <from>06/13/2011 6:32pm</from>
+      <to>07/23/2011 10:32am</to>
+    </date_range>
+    <datestamp>07/22/2011 12:13</datestamp>
+    <datestamp_range>
+      <from>8/1/2011 00:00</from>
+      <to>9/1/2011 00:00</to>
+    </datestamp_range>
+    <datetime>11/18/2011 06:00</datetime>
+    <datetime_range>
+      <from>10/30/2011 19:43</from>
+      <to>12/31/2011 23:59</to>
+      <timezone>America/Chicago</timezone>
+    </datetime_range>
+    <date_repeat>
+      <date>11/25/2011 9:01</date>
+      <rule>RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=20120512T040000Z;WKST=MO
+EXDATE:20111223</rule>
+    </date_repeat>
+  </item>
+  <item>
+    <id>8</id>
+    <title>Example with multi-value fields</title>
+    <body>This is not as straight-forward.</body>
+    <date>06/21/2012 15:32</date>
+    <date>12/02/2012 11:08</date>
+    <date_range>
+      <from>02/03/2004 1:15am</from>
+      <to>03/04/2005 10:11pm</to>
+    </date_range>
+    <date_range>
+      <from>09/01/2014 5:21pm</from>
+      <to>12/23/2015 00:01</to>
+    </date_range>
+    <datestamp>07/22/2011 12:13</datestamp>
+    <datestamp_range>
+      <from>8/1/2011 00:00</from>
+      <to>9/1/2011 00:00</to>
+    </datestamp_range>
+    <datetime>11/18/2011 06:00</datetime>
+    <datetime_range>
+      <from>10/30/2011 19:43</from>
+      <to>12/31/2011 23:59</to>
+      <timezone>America/Chicago</timezone>
+    </datetime_range>
+    <date_repeat>
+      <date>11/25/2011 9:01</date>
+      <rule>RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=20120512T040000Z;WKST=MO
+EXDATE:20111223</rule>
+    </date_repeat>
+  </item>
+</source_data>
diff --git a/sites/all/modules/date/date_popup/README.txt b/sites/all/modules/date/date_popup/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..149810f7062fb4d3f8d2cb047617e93320faee34
--- /dev/null
+++ b/sites/all/modules/date/date_popup/README.txt
@@ -0,0 +1,108 @@
+Drupal date_popup.module README.txt
+==============================================================================
+
+Javascript popup calendar and timeentry using the
+jquery UI calendar and a choice of jquery-timeentry libraries.
+
+================================================================================
+Datepicker
+================================================================================
+
+This code uses the jQuery UI datepicker that is included in core. Localization
+of the interface is handled by core.
+
+The popup will use the site default for the first day of the week.
+
+================================================================================
+Timepicker
+================================================================================
+
+There are three ways to let users select time in the Date Popup widgets.
+You can choose between them by going to admin/config/content/date_popup.
+
+The options are:
+
+1) Manual time entry - a plain textfield where users can type in the time.
+2) A 'default' jQuery timepicker, included in the code
+   (http://keith-wood.name/timeEntry.html).
+3) The wvega timepicker (https://github.com/wvega/timepicker).
+
+To install the alternate dropdown (wvega) timepicker:
+
+Create a 'sites/all/libraries/wvega-timepicker' directory in your site
+installation.  Then visit https://github.com/wvega/timepicker/archives/master,
+download the latest copy and unzip it. You will see files with names like
+jquery.timepicker-1.1.2.js and jquery.timepicker-1.1.2.css. Rename them to
+jquery.timepicker.js and jquery.timepicker.css and copy them into
+'sites/all/libraries/wvega-timepicker'.
+
+================================================================================
+Usage
+================================================================================
+
+To include a popup calendar in a form, use the type 'date_popup':
+
+  $form['date'] = array(
+    '#type' => 'date_popup':
+    '#title => t('My Date'),
+    ....
+  );
+
+Set the #type to date_popup and fill the element #default_value with
+a date adjusted to the proper local timezone, or leave it blank.
+
+The element will create two textfields, one for the date and one for the
+time. The date textfield will include a jQuery popup calendar date picker,
+and the time textfield uses a jQuery timepicker.
+
+NOTE - Converting a date stored in the database from UTC to the local zone
+and converting it back to UTC before storing it is not handled by this
+element and must be done in pre-form and post-form processing!!
+
+================================================================================
+Customization
+================================================================================
+
+To change the default display and functionality of the calendar, set startup
+parameters by adding selectors to your element. The configurable options
+are:
+
+#date_type
+  The type of date to convert the input value to, DATE_DATETIME, DATE_ISO, or
+  DATE_UNIX
+
+#date_format
+  a standard PHP date format string that represents the way the month, day,
+  and year will be displayed in the textfield, like m/d/Y. Months and days
+  must be in the 'm' and 'd' formats that include the zero prefix, the year
+  must be in the 'Y' (four digit) format.
+
+  Any standard separator can be used, '/', '-', '.', or a space.
+
+  The m, d, and Y elements can be in any order and the order will be preserved.
+
+  The time selector will add AM/PM if 'a' is in the format string.
+
+  The default format uses the short site default format.
+
+#date_year_range
+  the number of years to go backwards and forwards from current year
+  in year selector, in the format -{years back}:+{years forward},
+  like -3:+3
+
+#date_increment
+   increment minutes and seconds by this amount, default is 1
+
+================================================================================
+Example:
+================================================================================
+
+$form['date'] = array(
+  '#type' => 'date_popup',
+  '#default_value' => '2007-01-01 10:30:00,
+  '#date_type' => DATE_DATETIME,
+  '#date_timezone' => date_default_timezone(),
+  '#date_format' => 'm/d/Y - H:i',
+  '#date_increment' => 1,
+  '#date_year_range' => '-3:+3',
+);
diff --git a/sites/all/modules/date/date_popup/date_popup.info b/sites/all/modules/date/date_popup/date_popup.info
new file mode 100644
index 0000000000000000000000000000000000000000..f781721292ad9385fb9cee69af3564fc59c8fcb5
--- /dev/null
+++ b/sites/all/modules/date/date_popup/date_popup.info
@@ -0,0 +1,15 @@
+name = Date Popup
+description = Enables jquery popup calendars and time entry widgets for selecting dates and times.
+dependencies[] = date_api
+package = Date/Time
+core = 7.x
+configure = admin/config/date/date_popup
+
+stylesheets[all][] = themes/datepicker.1.7.css
+
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date_popup/date_popup.install b/sites/all/modules/date/date_popup/date_popup.install
new file mode 100644
index 0000000000000000000000000000000000000000..790a514a5f9639eca78f26474fa855e321549775
--- /dev/null
+++ b/sites/all/modules/date/date_popup/date_popup.install
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the Date Popup module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function date_popup_install() {
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function date_popup_uninstall() {
+
+}
+
+/**
+ * Implements hook_enable().
+ */
+function date_popup_enable() {
+
+}
+
+/**
+ * Implements hook_disable().
+ */
+function date_popup_disable() {
+
+}
diff --git a/sites/all/modules/date/date_popup/date_popup.js b/sites/all/modules/date/date_popup/date_popup.js
new file mode 100644
index 0000000000000000000000000000000000000000..1847f84f26846df32557ed8ecb73207b04e5c9c3
--- /dev/null
+++ b/sites/all/modules/date/date_popup/date_popup.js
@@ -0,0 +1,62 @@
+/**
+ * Attaches the calendar behavior to all required fields
+ */
+(function ($) {
+Drupal.behaviors.date_popup = {
+  attach: function (context) {
+  for (var id in Drupal.settings.datePopup) {
+    $('#'+ id).bind('focus', Drupal.settings.datePopup[id], function(e) {
+      if (!$(this).hasClass('date-popup-init')) {
+        var datePopup = e.data;
+        // Explicitely filter the methods we accept.
+        switch (datePopup.func) {
+          case 'datepicker':
+            $(this)
+              .datepicker(datePopup.settings)
+              .addClass('date-popup-init')
+            $(this).click(function(){
+              $(this).focus();
+            });
+            break;
+
+          case 'timeEntry':
+            $(this)
+              .timeEntry(datePopup.settings)
+              .addClass('date-popup-init')
+            $(this).click(function(){
+              $(this).focus();
+            });
+            break;
+          case 'timepicker':
+            // Translate the PHP date format into the style the timepicker uses.
+            datePopup.settings.timeFormat = datePopup.settings.timeFormat
+              // 12-hour, leading zero,
+              .replace('h', 'hh')
+              // 12-hour, no leading zero.
+              .replace('g', 'h')
+              // 24-hour, leading zero.
+              .replace('H', 'HH')
+              // 24-hour, no leading zero.
+              .replace('G', 'H')
+              // AM/PM.
+              .replace('A', 'p')
+              // Minutes with leading zero.
+              .replace('i', 'mm')
+              // Seconds with leading zero.
+              .replace('s', 'ss');
+
+            datePopup.settings.startTime = new Date(datePopup.settings.startTime);
+            $(this)
+              .timepicker(datePopup.settings)
+              .addClass('date-popup-init');
+            $(this).click(function(){
+              $(this).focus();
+            });
+            break;
+        }
+      }
+    });
+  }
+  }
+};
+})(jQuery);
diff --git a/sites/all/modules/date/date_popup/date_popup.module b/sites/all/modules/date/date_popup/date_popup.module
new file mode 100644
index 0000000000000000000000000000000000000000..aa780333361d3ebf464df26e55a0e2decbc704d7
--- /dev/null
+++ b/sites/all/modules/date/date_popup/date_popup.module
@@ -0,0 +1,726 @@
+<?php
+/**
+ * @file
+ * A module to enable jquery calendar and time entry popups.
+ * Requires the Date API.
+ *
+ * Add a type of #date_popup to any date, time, or datetime field that will
+ * use this popup. Set #date_format to the way the date should be presented
+ * to the user in the form. Set #default_value to be a date in the local
+ * timezone, and note the timezone name in #date_timezone.
+ *
+ * The element will create two textfields, one for the date and one for the
+ * time. The date textfield will include a jQuery popup calendar date picker,
+ * and the time textfield uses a jQuery timepicker.
+ *
+ * If no time elements are included in the format string, only the date
+ * textfield will be created. If no date elements are included in the format
+ * string, only the time textfield, will be created.
+ *
+ */
+
+/**
+ * Load needed files.
+ *
+ * Play nice with jQuery UI.
+ */
+function date_popup_add() {
+  static $loaded = FALSE;
+  if ($loaded) {
+    return;
+  }
+  drupal_add_library('system', 'ui.datepicker');
+  drupal_add_library('date_popup', 'timeentry');
+
+  // Add the wvega-timepicker library if it's available.
+  $wvega_path = date_popup_get_wvega_path();
+  if ($wvega_path) {
+    drupal_add_js($wvega_path . '/jquery.timepicker.js');
+    drupal_add_css($wvega_path . '/jquery.timepicker.css');
+  }
+  $loaded = TRUE;
+}
+
+/**
+ * Get the location of the Willington Vega timepicker library.
+ *
+ * @return
+ *   The location of the library, or FALSE if the library isn't installed.
+ */
+function date_popup_get_wvega_path() {
+  $path = FALSE;
+  if (function_exists('libraries_get_path')) {
+    $path = libraries_get_path('wvega-timepicker');
+    if (!file_exists($path)) {
+      $path = FALSE;
+    }
+  }
+  elseif (file_exists('sites/all/libraries/wvega-timepicker/jquery.timepicker.js')) {
+    $path = 'sites/all/libraries/wvega-timepicker';
+  }
+  return $path;
+}
+
+/**
+ * Get the name of the preferred default timepicker.
+ *
+ * If the wvega timepicker is available on the system, default to using that,
+ * unless the administrator has specifically chosen otherwise.
+ */
+function date_popup_get_preferred_timepicker() {
+  $wvega_available = date_popup_get_wvega_path();
+  return $wvega_available ? 'wvega' : 'default';
+}
+
+/**
+ * Implements hook_library().
+ */
+function date_popup_library() {
+  $libraries = array();
+
+  $path = drupal_get_path('module', 'date_popup');
+  $libraries['timeentry'] = array(
+    'title' => 'Time Entry',
+    'website' => 'http://plugins.jquery.com/project/timeEntry',
+    'version' => '1.4.7',
+    'js' => array(
+      $path . '/jquery.timeentry.pack.js' => array(),
+    ),
+    'css' => array(
+      $path . '/themes/jquery.timeentry.css' => array('preprocess' => FALSE),
+    ),
+  );
+  return $libraries;
+}
+
+/**
+ * Create a unique CSS id name and output a single inline JS block for
+ * each startup function to call and settings array to pass it.  This
+ * used to create a unique CSS class for each unique combination of
+ * function and settings, but using classes requires a DOM traversal
+ * and is much slower than an id lookup.  The new approach returns to
+ * requiring a duplicate copy of the settings/code for every element
+ * that uses them, but is much faster.  We could combine the logic by
+ * putting the ids for each unique function/settings combo into
+ * Drupal.settings and searching for each listed id.
+ *
+ * @param $pfx
+ *   The CSS class prefix to search the DOM for.
+ *   TODO : unused ?
+ * @param $func
+ *   The jQuery function to invoke on each DOM element containing the
+ * returned CSS class.
+ * @param $settings
+ *   The settings array to pass to the jQuery function.
+ * @returns
+ *   The CSS id to assign to the element that should have
+ * $func($settings) invoked on it.
+ */
+function date_popup_js_settings_id($id, $func, $settings) {
+  static $js_added = FALSE;
+  static $id_count = array();
+
+  // Make sure popup date selector grid is in correct year.
+  if (!empty($settings['yearRange'])) {
+    $parts = explode(':', $settings['yearRange']);
+    // Set the default date to 0 or the lowest bound if the date ranges do not include the current year
+    // Necessary for the datepicker to render and select dates correctly
+    $defaultDate = ($parts[0] > 0 || 0 > $parts[1]) ? $parts[0] : 0;
+    $settings += array('defaultDate' => (string) $defaultDate . 'y');
+  }
+
+  if (!$js_added) {
+    drupal_add_js(drupal_get_path('module', 'date_popup') .'/date_popup.js');
+    $js_added = TRUE;
+  }
+
+  // We use a static array to account for possible multiple form_builder()
+  // calls in the same request (form instance on 'Preview').
+  if (!isset($id_count[$id])) {
+    $id_count[$id] = 0;
+  }
+
+// It looks like we need the additional id_count for this to
+// work correctly when there are multiple values.
+//  $return_id = "$id-$func-popup";
+  $return_id = "$id-$func-popup-". $id_count[$id]++;
+  $js_settings['datePopup'][$return_id] = array(
+    'func' => $func,
+    'settings' => $settings
+  );
+  drupal_add_js($js_settings, 'setting');
+  return $return_id;
+}
+
+function date_popup_theme() {
+  return array(
+    'date_popup' => array('render element' => 'element'),
+    );
+}
+
+/**
+ * Implements hook_element_info().
+ *
+ * Set the #type to date_popup and fill the element #default_value with
+ * a date adjusted to the proper local timezone in datetime format (YYYY-MM-DD HH:MM:SS).
+ *
+ * The element will create two textfields, one for the date and one for the
+ * time. The date textfield will include a jQuery popup calendar date picker,
+ * and the time textfield uses a jQuery timepicker.
+ *
+ * NOTE - Converting a date stored in the database from UTC to the local zone
+ * and converting it back to UTC before storing it is not handled by this
+ * element and must be done in pre-form and post-form processing!!
+ *
+ * #date_timezone
+ *   The local timezone to be used to create this date.
+ *
+ * #date_format
+ *   Unlike earlier versions of this popup, most formats will work.
+ *
+ * #date_increment
+ *   Increment minutes and seconds by this amount, default is 1.
+ *
+ * #date_year_range
+ *   The number of years to go back and forward in a year selector,
+ *   default is -3:+3 (3 back and 3 forward).
+ *
+ */
+function date_popup_element_info() {
+  $timepicker = date_popup_get_preferred_timepicker();
+  $type['date_popup'] = array(
+    '#input' => TRUE,
+    '#tree' => TRUE,
+    '#date_timezone' => date_default_timezone(),
+    '#date_flexible' => 0,
+    '#date_format' => variable_get('date_format_short', 'm/d/Y - H:i'),
+    '#timepicker' => variable_get('date_popup_timepicker', $timepicker),
+    '#date_increment' => 1,
+    '#date_year_range' => '-3:+3',
+    '#date_label_position' => 'above',
+    '#process' => array('date_popup_element_process'),
+    '#value_callback' => 'date_popup_element_value_callback',
+    '#theme_wrappers' => array('date_popup'),
+  );
+  if (module_exists('ctools')) {
+    $type['date_popup']['#pre_render'] = array('ctools_dependent_pre_render');
+  }
+  return $type;
+}
+
+function date_popup_date_granularity($element) {
+  $granularity = date_format_order($element['#date_format']);
+  return array_intersect($granularity, array('month', 'day', 'year'));
+}
+
+function date_popup_time_granularity($element) {
+  $granularity = date_format_order($element['#date_format']);
+  return array_intersect($granularity, array('hour', 'minute', 'second'));
+}
+
+function date_popup_date_format($element) {
+  return (date_limit_format($element['#date_format'], date_popup_date_granularity($element)));
+}
+
+function date_popup_time_format($element) {
+  return date_popup_format_to_popup_time(date_limit_format($element['#date_format'], date_popup_time_granularity($element)), $element['#timepicker']);
+}
+
+/**
+ * Element value callback for date_popup element.
+ */
+function date_popup_element_value_callback($element, $input = FALSE, &$form_state) {
+  $granularity = date_format_order($element['#date_format']);
+  $has_time = date_has_time($granularity);
+  $date = NULL;
+  $return = $has_time ? array('date' => '', 'time' => '') : array('date' => '');
+  // Normal input from submitting the form element.
+  // Check is_array() to skip the string input values created by Views pagers.
+  // Those string values, if present, should be interpreted as empty input.
+  if ($input !== FALSE && is_array($input)) {
+    $return = $input;
+    $date = date_popup_input_date($element, $input);
+  }
+  // No input? Try the default value.
+  elseif (!empty($element['#default_value'])) {
+    $date = date_default_date($element);
+  }
+  // Date with errors won't re-display.
+  if (date_is_date($date)) {
+    $return['date'] = !$date->timeOnly ? date_format_date($date, 'custom', date_popup_date_format($element)) : '';
+    $return['time'] = $has_time ? date_format_date($date, 'custom', date_popup_time_format($element)) : '';
+  }
+  elseif (!empty($input)) {
+    $return = $input;
+  }
+  return $return;
+
+}
+
+/**
+ * Javascript popup element processing.
+ * Add popup attributes to $element.
+ */
+function date_popup_element_process($element, &$form_state, $form) {
+  if (date_hidden_element($element)) {
+    return $element;
+  }
+
+  date_popup_add();
+  module_load_include('inc', 'date_api', 'date_api_elements');
+
+  $element['#tree'] = TRUE;
+  $element['#theme_wrappers'] = array('date_popup');
+
+  if (!empty($element['#ajax'])) {
+    $element['#ajax'] += array(
+      'trigger_as' => array('name' =>$element['#name']),
+      'event' => 'change',
+    );
+  }
+
+  $element['date'] = date_popup_process_date_part($element);
+  $element['time'] = date_popup_process_time_part($element);
+
+  if (isset($element['#element_validate'])) {
+    array_push($element['#element_validate'], 'date_popup_validate');
+  }
+  else {
+    $element['#element_validate'] = array('date_popup_validate');
+  }
+
+  $context = array(
+   'form' => $form,
+  );
+  drupal_alter('date_popup_process', $element, $form_state, $context);
+
+  return $element;
+}
+
+/**
+ * Process the date portion of the element.
+ */
+function date_popup_process_date_part(&$element) {
+  $granularity = date_format_order($element['#date_format']);
+  $date_granularity = date_popup_date_granularity($element);
+  if (empty($date_granularity)) return array();
+
+  // The datepicker can't handle zero or negative values like 0:+1
+  // even though the Date API can handle them, so rework the value
+  // we pass to the datepicker to use defaults it can accept (such as +0:+1)
+  // date_range_string() adds the necessary +/- signs to the range string.
+  $this_year = date_format(date_now(), 'Y');
+  $date = '';
+  if (!empty($element['#value']['date'])) {
+    $date = new DateObject($element['#value']['date'], $element['#date_timezone'], date_popup_date_format($element));
+  }
+  $range = date_range_years($element['#date_year_range'], $date);
+  $year_range = date_range_string($range);
+
+  $settings = array(
+    'changeMonth' => TRUE,
+    'changeYear' => TRUE,
+    'firstDay' => intval(variable_get('date_first_day', 0)),
+    //'buttonImage' => base_path() . drupal_get_path('module', 'date_api') ."/images/calendar.png",
+    //'buttonImageOnly' => TRUE,
+    'autoPopUp' => 'focus',
+    'closeAtTop' => FALSE,
+    'speed' => 'immediate',
+    'dateFormat' => date_popup_format_to_popup(date_popup_date_format($element), 'datepicker'),
+    'yearRange' => $year_range,
+    // Custom setting, will be expanded in Drupal.behaviors.date_popup()
+    'fromTo' => isset($fromto),
+    );
+
+  // Create a unique id for each set of custom settings.
+  $id = date_popup_js_settings_id($element['#id'], 'datepicker', $settings);
+
+  // Manually build this element and set the value - this will prevent corrupting
+  // the parent value
+  $parents = array_merge($element['#parents'], array('date'));
+  $sub_element = array(
+    '#type' => 'textfield',
+    '#title' => $element['#date_label_position'] == 'above' ? theme('date_part_label_date', array('part_type' => 'date', 'element' => $element)) : '',
+    '#default_value' => $element['#value']['date'],
+    '#id' => $id,
+    '#input' => FALSE,
+    '#size' => !empty($element['#size']) ? $element['#size'] : 20,
+    '#maxlength' => !empty($element['#maxlength']) ? $element['#maxlength'] : 30,
+    '#attributes' => $element['#attributes'],
+    '#parents' => $parents,
+    '#name' => array_shift($parents) . '['. implode('][', $parents) .']',
+    '#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
+  );
+  $sub_element['#value'] = $sub_element['#default_value'];
+  // TODO, figure out exactly when we want this description. In many places it is not desired.
+  $sub_element['#description'] = ' '. t('E.g., @date', array('@date' => date_format_date(date_now(), 'custom', date_popup_date_format($element))));
+
+  return $sub_element;
+}
+
+/**
+ * Process the time portion of the element.
+ */
+function date_popup_process_time_part(&$element) {
+  $granularity = date_format_order($element['#date_format']);
+  $has_time = date_has_time($granularity);
+  if (empty($has_time)) return array();
+
+  switch ($element['#timepicker']) {
+    case 'default':
+      $func = 'timeEntry';
+      $settings = array(
+        'show24Hours' => strpos($element['#date_format'], 'H') !== FALSE ? TRUE : FALSE,
+        'showSeconds' => (in_array('second', $granularity) ? TRUE : FALSE),
+        'timeSteps' => array(1, intval($element['#date_increment']), (in_array('second', $granularity) ? $element['#date_increment'] : 0)),
+        'spinnerImage' => '',
+        'fromTo' => isset($fromto),
+        );
+      if (strpos($element['#date_format'], 'a') !== FALSE) {
+        // Then we are using lowercase am/pm.
+        $settings['ampmNames'] = array('am', 'pm');
+      }
+      if (strpos($element['#date_format'], ' A') !== FALSE || strpos($element['#date_format'], ' a') !== FALSE) {
+        $settings['ampmPrefix'] = ' ';
+      }
+      break;
+    case 'wvega':
+      $func = 'timepicker';
+      $time_granularity = array_intersect($granularity, array('hour', 'minute', 'second'));
+      $format = date_popup_format_to_popup_time(date_limit_format($element['#date_format'], $time_granularity), 'wvega');
+      // The first value in the dropdown list should be the same as the element
+      // default_value, but it needs to be in JS format (i.e. milliseconds since
+      // the epoch).
+      $start_time = new DateObject($element['#default_value'], $element['#date_timezone'], DATE_FORMAT_DATETIME);
+      date_increment_round($start_time, $element['#date_increment']);
+      $start_time = $start_time->format(DATE_FORMAT_UNIX) * 1000;
+      $settings = array(
+        'timeFormat' => $format,
+        'interval' => $element['#date_increment'],
+        'startTime' => $start_time,
+        'scrollbar' => TRUE,
+      );
+      break;
+    default:
+      $func = '';
+      $settings = array();
+      break;
+  }
+
+  // Create a unique id for each set of custom settings.
+  $id = date_popup_js_settings_id($element['#id'], $func, $settings);
+
+  // Manually build this element and set the value - this will prevent corrupting
+  // the parent value
+  $parents = array_merge($element['#parents'], array('time'));
+  $sub_element = array(
+    '#type' => 'textfield',
+    '#title' => $element['#date_label_position'] == 'above' ? theme('date_part_label_time', array('part_type' => 'time', 'element' => $element)) : '',
+    '#default_value' => $element['#value']['time'],
+    '#id' => $id,
+    '#size' => 15,
+    '#maxlength' => 10,
+    '#attributes' => $element['#attributes'],
+    '#parents' => $parents,
+    '#name' => array_shift($parents) . '['. implode('][', $parents) .']',
+    '#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
+  );
+
+  $sub_element['#value'] = $sub_element['#default_value'];
+
+  // TODO, figure out exactly when we want this description. In many places it is not desired.
+  $example_date = date_now();
+  date_increment_round($example_date, $element['#date_increment']);
+  $sub_element['#description'] = t('E.g., @date', array('@date' => date_format_date($example_date, 'custom', date_popup_time_format($element))));
+
+  return ($sub_element);
+}
+
+/**
+ * Massage the input values back into a single date.
+ *
+ * When used as a Views widget, the validation step always gets triggered,
+ * even with no form submission. Before form submission $element['#value']
+ * contains a string, after submission it contains an array.
+ *
+ */
+function date_popup_validate($element, &$form_state) {
+
+  if (date_hidden_element($element)) {
+    return;
+  }
+
+  if (is_string($element['#value'])) {
+    return;
+  }
+
+  module_load_include('inc', 'date_api', 'date_api_elements');
+  date_popup_add();
+
+  $input_exists = NULL;
+  $input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
+
+  drupal_alter('date_popup_pre_validate', $element, $form_state, $input);
+
+  $granularity = date_format_order($element['#date_format']);
+  $date_granularity = date_popup_date_granularity($element);
+  $time_granularity = date_popup_time_granularity($element);
+  $has_time = date_has_time($granularity);
+
+  $label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
+  $label = t($label);
+
+  $date = date_popup_input_date($element, $input);
+
+  // If the date has errors, display them.
+  // If something was input but there is no date, the date is invalid.
+  // If the field is empty and required, set error message and return.
+  $error_field = implode('][', $element['#parents']);
+  if (empty($date) || !empty($date->errors)) {
+    if (is_object($date) && !empty($date->errors)) {
+      $message = t('The value input for field %field is invalid:', array('%field' => $label));
+      $message .= '<br />' . implode('<br />', $date->errors);
+      form_set_error($error_field, $message);
+      return;
+    }
+    if (!empty($input['date'])) {
+      $message = t('The value input for field %field is invalid.', array('%field' => $label));
+      form_set_error($error_field, $message);
+      return;
+    }
+    if ($element['#required']) {
+      $message = t('A valid date is required for %title.', array('%title' => $label));
+      form_set_error($error_field, $message);
+      return;
+    }
+  }
+
+  // If the created date is valid, set it.
+  $value = !empty($date) ? $date->format(DATE_FORMAT_DATETIME) : NULL;
+  form_set_value($element, $value, $form_state);
+}
+
+/**
+ * Helper function for extracting a date value out of user input.
+ *
+ * @param autocomplete
+ *   Should we add a time value to complete the date if there is no time?
+ *   Useful anytime the time value is optional.
+ */
+function date_popup_input_date($element, $input, $auto_complete = FALSE) {
+  if (empty($input) || !is_array($input) || !array_key_exists('date', $input) || empty($input['date'])) {
+    return NULL;
+  }
+  date_popup_add();
+  $granularity = date_format_order($element['#date_format']);
+  $has_time = date_has_time($granularity);
+  $flexible = !empty($element['#date_flexible']) ? $element['#date_flexible'] : 0;
+
+  $format = date_popup_date_format($element);
+  $format .= $has_time ? ' ' . date_popup_time_format($element) : '';
+  $datetime = $input['date'];
+  $datetime .= $has_time ? ' ' . $input['time'] : '';
+  $date = new DateObject($datetime, $element['#date_timezone'], $format);
+  if (is_object($date)) {
+    $date->limitGranularity($granularity);
+    if ($date->validGranularity($granularity, $flexible)) {
+      date_increment_round($date, $element['#date_increment']);
+    }
+    return $date;
+  }
+  return NULL;
+}
+
+/**
+ * Allowable time formats.
+ */
+function date_popup_time_formats($with_seconds = FALSE) {
+  return array(
+    'H:i:s',
+    'h:i:sA',
+    );
+}
+
+/**
+ * Format options array.
+ *
+ * TODO Remove any formats not supported by the widget, if any.
+ */
+function date_popup_formats() {
+  $formats = str_replace('i', 'i:s', array_keys(system_get_date_formats('short')));
+  $formats = drupal_map_assoc($formats);
+  return $formats;
+}
+
+/**
+ * Recreate a date format string so it has the values popup expects.
+ *
+ * @param string $format
+ *   a normal date format string, like Y-m-d
+ * @return string
+ *   A format string in popup format, like YMD-, for the
+ *   earlier 'calendar' version, or m/d/Y for the later 'datepicker'
+ *   version.
+ */
+function date_popup_format_to_popup($format) {
+  if (empty($format)) {
+    $format = 'Y-m-d';
+  }
+  $replace = date_popup_datepicker_format_replacements();
+  return strtr($format, $replace);
+}
+
+/**
+ * Recreate a time format string so it has the values popup expects.
+ *
+ * @param string $format
+ *   a normal time format string, like h:i (a)
+ * @return string
+ *   a format string that the popup can accept like h:i a
+ */
+function date_popup_format_to_popup_time($format, $timepicker = NULL) {
+  if (empty($format)) {
+    $format = 'H:i';
+  }
+  $format = str_replace(array('/', '-', ' .', ',', 'F', 'M', 'l', 'z', 'w', 'W', 'd', 'j', 'm', 'n', 'y', 'Y'), '', $format);
+  $format = strtr($format, date_popup_timepicker_format_replacements($timepicker));
+  return $format;
+}
+
+/**
+ * Reconstruct popup format string into normal format string.
+ *
+ * @param string $format
+ *   a string in popup format, like YMD-
+ * @return string
+ *   a normal date format string, like Y-m-d
+ */
+function date_popup_popup_to_format($format) {
+  $replace = array_flip(date_popup_datepicker_format_replacements());
+  return strtr($format, $replace);
+}
+
+/**
+ * Return a map of format replacements required for a given timepicker.
+ *
+ * Client-side time entry plugins don't support all possible date formats.
+ * This function returns a map of format replacements required to change any
+ * input format into one that the given timepicker can support.
+ *
+ * @param $timepicker
+ *   The time entry plugin being used: either 'wvega' or 'default'.
+ * @return
+ *   A map of replacements.
+ */
+function date_popup_timepicker_format_replacements($timepicker = 'default') {
+  switch ($timepicker) {
+    case 'wvega':
+      return array(
+        'a' => 'A', // The wvega timepicker only supports uppercase AM/PM.
+      );
+    default:
+      return array(
+        'G' => 'H', // The default timeEntry plugin requires leading zeros.
+        'g' => 'h',
+        );
+  }
+}
+
+/**
+ * The format replacement patterns for the new datepicker.
+ */
+function date_popup_datepicker_format_replacements() {
+  return array(
+  'd' => 'dd',
+  'j' => 'd',
+  'l' => 'DD',
+  'D' => 'D',
+  'm' => 'mm',
+  'n' => 'm',
+  'F' => 'MM',
+  'M' => 'M',
+  'Y' => 'yy',
+  'y' => 'y',
+  );
+}
+
+/**
+ * Format a date popup element.
+ *
+ * Use a class that will float date and time next to each other.
+ */
+function theme_date_popup($vars) {
+  $element = $vars['element'];
+  $attributes = !empty($element['#wrapper_attributes']) ? $element['#wrapper_attributes'] : array('class' => array());
+  $attributes['class'][] = 'container-inline-date';
+  // If there is no description, the floating date elements need some extra padding below them.
+  $wrapper_attributes = array('class' => array('date-padding'));
+  if (empty($element['date']['#description'])) {
+    $wrapper_attributes['class'][] = 'clearfix';
+  }
+  // Add an wrapper to mimic the way a single value field works, for ease in using #states.
+  if (isset($element['#children'])) {
+    $element['#children'] = '<div id="' . $element['#id'] . '" ' . drupal_attributes($wrapper_attributes) .'>' . $element['#children'] . '</div>';
+  }
+  return '<div ' . drupal_attributes($attributes) .'>' . theme('form_element', $element) . '</div>';
+}
+
+/**
+ * Implements hook_menu().
+ */
+function date_popup_menu() {
+  $items = array();
+  // TODO Fix this later.
+  $items['admin/config/date/date_popup'] = array(
+    'title' => 'Date Popup',
+    'description' => 'Configure the Date Popup settings.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('date_popup_settings'),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer site configuration'),
+  );
+  return $items;
+}
+/**
+ * General configuration form for controlling the Date Popup behaviour.
+ */
+function date_popup_settings() {
+  $wvega_available = date_popup_get_wvega_path();
+  $preferred_timepicker = date_popup_get_preferred_timepicker();
+
+  $form['#prefix'] = t('<p>The Date Popup module allows for manual time entry or use of a jQuery timepicker plugin. The Date module comes with a default jQuery timepicker which is already installed. The module also supports a dropdown timepicker that must be downloaded separately. The dropdown timepicker will not appear as an option until the code is available in the libraries folder. If you do not want to use a jQuery timepicker, you can choose the "Manual time entry" option below and users will get a regular textfield instead.</p>');
+  $form['date_popup_timepicker'] = array(
+    '#type' => 'select',
+    '#options' => array(
+      'default' => t('Use default jQuery timepicker'),
+      'wvega' => t('Use dropdown timepicker'),
+      'none' => t('Manual time entry, no jQuery timepicker')
+    ),
+    '#title' => t('Timepicker'),
+    '#default_value' => variable_get('date_popup_timepicker', $preferred_timepicker),
+  );
+
+  if (!$wvega_available) {
+    $form['#prefix'] .= t('<p>To install the dropdown timepicker, create a <code>!directory</code> directory in your site installation. Then visit <a href="@download">@download</a>, download the latest copy and unzip it. You will see files with names like jquery.timepicker-1.1.2.js and jquery.timepicker-1.1.2.css. Rename them to jquery.timepicker.js and jquery.timepicker.css and copy them into <code>!directory</code>.</p>', array('!directory' => 'sites/all/libraries/wvega-timepicker', '@download' => 'https://github.com/wvega/timepicker/archives/master'));
+    unset($form['date_popup_timepicker']['#options']['wvega']);
+  }
+
+  $css = <<<EOM
+/* ___________ IE6 IFRAME FIX ________ */
+.ui-datepicker-cover {
+  display: none; /*sorry for IE5*/
+  display/**/: block; /*sorry for IE5*/
+  position: absolute; /*must have*/
+  z-index: -1; /*must have*/
+  filter: mask(); /*must have*/
+  top: -4px; /*must have*/
+  left: -4px; /*must have*/ /* LTR */
+  width: 200px; /*must have*/
+  height: 200px; /*must have*/
+}
+EOM;
+
+  $form['#suffix'] = t('<p>The Date Popup calendar includes some css for IE6 that breaks css validation. Since IE 6 is now superceded by IE 7, 8, and 9, the special css for IE 6 has been removed from the regular css used by the Date Popup. If you find you need that css after all, you can add it back in your theme. Look at the way the Garland theme adds special IE-only css in in its page.tpl.php file. The css you need is:</p>') .'<blockquote><PRE>' . $css .'</PRE></blockquote>';
+
+  return system_settings_form($form);
+}
diff --git a/sites/all/modules/date/date_popup/jquery.timeentry.pack.js b/sites/all/modules/date/date_popup/jquery.timeentry.pack.js
new file mode 100644
index 0000000000000000000000000000000000000000..e26c64bf654cb906faa67f4d534266e17bc4ad0d
--- /dev/null
+++ b/sites/all/modules/date/date_popup/jquery.timeentry.pack.js
@@ -0,0 +1,7 @@
+/* http://keith-wood.name/timeEntry.html
+   Time entry for jQuery v1.4.8.
+   Written by Keith Wood (kbwood{at}iinet.com.au) June 2007.
+   Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
+   MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
+   Please attribute the author if you use it. */
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(r($){r 1n(){p.Y=[];p.26=[];p.26[\'\']={1c:B,1d:\':\',1o:\'\',Z:[\'3J\',\'3K\'],2C:[\'3L\',\'3M 2D\',\'3N 2D\',\'3O\',\'3P\']};p.1B={2E:\'\',1C:B,27:[1,1,1],2F:0,2G:L,2H:v,2I:v,2J:v,2K:\'3Q.3R\',1p:[20,20,8],2L:\'\',1D:[40,40,16],2M:B,28:[3S,3T],2N:v,2O:v};$.1q(p.1B,p.26[\'\'])}7 m=\'o\';$.1q(1n.2P,{1e:\'3U\',3V:r(a){1E(p.1B,a||{});u p},2Q:r(b,c){7 d=$(b);q(d.2R(p.1e)){u}7 e={};e.1r=$.1q({},c);e.E=0;e.13=0;e.14=0;e.x=0;e.w=$(b);$.y(b,m,e);7 f=p.t(e,\'2K\');7 g=p.t(e,\'3W\');7 h=p.t(e,\'1p\');7 i=p.t(e,\'2E\');7 j=(!f?v:$(\'<15 1F="3X" 2S="3Y: 3Z-41; \'+\'29: 2T(\\\'\'+f+\'\\\') 0 0 2U-2V; \'+\'2a: \'+h[0]+\'O; 2W: \'+h[1]+\'O;\'+($.K.2X&&$.K.42<\'1.9\'?\' 2Y-U: \'+h[0]+\'O; 2Y-43: \'+(h[1]-18)+\'O;\':\'\')+\'"></15>\'));d.44(\'<15 1F="45"></15>\').2Z(i?\'<15 1F="47">\'+i+\'</15>\':\'\').2Z(j||\'\');d.49(p.1e).17(\'2b.o\',p.2c).17(\'4a.o\',p.30).17(\'4b.o\',p.31).17(\'4c.o\',p.32).17(\'4d.o\',p.33);q($.K.2X){d.17(\'w.o\',r(a){$.o.1f(e)})}q($.K.2d){d.17(\'4e.o\',r(a){1G(r(){$.o.1f(e)},1)})}q(p.t(e,\'2G\')&&$.1H.2e){d.2e(p.34)}q(j){j.3a(p.2f).2g(p.1I).4f(p.3b).2h(p.1I).3c(p.2i)}},4g:r(a){p.2j(a,B)},4h:r(a){p.2j(a,L)},2j:r(b,c){7 d=$.y(b,m);q(!d){u}b.3d=c;q(b.2k&&b.2k.1J.1g()==\'15\'){$.o.1K(d,b.2k,(c?5:-1))}$.o.Y=$.3e($.o.Y,r(a){u(a==b?v:a)});q(c){$.o.Y.4i(b)}},1s:r(a){u $.3f(a,p.Y)>-1},4j:r(a,b,c){7 d=$.y(a,m);q(d){q(1h b==\'1L\'){7 e=b;b={};b[e]=c}7 f=p.1i(d);1E(d.1r,b||{});q(f){p.19(d,F J(0,0,0,f[0],f[1],f[2]))}}$.y(a,m,d)},4k:r(b){$w=$(b);q(!$w.2R(p.1e)){u}$w.4l(p.1e).4m(\'.o\');q($.1H.2e){$w.4n()}p.Y=$.3e(p.Y,r(a){u(a==b?v:a)});$w.4o().4p($w);$.4q(b,m)},4r:r(a,b){7 c=$.y(a,m);q(c){p.19(c,b?(1h b==\'4s\'?F J(b.2l()):b):v)}},3g:r(a){7 b=$.y(a,m);7 c=(b?p.1i(b):v);u(!c?v:F J(0,0,0,c[0],c[1],c[2]))},4t:r(a){7 b=$.y(a,m);7 c=(b?p.1i(b):v);u(!c?0:(c[0]*4u+c[1]*2m+c[2])*3h)},2c:r(a){7 b=(a.1J&&a.1J.1g()==\'w\'?a:p);q($.o.P==b||$.o.1s(b)){$.o.1M=B;u}7 c=$.y(b,m);$.o.1M=L;$.o.P=b;$.o.1j=v;7 d=$.o.t(c,\'2N\');1E(c.1r,(d?d.1N(b,[b]):{}));$.y(b,m,c);$.o.1f(c);1G(r(){$.o.1a(c)},10)},30:r(a){$.o.1j=$.o.P;$.o.P=v},31:r(b){7 c=b.1k;7 d=$.y(c,m);q(!$.o.1M){7 e=$.o.t(d,\'1d\').G+2;d.x=0;q(c.3i!=v){1O(7 f=0;f<=I.1l(1,d.V,d.D);f++){7 g=(f!=d.D?(f*e)+2:(d.D*e)+$.o.t(d,\'1o\').G+$.o.t(d,\'Z\')[0].G);d.x=f;q(c.3i<g){C}}}N q(c.1P){7 h=$(b.3j);7 i=c.1P();7 j=r(a){u{4v:2,4w:4,4x:6}[a]||a};7 k=b.3k+1t.2n.1u-(h.1Q().U+Q(j(h.1v(\'4y-U-2a\')),10))-i.2o;1O(7 f=0;f<=I.1l(1,d.V,d.D);f++){7 g=(f!=d.D?(f*e)+2:(d.D*e)+$.o.t(d,\'1o\').G+$.o.t(d,\'Z\')[0].G);i.4z();i.3l(\'2p\',g);d.x=f;q(k<i.4A){C}}}}$.y(c,m,d);$.o.1a(d);$.o.1M=B},32:r(a){q(a.2q>=48){u L}7 b=$.y(a.1k,m);2r(a.2q){A 9:u(a.4B?$.o.W(b,-1,L):$.o.W(b,+1,L));A 35:q(a.3m){$.o.1R(b,\'\')}N{b.x=I.1l(1,b.V,b.D);$.o.R(b,0)}C;A 36:q(a.3m){$.o.19(b)}N{b.x=0;$.o.R(b,0)}C;A 37:$.o.W(b,-1,B);C;A 38:$.o.R(b,+1);C;A 39:$.o.W(b,+1,B);C;A 40:$.o.R(b,-1);C;A 46:$.o.1R(b,\'\');C}u B},33:r(a){7 b=4C.4D(a.3n==4E?a.2q:a.3n);q(b<\' \'){u L}7 c=$.y(a.1k,m);$.o.3o(c,b);u B},34:r(a,b){q($.o.1s(a.1k)){u}b=($.K.3p?-b/I.1S(b):($.K.2s?b/I.1S(b):b));7 c=$.y(a.1k,m);c.w.2b();q(!c.w.T()){$.o.1f(c)}$.o.R(c,b);a.4F()},3b:r(b){7 c=$.o.1b(b);7 d=$.y($.o.1m(c),m);7 e=$.o.t(d,\'2L\');q(e){d.1T=L;7 f=$(c).1Q();7 g=v;$(c).3q().2t(r(){7 a=$(p);q(a.1v(\'1w\')==\'4G\'||a.1v(\'1w\')==\'3r\'){g=a.1Q()}u!g});7 h=$.o.t(d,\'1p\');7 i=$.o.t(d,\'1D\');$(\'<3s 1F="4H" 2S="1w: 3r; U: \'+(f.U-(i[0]-h[0])/2-(g?g.U:0))+\'O; 1x: \'+(f.1x-(i[1]-h[1])/2-(g?g.1x:0))+\'O; 2a: \'+i[0]+\'O; 2W: \'+i[1]+\'O; 29: 4I 2T(\'+e+\') 2U-2V 2u 2u; z-4J: 10;"></3s>\').3a($.o.2f).2g($.o.1I).2h($.o.3t).3c($.o.2i).4K(c)}},1m:r(a){u $(a).4L(\'.\'+$.o.1e)[0]},2i:r(a){7 b=$.o.1b(a);7 c=$.y($.o.1m(b),m);b.4M=$.o.t(c,\'2C\')[$.o.2v(c,a)]},2f:r(a){7 b=$.o.1b(a);7 c=$.o.1m(b);q($.o.1s(c)){u}q(c==$.o.1j){$.o.P=c;$.o.1j=v}7 d=$.y(c,m);$.o.2c(c);7 e=$.o.2v(d,a);$.o.1K(d,b,e);$.o.2w(d,e);$.o.X=v;$.o.1U=L;7 f=$.o.t(d,\'28\');q(e>=3&&f[0]){$.o.X=1G(r(){$.o.2x(d,e)},f[0]);$(b).3u(\'2h\',$.o.2y).3u(\'2g\',$.o.2y)}},2w:r(a,b){q(!a.w.T()){$.o.1f(a)}2r(b){A 0:p.19(a);C;A 1:p.W(a,-1,B);C;A 2:p.W(a,+1,B);C;A 3:p.R(a,+1);C;A 4:p.R(a,-1);C}},2x:r(a,b){q(!$.o.X){u}$.o.P=$.o.1j;p.2w(a,b);p.X=1G(r(){$.o.2x(a,b)},p.t(a,\'28\')[1])},2y:r(a){4N($.o.X);$.o.X=v},3t:r(a){$.o.X=v;7 b=$.o.1b(a);7 c=$.o.1m(b);7 d=$.y(c,m);$(b).4O();d.1T=B},1I:r(a){$.o.X=v;7 b=$.o.1b(a);7 c=$.o.1m(b);7 d=$.y(c,m);q(!$.o.1s(c)){$.o.1K(d,b,-1)}q($.o.1U){$.o.P=$.o.1j}q($.o.P&&$.o.1U){$.o.1a(d)}$.o.1U=B},1b:r(a){u a.1k||a.3j},2v:r(a,b){7 c=p.1b(b);7 d=($.K.3p||$.K.2s?$.o.3v(c):$(c).1Q());7 e=($.K.2s?$.o.3w(c):[1t.2n.1u||1t.3x.1u,1t.2n.1V||1t.3x.1V]);7 f=p.t(a,\'2M\');7 g=(f?3y:b.3k+e[0]-d.U-($.K.2d?2:0));7 h=b.4P+e[1]-d.1x-($.K.2d?2:0);7 i=p.t(a,(a.1T?\'1D\':\'1p\'));7 j=(f?3y:i[0]-1-g);7 k=i[1]-1-h;q(i[2]>0&&I.1S(g-j)<=i[2]&&I.1S(h-k)<=i[2]){u 0}7 l=I.3z(g,h,j,k);u(l==g?1:(l==j?2:(l==h?3:4)))},1K:r(a,b,c){$(b).1v(\'29-1w\',\'-\'+((c+1)*p.t(a,(a.1T?\'1D\':\'1p\'))[0])+\'O 2u\')},3v:r(a){7 b=1W=0;q(a.3A){b=a.2o;1W=a.3B;2z(a=a.3A){7 c=b;b+=a.2o;q(b<0){b=c}1W+=a.3B}}u{U:b,1x:1W}},3w:r(a){7 b=B;$(a).3q().2t(r(){b|=$(p).1v(\'1w\')==\'4Q\'});q(b){u[0,0]}7 c=a.1u;7 d=a.1V;2z(a=a.4R){c+=a.1u||0;d+=a.1V||0}u[c,d]},t:r(a,b){u(a.1r[b]!=v?a.1r[b]:$.o.1B[b])},1f:r(a){7 b=p.1i(a);7 c=p.t(a,\'1C\');q(b){a.E=b[0];a.13=b[1];a.14=b[2]}N{7 d=p.1y(a);a.E=d[0];a.13=d[1];a.14=(c?d[2]:0)}a.V=(c?2:-1);a.D=(p.t(a,\'1c\')?-1:(c?3:2));a.1X=\'\';a.x=I.1l(0,I.3z(I.1l(1,a.V,a.D),p.t(a,\'2F\')));q(a.w.T()!=\'\'){p.2A(a)}},1i:r(a,b){b=b||a.w.T();7 c=p.t(a,\'1d\');7 d=b.4S(c);q(c==\'\'&&b!=\'\'){d[0]=b.1z(0,2);d[1]=b.1z(2,4);d[2]=b.1z(4,6)}7 e=p.t(a,\'Z\');7 f=p.t(a,\'1c\');q(d.G>=2){7 g=!f&&(b.3C(e[0])>-1);7 h=!f&&(b.3C(e[1])>-1);7 i=Q(d[0],10);i=(2B(i)?0:i);i=((g||h)&&i==12?0:i)+(h?12:0);7 j=Q(d[1],10);j=(2B(j)?0:j);7 k=(d.G>=3?Q(d[2],10):0);k=(2B(k)||!p.t(a,\'1C\')?0:k);u p.1y(a,[i,j,k])}u v},1y:r(a,b){7 c=(b!=v);q(!c){7 d=p.1A(a,p.t(a,\'2H\'))||F J();b=[d.1Y(),d.1Z(),d.21()]}7 e=B;7 f=p.t(a,\'27\');1O(7 i=0;i<f.G;i++){q(e){b[i]=0}N q(f[i]>1){b[i]=I.4T(b[i]/f[i])*f[i];e=L}}u b},2A:r(a){7 b=p.t(a,\'1c\');7 c=p.t(a,\'1d\');7 d=(p.22(b?a.E:((a.E+11)%12)+1)+c+p.22(a.13)+(p.t(a,\'1C\')?c+p.22(a.14):\'\')+(b?\'\':p.t(a,\'1o\')+p.t(a,\'Z\')[(a.E<12?0:1)]));p.1R(a,d);p.1a(a)},1a:r(a){7 b=a.w[0];q(a.w.4U(\':4V\')||$.o.P!=b){u}7 c=p.t(a,\'1d\');7 d=c.G+2;7 e=(a.x!=a.D?(a.x*d):(a.D*d)-c.G+p.t(a,\'1o\').G);7 f=e+(a.x!=a.D?2:p.t(a,\'Z\')[0].G);q(b.3D){b.3D(e,f)}N q(b.1P){7 g=b.1P();g.4W(\'2p\',e);g.3l(\'2p\',f-a.w.T().G);g.4X()}q(!b.3d){b.2b()}},22:r(a){u(a<10?\'0\':\'\')+a},1R:r(a,b){q(b!=a.w.T()){a.w.T(b).4Y(\'4Z\')}},W:r(a,b,c){7 d=(a.w.T()==\'\'||a.x==(b==-1?0:I.1l(1,a.V,a.D)));q(!d){a.x+=b}p.1a(a);a.1X=\'\';$.y(a.w[0],m,a);u(d&&c)},R:r(a,b){q(a.w.T()==\'\'){b=0}7 c=p.t(a,\'27\');p.19(a,F J(0,0,0,a.E+(a.x==0?b*c[0]:0)+(a.x==a.D?b*12:0),a.13+(a.x==1?b*c[1]:0),a.14+(a.x==a.V?b*c[2]:0)))},19:r(a,b){b=p.1A(a,b);7 c=p.1y(a,b?[b.1Y(),b.1Z(),b.21()]:v);b=F J(0,0,0,c[0],c[1],c[2]);7 b=p.25(b);7 d=p.25(p.1A(a,p.t(a,\'2I\')));7 e=p.25(p.1A(a,p.t(a,\'2J\')));b=(d&&b<d?d:(e&&b>e?e:b));7 f=p.t(a,\'2O\');q(f){b=f.1N(a.w[0],[p.3g(a.w[0]),b,d,e])}a.E=b.1Y();a.13=b.1Z();a.14=b.21();p.2A(a);$.y(a.w[0],m,a)},25:r(a){q(!a){u v}a.50(51);a.52(0);a.53(0);u a},1A:r(i,j){7 k=r(a){7 b=F J();b.54(b.2l()+a*3h);u b};7 l=r(a){7 b=$.o.1i(i,a);7 c=F J();7 d=(b?b[0]:c.1Y());7 e=(b?b[1]:c.1Z());7 f=(b?b[2]:c.21());q(!b){7 g=/([+-]?[0-9]+)\\s*(s|S|m|M|h|H)?/g;7 h=g.3E(a);2z(h){2r(h[2]||\'s\'){A\'s\':A\'S\':f+=Q(h[1],10);C;A\'m\':A\'M\':e+=Q(h[1],10);C;A\'h\':A\'H\':d+=Q(h[1],10);C}h=g.3E(a)}}c=F J(0,0,10,d,e,f,0);q(/^!/.55(a)){q(c.3F()>10){c=F J(0,0,10,23,59,59)}N q(c.3F()<10){c=F J(0,0,10,0,0,0)}}u c};u(j?(1h j==\'1L\'?l(j):(1h j==\'56\'?k(j):j)):v)},3o:r(a,b){q(b==p.t(a,\'1d\')){p.W(a,+1,B)}N q(b>=\'0\'&&b<=\'9\'){7 c=Q(b,10);7 d=Q(a.1X+b,10);7 e=p.t(a,\'1c\');7 f=(a.x!=0?a.E:(e?(d<24?d:c):(d>=1&&d<=12?d:(c>0?c:a.E))%12+(a.E>=12?12:0)));7 g=(a.x!=1?a.13:(d<2m?d:c));7 h=(a.x!=a.V?a.14:(d<2m?d:c));7 i=p.1y(a,[f,g,h]);p.19(a,F J(0,0,0,i[0],i[1],i[2]));a.1X=b}N q(!p.t(a,\'1c\')){b=b.1g();7 j=p.t(a,\'Z\');q((b==j[0].1z(0,1).1g()&&a.E>=12)||(b==j[1].1z(0,1).1g()&&a.E<12)){7 k=a.x;a.x=a.D;p.R(a,+1);a.x=k;p.1a(a)}}}});r 1E(a,b){$.1q(a,b);1O(7 c 57 b){q(b[c]==v){a[c]=v}}u a}7 n=[\'58\',\'2l\',\'5a\'];$.1H.o=r(c){7 d=5b.2P.5c.5d(5e,1);q(1h c==\'1L\'&&$.3f(c,n)>-1){u $.o[\'3G\'+c+\'1n\'].1N($.o,[p[0]].3H(d))}u p.2t(r(){7 a=p.1J.1g();q(a==\'w\'){q(1h c==\'1L\'){$.o[\'3G\'+c+\'1n\'].1N($.o,[p].3H(d))}N{7 b=($.1H.3I?$(p).3I():{});$.o.2Q(p,$.1q(b,c))}}})};$.o=F 1n()})(5f);',62,326,'|||||||var|||||||||||||||||timeEntry|this|if|function||_get|return|null|input|_field|data||case|false|break|_ampmField|_selectedHour|new|length||Math|Date|browser|true||else|px|_lastInput|parseInt|_adjustField||val|left|_secondField|_changeField|_timer|_disabledInputs|ampmNames||||_selectedMinute|_selectedSecond|span||bind||_setTime|_showField|_getSpinnerTarget|show24Hours|separator|markerClassName|_parseTime|toLowerCase|typeof|_extractTime|_blurredInput|target|max|_getInput|TimeEntry|ampmPrefix|spinnerSize|extend|options|_isDisabledTimeEntry|document|scrollLeft|css|position|top|_constrainTime|substring|_determineTime|_defaults|showSeconds|spinnerBigSize|extendRemove|class|setTimeout|fn|_endSpinner|nodeName|_changeSpinner|string|_focussed|apply|for|createTextRange|offset|_setValue|abs|_expanded|_handlingSpinner|scrollTop|curTop|_lastChr|getHours|getMinutes||getSeconds|_formatNumber|||_normaliseTime|regional|timeSteps|spinnerRepeat|background|width|focus|_doFocus|msie|mousewheel|_handleSpinner|mouseup|mouseout|_describeSpinner|_enableDisable|nextSibling|getTime|60|documentElement|offsetLeft|character|keyCode|switch|safari|each|0px|_getSpinnerRegion|_actionSpinner|_repeatSpinner|_releaseSpinner|while|_showTime|isNaN|spinnerTexts|field|appendText|initialField|useMouseWheel|defaultTime|minTime|maxTime|spinnerImage|spinnerBigImage|spinnerIncDecOnly|beforeShow|beforeSetTime|prototype|_connectTimeEntry|hasClass|style|url|no|repeat|height|mozilla|padding|after|_doBlur|_doClick|_doKeyDown|_doKeyPress|_doMouseWheel||||||mousedown|_expandSpinner|mousemove|disabled|map|inArray|_getTimeTimeEntry|1000|selectionStart|srcElement|clientX|moveEnd|ctrlKey|charCode|_handleKeyPress|opera|parents|absolute|div|_endExpand|one|_findPos|_findScroll|body|99|min|offsetParent|offsetTop|indexOf|setSelectionRange|exec|getDate|_|concat|metadata|AM|PM|Now|Previous|Next|Increment|Decrement|spinnerDefault|png|500|250|hasTimeEntry|setDefaults|spinnerText|timeEntry_control|display|inline||block|version|bottom|wrap|timeEntry_wrap||timeEntry_append||addClass|blur|click|keydown|keypress|paste|mouseover|_enableTimeEntry|_disableTimeEntry|push|_changeTimeEntry|_destroyTimeEntry|removeClass|unbind|unmousewheel|parent|replaceWith|removeData|_setTimeTimeEntry|object|_getOffsetTimeEntry|3600|thin|medium|thick|border|collapse|boundingWidth|shiftKey|String|fromCharCode|undefined|preventDefault|relative|timeEntry_expand|transparent|index|insertAfter|siblings|title|clearTimeout|remove|clientY|fixed|parentNode|split|round|is|hidden|moveStart|select|trigger|change|setFullYear|1900|setMonth|setDate|setTime|test|number|in|getOffset||isDisabled|Array|slice|call|arguments|jQuery'.split('|'),0,{}))
\ No newline at end of file
diff --git a/sites/all/modules/date/date_popup/themes/datepicker.1.7.css b/sites/all/modules/date/date_popup/themes/datepicker.1.7.css
new file mode 100644
index 0000000000000000000000000000000000000000..d386c9853d51d84441542b3b9d933e27177b8c77
--- /dev/null
+++ b/sites/all/modules/date/date_popup/themes/datepicker.1.7.css
@@ -0,0 +1,59 @@
+#ui-datepicker-div {
+font-size: 100%;
+font-family: Verdana, sans-serif;
+background: #eee;
+border-right:2px #666 solid;
+border-bottom:2px #666 solid;
+z-index: 9999;
+}
+
+/* Datepicker
+----------------------------------*/
+.ui-datepicker { width: 17em; padding: .2em .2em 0; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px;  }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { float:left; font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker .ui-datepicker-title select.ui-datepicker-year { float: right; }
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0;  }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
diff --git a/sites/all/modules/date/date_popup/themes/jquery.timeentry.css b/sites/all/modules/date/date_popup/themes/jquery.timeentry.css
new file mode 100644
index 0000000000000000000000000000000000000000..7ddefbac99d7b14e62d407e3418abe366618824e
--- /dev/null
+++ b/sites/all/modules/date/date_popup/themes/jquery.timeentry.css
@@ -0,0 +1,8 @@
+/* TimeEntry styles */
+.timeEntry_control {
+vertical-align: middle;
+margin-left: 2px;
+}
+* html .timeEntry_control { /* IE only */
+margin-top: -4px;
+}
diff --git a/sites/all/modules/date/date_repeat.inc b/sites/all/modules/date/date_repeat.inc
new file mode 100644
index 0000000000000000000000000000000000000000..2df03dc852bbd85cdf9a16f7d864f3e1ce36edc7
--- /dev/null
+++ b/sites/all/modules/date/date_repeat.inc
@@ -0,0 +1,6 @@
+<?php
+/**
+ * @file
+ * Empty file to avoid fatal error if it doesn't exist.
+ * Formerly the Date Repeat field code.
+ */
\ No newline at end of file
diff --git a/sites/all/modules/date/date_repeat/date_repeat.info b/sites/all/modules/date/date_repeat/date_repeat.info
new file mode 100644
index 0000000000000000000000000000000000000000..c1ff662e19769a6c144bdf220097953430ca633f
--- /dev/null
+++ b/sites/all/modules/date/date_repeat/date_repeat.info
@@ -0,0 +1,15 @@
+name = Date Repeat API
+description = A Date Repeat API to calculate repeating dates and times from iCal rules.
+dependencies[] = date_api
+package = Date/Time
+core = 7.x
+php = 5.2
+files[] = tests/date_repeat.test
+files[] = tests/date_repeat_form.test
+
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date_repeat/date_repeat.install b/sites/all/modules/date/date_repeat/date_repeat.install
new file mode 100644
index 0000000000000000000000000000000000000000..65c3adbbbece0307e9b52470320bea7bcc177e2c
--- /dev/null
+++ b/sites/all/modules/date/date_repeat/date_repeat.install
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the Date Repeat module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function date_repeat_install() {
+  // Make sure this module loads after date_api.
+  db_query("UPDATE {system} SET weight = 1 WHERE name = 'date_repeat'");
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function date_repeat_uninstall() {
+}
+
+/**
+ * Implements hook_enable().
+ */
+function date_repeat_enable() {
+}
+
+/**
+ * Implements hook_disable().
+ */
+function date_repeat_disable() {
+}
diff --git a/sites/all/modules/date/date_repeat/date_repeat.module b/sites/all/modules/date/date_repeat/date_repeat.module
new file mode 100644
index 0000000000000000000000000000000000000000..d742dc8895522bf2411ab0a4c9bad228ba7245b3
--- /dev/null
+++ b/sites/all/modules/date/date_repeat/date_repeat.module
@@ -0,0 +1,419 @@
+<?php
+/**
+ * @file
+ *
+ * This module creates a form element that allows users to select
+ * repeat rules for a date, and reworks the result into an iCal
+ * RRULE string that can be stored in the database.
+ *
+ * The module also parses iCal RRULEs to create an array of dates
+ * that meet their criteria.
+ *
+ * Other modules can use this API to add self-validating form elements
+ * to their dates, and identify dates that meet the RRULE criteria.
+ *
+ */
+/**
+ * Implements hook_element_info().
+ */
+function date_repeat_element_info() {
+  $type['date_repeat_rrule'] = array(
+    '#input' => TRUE,
+    '#process' => array('date_repeat_rrule_process'),
+    '#element_validate' => array('date_repeat_rrule_validate'),
+    '#theme_wrappers' => array('date_repeat_rrule'),
+  );
+  $type['date_repeat_form_element_radios'] = array(
+    '#input' => TRUE,
+    '#process' => array('date_repeat_form_element_radios_process'),
+    '#theme_wrappers' => array('radios'),
+    '#pre_render' => array('form_pre_render_conditional_form_element'),
+  );
+  if (module_exists('ctools')) {
+    $type['date_repeat_rrule']['#pre_render'] = array('ctools_dependent_pre_render');
+  }
+  return $type;
+}
+
+function date_repeat_theme() {
+  return array(
+    'date_repeat_current_exceptions' => array('render element' => 'element'),
+    'date_repeat_current_additions' => array('render element' => 'element'),
+    'date_repeat_rrule' => array('render element' => 'element'),
+  );
+}
+
+/**
+ * Helper function for FREQ options.
+ */
+function date_repeat_freq_options() {
+  return array(
+    'DAILY' => t('Daily', array(), array('context' => 'datetime_singular')),
+    'WEEKLY' => t('Weekly', array(), array('context' => 'datetime_singular')),
+    'MONTHLY' => t('Monthly', array(), array('context' => 'datetime_singular')),
+    'YEARLY' => t('Yearly', array(), array('context' => 'datetime_singular')),
+  );
+}
+
+function date_repeat_interval_options() {
+  $options = range(0, 366);
+  unset($options[0]);
+
+  return $options;
+}
+
+/**
+ * Helper function for FREQ options.
+ *
+ * Translated and untranslated arrays of the iCal day of week names.
+ * We need the untranslated values for date_modify(), translated
+ * values when displayed to user.
+ */
+function date_repeat_dow_day_options($translated = TRUE) {
+  return array(
+    'SU' => $translated ? t('Sunday', array(), array('context' => 'day_name')) : 'Sunday',
+    'MO' => $translated ? t('Monday', array(), array('context' => 'day_name')) : 'Monday',
+    'TU' => $translated ? t('Tuesday', array(), array('context' => 'day_name')) : 'Tuesday',
+    'WE' => $translated ? t('Wednesday', array(), array('context' => 'day_name')) : 'Wednesday',
+    'TH' => $translated ? t('Thursday', array(), array('context' => 'day_name')) : 'Thursday',
+    'FR' => $translated ? t('Friday', array(), array('context' => 'day_name')) : 'Friday',
+    'SA' => $translated ? t('Saturday', array(), array('context' => 'day_name')) : 'Saturday',
+  );
+}
+
+/**
+ * Helper function for FREQ options.
+ *
+ * Translated and untranslated arrays of the iCal abbreviated day of week names.
+ */
+function date_repeat_dow_day_options_abbr($translated = TRUE, $length = 3) {
+  $return = array();
+  switch ($length) {
+    case 1:
+      $context = 'day_abbr1';
+      break;
+    case 2:
+      $context = 'day_abbr2';
+      break;
+    default:
+      $context = '';
+      break;
+  }
+  foreach (date_repeat_dow_day_untranslated() as $key => $day) {
+    $return[$key] = $translated ? t(substr($day, 0, $length), array(), array('context' => $context)) : substr($day, 0, $length);
+  }
+  return $return;
+}
+
+function date_repeat_dow_day_untranslated() {
+  static $date_repeat_weekdays;
+  if (empty($date_repeat_weekdays)) {
+    $date_repeat_weekdays = array('SU' => 'Sunday', 'MO' => 'Monday', 'TU' => 'Tuesday',
+      'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday',
+      'SA' => 'Saturday');
+  }
+  return $date_repeat_weekdays;
+}
+
+function date_repeat_dow_day_options_ordered($weekdays) {
+  $day_keys = array_keys($weekdays);
+  $day_values = array_values($weekdays);
+  for ($i = 1; $i <= variable_get('date_first_day', 0); $i++) {
+    $last_key = array_shift($day_keys);
+    array_push($day_keys, $last_key);
+    $last_value = array_shift($day_values);
+    array_push($day_values, $last_value);
+  }
+  $weekdays = array_combine($day_keys, $day_values);
+  return $weekdays;
+}
+
+/**
+ * Helper function for BYDAY options.
+ */
+function date_repeat_dow_count_options() {
+  return array('' => t('Every', array(), array('context' => 'date_order'))) + date_order_translated();
+}
+
+/**
+ * Helper function for BYDAY options.
+ *
+ * Creates options like -1SU and 2TU
+ */
+function date_repeat_dow_options() {
+  $options = array();
+  foreach (date_repeat_dow_count_options() as $count_key => $count_value) {
+    foreach (date_repeat_dow_day_options() as $dow_key => $dow_value) {
+      $options[$count_key . $dow_key] = $count_value . ' ' . $dow_value;
+    }
+  }
+  return $options;
+}
+
+/**
+ * Translate a day of week position to the iCal day name.
+ *
+ * Used with date_format($date, 'w') or get_variable('date_first_day'),
+ * which return 0 for Sunday, 1 for Monday, etc.
+ *
+ * dow 2 becomes 'TU', dow 3 becomes 'WE', and so on.
+ */
+function date_repeat_dow2day($dow) {
+  $days_of_week = array_keys(date_repeat_dow_day_options(FALSE));
+  return $days_of_week[$dow];
+}
+
+/**
+ * Shift the array of iCal day names into the right order
+ * for a specific week start day.
+ */
+function date_repeat_days_ordered($week_start_day) {
+  $days = array_flip(array_keys(date_repeat_dow_day_options(FALSE)));
+  $start_position = $days[$week_start_day];
+  $keys = array_flip($days);
+  if ($start_position > 0) {
+    for ($i = 1; $i <= $start_position; $i++) {
+      $last = array_shift($keys);
+      array_push($keys, $last);
+    }
+  }
+  return $keys;
+}
+
+/**
+ * Build a description of an iCal rule.
+ *
+ * Constructs a human-readable description of the rule.
+ */
+function date_repeat_rrule_description($rrule, $format = 'D M d Y') {
+  // Empty or invalid value.
+  if (empty($rrule) || !strstr($rrule, 'RRULE')) {
+    return;
+  }
+
+  module_load_include('inc', 'date_api', 'date_api_ical');
+  module_load_include('inc', 'date_repeat', 'date_repeat_calc');
+
+  $parts = date_repeat_split_rrule($rrule);
+  $additions = $parts[2];
+  $exceptions = $parts[1];
+  $rrule = $parts[0];
+  if ($rrule['FREQ'] == 'NONE') {
+    return;
+  }
+
+  // Make sure there will be an empty description for any unused parts.
+  $description = array(
+    '!interval' => '',
+    '!byday' => '',
+    '!bymonth' => '',
+    '!count' => '',
+    '!until' => '',
+    '!except' => '',
+    '!additional' => '',
+    '!week_starts_on' => '',
+    );
+  $interval = date_repeat_interval_options();
+  switch ($rrule['FREQ']) {
+    case 'WEEKLY':
+      $description['!interval'] = format_plural($rrule['INTERVAL'], 'every week', 'every @count weeks') . ' ';
+      break;
+    case 'MONTHLY':
+      $description['!interval'] = format_plural($rrule['INTERVAL'], 'every month', 'every @count months') . ' ';
+      break;
+    case 'YEARLY':
+      $description['!interval'] = format_plural($rrule['INTERVAL'], 'every year', 'every @count years') . ' ';
+      break;
+    default:
+      $description['!interval'] = format_plural($rrule['INTERVAL'], 'every day', 'every @count days') . ' ';
+      break;
+  }
+
+  if (!empty($rrule['BYDAY'])) {
+    $days = date_repeat_dow_day_options();
+    $counts = date_repeat_dow_count_options();
+    $results = array();
+    foreach ($rrule['BYDAY'] as $byday) {
+      // Get the numeric part of the BYDAY option, i.e. +3 from +3MO.
+      $day = substr($byday, -2);
+      $count = str_replace($day, '', $byday);
+      if (!empty($count)) {
+        // See if there is a 'pretty' option for this count, i.e. +1 => First.
+        $order = array_key_exists($count, $counts) ? strtolower($counts[$count]) : $count;
+        $results[] = trim(t('!repeats_every_interval on the !date_order !day_of_week', array('!repeats_every_interval ' => '', '!date_order' => $order, '!day_of_week' => $days[$day])));
+      }
+      else {
+        $results[] = trim(t('!repeats_every_interval every !day_of_week', array('!repeats_every_interval ' => '', '!day_of_week' => $days[$day])));
+      }
+    }
+    $description['!byday'] = implode(' ' . t('and') . ' ', $results);
+  }
+  if (!empty($rrule['BYMONTH'])) {
+    if (sizeof($rrule['BYMONTH']) < 12) {
+      $results = array();
+      $months = date_month_names();
+      foreach ($rrule['BYMONTH'] as $month) {
+        $results[] = $months[$month];
+      }
+      if (!empty($rrule['BYMONTHDAY'])) {
+        $description['!bymonth'] = trim(t('!repeats_every_interval on the !month_days of !month_names', array('!repeats_every_interval ' => '', '!month_days' => implode(', ', $rrule['BYMONTHDAY']), '!month_names' => implode(', ', $results))));
+      }
+      else {
+        $description['!bymonth'] = trim(t('!repeats_every_interval on !month_names', array('!repeats_every_interval ' => '', '!month_names' => implode(', ', $results))));
+      }
+    }
+  }
+  if ($rrule['INTERVAL'] < 1) {
+    $rrule['INTERVAL'] = 1;
+  }
+  if (!empty($rrule['COUNT'])) {
+    $description['!count'] = trim(t('!repeats_every_interval !count times', array('!repeats_every_interval ' => '', '!count' => $rrule['COUNT'])));
+  }
+  if (!empty($rrule['UNTIL'])) {
+    $until = date_ical_date($rrule['UNTIL'], 'UTC');
+    date_timezone_set($until, date_default_timezone_object());
+    $description['!until'] = trim(t('!repeats_every_interval until !until_date', array('!repeats_every_interval ' => '', '!until_date' => date_format_date($until, 'custom', $format))));
+  }
+  if ($exceptions) {
+    $values = array();
+    foreach ($exceptions as $exception) {
+      $except = date_ical_date($exception, 'UTC');
+      date_timezone_set($except, date_default_timezone_object());
+      $values[] = date_format_date($except, 'custom', $format);
+    }
+    $description['!except'] = trim(t('!repeats_every_interval except !except_dates', array('!repeats_every_interval ' => '', '!except_dates' => implode(', ', $values))));
+  }
+  if (!empty($rrule['WKST'])) {
+    $day_names = date_repeat_dow_day_options();
+    $description['!week_starts_on'] = trim(t('!repeats_every_interval where the week start on !day_of_week', array('!repeats_every_interval ' => '', '!day_of_week' => $day_names[trim($rrule['WKST'])])));
+  }
+  if ($additions) {
+    $values = array();
+    foreach ($additions as $addition) {
+      $add = date_ical_date($addition, 'UTC');
+      date_timezone_set($add, date_default_timezone_object());
+      $values[] = date_format_date($add, 'custom', $format);
+    }
+    $description['!additional'] = trim(t('Also includes !additional_dates.', array('!additional_dates' => implode(', ', $values))));
+  }
+  return t('Repeats !interval !bymonth !byday !count !until !except. !additional', $description);
+}
+
+/**
+ * Parse an iCal rule into a parsed RRULE array and an EXDATE array.
+ */
+function date_repeat_split_rrule($rrule) {
+  $parts = explode("\n", str_replace("\r\n", "\n", $rrule));
+  $rrule = array();
+  $exceptions = array();
+  $additions = array();
+  $additions = array();
+  foreach ($parts as $part) {
+    if (strstr($part, 'RRULE')) {
+      $RRULE = str_replace('RRULE:', '', $part);
+      $rrule = (array) date_ical_parse_rrule('RRULE:', $RRULE);
+    }
+    elseif (strstr($part, 'EXDATE')) {
+      $EXDATE = str_replace('EXDATE:', '', $part);
+      $exceptions = (array) date_ical_parse_exceptions('EXDATE:', $EXDATE);
+      unset($exceptions['DATA']);
+    }
+    elseif (strstr($part, 'RDATE')) {
+      $RDATE = str_replace('RDATE:', '', $part);
+      $additions = (array) date_ical_parse_exceptions('RDATE:', $RDATE);
+      unset($additions['DATA']);
+    }
+  }
+  return array($rrule, $exceptions, $additions);
+}
+
+/**
+ * Analyze a RRULE and return dates that match it.
+ */
+function date_repeat_calc($rrule, $start, $end, $exceptions = array(), $timezone = NULL, $additions = array()) {
+  module_load_include('inc', 'date_repeat', 'date_repeat_calc');
+  return _date_repeat_calc($rrule, $start, $end, $exceptions, $timezone, $additions);
+}
+
+/**
+ * Generate the repeat rule setting form.
+ */
+function date_repeat_rrule_process($element, &$form_state, $form) {
+  module_load_include('inc', 'date_repeat', 'date_repeat_form');
+  return _date_repeat_rrule_process($element, $form_state, $form);
+}
+
+/**
+ * Process function for 'date_repeat_form_element_radios'.
+ */
+function date_repeat_form_element_radios_process($element) {
+  $childrenkeys = element_children($element);
+
+  if (count($element['#options']) &&
+      count($element['#options']) == count($childrenkeys)) {
+    $weight = 0;
+    $children = array();
+    $classes = isset($element['#div_classes']) ?
+      $element['#div_classes'] : array();
+    foreach ($childrenkeys as $childkey) {
+      $children[$childkey] = $element[$childkey];
+      unset($element[$childkey]);
+    }
+    foreach ($element['#options'] as $key => $choice) {
+      $currentchildkey = array_shift($childrenkeys);
+      $weight += 0.001;
+      $class = array_shift($classes);
+      $element += array($key => array());
+      $parents_for_id = array_merge($element['#parents'], array($key));
+      $element[$key] += array(
+        '#prefix' => '<div' . ($class ? " class=\"{$class}\"" : '') . '>',
+        '#type' => 'radio',
+        '#title' => $choice,
+        '#title_display' => 'invisible',
+        '#return_value' => $key,
+        '#default_value' => isset($element['#default_value']) ?
+          $element['#default_value'] : NULL,
+        '#attributes' => $element['#attributes'],
+        '#parents' => $element['#parents'],
+        '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
+        '#ajax' => isset($element['#ajax']) ? $element['ajax'] : NULL,
+        '#weight' => $weight,
+        '#theme_wrappers' => array(),
+        '#suffix' => ' ',
+      );
+
+      $child = $children[$currentchildkey];
+
+      $weight += 0.001;
+
+      $child['#weight'] = $weight;
+      $child['#title_display'] = 'invisible';
+      $child['#suffix'] = (!empty($child['#suffix']) ? $child['#suffix'] : '') .
+        '</div>';
+      $child['#parents'] = $element['#parents'];
+      array_pop($child['#parents']);
+      array_push($child['#parents'], $currentchildkey);
+
+      $element_prototype = element_info($child['#type']);
+      $old_wrappers = array();
+      if (isset($child['#theme_wrappers'])) {
+        $old_wrappers += $child['#theme_wrappers'];
+      }
+      if (isset($element_prototype['#theme_wrappers'])) {
+        $old_wrappers += $element_prototype['#theme_wrappers'];
+      }
+
+      $child['#theme_wrappers'] = array();
+
+      foreach ($old_wrappers as $wrapper) {
+        if ($wrapper != 'form_element') {
+          $child['#theme_wrappers'][] = $wrapper;
+        }
+      }
+
+      $element[$currentchildkey] = $child;
+    }
+  }
+
+  return $element;
+}
diff --git a/sites/all/modules/date/date_repeat/date_repeat_calc.inc b/sites/all/modules/date/date_repeat/date_repeat_calc.inc
new file mode 100644
index 0000000000000000000000000000000000000000..2a02d94b9c5b6cf07b29cb5e47ba9265704facec
--- /dev/null
+++ b/sites/all/modules/date/date_repeat/date_repeat_calc.inc
@@ -0,0 +1,581 @@
+<?php
+/**
+ * @file
+ * Code to compute the dates that match an iCal RRULE.
+ *
+ * Moved to a separate file since it is not used on most pages
+ * so the code is not parsed unless needed.
+ *
+ * Extensive simpletests have been created to test the RRULE calculation
+ * results against official examples from RFC 2445.
+ *
+ * These calculations are expensive and results should be stored or cached
+ * so the calculation code is not called more often than necessary.
+ *
+ * Currently implemented:
+ * INTERVAL, UNTIL, COUNT, EXDATE, RDATE, BYDAY, BYMONTHDAY, BYMONTH,
+ * YEARLY, MONTHLY, WEEKLY, DAILY
+ *
+ * Currently not implemented:
+ *
+ * BYYEARDAY, MINUTELY, HOURLY, SECONDLY, BYMINUTE, BYHOUR, BYSECOND
+ *   These could be implemented in the future.
+ *
+ * BYSETPOS
+ *   Seldom used anywhere, so no reason to complicated the code.
+ */
+
+/**
+ * Private implementation of date_repeat_calc().
+ *
+ * Compute dates that match the requested rule, within a specified date range.
+ */
+function _date_repeat_calc($rrule, $start, $end, $exceptions, $timezone, $additions) {
+  module_load_include('inc', 'date_api', 'date_api_ical');
+
+  if (empty($timezone)) {
+    $timezone = date_default_timezone();
+  }
+
+  // Make sure the 'EXCEPTIONS' string isn't appended to the rule.
+  $parts = explode("\n", $rrule);
+  if (count($parts)) {
+    $rrule = $parts[0];
+  }
+  // Get the parsed array of rule values.
+  $rrule = date_ical_parse_rrule('RRULE:', $rrule);
+
+  // These default values indicate there is no RRULE here.
+  if ($rrule['FREQ'] == 'NONE' || (isset($rrule['INTERVAL']) && $rrule['INTERVAL'] == 0)) {
+    return array();
+  }
+
+  // Create a date object for the start and end dates.
+  $start_date = new DateObject($start, $timezone);
+
+  // Versions of PHP greater than PHP 5.3.5 require that we set an explicit time when
+  // using date_modify() or the time may not match the original value. Adding this
+  // modifier gives us the same results in both older and newer versions of PHP.
+  $modify_time = ' ' . $start_date->format('g:ia');
+
+  // If the rule has an UNTIL, see if that is earlier than the end date.
+  if (!empty($rrule['UNTIL'])) {
+    $end_date = new DateObject($end, $timezone);
+    $until_date = date_ical_date($rrule['UNTIL'], $timezone);
+    if (date_format($until_date, 'U') < date_format($end_date, 'U')) {
+      $end_date = $until_date;
+    }
+  }
+  // The only valid option for an empty end date is when we have a count.
+  elseif (empty($end)) {
+    if (!empty($rrule['COUNT'])) {
+      $end_date = NULL;
+    }
+    else {
+      return array();
+    }
+  }
+  else {
+    $end_date = new DateObject($end, $timezone);
+  }
+
+  // Get an integer value for the interval, if none given, '1' is implied.
+  if (empty($rrule['INTERVAL'])) {
+    $rrule['INTERVAL'] = 1;
+  }
+  $interval = max(1, $rrule['INTERVAL']);
+  $count = isset($rrule['COUNT']) ? $rrule['COUNT'] : NULL;
+
+  if (empty($rrule['FREQ'])) {
+    $rrule['FREQ'] = 'DAILY';
+  }
+
+  // Make sure DAILY frequency isn't used in places it won't work;
+  if (!empty($rrule['BYMONTHDAY']) && !in_array($rrule['FREQ'], array('MONTHLY', 'YEARLY'))) {
+    $rrule['FREQ'] = 'MONTHLY';
+  }
+  elseif (!empty($rrule['BYDAY']) && !in_array($rrule['FREQ'], array('MONTHLY', 'WEEKLY', 'YEARLY'))) {
+    $rrule['FREQ'] = 'WEEKLY';
+   }
+
+  // Find the time period to jump forward between dates.
+  switch ($rrule['FREQ']) {
+   case 'DAILY':
+     $jump = $interval . ' days';
+     break;
+   case 'WEEKLY':
+     $jump = $interval . ' weeks';
+     break;
+   case 'MONTHLY':
+     $jump = $interval . ' months';
+     break;
+   case 'YEARLY':
+     $jump = $interval . ' years';
+     break;
+  }
+  $rrule = date_repeat_adjust_rrule($rrule, $start_date);
+
+  // The start date always goes into the results, whether or not it meets
+  // the rules. RFC 2445 includes examples where the start date DOES NOT
+  // meet the rules, but the expected results always include the start date.
+  $days = array(date_format($start_date, DATE_FORMAT_DATETIME));
+
+  // BYMONTHDAY will look for specific days of the month in one or more months.
+  // This process is only valid when frequency is monthly or yearly.
+
+  if (!empty($rrule['BYMONTHDAY'])) {
+    $finished = FALSE;
+    $current_day = clone($start_date);
+    $direction_days = array();
+    // Deconstruct the day in case it has a negative modifier.
+    foreach ($rrule['BYMONTHDAY'] as $day) {
+      preg_match("@(-)?([0-9]{1,2})@", $day, $regs);
+      if (!empty($regs[2])) {
+        // Convert parameters into full day name, count, and direction.
+        $direction_days[$day] = array(
+          'direction' => !empty($regs[1]) ? $regs[1] : '+',
+          'direction_count' => $regs[2],
+          );
+      }
+    }
+    while (!$finished) {
+      $period_finished = FALSE;
+      while (!$period_finished) {
+        foreach ($rrule['BYMONTHDAY'] as $monthday) {
+          $day = $direction_days[$monthday];
+          $current_day = date_repeat_set_month_day($current_day, NULL, $day['direction_count'], $day['direction'], $timezone, $modify_time);
+          date_repeat_add_dates($days, $current_day, $start_date, $end_date, $exceptions, $rrule);
+          if ($finished = date_repeat_is_finished($current_day, $days, $count, $end_date)) {
+            $period_finished = TRUE;
+          }
+        }
+        // If it's monthly, keep looping through months, one INTERVAL at a time.
+        if ($rrule['FREQ'] == 'MONTHLY') {
+          if ($finished = date_repeat_is_finished($current_day, $days, $count, $end_date)) {
+            $period_finished = TRUE;
+          }
+          // Back up to first of month and jump.
+          $current_day = date_repeat_set_month_day($current_day, NULL, 1, '+', $timezone, $modify_time);
+          date_modify($current_day, '+' . $jump . $modify_time);
+        }
+        // If it's yearly, break out of the loop at the
+        // end of every year, and jump one INTERVAL in years.
+        else {
+          if (date_format($current_day, 'n') == 12) {
+            $period_finished = TRUE;
+          }
+          else {
+            // Back up to first of month and jump.
+            $current_day = date_repeat_set_month_day($current_day, NULL, 1, '+', $timezone, $modify_time);
+            date_modify($current_day, '+1 month' . $modify_time);
+          }
+        }
+      }
+      if ($rrule['FREQ'] == 'YEARLY') {
+        // Back up to first of year and jump.
+        $current_day = date_repeat_set_year_day($current_day, NULL, 1, '+', $timezone, $modify_time);
+        date_modify($current_day, '+' . $jump . $modify_time);
+      }
+      $finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
+    }
+  }
+
+  // This is the simple fallback case, not looking for any BYDAY,
+  // just repeating the start date. Because of imputed BYDAY above, this
+  // will only test TRUE for a DAILY or less frequency (like HOURLY).
+
+  elseif (empty($rrule['BYDAY'])) {
+    // $current_day will keep track of where we are in the calculation.
+    $current_day = clone($start_date);
+    $finished = FALSE;
+    $months = !empty($rrule['BYMONTH']) ? $rrule['BYMONTH'] : array();
+    while (!$finished) {
+      date_repeat_add_dates($days, $current_day, $start_date, $end_date, $exceptions, $rrule);
+      $finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
+      date_modify($current_day, '+' . $jump . $modify_time);
+    }
+  }
+
+  else {
+
+    // More complex searches for day names and criteria like '-1SU' or '2TU,2TH',
+    // require that we interate through the whole time period checking each BYDAY.
+
+    // Create helper array to pull day names out of iCal day strings.
+    $day_names = date_repeat_dow_day_options(FALSE);
+    $days_of_week = array_keys($day_names);
+
+    // Parse out information about the BYDAYs and separate them
+    // depending on whether they have directional parameters like -1SU or 2TH.
+    $month_days = array();
+    $week_days = array();
+
+    // Find the right first day of the week to use, iCal rules say Monday
+    // should be used if none is specified.
+    $week_start_rule = !empty($rrule['WKST']) ? trim($rrule['WKST']) : 'MO';
+    $week_start_day = $day_names[$week_start_rule];
+
+    // Make sure the week days array is sorted into week order,
+    // we use the $ordered_keys to get the right values into the key
+    // and force the array to that order. Needed later when we
+    // iterate through each week looking for days so we don't
+    // jump to the next week when we hit a day out of order.
+    $ordered = date_repeat_days_ordered($week_start_rule);
+    $ordered_keys = array_flip($ordered);
+
+    foreach ($rrule['BYDAY'] as $day) {
+      preg_match("@(-)?([0-9]+)?([SU|MO|TU|WE|TH|FR|SA]{2})@", trim($day), $regs);
+      if (!empty($regs[2])) {
+        // Convert parameters into full day name, count, and direction.
+        $direction_days[] = array(
+          'day' => $day_names[$regs[3]],
+          'direction' => !empty($regs[1]) ? $regs[1] : '+',
+          'direction_count' => $regs[2],
+          );
+      }
+      else {
+        $week_days[$ordered_keys[$regs[3]]] = $day_names[$regs[3]];
+      }
+    }
+    ksort($week_days);
+
+    // BYDAYs with parameters like -1SU (last Sun) or 2TH (second Thur)
+    // need to be processed one month or year at a time.
+    if (!empty($direction_days) && in_array($rrule['FREQ'], array('MONTHLY', 'YEARLY'))) {
+      $finished = FALSE;
+      $current_day = clone($start_date);
+      while (!$finished) {
+        foreach ($direction_days as $day) {
+          // Find the BYDAY date in the current month.
+          if ($rrule['FREQ'] == 'MONTHLY') {
+            $current_day = date_repeat_set_month_day($current_day, $day['day'], $day['direction_count'], $day['direction'], $timezone, $modify_time);
+          }
+          else {
+            $current_day = date_repeat_set_year_day($current_day, $day['day'], $day['direction_count'], $day['direction'], $timezone, $modify_time);
+          }
+          date_repeat_add_dates($days, $current_day, $start_date, $end_date, $exceptions, $rrule);
+        }
+        $finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
+        // Reset to beginning of period before jumping to next period.
+        // Needed especially when working with values like 'last Saturday'
+        // to be sure we don't skip months like February.
+        $year = date_format($current_day, 'Y');
+        $month = date_format($current_day, 'n');
+        if ($rrule['FREQ'] == 'MONTHLY') {
+          date_date_set($current_day, $year, $month, 1);
+        }
+        else {
+          date_date_set($current_day, $year, 1, 1);
+        }
+        // Jump to the next period.
+        date_modify($current_day, '+' . $jump . $modify_time);
+      }
+    }
+
+    // For BYDAYs without parameters,like TU,TH (every Tues and Thur),
+    // we look for every one of those days during the frequency period.
+    // Iterate through periods of a WEEK, MONTH, or YEAR, checking for
+    // the days of the week that match our criteria for each week in the
+    // period, then jumping ahead to the next week, month, or year,
+    // an INTERVAL at a time.
+
+    if (!empty($week_days) && in_array($rrule['FREQ'], array('MONTHLY', 'WEEKLY', 'YEARLY'))) {
+      $finished = FALSE;
+      $current_day = clone($start_date);
+      $format = $rrule['FREQ'] == 'YEARLY' ? 'Y' : 'n';
+      $current_period = date_format($current_day, $format);
+
+      // Back up to the beginning of the week in case we are somewhere in the
+      // middle of the possible week days, needed so we don't prematurely
+      // jump to the next week. The date_repeat_add_dates() function will
+      // keep dates outside the range from getting added.
+      if (date_format($current_day, 'l') != $day_names[$day]) {
+        date_modify($current_day, '-1 ' . $week_start_day . $modify_time);
+      }
+      while (!$finished) {
+        $period_finished = FALSE;
+        while (!$period_finished) {
+          $moved = FALSE;
+          foreach ($week_days as $delta => $day) {
+            // Find the next occurence of each day in this week, only add it
+            // if we are still in the current month or year. The date_repeat_add_dates
+            // function is insufficient to test whether to include this date
+            // if we are using a rule like 'every other month', so we must
+            // explicitly test it here.
+
+            // If we're already on the right day, don't jump or we
+            // will prematurely move into the next week.
+            if (date_format($current_day, 'l') != $day) {
+              date_modify($current_day, '+1 ' . $day . $modify_time);
+              $moved = TRUE;
+            }
+            if ($rrule['FREQ'] == 'WEEKLY' || date_format($current_day, $format) == $current_period) {
+              date_repeat_add_dates($days, $current_day, $start_date, $end_date, $exceptions, $rrule);
+            }
+          }
+          $finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
+
+          // Make sure we don't get stuck in endless loop if the current
+          // day never got changed above.
+          if (!$moved) {
+            date_modify($current_day, '+1 day' . $modify_time);
+          }
+
+          // If this is a WEEKLY frequency, stop after each week,
+          // otherwise, stop when we've moved outside the current period.
+          // Jump to the end of the week, then test the period.
+          if ($finished || $rrule['FREQ'] == 'WEEKLY') {
+            $period_finished = TRUE;
+          }
+          elseif ($rrule['FREQ'] != 'WEEKLY' && date_format($current_day, $format) != $current_period) {
+            $period_finished = TRUE;
+          }
+        }
+
+        if ($finished) {
+          continue;
+        }
+
+        // We'll be at the end of a week, month, or year when
+        // we get to this point in the code.
+
+        // Go back to the beginning of this period before we jump, to
+        // ensure we jump to the first day of the next period.
+        switch ($rrule['FREQ']) {
+          case 'WEEKLY':
+            date_modify($current_day, '+1 ' . $week_start_day . $modify_time);
+            date_modify($current_day, '-1 week' . $modify_time);
+            break;
+          case 'MONTHLY':
+            date_modify($current_day, '-' . (date_format($current_day, 'j') - 1) . ' days' . $modify_time);
+            date_modify($current_day, '-1 month' . $modify_time);
+            break;
+          case 'YEARLY':
+            date_modify($current_day, '-' . date_format($current_day, 'z') . ' days' . $modify_time);
+            date_modify($current_day, '-1 year' . $modify_time);
+            break;
+        }
+        // Jump ahead to the next period to be evaluated.
+        date_modify($current_day, '+' . $jump . $modify_time);
+        $current_period = date_format($current_day, $format);
+        $finished = date_repeat_is_finished($current_day, $days, $count, $end_date);
+      }
+    }
+  }
+
+  // add additional dates
+  foreach ($additions as $addition) {
+    $date = new dateObject($addition . ' ' . $start_date->format('H:i:s'), $timezone);
+    $days[] = date_format($date, DATE_FORMAT_DATETIME);
+  }
+
+  sort($days);
+  return $days;
+}
+
+/**
+ * See if the RRULE needs some imputed values added to it.
+ */
+function date_repeat_adjust_rrule($rrule, $start_date) {
+  // If this is not a valid value, do nothing;
+  if (empty($rrule) || empty($rrule['FREQ'])) {
+    return array();
+  }
+
+  // RFC 2445 says if no day or monthday is specified when creating repeats for
+  // weeks, months, or years, impute the value from the start date.
+
+  if (empty($rrule['BYDAY']) && $rrule['FREQ'] == 'WEEKLY') {
+    $rrule['BYDAY'] = array(date_repeat_dow2day(date_format($start_date, 'w')));
+  }
+  elseif (empty($rrule['BYDAY']) && empty($rrule['BYMONTHDAY']) && $rrule['FREQ'] == 'MONTHLY') {
+    $rrule['BYMONTHDAY'] = array(date_format($start_date, 'j'));
+  }
+  elseif (empty($rrule['BYDAY']) && empty($rrule['BYMONTHDAY']) && empty($rrule['BYYEARDAY']) && $rrule['FREQ'] == 'YEARLY') {
+    $rrule['BYMONTHDAY'] = array(date_format($start_date, 'j'));
+    if (empty($rrule['BYMONTH'])) {
+      $rrule['BYMONTH'] = array(date_format($start_date, 'n'));
+    }
+  }
+  // If we are processing rules for period other than YEARLY or MONTHLY
+  // and have BYDAYS like 2SU or -1SA, simplify them to SU or SA since the
+  // position rules make no sense in other periods and just add complexity.
+
+  elseif (!empty($rrule['BYDAY']) && !in_array($rrule['FREQ'], array('MONTHLY', 'YEARLY'))) {
+    foreach ($rrule['BYDAY'] as $delta => $BYDAY) {
+      $rrule['BYDAY'][$delta] = substr($BYDAY, -2);
+    }
+  }
+
+  return $rrule;
+}
+
+/**
+ * Helper function to add found date to the $dates array.
+ *
+ * Check that the date to be added is between the start and end date
+ * and that it is not in the $exceptions, nor already in the $days array,
+ * and that it meets other criteria in the RRULE.
+ */
+function date_repeat_add_dates(&$days, $current_day, $start_date, $end_date, $exceptions, $rrule) {
+  if (isset($rrule['COUNT']) && sizeof($days) >= $rrule['COUNT']) {
+    return FALSE;
+  }
+  $formatted = date_format($current_day, DATE_FORMAT_DATETIME);
+  if (!empty($end_date) && $formatted > date_format($end_date, DATE_FORMAT_DATETIME)) {
+    return FALSE;
+  }
+  if ($formatted < date_format($start_date, DATE_FORMAT_DATETIME)) {
+    return FALSE;
+  }
+  if (in_array(date_format($current_day, 'Y-m-d'), $exceptions)) {
+    return FALSE;
+  }
+  if (!empty($rrule['BYDAY'])) {
+    $BYDAYS = $rrule['BYDAY'];
+    foreach ($BYDAYS as $delta => $BYDAY) {
+      $BYDAYS[$delta] = substr($BYDAY, -2);
+    }
+    if (!in_array(date_repeat_dow2day(date_format($current_day, 'w')), $BYDAYS)) {
+      return FALSE;
+    }}
+  if (!empty($rrule['BYYEAR']) && !in_array(date_format($current_day, 'Y'), $rrule['BYYEAR'])) {
+    return FALSE;
+  }
+  if (!empty($rrule['BYMONTH']) && !in_array(date_format($current_day, 'n'), $rrule['BYMONTH'])) {
+    return FALSE;
+  }
+  if (!empty($rrule['BYMONTHDAY'])) {
+    // Test month days, but only if there are no negative numbers.
+    $test = TRUE;
+    $BYMONTHDAYS = array();
+    foreach ($rrule['BYMONTHDAY'] as $day) {
+      if ($day > 0) {
+        $BYMONTHDAYS[] = $day;
+      }
+      else {
+        $test = FALSE;
+        break;
+      }
+    }
+    if ($test && !empty($BYMONTHDAYS) && !in_array(date_format($current_day, 'j'), $BYMONTHDAYS)) {
+      return FALSE;
+    }
+  }
+  // Don't add a day if it is already saved so we don't throw the count off.
+  if (in_array($formatted, $days)) {
+    return TRUE;
+  }
+  else {
+    $days[] = $formatted;
+  }
+}
+
+/**
+ * Stop when $current_day is greater than $end_date or $count is reached.
+ */
+function date_repeat_is_finished($current_day, $days, $count, $end_date) {
+  if (($count && sizeof($days) >= $count)
+  || (!empty($end_date) && date_format($current_day, 'U') > date_format($end_date, 'U'))) {
+    return TRUE;
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Set a date object to a specific day of the month.
+ *
+ * Example,
+ *   date_set_month_day($date, 'Sunday', 2, '-')
+ *   will reset $date to the second to last Sunday in the month.
+ *   If $day is empty, will set to the number of days from the
+ *   beginning or end of the month.
+ */
+function date_repeat_set_month_day($date_in, $day, $count = 1, $direction = '+', $timezone = 'UTC', $modify_time) {
+  if (is_object($date_in)) {
+    $current_month = date_format($date_in, 'n');
+
+    // Reset to the start of the month.
+    // We should be able to do this with date_date_set(), but
+    // for some reason the date occasionally gets confused if run
+    // through this function multiple times. It seems to work
+    // reliably if we create a new object each time.
+    $datetime = date_format($date_in, DATE_FORMAT_DATETIME);
+    $datetime = substr_replace($datetime, '01', 8, 2);
+    $date = new DateObject($datetime, $timezone);
+    if ($direction == '-') {
+      // For negative search, start from the end of the month.
+      date_modify($date, '+1 month' . $modify_time);
+    }
+    else {
+      // For positive search, back up one day to get outside the
+      // current month, so we can catch the first of the month.
+      date_modify($date, '-1 day' . $modify_time);
+    }
+
+    if (empty($day)) {
+      date_modify($date, $direction . $count . ' days' . $modify_time);
+    }
+    else {
+      // Use the English text for order, like First Sunday
+      // instead of +1 Sunday to overcome PHP5 bug, (see #369020).
+      $order = date_order();
+      $step = $count <= 5 ? $order[$direction . $count] : $count;
+      date_modify($date, $step . ' ' . $day . $modify_time);
+    }
+
+    // If that takes us outside the current month, don't go there.
+    if (date_format($date, 'n') == $current_month) {
+      return $date;
+    }
+  }
+  return $date_in;
+}
+
+/**
+ * Set a date object to a specific day of the year.
+ *
+ * Example,
+ *   date_set_year_day($date, 'Sunday', 2, '-')
+ *   will reset $date to the second to last Sunday in the year.
+ *   If $day is empty, will set to the number of days from the
+ *   beginning or end of the year.
+ */
+function date_repeat_set_year_day($date_in, $day, $count = 1, $direction = '+', $timezone = 'UTC', $modify_time) {
+  if (is_object($date_in)) {
+    $current_year = date_format($date_in, 'Y');
+
+    // Reset to the start of the month.
+    // See note above.
+    $datetime = date_format($date_in, DATE_FORMAT_DATETIME);
+    $datetime = substr_replace($datetime, '01-01', 5, 5);
+    $date = new DateObject($datetime, $timezone);
+    if ($direction == '-') {
+      // For negative search, start from the end of the year.
+      date_modify($date, '+1 year' . $modify_time);
+    }
+    else {
+      // For positive search, back up one day to get outside the
+      // current year, so we can catch the first of the year.
+      date_modify($date, '-1 day' . $modify_time);
+    }
+    if (empty($day)) {
+      date_modify($date, $direction . $count . ' days' . $modify_time);
+    }
+    else {
+      // Use the English text for order, like First Sunday
+      // instead of +1 Sunday to overcome PHP5 bug, (see #369020).
+      $order = date_order();
+      $step = $count <= 5 ? $order[$direction . $count] : $count;
+      date_modify($date, $step . ' ' . $day . $modify_time);
+    }
+
+    // If that takes us outside the current year, don't go there.
+    if (date_format($date, 'Y') == $current_year) {
+      return $date;
+    }
+  }
+  return $date_in;
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date_repeat/date_repeat_form.inc b/sites/all/modules/date/date_repeat/date_repeat_form.inc
new file mode 100644
index 0000000000000000000000000000000000000000..9cef000e5bbd2aebcc3822e5e60645d9a4d426f9
--- /dev/null
+++ b/sites/all/modules/date/date_repeat/date_repeat_form.inc
@@ -0,0 +1,977 @@
+<?php
+/**
+ * @file
+ * Code to add a date repeat selection form to a date field and create
+ * an iCal RRULE from the chosen selections.
+ *
+ * Moved to a separate file since it is not used on most pages
+ * so the code is not parsed unless needed.
+ *
+ * Currently implemented:
+ * INTERVAL, UNTIL, EXDATE, RDATE, BYDAY, BYMONTHDAY, BYMONTH,
+ * YEARLY, MONTHLY, WEEKLY, DAILY
+ *
+ * Currently not implemented:
+ *
+ * BYYEARDAY, MINUTELY, HOURLY, SECONDLY, BYMINUTE, BYHOUR, BYSECOND
+ *   These could be implemented in the future.
+ *
+ * COUNT
+ *   The goal of this module is to create a way we can parse an iCal
+ *   RRULE and pull out just dates for a specified date range, for
+ *   instance with a date that repeats daily for several years, we might
+ *   want to only be able to pull out the dates for the current year.
+ *
+ *   Adding COUNT to the rules we create makes it impossible to do that
+ *   without parsing and computing the whole range of dates that the rule
+ *   will create. COUNT is left off of the user form completely for this
+ *   reason.
+ *
+ * BYSETPOS
+ *   Seldom used anywhere, so no reason to complicated the code.
+ */
+/**
+ * Generate the repeat setting form.
+ */
+function _date_repeat_rrule_process($element, &$form_state, $form) {
+
+  // If the RRULE field is not visible to the user, needs no processing or validation.
+  // The Date field module is not adding this element to forms if the field is hidden,
+  // this test is just in case some other module attempts to do so.
+
+  if (date_hidden_element($element)) {
+    return $element;
+  }
+
+  module_load_include('inc', 'date_api', 'date_api_ical');
+  if (empty($element['#date_repeat_widget'])) {
+    $element['#date_repeat_widget'] = module_exists('date_popup') ? 'date_popup' : 'date_select';
+  }
+  if (is_array($element['#default_value'])) {
+    $element['#value'] = date_repeat_merge($element['#value'], $element);
+    $rrule = date_api_ical_build_rrule($element['#value']);
+  }
+  else {
+    $rrule = $element['#default_value'];
+  }
+
+  // Empty the original string value of the RRULE so we can create
+  // an array of values for the form from the RRULE's contents.
+  $element['#value'] = '';
+
+  $parts = date_repeat_split_rrule($rrule);
+  $rrule = $parts[0];
+
+  $exceptions = $parts[1];
+  $additions = $parts[2];
+  $timezone = !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone();
+  $merged_values = date_repeat_merge($rrule, $element);
+
+  $UNTIL = '';
+  if (!empty($merged_values['UNTIL']['datetime'])) {
+    $until_date = new DateObject($merged_values['UNTIL']['datetime'], $merged_values['UNTIL']['tz']);
+    date_timezone_set($until_date, timezone_open($timezone));
+    $UNTIL = date_format($until_date, DATE_FORMAT_DATETIME);
+  }
+
+  $COUNT = '';
+  if (!empty($merged_values['COUNT'])) {
+    $COUNT = $merged_values['COUNT'];
+  }
+
+  $element['FREQ'] = array(
+    '#type' => 'select',
+    '#title' => t('Repeats', array(), array('context' => 'Date repeat')),
+    '#default_value' => !empty($rrule['FREQ']) ? $rrule['FREQ'] : 'WEEKLY',
+    '#options' => date_repeat_freq_options(),
+    '#prefix' => '<div class="date-repeat-input">',
+    '#suffix' => '</div>',
+  );
+
+  $element['daily'] = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+    '#prefix' => '<div class="date-clear daily">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'visible' => array(
+        ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'DAILY'),
+      ),
+    ),
+  );
+
+  $element['weekly'] = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+    '#prefix' => '<div class="date-clear weekly">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'visible' => array(
+        ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'WEEKLY'),
+      ),
+    ),
+  );
+
+  $element['monthly'] = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+    '#prefix' => '<div class="date-clear monthly">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'visible' => array(
+        ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'MONTHLY'),
+      ),
+    ),
+  );
+
+  $element['yearly'] = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+    '#prefix' => '<div class="date-clear yearly">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'visible' => array(
+        ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'YEARLY'),
+      ),
+    ),
+  );
+
+  list($prefix, $suffix) = explode('@interval', t('Every @interval days', array(), array('context' => 'Date repeat')));
+  $DAILY_INTERVAL = array(
+    '#type' => 'textfield',
+    '#title' => t('Repeats', array(), array('context' => 'Date repeat')),
+    '#title_display' => 'invisible',
+    '#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1),
+    '#element_validate' => array('element_validate_integer_positive'),
+    '#attributes' => array('placeholder' => array('#')),
+    '#size' => 3,
+    '#maxlength' => 3,
+    '#prefix' => '<div class="date-clear">',
+    '#suffix' => t('days') . '</div>',
+    '#field_prefix' => $prefix,
+    '#field_suffix' => $suffix,
+  );
+
+  list($prefix, $suffix) = explode('@interval', t('Every @interval weeks', array(), array('context' => 'Date repeat')));
+  $element['weekly']['INTERVAL'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Repeats', array(), array('context' => 'Date repeat')),
+    '#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1),
+    '#element_validate' => array('element_validate_integer_positive'),
+    '#attributes' => array('placeholder' => array('#')),
+    '#size' => 3,
+    '#maxlength' => 3,
+    '#prefix' => '<div class="date-clear">',
+    '#suffix' => '</div>',
+    '#field_prefix' => $prefix,
+    '#field_suffix' => $suffix,
+  );
+
+  list($prefix, $suffix) = explode('@interval', t('Every @interval months', array(), array('context' => 'Date repeat')));
+  $element['monthly']['INTERVAL'] = array(
+    '#access' => FALSE,
+    '#type' => 'textfield',
+    '#title' => t('Repeats', array(), array('context' => 'Date repeat')),
+    '#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1),
+    '#element_validate' => array('element_validate_integer_positive'),
+    '#attributes' => array('placeholder' => array('#')),
+    '#size' => 3,
+    '#maxlength' => 3,
+    '#prefix' => '<div class="date-clear">',
+    '#suffix' => '</div>',
+    '#field_prefix' => $prefix,
+    '#field_suffix' => $suffix,
+  );
+
+  list($prefix, $suffix) = explode('@interval', t('Every @interval years', array(), array('context' => 'Date repeat')));
+  $element['yearly']['INTERVAL'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Repeats', array(), array('context' => 'Date repeat')),
+    '#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1),
+    '#element_validate' => array('element_validate_integer_positive'),
+    '#attributes' => array('placeholder' => array('#')),
+    '#size' => 3,
+    '#maxlength' => 3,
+    '#prefix' => '<div class="date-clear">',
+    '#suffix' => '</div>',
+    '#field_prefix' => $prefix,
+    '#field_suffix' => $suffix,
+  );
+  $options = date_repeat_dow_day_options_abbr(TRUE);
+  $options = date_repeat_dow_day_options_ordered($options);
+  $element['weekly']['BYDAY'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Repeat on', array(), array('context' => 'Date repeat')),
+    '#default_value' => !empty($rrule['BYDAY']) && $rrule['FREQ'] === 'WEEKLY' ? $rrule['BYDAY'] : array(),
+    '#options' => $options,
+    '#attributes' => array('class' => array('container-inline byday')),
+    '#multiple' => TRUE,
+    '#prefix' => '<div class="date-clear">',
+    '#suffix' => '</div>',
+  );
+
+  $DAILY_radios_default = 'INTERVAL';
+  if (isset($rrule['FREQ']) && $rrule['FREQ'] === 'DAILY' && !empty($rrule['BYDAY'])) {
+    switch (count($rrule['BYDAY'])) {
+      case 2:
+        $DAILY_radios_default = 'every_tu_th';
+        break;
+      case 3:
+        $DAILY_radios_default = 'every_mo_we_fr';
+        break;
+      case 5:
+        $DAILY_radios_default = 'every_weekday';
+        break;
+    }
+  }
+
+  $DAILY_every_weekday = array(
+    '#type' => 'item',
+    '#markup' => '<div>' . t('Every weekday', array(), array('context' => 'Date repeat')) . '</div>',
+  );
+
+  $DAILY_mo_we_fr = array(
+    '#type' => 'item',
+    '#markup' => '<div>' . t('Every Mon, Wed, Fri', array(), array('context' => 'Date repeat')) . '</div>',
+  );
+
+  $DAILY_tu_th = array(
+    '#type' => 'item',
+    '#markup' => '<div>' . t('Every Tue, Thu', array(), array('context' => 'Date repeat')) . '</div>',
+  );
+
+  $element['daily']['byday_radios'] = array(
+    '#type' => 'date_repeat_form_element_radios',
+    '#tree' => TRUE,
+    '#title' => t('Repeats every', array(), array('context' => 'Date repeat')),
+    '#prefix' => '<div class="date-clear">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'visible' => array(
+        ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'DAILY'),
+      ),
+    ),
+    '#default_value' => $DAILY_radios_default,
+    '#options' => array(
+      'INTERVAL' => t('interval'),
+      'every_weekday' => t('every weekday'),
+      'every_mo_we_fr' => t('monday wednesday friday'),
+      'every_tu_th' => t('tuesday thursday'),
+    ),
+    'INTERVAL_child' => $DAILY_INTERVAL,
+    'every_weekday_child' => $DAILY_every_weekday,
+    'mo_we_fr_child' => $DAILY_mo_we_fr,
+    'tu_th_child' => $DAILY_tu_th,
+    '#div_classes' => array(
+      'container-inline interval',
+      'container-inline weekday',
+      'container-inline mo-we-fr',
+      'container-inline tu-th',
+    ),
+  );
+
+  $MONTHLY_day_month_default = 'BYMONTHDAY_BYMONTH';
+  if (isset($rrule['FREQ']) && $rrule['FREQ'] === 'MONTHLY' && !empty($rrule['BYDAY'])) {
+    $MONTHLY_day_month_default = 'BYDAY_BYMONTH';
+  }
+
+  $MONTHLY_on_day_BYMONTHDAY_of_BYMONTH = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+  );
+
+  list($bymonthday_title, $bymonthday_suffix) = explode('@bymonthday', t('On day @bymonthday of', array(), array('context' => 'Date repeat')));
+  $MONTHLY_on_day_BYMONTHDAY_of_BYMONTH['BYMONTHDAY'] = array(
+    '#type' => 'select',
+    '#title' => $bymonthday_title,
+    '#default_value' => !empty($rrule['BYMONTHDAY']) && $rrule['FREQ'] === 'MONTHLY' ? $rrule['BYMONTHDAY'] : '',
+    '#options' => drupal_map_assoc(range(1, 31)) + drupal_map_assoc(range(-1, -31)),
+    '#multiple' => FALSE,
+    '#prefix' => '<div class="date-clear bymonthday">',
+    '#suffix' => '</div>',
+    '#field_suffix' => $bymonthday_suffix,
+  );
+
+  $MONTHLY_on_day_BYMONTHDAY_of_BYMONTH['BYMONTH'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Bymonth', array(), array('context' => 'Date repeat')),
+    '#title_display' => 'invisible',
+    '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'MONTHLY' && $MONTHLY_day_month_default === 'BYMONTHDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
+    '#options' => date_month_names_abbr(TRUE),
+    '#attributes' => array('class' => array('container-inline')),
+    '#multiple' => TRUE,
+    '#prefix' => '<div class="date-clear bymonth">',
+    '#suffix' => '</div>',
+  );
+
+  $MONTHLY_on_the_BYDAY_of_BYMONTH = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+  );
+
+  $MONTHLY_BYDAY_COUNT = '';
+  $MONTHLY_BYDAY_DAY = '';
+  if (isset($rrule['BYDAY']) && !empty($rrule['BYDAY']) && $rrule['FREQ'] === 'MONTHLY') {
+    $MONTHLY_BYDAY_COUNT = substr($rrule['BYDAY'][0], 0, -2);
+    $MONTHLY_BYDAY_DAY = substr($rrule['BYDAY'][0], -2);;
+  }
+
+  list($byday_count_title, $byday_day_title) = explode('@byday', t('On the @byday of', array(), array('context' => 'Date repeat')));
+  $MONTHLY_on_the_BYDAY_of_BYMONTH['BYDAY_COUNT'] = array(
+    '#type' => 'select',
+    '#title' => $byday_count_title,
+    '#default_value' => !empty($MONTHLY_BYDAY_COUNT) ? $MONTHLY_BYDAY_COUNT : '',
+    '#options' => date_order_translated(),
+    '#multiple' => FALSE,
+    '#prefix' => '<div class="date-repeat-input byday-count">',
+    '#suffix' => '</div>',
+  );
+
+  $MONTHLY_on_the_BYDAY_of_BYMONTH['BYDAY_DAY'] = array(
+    '#type' => 'select',
+    '#title' => $byday_day_title,
+    '#title_display' => 'after',
+    '#default_value' => !empty($MONTHLY_BYDAY_DAY) ? $MONTHLY_BYDAY_DAY : '',
+    '#options' => date_repeat_dow_day_options(TRUE),
+    '#multiple' => FALSE,
+    '#prefix' => '<div class="date-repeat-input byday-day">',
+    '#suffix' => '</div>',
+  );
+
+  $MONTHLY_on_the_BYDAY_of_BYMONTH['BYMONTH'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Bymonth', array(), array('context' => 'Date repeat')),
+    '#title_display' => 'invisible',
+    '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'MONTHLY' && $MONTHLY_day_month_default === 'BYDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
+    '#options' => date_month_names_abbr(TRUE),
+    '#attributes' => array('class' => array('container-inline')),
+    '#multiple' => TRUE,
+    '#prefix' => '<div class="date-clear bymonth">',
+    '#suffix' => '</div>',
+  );
+
+  $element['monthly']['day_month'] = array(
+    '#type' => 'date_repeat_form_element_radios',
+    '#tree' => TRUE,
+    '#prefix' => '<div class="date-clear">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'visible' => array(
+        ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'MONTHLY'),
+      ),
+    ),
+    '#attributes' => array('class' => array('date-repeat-radios clearfix')),
+    '#default_value' => $MONTHLY_day_month_default,
+    '#options' => array(
+      'BYMONTHDAY_BYMONTH' => t('On day ... of ...'),
+      'BYDAY_BYMONTH' => t('On the ... of ...'),
+    ),
+    'BYMONTHDAY_BYMONTH_child' => $MONTHLY_on_day_BYMONTHDAY_of_BYMONTH,
+    'BYDAY_BYMONTH_child' => $MONTHLY_on_the_BYDAY_of_BYMONTH,
+    '#div_classes' => array(
+      'date-repeat-radios-item date-clear clearfix bymonthday-bymonth',
+      'date-repeat-radios-item date-clear clearfix byday-bymonth',
+    ),
+  );
+
+  $YEARLY_day_month_default = 'BYMONTHDAY_BYMONTH';
+  if (isset($rrule['FREQ']) && $rrule['FREQ'] === 'YEARLY' && !empty($rrule['BYDAY'])) {
+    $YEARLY_day_month_default = 'BYDAY_BYMONTH';
+  }
+
+  $YEARLY_on_day_BYMONTHDAY_of_BYMONTH = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+  );
+
+  list($bymonthday_title, $bymonthday_suffix) = explode('@bymonthday', t('On day @bymonthday of', array(), array('context' => 'Date repeat')));
+  $YEARLY_on_day_BYMONTHDAY_of_BYMONTH['BYMONTHDAY'] = array(
+    '#type' => 'select',
+    '#title' => $bymonthday_title,
+    '#default_value' => !empty($rrule['BYMONTHDAY']) && $rrule['FREQ'] === 'YEARLY' ? $rrule['BYMONTHDAY'] : '',
+    '#options' => drupal_map_assoc(range(1, 31)) + drupal_map_assoc(range(-1, -31)),
+    '#multiple' => FALSE,
+    '#prefix' => '<div class="date-clear bymonthday">',
+    '#suffix' => '</div>',
+    '#field_suffix' => $bymonthday_suffix,
+  );
+
+  $YEARLY_on_day_BYMONTHDAY_of_BYMONTH['BYMONTH'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Bymonth', array(), array('context' => 'Date repeat')),
+    '#title_display' => 'invisible',
+    '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'YEARLY' && $YEARLY_day_month_default === 'BYMONTHDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
+    '#options' => date_month_names_abbr(TRUE),
+    '#attributes' => array('class' => array('container-inline')),
+    '#multiple' => TRUE,
+    '#prefix' => '<div class="date-clear bymonth">',
+    '#suffix' => '</div>',
+  );
+
+  $YEARLY_on_the_BYDAY_of_BYMONTH = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+  );
+
+  $YEARLY_BYDAY_COUNT = '';
+  $YEARLY_BYDAY_DAY = '';
+  if (isset($rrule['BYDAY']) && !empty($rrule['BYDAY']) && $rrule['FREQ'] === 'YEARLY') {
+    $YEARLY_BYDAY_COUNT = substr($rrule['BYDAY'][0], 0, -2);
+    $YEARLY_BYDAY_DAY = substr($rrule['BYDAY'][0], -2);;
+  }
+
+  list($byday_count_title, $byday_day_title) = explode('@byday', t('On the @byday of', array(), array('context' => 'Date repeat')));
+  $YEARLY_on_the_BYDAY_of_BYMONTH['BYDAY_COUNT'] = array(
+    '#type' => 'select',
+    '#title' => $byday_count_title,
+    '#default_value' => !empty($YEARLY_BYDAY_COUNT) ? $YEARLY_BYDAY_COUNT : '',
+    '#options' => date_order_translated(),
+    '#multiple' => FALSE,
+    '#prefix' => '<div class="date-repeat-input byday-count">',
+    '#suffix' => '</div>',
+  );
+
+  $YEARLY_on_the_BYDAY_of_BYMONTH['BYDAY_DAY'] = array(
+    '#type' => 'select',
+    '#title' => $byday_day_title,
+    '#title_display' => 'after',
+    '#default_value' => !empty($YEARLY_BYDAY_DAY) ? $YEARLY_BYDAY_DAY : '',
+    '#options' => date_repeat_dow_day_options(TRUE),
+    '#multiple' => FALSE,
+    '#prefix' => '<div class="date-repeat-input byday-day">',
+    '#suffix' => '</div>',
+  );
+
+  $YEARLY_on_the_BYDAY_of_BYMONTH['BYMONTH'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Bymonth', array(), array('context' => 'Date repeat')),
+    '#title_display' => 'invisible',
+    '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'YEARLY' && $YEARLY_day_month_default === 'BYDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
+    '#options' => date_month_names_abbr(TRUE),
+    '#attributes' => array('class' => array('container-inline')),
+    '#multiple' => TRUE,
+    '#prefix' => '<div class="date-clear bymonth">',
+    '#suffix' => '</div>',
+  );
+
+  $element['yearly']['day_month'] = array(
+    '#type' => 'date_repeat_form_element_radios',
+    '#tree' => TRUE,
+    '#prefix' => '<div class="date-clear">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'visible' => array(
+        ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'YEARLY'),
+      ),
+    ),
+    '#attributes' => array('class' => array('date-repeat-radios clearfix')),
+    '#default_value' => $YEARLY_day_month_default,
+    '#options' => array(
+      'BYMONTHDAY_BYMONTH' => t('On day ... of ...'),
+      'BYDAY_BYMONTH' => t('On the ... of ...'),
+    ),
+    'BYMONTHDAY_BYMONTH_child' => $YEARLY_on_day_BYMONTHDAY_of_BYMONTH,
+    'BYDAY_BYMONTH_child' => $YEARLY_on_the_BYDAY_of_BYMONTH,
+    '#div_classes' => array(
+      'date-repeat-radios-item date-clear clearfix bymonthday-bymonth',
+      'date-repeat-radios-item date-clear clearfix byday-bymonth',
+    ),
+  );
+
+  list($prefix, $suffix) = explode('@count', t('After @count occurrences', array(), array('context' => 'Date repeat')));
+  $count_form_element = array(
+    '#type' => 'textfield',
+    '#title' => t('Count', array(), array('context' => 'Date repeat')),
+    '#default_value' => $COUNT,
+    '#element_validate' => array('element_validate_integer_positive'),
+    '#attributes' => array('placeholder' => array('#')),
+    '#prefix' => $prefix,
+    '#suffix' => $suffix,
+    '#size' => 10,
+    '#maxlength' => 10,
+  );
+
+  $until_form_element = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+    '#prefix' => '<div class="date-prefix-inline">' . t('On', array(), array('context' => 'Date repeat')) . '</div>',
+    'datetime' => array(
+      '#type' => $element['#date_repeat_widget'],
+      '#title' => t('Until', array(), array('context' => 'Date repeat')),
+      '#title_display' => 'invisible',
+      '#default_value' => $UNTIL,
+      '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
+      '#date_timezone' => $timezone,
+      '#date_text_parts'  => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
+      '#date_year_range'  => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
+      '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
+      '#date_flexible' => 0,
+    ),
+    'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
+    'all_day' => array('#type' => 'hidden', '#value' => 1),
+    'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
+  );
+
+  $range_of_repeat_default = 'COUNT';
+  if (!empty($UNTIL)) {
+    $range_of_repeat_default = 'UNTIL';
+  }
+  $element['range_of_repeat'] = array(
+    '#type' => 'date_repeat_form_element_radios',
+    '#tree' => TRUE,
+    '#title' => t('Stop repeating', array(), array('context' => 'Date repeat')),
+    '#title_display' => 'before',
+    '#prefix' => '<div class="date-clear range-of-repeat">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'invisible' => array(
+        ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'NONE'),
+      ),
+    ),
+    '#default_value' =>  $range_of_repeat_default,
+    '#options' => array(
+      'COUNT' => t('Count'),
+      'UNTIL' => t('Until'),
+    ),
+    'count_child' => $count_form_element,
+    'until_child' => $until_form_element,
+    '#div_classes' => array(
+      'container-inline count',
+      "until widget-{$element['#date_repeat_widget']} label-{$element['#date_label_position']}",
+    ),
+  );
+
+  $parents = $element['#array_parents'];
+  $instance = implode('-', $parents);
+
+  // Make sure this will work right either in the normal form or in an ajax callback from the 'Add more' button.
+  if (empty($form_state['num_exceptions'][$instance])) {
+    $form_state['num_exceptions'][$instance] = count($exceptions);
+  }
+  if ($form_state['num_exceptions'][$instance] == 0) {
+    $collapsed = TRUE;
+  }
+  else {
+    $collapsed = FALSE;
+  }
+
+  $element['show_exceptions'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Exclude dates', array(), array('context' => 'Date repeat')),
+    '#states' => array(
+      'invisible' => array(
+        ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'NONE'),
+      ),
+    ),
+    '#default_value' => empty($form_state['num_exceptions'][$instance]) ? 0 : 1,
+  );
+
+  $element['exceptions'] = array(
+    '#type' => 'container',
+    '#prefix' => '<div id="date-repeat-exceptions-' . $instance . '" class="date-repeat">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'visible' => array(
+        ":input[name=\"{$element['#name']}[show_exceptions]\"]" => array('checked' => TRUE),
+      ),
+    ),
+  );
+  for ($i = 0; $i < max($form_state['num_exceptions'][$instance], 1) ; $i++) {
+    $EXCEPT = '';
+    if (!empty($exceptions[$i]['datetime'])) {
+      $ex_date = new DateObject($exceptions[$i]['datetime'], $exceptions[$i]['tz']);
+      date_timezone_set($ex_date, timezone_open($timezone));
+      $EXCEPT = date_format($ex_date, DATE_FORMAT_DATETIME);
+    }
+    $element['exceptions']['EXDATE'][$i] = array(
+      '#tree' => TRUE,
+      'datetime' => array(
+        '#name' => 'exceptions|' . $instance,
+        '#type' => $element['#date_repeat_widget'],
+        '#default_value' => $EXCEPT,
+        '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone(),
+        '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
+        '#date_text_parts'  => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
+        '#date_year_range'  => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
+        '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
+        '#date_flexible' => 0,
+        ),
+      'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
+      'all_day' => array('#type' => 'hidden', '#value' => 1),
+      'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
+      );
+  }
+
+  // collect additions in the same way as exceptions - implements RDATE.
+  if (empty($form_state['num_additions'][$instance])) {
+    $form_state['num_additions'][$instance] = count($additions);
+  }
+  if ($form_state['num_additions'][$instance] == 0) {
+    $collapsed = TRUE;
+  }
+  else {
+    $collapsed = FALSE;
+  }
+
+  $element['show_additions'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Include dates', array(), array('context' => 'Date repeat')),
+    '#states' => array(
+      'invisible' => array(
+        ":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'NONE'),
+      ),
+    ),
+    '#default_value' => empty($form_state['num_additions'][$instance]) ? 0 : 1,
+  );
+
+  $element['additions'] = array(
+    '#type' => 'container',
+    '#prefix' => '<div id="date-repeat-additions-' . $instance . '" class="date-repeat">',
+    '#suffix' => '</div>',
+    '#states' => array(
+      'visible' => array(
+        ":input[name=\"{$element['#name']}[show_additions]\"]" => array('checked' => TRUE),
+      ),
+    ),
+  );
+  for ($i = 0; $i < max($form_state['num_additions'][$instance], 1) ; $i++) {
+    $RDATE = '';
+    if (!empty($additions[$i]['datetime'])) {
+      $rdate = new DateObject($additions[$i]['datetime'], $additions[$i]['tz']);
+      date_timezone_set($rdate, timezone_open($timezone));
+      $RDATE = date_format($rdate, DATE_FORMAT_DATETIME);
+    }
+    $element['additions']['RDATE'][$i] = array(
+      '#tree' => TRUE,
+      'datetime' => array(
+        '#type' => $element['#date_repeat_widget'],
+        '#name' => 'additions|' . $instance,
+        '#default_value' => $RDATE,
+        '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone(),
+        '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
+        '#date_text_parts'  => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
+        '#date_year_range'  => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
+        '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
+        '#date_flexible' => 0,
+        ),
+      'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
+      'all_day' => array('#type' => 'hidden', '#value' => 1),
+      'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
+      );
+  }
+
+  $element['exceptions']['exceptions_add'] = array(
+    '#type' => 'submit',
+    '#name' => 'exceptions_add|' . $instance,
+    '#value' => t('Add exception'),
+    '#submit' => array('date_repeat_add_exception'),
+    '#limit_validation_errors' => array(),
+    '#ajax' => array(
+      'callback' => 'date_repeat_add_exception_callback',
+      'wrapper' => 'date-repeat-exceptions-' . $instance,
+    ),
+  );
+  $element['additions']['additions_add'] = array(
+    '#type' => 'submit',
+    '#name' => 'additions_add|' . $instance,
+    '#value' => t('Add addition'),
+    '#submit' => array('date_repeat_add_addition'),
+    '#limit_validation_errors' => array(),
+    '#ajax' => array(
+      'callback' => 'date_repeat_add_addition_callback',
+      'wrapper' => 'date-repeat-additions-' . $instance,
+    ),
+  );
+
+  $element['#date_repeat_collapsed'] = !empty($rrule['INTERVAL']) || !empty($rrule['FREQ']) ? 0 : (!empty($element['#date_repeat_collapsed']) ? $element['#date_repeat_collapsed'] : 0);
+  return $element;
+}
+
+function date_repeat_add_exception_callback($form, &$form_state) {
+  $parents = $form_state['triggering_element']['#array_parents'];
+  $button_key = array_pop($parents);
+  $element = drupal_array_get_nested_value($form, $parents);
+  return $element;
+}
+
+function date_repeat_add_addition_callback($form, &$form_state) {
+  $parents = $form_state['triggering_element']['#array_parents'];
+  $button_key = array_pop($parents);
+  $element = drupal_array_get_nested_value($form, $parents);
+  return $element;
+}
+
+function date_repeat_add_exception($form, &$form_state) {
+  $parents = $form_state['triggering_element']['#array_parents'];
+  $instance = implode('-', array_slice($parents, 0, count($parents) - 2));
+  $form_state['num_exceptions'][$instance]++;
+  $form_state['rebuild'] = TRUE;
+}
+
+function date_repeat_add_addition($form, &$form_state) {
+  $parents = $form_state['triggering_element']['#array_parents'];
+  $instance = implode('-', array_slice($parents, 0, count($parents) - 2));
+  $form_state['num_additions'][$instance]++;
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Regroup values back into a consistant array, no matter what state it is in.
+ */
+function date_repeat_merge($form_values, $element) {
+  if (empty($form_values) || !is_array($form_values)) {
+    return $form_values;
+  }
+  if (array_key_exists('exceptions', $form_values) || array_key_exists('additions', $form_values)) {
+    if (!array_key_exists('exceptions', $form_values)) $form_values['exceptions'] = array();
+    if (!array_key_exists('additions', $form_values)) $form_values['additions'] = array();
+    $form_values = array_merge($form_values, (array) $form_values['exceptions'], (array) $form_values['additions']);
+    unset($form_values['exceptions']);
+    unset($form_values['additions']);
+  }
+
+  if (array_key_exists('FREQ', $form_values)) {
+    switch ($form_values['FREQ']) {
+      case 'DAILY':
+        if (array_key_exists('daily', $form_values)) {
+          switch ($form_values['daily']['byday_radios']) {
+            case 'INTERVAL':
+              $form_values['INTERVAL'] = $form_values['daily']['INTERVAL_child'];
+              break;
+            case 'every_weekday':
+              $form_values['BYDAY'] = array('MO', 'TU', 'WE', 'TH', 'FR');
+              break;
+            case 'every_mo_we_fr':
+              $form_values['BYDAY'] = array('MO', 'WE', 'FR');
+              break;
+            case 'every_tu_th':
+              $form_values['BYDAY'] = array('TU', 'TH');
+              break;
+          }
+        }
+        break;
+      case 'WEEKLY':
+        if (array_key_exists('weekly', $form_values)) {
+          $form_values = array_merge($form_values, (array) $form_values['weekly']);
+          if (array_key_exists('BYDAY', $form_values)) {
+            $form_values['BYDAY'] = date_repeat_transform_checkbox_values_to_select_values($form_values['BYDAY']);
+          }
+        }
+        break;
+      case 'MONTHLY':
+        if (array_key_exists('monthly', $form_values)) {
+          switch ($form_values['monthly']['day_month']) {
+            case 'BYMONTHDAY_BYMONTH':
+              $form_values['monthly'] = array_merge($form_values['monthly'], (array) $form_values['monthly']['BYMONTHDAY_BYMONTH_child']);
+              break;
+            case 'BYDAY_BYMONTH':
+              $form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY'] = $form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY_COUNT'] . $form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY_DAY'];
+              $form_values['monthly'] = array_merge($form_values['monthly'], (array) $form_values['monthly']['BYDAY_BYMONTH_child']);
+              break;
+          }
+          unset($form_values['monthly']['BYDAY_BYMONTH_child']);
+          unset($form_values['monthly']['BYMONTHDAY_BYMONTH_child']);
+          $form_values = array_merge($form_values, (array) $form_values['monthly']);
+          if (array_key_exists('BYMONTH', $form_values)) {
+            $form_values['BYMONTH'] = date_repeat_transform_checkbox_values_to_select_values($form_values['BYMONTH']);
+          }
+          if (array_key_exists('BYMONTHDAY', $form_values) && !is_array($form_values['BYMONTHDAY'])) {
+            $form_values['BYMONTHDAY'] = (array) $form_values['BYMONTHDAY'];
+          }
+          if (array_key_exists('BYDAY', $form_values) && !is_array($form_values['BYDAY'])) {
+            $form_values['BYDAY'] = (array) $form_values['BYDAY'];
+          }
+        }
+        break;
+      case 'YEARLY':
+        if (array_key_exists('yearly', $form_values)) {
+          switch ($form_values['yearly']['day_month']) {
+            case 'BYMONTHDAY_BYMONTH':
+              $form_values['yearly'] = array_merge($form_values['yearly'], (array) $form_values['yearly']['BYMONTHDAY_BYMONTH_child']);
+              break;
+            case 'BYDAY_BYMONTH':
+              $form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY'] = $form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY_COUNT'] . $form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY_DAY'];
+              $form_values['yearly'] = array_merge($form_values['yearly'], (array) $form_values['yearly']['BYDAY_BYMONTH_child']);
+              break;
+          }
+          unset($form_values['yearly']['BYDAY_BYMONTH_child']);
+          unset($form_values['yearly']['BYMONTHDAY_BYMONTH_child']);
+          $form_values = array_merge($form_values, (array) $form_values['yearly']);
+          if (array_key_exists('BYMONTH', $form_values)) {
+            $form_values['BYMONTH'] = date_repeat_transform_checkbox_values_to_select_values($form_values['BYMONTH']);
+          }
+          if (array_key_exists('BYMONTHDAY', $form_values) && !is_array($form_values['BYMONTHDAY'])) {
+            $form_values['BYMONTHDAY'] = (array) $form_values['BYMONTHDAY'];
+          }
+          if (array_key_exists('BYDAY', $form_values) && !is_array($form_values['BYDAY'])) {
+            $form_values['BYDAY'] = (array) $form_values['BYDAY'];
+          }
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  unset($form_values['daily']);
+  unset($form_values['weekly']);
+  unset($form_values['monthly']);
+  unset($form_values['yearly']);
+
+  if (array_key_exists('range_of_repeat', $form_values)) {
+    switch ($form_values['range_of_repeat']) {
+      case 'COUNT':
+        $form_values['COUNT'] = $form_values['count_child'];
+        break;
+      case 'UNTIL':
+        $form_values['UNTIL'] = $form_values['until_child'];
+        break;
+    }
+  }
+
+  unset($form_values['count_child']);
+  unset($form_values['until_child']);
+
+  if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) unset($form_values['BYDAY']['']);
+  if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH'])) unset($form_values['BYMONTH']['']);
+  if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY'])) unset($form_values['BYMONTHDAY']['']);
+
+  if (array_key_exists('UNTIL', $form_values) && is_array($form_values['UNTIL']['datetime'])) {
+    $function = $element['#date_repeat_widget'] . '_input_date';
+    $until_element = $element;
+    $until_element['#date_format'] = !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
+    $date = $function($until_element, $form_values['UNTIL']['datetime']);
+    $form_values['UNTIL']['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
+  }
+  if (array_key_exists('show_exceptions', $form_values) && $form_values['show_exceptions'] === 0) {
+    unset($form_values['EXDATE']);
+  }
+  if (array_key_exists('EXDATE', $form_values) && is_array($form_values['EXDATE'])) {
+    $function = $element['#date_repeat_widget'] . '_input_date';
+    $exdate_element = $element;
+    foreach ($form_values['EXDATE'] as $delta => $value) {
+      if (is_array($value['datetime'])) {
+        $exdate_element['#date_format'] = !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
+        $date = $function($exdate_element, $form_values['EXDATE'][$delta]['datetime']);
+        $form_values['EXDATE'][$delta]['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
+      }
+    }
+  }
+
+  if (array_key_exists('show_additions', $form_values) && $form_values['show_additions'] === 0) {
+    unset($form_values['RDATE']);
+  }
+  if (array_key_exists('RDATE', $form_values) && is_array($form_values['RDATE'])) {
+    $function = $element['#date_repeat_widget'] . '_input_date';
+    $rdate_element = $element;
+    foreach ($form_values['RDATE'] as $delta => $value) {
+      if (is_array($value['datetime'])) {
+        $rdate_element['#date_format'] = !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
+        $date = $function($rdate_element, $form_values['RDATE'][$delta]['datetime']);
+        $form_values['RDATE'][$delta]['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
+      }
+    }
+  }
+  return $form_values;
+}
+
+/**
+ * Build a RRULE out of the form values.
+ */
+function date_repeat_rrule_validate($element, &$form_state) {
+
+  if (date_hidden_element($element)) {
+    return;
+  }
+
+  $parents = $element['#parents'];
+  array_pop($parents);
+  $field_values = drupal_array_get_nested_value($form_state['values'], $parents);
+  if ($field_values['show_repeat_settings'] === 0 || $field_values['rrule']['FREQ'] === 'NONE') {
+    form_set_value($element, NULL, $form_state);
+    return;
+  }
+
+  // Clean the buttons off of the form. Needed to avoid errors when
+  // the date is used on a user object, which then passes the form
+  // through form_state_values_clean().
+  foreach ($form_state['buttons'] as $delta => $item) {
+    if (!empty($item['#ajax']['callback']) && in_array($item['#ajax']['callback'], array('date_repeat_add_exception_callback', 'date_repeat_add_addition_callback'))) {
+      unset($form_state['buttons'][$delta]);
+    }
+  }
+
+  module_load_include('inc', 'date_api', 'date_api_ical');
+
+  $item = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
+  $item = date_repeat_merge($item, $element);
+  $rrule = date_api_ical_build_rrule($item);
+  form_set_value($element, $rrule, $form_state);
+}
+
+/**
+ * Theme the exception list as a table so the buttons line up
+ */
+function theme_date_repeat_current_exceptions($vars) {
+  $rows = $vars['rows'];
+  $rows_info = array();
+  foreach ($rows as $key => $value) {
+    if (substr($key, 0, 1) != '#') {
+      $rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
+    }
+  }
+  return theme('table', array('header' => array(t('Delete'), t('Current exceptions')), 'rows' => $rows_info));
+}
+
+ /**
+ * Theme the exception list as a table so the buttons line up
+ */
+function theme_date_repeat_current_additions($rows = array()) {
+  $rows_info = array();
+  foreach ($rows as $key => $value) {
+    if (substr($key, 0, 1) != '#') {
+      $rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
+    }
+  }
+  return theme('table', array('header' => array(t('Delete'), t('Current additions')), 'rows' => $rows_info));
+}
+
+/**
+ * Wrapper fieldset for repeat rule.
+ */
+function theme_date_repeat_rrule($vars) {
+  $element = $vars['element'];
+  $class = $element['#date_repeat_collapsed'] ? array('date-no-float', 'collapsible', 'collapsed') : array('date-no-float', 'collapsible');
+  $id = drupal_html_id('repeat-settings-fieldset');
+  $parents = $element['#parents'];
+  $selector = "{$parents[0]}[{$parents[1]}][{$parents[2]}][show_repeat_settings]";
+  $fieldset = array(
+    '#type' => 'item',
+    '#title' => t('Repeat settings'),
+    '#title_display' => 'invisible',
+    '#attributes' => array('class' => $class),
+    '#markup' => $element['#children'],
+    '#states' => array(
+      'visible' => array(
+        ":input[name=\"{$selector}\"]" => array('checked' => TRUE),
+      ),
+    ),
+    '#id' => $id,
+  );
+
+  return drupal_render($fieldset);
+}
+
+function date_repeat_filter_non_zero_value($value) {
+  return $value !== 0;
+}
+
+/**
+ * Helper function for transforming the return value of checkbox(es) element.
+ *
+ * Can be used for transforming the returned value of checkbox(es) element
+ * to the format of returned value of multiple select element.
+ */
+function date_repeat_transform_checkbox_values_to_select_values($values) {
+  return array_filter($values, 'date_repeat_filter_non_zero_value');
+}
diff --git a/sites/all/modules/date/date_repeat/tests/date_repeat.test b/sites/all/modules/date/date_repeat/tests/date_repeat.test
new file mode 100644
index 0000000000000000000000000000000000000000..fd46e8109e2606dd628e2e502e7f40508aac71fc
--- /dev/null
+++ b/sites/all/modules/date/date_repeat/tests/date_repeat.test
@@ -0,0 +1,455 @@
+<?php
+
+/**
+ * @file
+ * Test Date Repeat calculations.
+ */
+
+class DateRepeatTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('Date Repeat'),
+      'description' => t('Test Date Repeat functions to create arrays of dates from iCal rules.') ,
+      'group' => t('Date'),
+    );
+  }
+
+  /**
+   * Implements setUp().
+   */
+  public function setUp() {
+    // Load the date_repeat module.
+    parent::setUp('date_api', 'date_repeat');
+  }
+
+  public function testDateRepeat() {
+    require_once('./' . drupal_get_path('module', 'date_api') . '/date_api_ical.inc');
+    require_once('./' . drupal_get_path('module', 'date_repeat') . '/date_repeat_calc.inc');
+    // Examples adapted from http://www.faqs.org/rfcs/rfc2445.html and
+    // http://www.kanzaki.com/docs/ical/rrule.html.
+
+    //  Invalid value:
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=NONE;INTERVAL=0;COUNT=10";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    //  should be (1997 9:00 AM EDT)September 2-11
+    $shouldbe = '';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //  Daily for 10 occurrences:
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=DAILY;COUNT=10";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    //  should be (1997 9:00 AM EDT)September 2-11
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-03 09:00:00, 1997-09-04 09:00:00, 1997-09-05 09:00:00, 1997-09-06 09:00:00, 1997-09-07 09:00:00, 1997-09-08 09:00:00, 1997-09-09 09:00:00, 1997-09-10 09:00:00, 1997-09-11 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Daily until September 24, 1997:
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=DAILY;UNTIL=19970924T000000Z";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    //  should be (1997 9:00 AM EDT)September 2-23
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-03 09:00:00, 1997-09-04 09:00:00, 1997-09-05 09:00:00, 1997-09-06 09:00:00, 1997-09-07 09:00:00, 1997-09-08 09:00:00, 1997-09-09 09:00:00, 1997-09-10 09:00:00, 1997-09-11 09:00:00, 1997-09-12 09:00:00, 1997-09-13 09:00:00, 1997-09-14 09:00:00, 1997-09-15 09:00:00, 1997-09-16 09:00:00, 1997-09-17 09:00:00, 1997-09-18 09:00:00, 1997-09-19 09:00:00, 1997-09-20 09:00:00, 1997-09-21 09:00:00, 1997-09-22 09:00:00, 1997-09-23 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every other day - until September 30:
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=DAILY;INTERVAL=2";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    // should be (1997 9:00 AM EDT)September2,4,6,8...24,26,28,30;
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-04 09:00:00, 1997-09-06 09:00:00, 1997-09-08 09:00:00, 1997-09-10 09:00:00, 1997-09-12 09:00:00, 1997-09-14 09:00:00, 1997-09-16 09:00:00, 1997-09-18 09:00:00, 1997-09-20 09:00:00, 1997-09-22 09:00:00, 1997-09-24 09:00:00, 1997-09-26 09:00:00, 1997-09-28 09:00:00, 1997-09-30 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every 10 days, 2 occurrences:
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=DAILY;INTERVAL=10;COUNT=2";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    //  should be (1997 9:00 AM EDT)September 2,12
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-12 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Weekly for 3 occurrences
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=WEEKLY;COUNT=3";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    //  should be (1997 9:00 AM EDT)September 2,9,16
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-09 09:00:00, 1997-09-16 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Weekly until September 24, 1997
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=WEEKLY;UNTIL=19970924T000000Z";
+    //  ==> (1997 9:00 AM EDT)September 2,9,16,23
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-09 09:00:00, 1997-09-16 09:00:00, 1997-09-23 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every other week - forever:
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU";
+    //  should be (1997 9:00 AM EDT)September 2,16,30
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-16 09:00:00, 1997-09-30 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Weekly on Tuesday and Thursday for 4 weeks:
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=WEEKLY;COUNT=8;WKST=SU;BYDAY=TU,TH";
+    // should be(1997 9:00 AM EDT)September 2,4,9,11,16,18,23,25
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-04 09:00:00, 1997-09-09 09:00:00, 1997-09-11 09:00:00, 1997-09-16 09:00:00, 1997-09-18 09:00:00, 1997-09-23 09:00:00, 1997-09-25 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every other week on Tuesday and Thursday, for 5 occurrences:
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=5;WKST=SU;BYDAY=TU,TH";
+    //  should be  (1997 9:00 AM EDT)September 2,4,16,18,30
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-04 09:00:00, 1997-09-16 09:00:00, 1997-09-18 09:00:00, 1997-09-30 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every other week on Monday, Wednesday and Friday until September 24, 1997,
+    $start = "1997-09-02 09:00:00";
+    $end = "1997-09-30 09:00:00";
+    $rule = "RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19970924T000000Z;WKST=SU;BYDAY=MO,WE,FR";
+    // should be (1997 9:00 AM EDT)September 2,3,5,15,17,19
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-03 09:00:00, 1997-09-05 09:00:00, 1997-09-15 09:00:00, 1997-09-17 09:00:00, 1997-09-19 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Monthly on the 1st Friday for 2 occurrences:
+    $start = "1997-09-05 09:00:00";
+    $end = "1997-10-31 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;COUNT=2;BYDAY=1FR";
+    //  should be (1997 9:00 AM EDT)September 5;October 3
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-05 09:00:00, 1997-10-03 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Monthly on the 1st Friday until December 24, 1997:
+    $start = "1997-09-05 09:00:00";
+    $end = "1998-10-01 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-05 09:00:00, 1997-10-03 09:00:00, 1997-11-07 09:00:00, 1997-12-05 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every other month on the 1st and last Sunday of the month for 10 occurrences:
+    $start = "1997-09-07 09:00:00";
+    $end = "1998-10-01 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU";
+    //  ==> (1997 9:00 AM EDT)September 7,28
+    //      (1997 9:00 AM EST)November 2,30
+    //      (1998 9:00 AM EST)January 4,25;March 1,29
+    //      (1998 9:00 AM EDT)May 3,31
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-07 09:00:00, 1997-09-28 09:00:00, 1997-11-02 09:00:00, 1997-11-30 09:00:00, 1998-01-04 09:00:00, 1998-01-25 09:00:00, 1998-03-01 09:00:00, 1998-03-29 09:00:00, 1998-05-03 09:00:00, 1998-05-31 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Monthly on the second to last Monday of the month for 6 months:
+    $start = "1997-09-22 09:00:00";
+    $end = "1998-10-01 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;COUNT=6;BYDAY=-2MO";
+    //==> (1997 9:00 AM EDT)September 22;October 20
+    //  (1997 9:00 AM EST)November 17;December 22
+    //  (1998 9:00 AM EST)January 19;February 16
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-22 09:00:00, 1997-10-20 09:00:00, 1997-11-17 09:00:00, 1997-12-22 09:00:00, 1998-01-19 09:00:00, 1998-02-16 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every Tuesday, every other month:
+    $start = "1997-09-02 09:00:00";
+    $end = "1998-02-01 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU";
+    //  ==> (1997 9:00 AM EDT)September 2,9,16,23,30
+    //      (1997 9:00 AM EST)November 4,11,18,25
+    //      (1998 9:00 AM EST)January 6,13,20,27;March 3,10,17,24,31
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-09 09:00:00, 1997-09-16 09:00:00, 1997-09-23 09:00:00, 1997-09-30 09:00:00, 1997-11-04 09:00:00, 1997-11-11 09:00:00, 1997-11-18 09:00:00, 1997-11-25 09:00:00, 1998-01-06 09:00:00, 1998-01-13 09:00:00, 1998-01-20 09:00:00, 1998-01-27 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Yearly in June and July for 10 occurrences:
+    $start = "1997-06-10 09:00:00";
+    $end = "2002-01-01 09:00:00";
+    $rule = "RRULE:FREQ=YEARLY;COUNT=10;BYMONTH=6,7";
+    //  ==> (1997 9:00 AM EDT)June 10;July 10
+    //      (1998 9:00 AM EDT)June 10;July 10
+    //      (1999 9:00 AM EDT)June 10;July 10
+    //      (2000 9:00 AM EDT)June 10;July 10
+    //      (2001 9:00 AM EDT)June 10;July 10
+    //  Note: Since none of the BYDAY, BYMONTHDAY or BYYEARDAY components
+    //  are specified, the day is gotten from DTSTART
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-06-10 09:00:00, 1997-07-10 09:00:00, 1998-06-10 09:00:00, 1998-07-10 09:00:00, 1999-06-10 09:00:00, 1999-07-10 09:00:00, 2000-06-10 09:00:00, 2000-07-10 09:00:00, 2001-06-10 09:00:00, 2001-07-10 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every other year on January, February, and March for 10 occurrences:
+    $start = "1997-03-10 09:00:00";
+    $end = "2004-01-01 09:00:00";
+    $rule = "RRULE:FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3";
+    //  ==> (1997 9:00 AM EST)March 10
+    //      (1999 9:00 AM EST)January 10;February 10;March 10
+    //      (2001 9:00 AM EST)January 10;February 10;March 10
+    //      (2003 9:00 AM EST)January 10;February 10;March 10
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-03-10 09:00:00, 1999-01-10 09:00:00, 1999-02-10 09:00:00, 1999-03-10 09:00:00, 2001-01-10 09:00:00, 2001-02-10 09:00:00, 2001-03-10 09:00:00, 2003-01-10 09:00:00, 2003-02-10 09:00:00, 2003-03-10 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //An example where the days generated makes a difference because of WKST:
+    $start = "1997-08-05 09:00:00";
+    $end = "2004-01-01 09:00:00";
+    $rule = "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=MO";
+    //  ==> (1997 EDT)Aug 5,10,19,24
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-08-05 09:00:00, 1997-08-10 09:00:00, 1997-08-19 09:00:00, 1997-08-24 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //changing only WKST from MO to SU, yields different results...
+    $start = "1997-08-05 09:00:00";
+    $end = "2004-01-01 09:00:00";
+    $rule = "RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=4;BYDAY=TU,SU;WKST=SU";
+    // Result: 1997 EDT August 5,17,19,31;
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-08-05 09:00:00, 1997-08-17 09:00:00, 1997-08-19 09:00:00, 1997-08-31 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every 18 months on the 10th thru 15th of the month for 10 occurrences:
+    $start = "1997-09-10 09:00:00";
+    $end = "2004-01-01 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,15";
+    //  ==> (1997 9:00 AM EDT)September 10,11,12,13,14,15
+    //      (1999 9:00 AM EST)March 10,11,12,13
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-10 09:00:00, 1997-09-11 09:00:00, 1997-09-12 09:00:00, 1997-09-13 09:00:00, 1997-09-14 09:00:00, 1997-09-15 09:00:00, 1999-03-10 09:00:00, 1999-03-11 09:00:00, 1999-03-12 09:00:00, 1999-03-13 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Monthly on the third to the last day of the month, forever:
+    $start = "1997-09-28 09:00:00";
+    $end = "1998-03-01 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;BYMONTHDAY=-3";
+    //  ==> (1997 9:00 AM EDT)September 28
+    //      (1997 9:00 AM EST)October 29;November 28;December 29
+    //      (1998 9:00 AM EST)January 29;February 26
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-28 09:00:00, 1997-10-29 09:00:00, 1997-11-28 09:00:00, 1997-12-29 09:00:00, 1998-01-29 09:00:00, 1998-02-26 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every Thursday in March, forever:
+    //  ==> (1997 9:00 AM EST)March 13,20,27
+    //      (1998 9:00 AM EST)March 5,12,19,26
+    //      (1999 9:00 AM EST)March 4,11,18,25
+    $start = "1997-03-13 09:00:00";
+    $end = "1999-03-31 09:00:00";
+    $rule = "RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-03-13 09:00:00, 1997-03-20 09:00:00, 1997-03-27 09:00:00, 1998-03-05 09:00:00, 1998-03-12 09:00:00, 1998-03-19 09:00:00, 1998-03-26 09:00:00, 1999-03-04 09:00:00, 1999-03-11 09:00:00, 1999-03-18 09:00:00, 1999-03-25 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every Thursday, but only during June, July, and August, forever:
+    //  ==> (1997 9:00 AM EDT)June 5,12,19,26;July 3,10,17,24,31;August 7,14,21,28
+    //      (1998 9:00 AM EDT)June 4,11,18,25;July 2,9,16,23,30;August 6,13,20,27
+    //      (1999 9:00 AM EDT)June 3,10,17,24;July 1,8,15,22,29;August 5,12,19,26
+    $start = "1997-06-05 09:00:00";
+    $end = "1999-08-31 09:00:00";
+    $rule = "RRULE:FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-06-05 09:00:00, 1997-06-12 09:00:00, 1997-06-19 09:00:00, 1997-06-26 09:00:00, 1997-07-03 09:00:00, 1997-07-10 09:00:00, 1997-07-17 09:00:00, 1997-07-24 09:00:00, 1997-07-31 09:00:00, 1997-08-07 09:00:00, 1997-08-14 09:00:00, 1997-08-21 09:00:00, 1997-08-28 09:00:00, 1998-06-04 09:00:00, 1998-06-11 09:00:00, 1998-06-18 09:00:00, 1998-06-25 09:00:00, 1998-07-02 09:00:00, 1998-07-09 09:00:00, 1998-07-16 09:00:00, 1998-07-23 09:00:00, 1998-07-30 09:00:00, 1998-08-06 09:00:00, 1998-08-13 09:00:00, 1998-08-20 09:00:00, 1998-08-27 09:00:00, 1999-06-03 09:00:00, 1999-06-10 09:00:00, 1999-06-17 09:00:00, 1999-06-24 09:00:00, 1999-07-01 09:00:00, 1999-07-08 09:00:00, 1999-07-15 09:00:00, 1999-07-22 09:00:00, 1999-07-29 09:00:00, 1999-08-05 09:00:00, 1999-08-12 09:00:00, 1999-08-19 09:00:00, 1999-08-26 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Monthly on the 2nd and 15th of the month for 10 occurrences:
+    //  ==> (1997 9:00 AM EDT)September 2,15;October 2,15
+    //      (1997 9:00 AM EST)November 2,15;December 2,15
+    //      (1998 9:00 AM EST)January 2,15
+    $start = "1997-09-02 09:00:00";
+    $end = "1998-01-31 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-02 09:00:00, 1997-09-15 09:00:00, 1997-10-02 09:00:00, 1997-10-15 09:00:00, 1997-11-02 09:00:00, 1997-11-15 09:00:00, 1997-12-02 09:00:00, 1997-12-15 09:00:00, 1998-01-02 09:00:00, 1998-01-15 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Monthly on the first and last day of the month for 10 occurrences:
+    //  ==> (1997 9:00 AM EDT)September 30;October 1
+    //      (1997 9:00 AM EST)October 31;November 1,30;December 1,31
+    //      (1998 9:00 AM EST)January 1,31;February 1
+    $start = "1997-09-30 09:00:00";
+    $end = "1998-03-31 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-30 09:00:00, 1997-10-01 09:00:00, 1997-10-31 09:00:00, 1997-11-01 09:00:00, 1997-11-30 09:00:00, 1997-12-01 09:00:00, 1997-12-31 09:00:00, 1998-01-01 09:00:00, 1998-01-31 09:00:00, 1998-02-01 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every Friday the 13th, forever:
+    $rule = "EXDATE;TZID=US-Eastern:19970902T090000";
+    //  ==> (1998 9:00 AM EST)February 13;March 13;November 13
+    //      (1999 9:00 AM EDT)August 13
+    //      (2000 9:00 AM EDT)October 13
+    $start = "1997-09-02 09:00:00";
+    $end = "2000-12-31 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-02 09:00:00, 1998-02-13 09:00:00, 1998-03-13 09:00:00, 1998-11-13 09:00:00, 1999-08-13 09:00:00, 2000-10-13 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //The first Saturday that follows the first Sunday of the month, forever:
+    //  ==> (1997 9:00 AM EDT)September 13;October 11
+    //      (1997 9:00 AM EST)November 8;December 13
+    //      (1998 9:00 AM EST)January 10;February 7;March 7
+    //      (1998 9:00 AM EDT)April 11;May 9;June 13...
+    $start = "1997-09-13 09:00:00";
+    $end = "1998-06-30 09:00:00";
+    $rule = "RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13";
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-09-13 09:00:00, 1997-10-11 09:00:00, 1997-11-08 09:00:00, 1997-12-13 09:00:00, 1998-01-10 09:00:00, 1998-02-07 09:00:00, 1998-03-07 09:00:00, 1998-04-11 09:00:00, 1998-05-09 09:00:00, 1998-06-13 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every four years, the first Tuesday after a Monday in November,
+    //forever (U.S. Presidential Election day):
+    //  ==> (1996 9:00 AM EST)November 5
+    //      (2000 9:00 AM EST)November 7
+    //      (2004 9:00 AM EST)November 2
+    $start = "1996-11-05 09:00:00";
+    $end = "2004-11-30 09:00:00";
+    $rule = "RRULE:FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8";
+    $shouldbe = '1996-11-05 09:00:00, 2000-11-07 09:00:00, 2004-11-02 09:00:00';
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every 20th Monday of the year, forever:
+    $start = "1997-05-19 09:00:00";
+    $end = "2000-01-01 09:00:00";
+    $rule = "RRULE:FREQ=YEARLY;BYDAY=20MO";
+    //  ==> (1997 9:00 AM EDT)May 19
+    //      (1998 9:00 AM EDT)May 18
+    //      (1999 9:00 AM EDT)May 17
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-05-19 09:00:00, 1998-05-18 09:00:00, 1999-05-17 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+    //Every Sunday in January, every other year, forever:
+    $start = "1997-01-05 09:00:00";
+    $end = "2001-02-01 09:00:00";
+    $rule = 'RRULE:FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU';
+    //  ==> (1997 9:00 AM EDT)January 5,12,19,26
+    //      (1999 9:00 AM EDT)January 3,10,17,24,31
+    //      (2001 9:00 AM EDT)January 7,14,21,28
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '1997-01-05 09:00:00, 1997-01-12 09:00:00, 1997-01-19 09:00:00, 1997-01-26 09:00:00, 1999-01-03 09:00:00, 1999-01-10 09:00:00, 1999-01-17 09:00:00, 1999-01-24 09:00:00, 1999-01-31 09:00:00, 2001-01-07 09:00:00, 2001-01-14 09:00:00, 2001-01-21 09:00:00, 2001-01-28 09:00:00';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+return;
+
+    //Every Thanksgiving, forever:
+    $start = "1997-01-01 09:00:00";
+    $end = "2001-02-01 09:00:00";
+    $rule = 'RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=11;BYDAY=4TH';
+    //  ==> (1997 9:00 AM EDT)Nov
+    //      (1999 9:00 AM EDT)Nov
+    //      (2001 9:00 AM EDT)Nov
+    $dates = date_repeat_calc($rule, $start, $end, array());
+    $shouldbe = '';
+    $result = implode(', ', $dates);
+    $this->assertEqual($result, $shouldbe, $rule . '; Starting ' . $start . ';  results: ' . $result);
+
+// TODO:
+// BYYEARDAY, BYSETPOS,
+// BYHOUR, BYMINUTE, HOURLY, MINUTELY, SECONDLY
+// have not yet been implemented in date_repeat.
+
+//Every 3rd year on the 1st, 100th and 200th day for 10 occurrences:
+$date = "DTSTART;TZID=US-Eastern:19970101T090000";
+$rule = "RRULE:FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200";
+//  ==> (1997 9:00 AM EST)January 1
+//      (1997 9:00 AM EDT)April 10;July 19
+//      (2000 9:00 AM EST)January 1
+//      (2000 9:00 AM EDT)April 9;July 18
+//      (2003 9:00 AM EST)January 1
+//      (2003 9:00 AM EDT)April 10;July 19
+//      (2006 9:00 AM EST)January 1
+
+//Monday of week number 20 (where the default start of the week is Monday), forever:
+$date = "DTSTART;TZID=US-Eastern:19970512T090000";
+$rule = "RRULE:FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO";
+//  ==> (1997 9:00 AM EDT)May 12
+//      (1998 9:00 AM EDT)May 11
+//      (1999 9:00 AM EDT)May 17
+
+//The 3rd instance into the month of one of Tuesday, Wednesday or
+//Thursday, for the next 3 months:
+$date = "DTSTART;TZID=US-Eastern:19970904T090000";
+$rule = "RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3";
+//  ==> (1997 9:00 AM EDT)September 4;October 7
+//      (1997 9:00 AM EST)November 6
+
+//The 2nd to last weekday of the month:
+$date = "DTSTART;TZID=US-Eastern:19970929T090000";
+$rule = "RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2";
+//  ==> (1997 9:00 AM EDT)September 29
+//      (1997 9:00 AM EST)October 30;November 27;December 30
+//      (1998 9:00 AM EST)January 29;February 26;March 30
+
+//Every 3 hours from 9:00 AM to 5:00 PM on a specific day:
+$date = "DTSTART;TZID=US-Eastern:19970902T090000";
+$rule = "RRULE:FREQ=HOURLY;INTERVAL=3;UNTIL=19970902T170000Z";
+//  ==> (September 2, 1997 EDT)09:00,12:00,15:00
+
+//Every 15 minutes for 6 occurrences:
+$date = "DTSTART;TZID=US-Eastern:19970902T090000";
+$rule = "RRULE:FREQ=MINUTELY;INTERVAL=15;COUNT=6";
+//  ==> (September 2, 1997 EDT)09:00,09:15,09:30,09:45,10:00,10:15
+
+//Every hour and a half for 4 occurrences:
+$date = "DTSTART;TZID=US-Eastern:19970902T090000";
+$rule = "RRULE:FREQ=MINUTELY;INTERVAL=90;COUNT=4";
+//  ==> (September 2, 1997 EDT)09:00,10:30;12:00;13:30
+
+//Every 20 minutes from 9:00 AM to 4:40 PM every day:
+$date = "DTSTART;TZID=US-Eastern:19970902T090000";
+$rule = "RRULE:FREQ=DAILY;BYHOUR=9,10,11,12,13,14,15,16;BYMINUTE=0,20,40";
+//  or
+$rule = "RRULE:FREQ=MINUTELY;INTERVAL=20;BYHOUR=9,10,11,12,13,14,15,16";
+//  ==> (September 2, 1997 EDT)9:00,9:20,9:40,10:00,10:20,16:00,16:20,16:40
+//      (September 3, 1997 EDT)9:00,9:20,9:40,10:00,10:20,16:00,16:20,16:40
+
+  }
+}
diff --git a/sites/all/modules/date/date_repeat/tests/date_repeat_form.test b/sites/all/modules/date/date_repeat/tests/date_repeat_form.test
new file mode 100644
index 0000000000000000000000000000000000000000..d514739d0e681e18d3846526657371402cce7994
--- /dev/null
+++ b/sites/all/modules/date/date_repeat/tests/date_repeat_form.test
@@ -0,0 +1,520 @@
+<?php
+
+/**
+ * @file
+ * Test Date Repeat form.
+ */
+
+class DateRepeatFormTestCase extends DrupalWebTestCase {
+  protected $privileged_user;
+
+  public static function getInfo() {
+    return array(
+      'name' => t('Date Repeat Form'),
+      'description' => t('Test Date Repeat form.') ,
+      'group' => t('Date'),
+    );
+  }
+
+  /**
+   * Implements setUp().
+   */
+  public function setUp() {
+    // Load the date_repeat module.
+    parent::setUp('field', 'field_ui', 'date_api', 'date_repeat', 'date', 'date_popup', 'date_repeat_field');
+
+    // Create and log in our privileged user.
+    $this->privileged_user = $this->drupalCreateUser(array(
+      'administer content types', 'administer nodes', 'bypass node access', 'view date repeats'
+    ));
+    $this->drupalLogin($this->privileged_user);
+
+    variable_set('date_format_short', 'Y-m-d H:i');
+  }
+
+  public function testDateRepeatForm() {
+    $edit = array();
+    $edit['name'] = 'Date';
+    $edit['type'] = 'date';
+    $this->drupalPost('admin/structure/types/add', $edit, t('Save content type'));
+    $this->assertText('The content type Date has been added.', 'Content type added.');
+    $display_all_day = FALSE;
+
+    // Testing options.
+    $widget_options = array(
+      'date_select' => 'select',
+      'date_text' => 'text',
+      'date_popup' => 'popup');
+
+    foreach ($widget_options as $widget => $options) {
+      // Daily tests
+      // Creates date field stored as a datetime.
+      $this->createDateField($type = 'datetime', $widget, $display_all_day);
+
+      $form_edit = $this->dateForm($options, 'daily_1');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'daily_2');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'daily_3');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'daily_4');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'daily_1', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'daily_2', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'daily_3', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'daily_4', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'daily_1', FALSE, 'exclude');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'daily_1', FALSE, 'include');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'daily_1', FALSE, 'exclude_include');
+      $this->verifyDateForm($form_edit);
+
+      // Weekly tests
+
+      $form_edit = $this->dateForm($options, 'weekly_1');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'weekly_2');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'weekly_3');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'weekly_4');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'weekly_1', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'weekly_2', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'weekly_3', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'weekly_4', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      // Monthly tests
+
+      $form_edit = $this->dateForm($options, 'monthly_1');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_2');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_3');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_4');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_5');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_6');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_1', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_2', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_3', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_4', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_5', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'monthly_6', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      // Yearly tests
+
+      $form_edit = $this->dateForm($options, 'yearly_1');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_2');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_3');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_4');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_5');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_6');
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_1', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_2', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_3', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_4', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_5', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $form_edit = $this->dateForm($options, 'yearly_6', TRUE);
+      $this->verifyDateForm($form_edit);
+
+      $this->deleteDateField();
+    }
+  }
+
+  function dateForm($options, $test_id = NULL, $is_count = FALSE, $exclude_include = NULL) {
+    // Tests that date field functions properly.
+    $edit = array();
+    $edit['title'] = $this->randomName(8);
+    $edit['body[und][0][value]'] = $this->randomName(16);
+
+    switch ($options) {
+      case 'select':
+        $edit['field_test[und][0][value][year]'] = '2010';
+        $edit['field_test[und][0][value][month]'] = '10';
+        $edit['field_test[und][0][value][day]'] = '7';
+        $edit['field_test[und][0][value][hour]'] = '10';
+        $edit['field_test[und][0][value][minute]'] = '30';
+        break;
+      case 'text':
+        $edit['field_test[und][0][value][date]'] = '2010-10-07 10:30';
+        break;
+      case 'popup':
+        $edit['field_test[und][0][value][date]'] = '2010-10-07';
+        $edit['field_test[und][0][value][time]'] = '10:30';
+        break;
+    }
+
+    // Tests that Date repeat settings function properly
+    if ($test_id !== NULL) {
+      $edit['field_test[und][0][show_repeat_settings]'] = TRUE;
+      $count = 5;
+
+      switch ($test_id) {
+        // Daily test cases
+        case 'daily_1':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'DAILY';
+          $edit['field_test[und][0][rrule][daily][byday_radios]'] = 'INTERVAL';
+          $edit['field_test[und][0][rrule][daily][INTERVAL_child]'] = 2;
+          break;
+        case 'daily_2':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'DAILY';
+          $edit['field_test[und][0][rrule][daily][byday_radios]'] = 'every_weekday';
+          break;
+        case 'daily_3':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'DAILY';
+          $edit['field_test[und][0][rrule][daily][byday_radios]'] = 'every_mo_we_fr';
+          break;
+        case 'daily_4':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'DAILY';
+          $edit['field_test[und][0][rrule][daily][byday_radios]'] = 'every_tu_th';
+          break;
+
+        // Weekly test cases
+        case 'weekly_1':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'WEEKLY';
+          $edit['field_test[und][0][rrule][weekly][BYDAY][MO]'] = TRUE;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][WE]'] = TRUE;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][TH]'] = TRUE;
+          break;
+        case 'weekly_2':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'WEEKLY';
+          $edit['field_test[und][0][rrule][weekly][INTERVAL]'] = 1;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][MO]'] = TRUE;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][FR]'] = TRUE;
+          break;
+        case 'weekly_3':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'WEEKLY';
+          $edit['field_test[und][0][rrule][weekly][INTERVAL]'] = 2;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][TU]'] = TRUE;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][TH]'] = TRUE;
+          break;
+        case 'weekly_4':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'WEEKLY';
+          $edit['field_test[und][0][rrule][weekly][INTERVAL]'] = 10;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][MO]'] = TRUE;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][TU]'] = TRUE;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][WE]'] = TRUE;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][TH]'] = TRUE;
+          $edit['field_test[und][0][rrule][weekly][BYDAY][FR]'] = TRUE;
+          break;
+
+        // Monthly test cases
+        case 'monthly_1':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'MONTHLY';
+          $edit['field_test[und][0][rrule][monthly][day_month]'] = 'BYDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYDAY_COUNT]'] = '+1';
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYDAY_DAY]'] = 'FR';
+          break;
+        case 'monthly_2':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'MONTHLY';
+          $edit['field_test[und][0][rrule][monthly][day_month]'] = 'BYDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYDAY_COUNT]'] = '+1';
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYDAY_DAY]'] = 'SU';
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYMONTH][1]'] = TRUE;
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYMONTH][3]'] = TRUE;
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYMONTH][5]'] = TRUE;
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYMONTH][7]'] = TRUE;
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYMONTH][9]'] = TRUE;
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYMONTH][11]'] = TRUE;
+          break;
+        case 'monthly_3':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'MONTHLY';
+          $edit['field_test[und][0][rrule][monthly][day_month]'] = 'BYDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYDAY_COUNT]'] = '-2';
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYDAY_DAY]'] = 'MO';
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYMONTH][6]'] = TRUE;
+          $edit['field_test[und][0][rrule][monthly][BYDAY_BYMONTH_child][BYMONTH][12]'] = TRUE;
+          break;
+        case 'monthly_4':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'MONTHLY';
+          $edit['field_test[und][0][rrule][monthly][day_month]'] = 'BYMONTHDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][monthly][BYMONTHDAY_BYMONTH_child][BYMONTHDAY]'] = '10';
+          break;
+        case 'monthly_5':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'MONTHLY';
+          $edit['field_test[und][0][rrule][monthly][day_month]'] = 'BYMONTHDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][monthly][BYMONTHDAY_BYMONTH_child][BYMONTHDAY]'] = '10';
+          $edit['field_test[und][0][rrule][monthly][BYMONTHDAY_BYMONTH_child][BYMONTH][1]'] = TRUE;
+          $edit['field_test[und][0][rrule][monthly][BYMONTHDAY_BYMONTH_child][BYMONTH][2]'] = TRUE;
+          $edit['field_test[und][0][rrule][monthly][BYMONTHDAY_BYMONTH_child][BYMONTH][3]'] = TRUE;
+          break;
+        case 'monthly_6':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'MONTHLY';
+          $edit['field_test[und][0][rrule][monthly][day_month]'] = 'BYMONTHDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][monthly][BYMONTHDAY_BYMONTH_child][BYMONTHDAY]'] = '-5';
+          $edit['field_test[und][0][rrule][monthly][BYMONTHDAY_BYMONTH_child][BYMONTH][2]'] = TRUE;
+          $edit['field_test[und][0][rrule][monthly][BYMONTHDAY_BYMONTH_child][BYMONTH][4]'] = TRUE;
+          $edit['field_test[und][0][rrule][monthly][BYMONTHDAY_BYMONTH_child][BYMONTH][6]'] = TRUE;
+          break;
+
+        // Yearly test cases
+        case 'yearly_1':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'YEARLY';
+          $edit['field_test[und][0][rrule][yearly][day_month]'] = 'BYDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYDAY_COUNT]'] = '+1';
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYDAY_DAY]'] = 'FR';
+          break;
+        case 'yearly_2':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'YEARLY';
+          $edit['field_test[und][0][rrule][yearly][INTERVAL]'] = 2;
+          $edit['field_test[und][0][rrule][yearly][day_month]'] = 'BYDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYDAY_COUNT]'] = '+1';
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYDAY_DAY]'] = 'SU';
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYMONTH][1]'] = TRUE;
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYMONTH][3]'] = TRUE;
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYMONTH][5]'] = TRUE;
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYMONTH][7]'] = TRUE;
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYMONTH][9]'] = TRUE;
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYMONTH][11]'] = TRUE;
+          break;
+        case 'yearly_3':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'YEARLY';
+          $edit['field_test[und][0][rrule][yearly][INTERVAL]'] = 3;
+          $edit['field_test[und][0][rrule][yearly][day_month]'] = 'BYDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYDAY_COUNT]'] = '-2';
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYDAY_DAY]'] = 'MO';
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYMONTH][6]'] = TRUE;
+          $edit['field_test[und][0][rrule][yearly][BYDAY_BYMONTH_child][BYMONTH][12]'] = TRUE;
+          break;
+        case 'yearly_4':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'YEARLY';
+          $edit['field_test[und][0][rrule][yearly][day_month]'] = 'BYMONTHDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][yearly][BYMONTHDAY_BYMONTH_child][BYMONTHDAY]'] = '10';
+          break;
+        case 'yearly_5':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'YEARLY';
+          $edit['field_test[und][0][rrule][yearly][INTERVAL]'] = 2;
+          $edit['field_test[und][0][rrule][yearly][day_month]'] = 'BYMONTHDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][yearly][BYMONTHDAY_BYMONTH_child][BYMONTHDAY]'] = '10';
+          $edit['field_test[und][0][rrule][yearly][BYMONTHDAY_BYMONTH_child][BYMONTH][1]'] = TRUE;
+          $edit['field_test[und][0][rrule][yearly][BYMONTHDAY_BYMONTH_child][BYMONTH][2]'] = TRUE;
+          $edit['field_test[und][0][rrule][yearly][BYMONTHDAY_BYMONTH_child][BYMONTH][3]'] = TRUE;
+          break;
+        case 'yearly_6':
+          $edit['field_test[und][0][rrule][FREQ]'] = 'YEARLY';
+          $edit['field_test[und][0][rrule][yearly][INTERVAL]'] = 3;
+          $edit['field_test[und][0][rrule][yearly][day_month]'] = 'BYMONTHDAY_BYMONTH';
+          $edit['field_test[und][0][rrule][yearly][BYMONTHDAY_BYMONTH_child][BYMONTHDAY]'] = '-5';
+          $edit['field_test[und][0][rrule][yearly][BYMONTHDAY_BYMONTH_child][BYMONTH][2]'] = TRUE;
+          $edit['field_test[und][0][rrule][yearly][BYMONTHDAY_BYMONTH_child][BYMONTH][4]'] = TRUE;
+          $edit['field_test[und][0][rrule][yearly][BYMONTHDAY_BYMONTH_child][BYMONTH][6]'] = TRUE;
+          break;
+      }
+
+      // Test COUNT or UNTIL (default)
+      if ($is_count) {
+        $edit['field_test[und][0][rrule][range_of_repeat]'] = 'COUNT';
+        $edit['field_test[und][0][rrule][count_child]'] = $count;
+      }
+      else {
+        $edit['field_test[und][0][rrule][range_of_repeat]'] = 'UNTIL';
+        $date = array(
+          'year' => '2011',
+          'month' => '10',
+          'day' => '07'
+        );
+        $edit += $this->formatDateForRRULEInputs('field_test[und][0][rrule][until_child]', $options, $date);
+      }
+
+      // Test date exceptions and/or additions
+      if ($exclude_include !== NULL) {
+        $exclude_include_edit = array();
+        switch ($exclude_include) {
+          case 'exclude':
+            $exclude_include_edit['field_test[und][0][rrule][show_exceptions]'] = TRUE;
+            $date = array(
+              'year' => '2010',
+              'month' => '10',
+              'day' => '07'
+            );
+            $exclude_include_edit += $this->formatDateForRRULEInputs('field_test[und][0][rrule][exceptions][EXDATE][0]', $options, $date);
+            break;
+          case 'include':
+            $exclude_include_edit['field_test[und][0][rrule][show_additions]'] = TRUE;
+            $date = array(
+              'year' => '2013',
+              'month' => '10',
+              'day' => '07'
+            );
+            $exclude_include_edit += $this->formatDateForRRULEInputs('field_test[und][0][rrule][additions][RDATE][0]', $options, $date);
+            break;
+          case 'exclude_include':
+            $exclude_include_edit['field_test[und][0][rrule][show_exceptions]'] = TRUE;
+            $date = array(
+              'year' => '2010',
+              'month' => '10',
+              'day' => '07'
+            );
+            $exclude_include_edit += $this->formatDateForRRULEInputs('field_test[und][0][rrule][exceptions][EXDATE][0]', $options, $date);
+
+            $exclude_include_edit['field_test[und][0][rrule][show_additions]'] = TRUE;
+            $date = array(
+              'year' => '2013',
+              'month' => '10',
+              'day' => '07'
+            );
+            $exclude_include_edit += $this->formatDateForRRULEInputs('field_test[und][0][rrule][additions][RDATE][0]', $options, $date);
+            break;
+        }
+        $edit += $exclude_include_edit;
+      }
+    }
+
+    $this->drupalPost('node/add/date', $edit, t('Save'));
+    $this->assertText($edit['body[und][0][value]'], 'Test node has been created');
+
+    // Return the settings for later use in verification
+    return $edit;
+  }
+
+  function verifyDateForm($edit) {
+    $title = $edit['title'];
+    $node = $this->drupalGetNodeByTitle($title);
+
+    $this->drupalGet("node/{$node->nid}/edit");
+
+    foreach ($edit as $field => $value) {
+      $this->assertFieldByName($field, $value);
+    }
+
+    $this->drupalPost("node/{$node->nid}/delete", NULL, t('Delete'));
+    $this->assertRaw(t('Date %title has been deleted.', array('%title' => $title)), t('Deleted Date content.'));
+  }
+
+  function createDateField($type, $widget, $display_all_day = FALSE) {
+    $edit = array();
+    $edit['fields[_add_new_field][label]'] = 'Test';
+    $edit['fields[_add_new_field][field_name]'] = 'test';
+    $edit['fields[_add_new_field][weight]'] = '-4';
+    $edit['fields[_add_new_field][type]'] = $type;
+    $edit['fields[_add_new_field][widget_type]'] = $widget;
+
+    $label = $edit['fields[_add_new_field][label]'];
+
+    $field_edit = array();
+    $field_edit['field[settings][repeat]'] = 1;
+
+    $instance_edit = array();
+    switch ($widget) {
+      case 'select':
+      case 'popup':
+      $instance_edit['instance[widget][settings][year_range][years_back]'] = '-5';
+      $instance_edit['instance[widget][settings][year_range][years_forward]'] = '+5';
+      break;
+    }
+
+    if ($display_all_day) {
+      $instance_edit['instance[widget][settings][display_all_day]'] = TRUE;
+    }
+
+    // First step : 'Add new field' on the 'Manage fields' page.
+    $this->drupalPost('admin/structure/types/manage/date/fields', $edit, t('Save'));
+    $this->assertRaw(t('These settings apply to the %label field everywhere it is used.', array('%label' => $label)), t('Field settings page was displayed.'));
+
+    // Second step : 'Field settings' form.
+    $this->drupalPost(NULL, $field_edit, t('Save field settings'));
+    $this->assertRaw(t('Updated field %label field settings.', array('%label' => $label)), t('Redirected to instance and widget settings page.'));
+
+    // Third step : 'Instance settings' form.
+    $this->drupalPost(NULL, $instance_edit, t('Save settings'));
+    $this->assertRaw(t('Saved %label configuration.', array('%label' => $label)), t('Redirected to "Manage fields" page.'));
+
+    // Check that the field appears in the overview form.
+    $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', $label, t('Field was created and appears in the overview page.'));
+  }
+
+  function deleteDateField() {
+    $this->drupalGet('admin/structure/types/manage/date/fields');
+    $this->clickLink('delete');
+    $this->drupalPost(NULL, NULL, t('Delete'));
+    $this->assertText(t('The field Test has been deleted from the Date content type.'), t('Removed date field.'));
+  }
+
+  function formatDateForRRULEInputs($form_field_name, $date_widget_type, $date) {
+    $return = array();
+
+    switch ($date_widget_type) {
+      case 'select':
+        $return["{$form_field_name}[datetime][year]"] = $date['year'];
+        $return["{$form_field_name}[datetime][month]"] = $date['month'];
+        $return["{$form_field_name}[datetime][day]"] = ltrim($date['day'], '0');
+        break;
+      case 'text':
+      case 'popup':
+        //$return["{$field_name}[datetime][date]"] = '2011-10-07';
+        $return["{$form_field_name}[datetime][date]"] = "{$date['year']}-{$date['month']}-{$date['day']}";
+        break;
+    }
+
+    return $return;
+  }
+}
diff --git a/sites/all/modules/date/date_repeat_field/README.txt b/sites/all/modules/date/date_repeat_field/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3c7aab5c69ace1adca3dd4975ff385fdd87dc0d4
--- /dev/null
+++ b/sites/all/modules/date/date_repeat_field/README.txt
@@ -0,0 +1,4 @@
+Date Repeat Field
+
+The functionality to integrate the Date Repeat API into date fields is being moved into this module,
+which can then be enabled or disabled, depending on whether repeating date fields are needed.
\ No newline at end of file
diff --git a/sites/all/modules/date/date_repeat_field/date_repeat_field.css b/sites/all/modules/date/date_repeat_field/date_repeat_field.css
new file mode 100644
index 0000000000000000000000000000000000000000..bb8926c038c6d04e53a319fbe3dd6d413a10205e
--- /dev/null
+++ b/sites/all/modules/date/date_repeat_field/date_repeat_field.css
@@ -0,0 +1,109 @@
+.date-repeat-input {
+  float: left; /* LTR */
+  margin-right: 5px; /* LTR */
+  width: auto;
+}
+.date-repeat-input select {
+  min-width: 7em;
+}
+.date-repeat fieldset {
+  clear: both;
+  float: none;
+}
+
+.date-repeat-radios {
+  margin-bottom: 1em;
+}
+
+.date-repeat-radios input[type=radio] {
+  float: left;
+  margin: 0.75em 0.75em 0 0;
+}
+
+.date-repeat-radios .form-wrapper {
+  float: left;
+}
+
+.date-repeat-radios .form-type-checkboxes .form-type-checkbox {
+  width: 15%;
+  float: left;
+  margin: 0;
+}
+
+.date-repeat-radios .date-repeat-radios-item {
+  margin-bottom: 1em;
+}
+
+.weekly .form-type-checkboxes .form-type-checkbox {
+  float: left;
+  margin-right: 10px;
+}
+
+.date-repeat-input.byday-count label,
+.date-repeat-input.byday-count select,
+.date-clear.bymonthday label,
+.date-clear.bymonthday select {
+  display: inline;
+}
+
+.date-repeat-input.byday-day label,
+.date-clear.bymonthday .field-suffix {
+  font-weight: bold;
+}
+
+.range-of-repeat .form-radios > div {
+  margin-top: 0.5em;
+}
+
+.range-of-repeat .count input[type=text] {
+  margin: 0 0.5em;
+}
+
+.range-of-repeat .until .form-wrapper {
+  margin: 0 0.5em;
+  display: inline-block;
+  vertical-align: middle;
+}
+
+.range-of-repeat .until .form-radio,
+.range-of-repeat .until .date-prefix-inline {
+  margin: 0 0 1.4em 0;
+  vertical-align: middle;
+}
+
+.range-of-repeat .until.widget-date_popup.label-above .form-radio,
+.range-of-repeat .until.widget-date_popup.label-above .date-prefix-inline {
+  margin: 0;
+  vertical-align: middle;
+}
+
+.range-of-repeat .until.widget-date_select.label-within .form-radio,
+.range-of-repeat .until.widget-date_select.label-within .date-prefix-inline {
+  margin: 0;
+  vertical-align: middle;
+}
+
+.range-of-repeat .until.widget-date_select.label-above .form-radio,
+.range-of-repeat .until.widget-date_select.label-above .date-prefix-inline {
+  margin: 1.4em 0 0 0;
+  vertical-align: middle;
+}
+
+.range-of-repeat .until .form-type-date-text .date-padding {
+  padding: 0;
+}
+
+.range-of-repeat .until.widget-date_select.label-within .date-padding {
+  padding: 0;
+}
+
+.range-of-repeat .until.widget-date_select.label-above .date-padding {
+  padding: 0;
+}
+
+.range-of-repeat .until .form-type-date-select,
+.range-of-repeat .until .form-type-date-popup,
+.range-of-repeat .until .form-type-date-text {
+  border: none;
+  margin: 0;
+}
diff --git a/sites/all/modules/date/date_repeat_field/date_repeat_field.devel_generate.inc b/sites/all/modules/date/date_repeat_field/date_repeat_field.devel_generate.inc
new file mode 100644
index 0000000000000000000000000000000000000000..3880e8b4d07fcea53d657d70fc9198733d4dd727
--- /dev/null
+++ b/sites/all/modules/date/date_repeat_field/date_repeat_field.devel_generate.inc
@@ -0,0 +1,158 @@
+<?php
+/*
+ * @file
+ * Handling of devel generate functionality for repeating dates.
+ */
+
+/**
+ * Implements hook_date_field_insert().
+ *
+ * A substitute for hook_devel_generate to handle repeating dates.
+ */
+function date_repeat_field_date_field_insert(&$items, $context) {
+
+  $entity_type = $context['entity_type'];
+  $entity = $context['entity'];
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $langcode = $context['langcode'];
+
+  // The first value was already created by the regular Devel Generate code.
+  // Skipping doing anything if there is no value for this field.
+  if (empty($items)) {
+    return;
+  }
+  $item = $items[0];
+
+  // Unset any previous dates past the first one.
+  $count = count($items);
+  for ($i = 1; $i < $count; $i++) {
+    unset($items[$i]);
+  }
+
+  // Compute repeating date values.
+  module_load_include('inc', 'date_repeat', 'date_repeat_calc');
+  module_load_include('inc', 'date_api', 'date_api_ical');
+
+  $increment = $instance['widget']['settings']['increment'];
+  $timezone = date_get_timezone($field['settings']['tz_handling'], $item['timezone']);
+  $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
+
+  switch ($field['type']) {
+    case 'date':
+      $format = DATE_FORMAT_ISO;
+      break;
+    case 'datestamp':
+      $format = DATE_FORMAT_UNIX;
+      break;
+    case 'datetime':
+      $format = DATE_FORMAT_DATETIME;
+      break;
+  }
+
+  $start = new dateObject($item['value'], $timezone_db, $format);
+  $start2 = new dateObject($item['value2'], $timezone_db, $format);
+
+  // Create a repeating date rule.
+  $duration = $start->difference($start2);
+  $form_values = array();
+
+  // Create the default case more frequently than case 1 or 2.
+  $which = mt_rand(0, 10);
+
+  $max_items = mt_rand(3, 10);
+
+  $intervals = array_keys(date_repeat_interval_options());
+  unset($intervals[0]);
+  $interval = $intervals[mt_rand(1, 3)];
+  switch ($which) {
+    case 1:
+      $mo = mt_rand(1, 28);
+      $options = array('YEARLY', 'MONTHLY');
+      $freq = date_content_generate_key($options);
+      $freq = $options[$freq];
+      $form_values['FREQ'] = $freq;
+      // Make sure we'll find a match in our range.
+      if ($freq == 'YEARLY') {
+        $interval = 1;
+      }
+      $form_values['BYMONTHDAY'] = array($mo);
+      break;
+    case 2:
+      $mo = mt_rand(1, 12);
+      $options = array('YEARLY', 'MONTHLY');
+      $freq = date_content_generate_key($options);
+      $freq = $options[$freq];
+      $form_values['FREQ'] = $freq;
+      // Make sure we'll find a match in our range.
+      if ($freq == 'YEARLY') {
+        $interval = 1;
+      }
+      $form_values['BYMONTH'] = array($mo);
+      break;
+    default:
+      $dows = array_keys(date_content_repeat_dow_options());
+      $day = date_content_generate_key($dows);
+      $dow = $dows[$day];
+      $options = array('MONTHLY', 'DAILY', 'WEEKLY');
+      $freq = date_content_generate_key($options);
+      $freq = $options[$freq];
+      $form_values['FREQ'] = $freq;
+      $form_values['BYDAY'] = array($dow);
+      break;
+  }
+
+  $form_values['INTERVAL'] = $interval;
+
+  switch ($freq) {
+    case 'YEARLY':
+      $period = 'year';
+      break;
+    case 'MONTHLY':
+      $period = 'month';
+      break;
+    case 'WEEKLY':
+      $period = 'week';
+      break;
+    default:
+      $period = 'day';
+      break;
+
+  }
+
+  $form_values['UNTIL'] = array();
+  $form_values['COUNT'] = $max_items;
+
+  $rrule = date_api_ical_build_rrule($form_values);
+  $items[0]['rrule'] = $rrule;
+
+  $values = date_repeat_build_dates($rrule, $form_values, $field, $item);
+
+  $items += $values;
+
+}
+
+function date_content_generate_key($array) {
+  $keys = array_keys($array);
+  $min = array_shift($keys);
+  $max = array_pop($keys);
+  return mt_rand($min, $max);
+}
+
+/**
+ * Helper function for BYDAY options.
+ *
+ * Creates options like -1SU and 2TU
+ * Omit options that won't find many matches, like 5th Sunday.
+ */
+function date_content_repeat_dow_options() {
+  $options = array();
+  foreach (date_repeat_dow_count_options() as $count_key => $count_value) {
+    foreach (date_repeat_dow_day_options() as $dow_key => $dow_value) {
+      if ($count_key != 5 && $count_key != -5) {
+        $options[$count_key . $dow_key] = $count_value . ' ' . $dow_value;
+      }
+    }
+  }
+  return $options;
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date_repeat_field/date_repeat_field.info b/sites/all/modules/date/date_repeat_field/date_repeat_field.info
new file mode 100644
index 0000000000000000000000000000000000000000..0b57d62d74d320f302bdb706fa41e02a02836397
--- /dev/null
+++ b/sites/all/modules/date/date_repeat_field/date_repeat_field.info
@@ -0,0 +1,15 @@
+name = Date Repeat Field
+description = Creates the option of Repeating date fields and manages Date fields that use the Date Repeat API.
+dependencies[] = date_api
+dependencies[] = date
+dependencies[] = date_repeat
+stylesheets[all][] = date_repeat_field.css
+package = Date/Time
+core = 7.x
+
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date_repeat_field/date_repeat_field.module b/sites/all/modules/date/date_repeat_field/date_repeat_field.module
new file mode 100644
index 0000000000000000000000000000000000000000..675ed025102feac2caea6fed9fe200a45b3e1af9
--- /dev/null
+++ b/sites/all/modules/date/date_repeat_field/date_repeat_field.module
@@ -0,0 +1,714 @@
+<?php
+
+/**
+ * @file
+ * Creates the option of Repeating date fields and manages Date fields that use the Date Repeat API.
+ *
+ * The Repeating functionality is pretty tightly intermingled with other code,
+ * so the process of pulling it out into this module will happen gradually.
+ *
+ * The current implementation adds a repeat form to the date field so the user
+ * can select the repeat rules. That selection is built into an RRULE
+ * which is stored in the zero position of the field values. During widget
+ * validation, the rule is parsed to see what dates it will create,
+ * and multiple values are added to the field, one for each repeat date.
+ * That update only happens when the rule, the start date, or the end date
+ * change, no need to waste processing cycles for other changes to the node
+ * values.
+ *
+ * Lots of possible TODOs, the biggest one is figuring out the best
+ * way to handle dates with no UNTIL date since we can't add an infinite
+ * number of values to the field. For now, we require the UNTIL date.
+ */
+
+/**
+ * Implements hook_theme().
+ */
+function date_repeat_field_theme() {
+  $themes = array(
+    'date_repeat_display' => array(
+      'variables' => array(
+        'field' => NULL,
+        'item' => NULL,
+        'entity_type' => NULL,
+        'entity' => NULL,
+        'dates' => NULL
+      ),
+      'function' => 'theme_date_repeat_display',
+    ),
+  );
+
+  return $themes;
+}
+
+/**
+ * Theme the human-readable description for a Date Repeat rule.
+ *
+ * TODO -
+ * add in ways to store the description in the date so it isn't regenerated
+ * over and over and find a way to allow description to be shown or hidden.
+ */
+function theme_date_repeat_display($vars) {
+  $field = $vars['field'];
+  $item = $vars['item'];
+  $entity = !empty($vars['node']) ? $vars['node'] : NULL;
+  $output = '';
+  if (!empty($item['rrule'])) {
+    $output = date_repeat_rrule_description($item['rrule']);
+    $output = '<div>' . $output . '</div>';
+  }
+  return $output;
+}
+
+/**
+ * Implements hook_menu().
+ *
+ * Add menu tabs to display pages with details about repeating date values.
+ */
+function date_repeat_field_menu() {
+  $items = array();
+
+  $values = date_repeat_field_bundles();
+  foreach ($values as $entity_type => $bundles) {
+    if (module_exists('field_collection') && $entity_type == 'field_collection_item') {
+      foreach ($bundles as $bundle => $fields) {
+        $field = field_info_field($bundle);
+        if ($field['type'] == 'field_collection') {
+          $path = field_collection_field_get_path($field);
+          $count = count(explode('/', $path));
+          $items[$path . '/%field_collection_item/repeats'] = array(
+           'title' => 'Repeats',
+           'page callback' => 'date_repeat_field_page',
+           'page arguments' => array($entity_type, $count),
+           'access callback' => 'date_repeat_field_show',
+           'access arguments' => array($entity_type, $count),
+           'type' => MENU_LOCAL_TASK,
+           'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+          );
+        }
+      }
+    }
+    else {
+      $path = $entity_type . '/%' . $entity_type;
+      $items[$path . '/repeats'] = array(
+       'title' => 'Repeats',
+       'page callback' => 'date_repeat_field_page',
+       'page arguments' => array($entity_type, 1),
+       'access callback' => 'date_repeat_field_show',
+       'access arguments' => array($entity_type, 1),
+       'type' => MENU_LOCAL_TASK,
+       'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+      );
+    }
+  }
+  return $items;
+}
+
+/**
+ * Implements hook_permission().
+ */
+function date_repeat_field_permission() {
+  return array('view date repeats' => array(
+    'title' => t('View Repeating Dates'),
+    'description' => t('Allow user to see a page with all the times a date repeats.'),
+  ));
+}
+
+/**
+ * See if the user can access repeat date info for this field.
+ */
+function date_repeat_field_show($entity_type = 'node', $entity = NULL) {
+  $bundle = date_get_entity_bundle($entity_type, $entity);
+  foreach (field_info_fields() as $field_name => $field) {
+    if (in_array($field['type'], array('date', 'datestamp', 'datetime'))
+        && array_key_exists($entity_type, $field['bundles'])
+        && in_array($bundle, $field['bundles'][$entity_type])
+        && date_is_repeat_field($field)) {
+      return user_access('view date repeats');
+    }
+  }
+  return FALSE;
+}
+
+/**
+ * A page to list all values for a repeating date.
+ */
+function date_repeat_field_page($entity_type = 'node', $entity = NULL) {
+  $bundle = date_get_entity_bundle($entity_type, $entity);
+  $info = entity_get_info($entity_type);
+  $key = $info['entity keys']['id'];
+  drupal_set_title(t('Repeats'));
+  $entity->date_repeat_show_all = TRUE;
+  $entity->content = array();
+  $output = '';
+  foreach (field_info_fields() as $field_name => $field) {
+    if (in_array($field['type'], array('date', 'datestamp', 'datetime')) && date_is_repeat_field($field)) {
+      foreach ($field['bundles'] as $field_entity_type => $bundles) {
+        foreach ($bundles as $field_bundle) {
+          if ($entity_type == $field_entity_type && $bundle == $field_bundle) {
+            $data = field_view_field($entity_type, $entity, $field_name);
+            $output .= drupal_render($data);
+          }
+        }
+      }
+    }
+  }
+  return $output;
+}
+
+/**
+ * Return an array of all entity types and bundles that have repeating date fields.
+ */
+function date_repeat_field_bundles() {
+  $values = array();
+  foreach (field_info_fields() as $field_name => $field) {
+    if (in_array($field['type'], array('date', 'datestamp', 'datetime')) && $field['settings']['repeat']) {
+      foreach ($field['bundles'] as $entity_type => $bundles) {
+        foreach ($bundles as $bundle) {
+          $values[$entity_type][$bundle][] = $field_name;
+        }
+      }
+    }
+  }
+  return $values;
+}
+
+function date_is_repeat_field($field, $instance = NULL) {
+  if (is_string($field)) {
+    $field = field_info_field($field);
+  }
+
+  if (!isset($field['settings']['repeat'])) {
+    return FALSE;
+  }
+
+  $value = $field['settings']['repeat'];
+
+  // This might be either a field form or a real field.
+  if (is_array($value)) {
+    return $value['#value'];
+  }
+  else {
+    return $value;
+  }
+}
+
+/*
+ * Implements hook_date_field_insert_alter().
+ */
+function date_repeat_field_date_field_insert_alter(&$items, $context) {
+
+  $entity = $context['entity'];
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $langcode = $context['langcode'];
+
+  // If an RRULE with a frequency of NONE made it this far, unset it.
+  if (!empty($items[0]['rrule']) && strpos($items[0]['rrule'], 'FREQ=NONE')) {
+    $items[0]['rrule'] = NULL;
+  }
+
+  // We can't use hook_devel_generate() because we need custom handling for
+  // repeating date fields. So we wait until the entity is inserted, then
+  // intervene here to fix it.
+  if (!empty($entity->devel_generate) && !empty($field['settings']['repeat'])) {
+    module_load_include('inc', 'date_repeat_field', 'date_repeat_field.devel_generate');
+    date_repeat_field_date_field_insert($items, $context);
+  }
+}
+
+/*
+ * Implements hook_date_field_update_alter().
+ */
+function date_repeat_field_date_field_update_alter(&$items, $context) {
+
+  // If an RRULE with a frequency of NONE made it this far, unset it.
+  if (!empty($items[0]['rrule']) && strpos($items[0]['rrule'], 'FREQ=NONE')) {
+    $items[0]['rrule'] = NULL;
+  }
+
+  // If you have a repeating date field on a user and don't check the box to repeat it,
+  // we end up with $items[0]['rrule'] = array('additions' => '', 'exceptions' => ''));
+  // This will clean it up by getting rid of those bogus values.
+  // @TODO Figure out where that's coming from. It doesn't happen on nodes.
+  if (!empty($items[0]['rrule']) && is_array($items[0]['rrule'])) {
+    $items[0]['rrule'] = NULL;
+  }
+}
+
+/**
+ * Implements hook_field_widget_form_alter().
+ */
+function date_repeat_field_field_widget_form_alter(&$element, &$form_state, $context) {
+
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $items = $context['items'];
+  $delta = $context['delta'];
+
+  if (in_array($field['type'], array('date', 'datetime', 'datestamp'))) {
+    if (!empty($field['settings']['repeat'])) {
+      $element['#element_validate'][] = 'date_repeat_field_widget_validate';
+      $element['show_repeat_settings'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Repeat'),
+        '#weight' => $instance['widget']['weight'] + .3,
+        '#prefix' => '<div class="date-clear">',
+        '#suffix' => '</div>',
+        '#default_value' => isset($items[$delta]['rrule']) && !empty($items[$delta]['rrule']) ? 1 : 0,
+      );
+    }
+  }
+}
+
+/**
+ * Validation for date repeat form element.
+ *
+ * Create multiple values from the RRULE results.
+ * Lots more work needed here.
+ */
+function date_repeat_field_widget_validate($element, &$form_state) {
+  $field = field_widget_field($element, $form_state);
+  if (empty($field['settings']['repeat'])) {
+    return;
+  }
+
+  $field_name = $element['#field_name'];
+  $delta = $element['#delta'];
+  $langcode = $element['#language'];
+
+  // If the widget has been hidden by #access, the RRULE will still be in its
+  // original string form here. Nothing to process.
+  if (date_hidden_element($element)) {
+
+    // If this was a hidden repeating date, we lost all the repeating values in the widget processing.
+    // Add them back here if that happened since we are skipping the re-creation of those values.
+    if (!empty($form_state['storage']['date_items'][$field_name])) {
+      array_pop($element['#parents']);
+      form_set_value($element, $form_state['storage']['date_items'][$field_name][$langcode], $form_state);
+    }
+    return;
+  }
+
+  module_load_include('inc', 'date_repeat', 'date_repeat_form');
+  $instance = field_widget_instance($element, $form_state);
+
+  // Here 'values' returns an array of input values, which includes the original RRULE, as a string.
+  // and 'input' returns an array of the form elements created by the repeating date widget, with
+  // RRULE values as an array of the selected elements and their chosen values.
+  $item = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
+  $input = drupal_array_get_nested_value($form_state['input'], $element['#parents'], $input_exists);
+
+  $rrule_values = date_repeat_merge($input['rrule'], $element['rrule']);
+
+  // If no repeat information was set, treat this as a normal, non-repeating value.
+  if ($rrule_values['FREQ'] == 'NONE' || empty($input['show_repeat_settings'])) {
+    $item['rrule'] = NULL;
+    form_set_value($element, $item, $form_state);
+    return;
+  }
+
+  // If no start date was set, clean up the form and return.
+  if (empty($item['value'])) {
+    form_set_value($element, NULL, $form_state);
+    return;
+  }
+
+  // Require the UNTIL date for now.
+  // The RRULE has already been created by this point, so go back
+  // to the posted values to see if this was filled out.
+  $error_field_base = implode('][', $element['#parents']);
+  $error_field_until =  $error_field_base . '][rrule][until_child][datetime][';
+  if (!empty($item['rrule']) && $rrule_values['range_of_repeat'] === 'UNTIL' && empty($rrule_values['UNTIL']['datetime'])) {
+    switch ($instance['widget']['type']) {
+      case 'date_text':
+      case 'date_popup':
+        form_set_error($error_field_until . 'date', t("Missing value in 'Range of repeat'. (UNTIL).", array(), array('context' => 'Date repeat')));
+        break;
+      case 'date_select':
+        form_set_error($error_field_until . 'year', t("Missing value in 'Range of repeat': Year (UNTIL)", array(), array('context' => 'Date repeat')));
+        form_set_error($error_field_until . 'month', t("Missing value in 'Range of repeat': Month (UNTIL)", array(), array('context' => 'Date repeat')));
+        form_set_error($error_field_until . 'day', t("Missing value in 'Range of repeat': Day (UNTIL)", array(), array('context' => 'Date repeat')));
+        break;
+    }
+  }
+
+  $error_field_count = $error_field_base . '][rrule][count_child';
+  if (!empty($item['rrule']) && $rrule_values['range_of_repeat'] === 'COUNT' && empty($rrule_values['COUNT'])) {
+    form_set_error($error_field_count, t("Missing value in 'Range of repeat'. (COUNT).", array(), array('context' => 'Date repeat')));
+  }
+
+  if (form_get_errors()) {
+    return;
+  }
+
+  // If the rule, the start date, or the end date have changed, re-calculate
+  // the repeating dates, wipe out the previous values, and populate the
+  // field with the new values.
+
+  // TODO
+  // Is it right to not do anything unless there are changes? Will that
+  // confuse anyone? Commenting that out for now...
+  $rrule = $item['rrule'];
+  if (!empty($rrule)
+    //&& ($rrule != $element['rrule']['#prev_rrule']
+    //|| $item['value'] != $element['rrule']['#prev_value']
+    //|| $item['value2'] != $element['rrule']['#prev_value2'])
+    ) {
+
+    // Avoid undefined index problems on dates that don't have all parts.
+    $possible_items = array('value', 'value2', 'timezone', 'offset', 'offset2');
+    foreach ($possible_items as $key) {
+      if (empty($item[$key])) {
+        $item[$key] = '';
+      }
+    }
+
+    // We only collect a date for UNTIL, but we need it to be inclusive,
+    // so force it to a full datetime element at the last possible second of the day.
+    if (!empty($rrule_values['UNTIL'])) {
+      $rrule_values['UNTIL']['datetime'] .= ' 23:59:59';
+      $rrule_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute', 'second')));
+      $rrule_values['UNTIL']['all_day'] = 0;
+    }
+    $value = date_repeat_build_dates($rrule, $rrule_values, $field, $item);
+    // Unset the delta value of the parents.
+    array_pop($element['#parents']);
+    // Set the new delta values for this item to the array of values returned by the repeat rule.
+    form_set_value($element, $value, $form_state);
+  }
+}
+
+/**
+ * Implements the form after_build().
+ *
+ * Remove the 'Add more' elements from a repeating date form.
+ */
+function date_repeat_after_build(&$element, &$form_state) {
+  foreach ($form_state['storage']['repeat_fields'] as $field_name => $parents) {
+    // Remove unnecessary items in the form added by the Add more handling.
+    $value = drupal_array_get_nested_value($element, $parents);
+    $langcode = $value['#language'];
+    unset($value[$langcode]['add_more'], $value[$langcode]['#suffix'], $value[$langcode]['#prefix'], $value[$langcode][0]['_weight']);
+    $value[$langcode]['#cardinality'] = 1;
+    $value[$langcode]['#max_delta'] = 1;
+    drupal_array_set_nested_value($element, $parents, $value);
+  }
+  return $element;
+}
+
+/**
+ * Helper function to build repeating dates from a $node_field.
+ *
+ * Pass in either the RRULE or the $form_values array for the RRULE,
+ * whichever is missing will be created when needed.
+ */
+function date_repeat_build_dates($rrule = NULL, $rrule_values = NULL, $field, $item) {
+
+  include_once(DRUPAL_ROOT . '/' . drupal_get_path('module', 'date_api') . '/date_api_ical.inc');
+  $field_name = $field['field_name'];
+
+  if (empty($rrule)) {
+    $rrule = date_api_ical_build_rrule($rrule_values);
+  }
+  elseif (empty($rrule_values)) {
+    $rrule_values = date_ical_parse_rrule(NULL, $rrule);
+  }
+
+  // By the time we get here, the start and end dates have been
+  // adjusted back to UTC, but we want localtime dates to do
+  // things like '+1 Tuesday', so adjust back to localtime.
+  $timezone = date_get_timezone($field['settings']['tz_handling'], $item['timezone']);
+  $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
+  $start = new DateObject($item['value'], $timezone_db, date_type_format($field['type']));
+  $start->limitGranularity($field['settings']['granularity']);
+  if ($timezone != $timezone_db) {
+    date_timezone_set($start, timezone_open($timezone));
+  }
+  if (!empty($item['value2']) && $item['value2'] != $item['value']) {
+    $end = new DateObject($item['value2'], date_get_timezone_db($field['settings']['tz_handling']), date_type_format($field['type']));
+    $end->limitGranularity($field['settings']['granularity']);
+    date_timezone_set($end, timezone_open($timezone));
+  }
+  else {
+    $end = $start;
+  }
+  $duration = $start->difference($end);
+  $start_datetime = date_format($start, DATE_FORMAT_DATETIME);
+
+  if (!empty($rrule_values['UNTIL']['datetime'])) {
+    $end = date_ical_date($rrule_values['UNTIL'], $timezone);
+    $end_datetime = date_format($end, DATE_FORMAT_DATETIME);
+  }
+  elseif (!empty($rrule_values['COUNT'])) {
+    $end_datetime = NULL;
+  }
+  else {
+    // No UNTIL and no COUNT?
+    return array();
+  }
+
+  // Split the RRULE into RRULE, EXDATE, and RDATE parts.
+  $parts = date_repeat_split_rrule($rrule);
+  $parsed_exceptions = (array) $parts[1];
+  $exceptions = array();
+  foreach ($parsed_exceptions as $exception) {
+    $date = date_ical_date($exception, $timezone);
+    $exceptions[] = date_format($date, 'Y-m-d');
+  }
+
+  $parsed_rdates = (array) $parts[2];
+  $additions = array();
+  foreach ($parsed_rdates as $rdate) {
+    $date = date_ical_date($rdate, $timezone);
+    $additions[] = date_format($date, 'Y-m-d');
+  }
+
+  $dates = date_repeat_calc($rrule, $start_datetime, $end_datetime, $exceptions, $timezone, $additions);
+  $value = array();
+  foreach ($dates as $delta => $date) {
+    // date_repeat_calc always returns DATE_DATETIME dates, which is
+    // not necessarily $field['type'] dates.
+    // Convert returned dates back to db timezone before storing.
+    $date_start = new DateObject($date, $timezone, DATE_FORMAT_DATETIME);
+    $date_start->limitGranularity($field['settings']['granularity']);
+    date_timezone_set($date_start, timezone_open($timezone_db));
+    $date_end = clone($date_start);
+    date_modify($date_end, '+' . $duration . ' seconds');
+    $value[$delta] = array(
+      'value' => date_format($date_start, date_type_format($field['type'])),
+      'value2' => date_format($date_end, date_type_format($field['type'])),
+      'offset' => date_offset_get($date_start),
+      'offset2' => date_offset_get($date_end),
+      'timezone' => $timezone,
+      'rrule' => $rrule,
+      );
+  }
+  return $value;
+}
+
+/**
+ * Implements hook_date_combo_process_alter().
+ *
+ * This hook lets us make changes to the date_combo element.
+ */
+function date_repeat_field_date_combo_process_alter(&$element, &$form_state, $context) {
+
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $field_name = $element['#field_name'];
+  $delta = $element['#delta'];
+
+  // Add a date repeat form element, if needed.
+  // We delayed until this point so we don't bother adding it to hidden fields.
+  if (date_is_repeat_field($field, $instance)) {
+
+    $item = $element['#value'];
+    $element['rrule'] = array(
+      '#type' => 'date_repeat_rrule',
+      '#theme_wrappers' => array('date_repeat_rrule'),
+      '#default_value' => isset($item['rrule']) ? $item['rrule'] : '',
+      '#date_timezone' => $element['#date_timezone'],
+      '#date_format'      => date_limit_format(date_input_format($element, $field, $instance), $field['settings']['granularity']),
+      '#date_text_parts'  => (array) $instance['widget']['settings']['text_parts'],
+      '#date_increment'   => $instance['widget']['settings']['increment'],
+      '#date_year_range'  => $instance['widget']['settings']['year_range'],
+      '#date_label_position' => $instance['widget']['settings']['label_position'],
+      '#prev_value' => isset($item['value']) ? $item['value'] : '',
+      '#prev_value2' => isset($item['value2']) ? $item['value2'] : '',
+      '#prev_rrule' => isset($item['rrule']) ? $item['rrule'] : '',
+      '#date_repeat_widget' => str_replace('_repeat', '', $instance['widget']['type']),
+      '#date_repeat_collapsed' => $instance['widget']['settings']['repeat_collapsed'],
+      '#date_flexible' => 0,
+      '#weight' => $instance['widget']['weight'] + .4,
+    );
+  }
+
+}
+
+/**
+ * Implements hook_date_combo_pre_validate_alter().
+ *
+ * This hook lets us alter the element or the form_state before the rest
+ * of the date_combo validation gets fired.
+ */
+function date_repeat_field_date_combo_pre_validate_alter(&$element, &$form_state, $context) {
+  // Just a placeholder for now.
+}
+
+/**
+ * Implements hook_field_info_alter().
+ *
+ * This Field API hook lets us add a new setting to the fields.
+ */
+function date_repeat_field_field_info_alter(&$info) {
+
+  $info['date']['settings'] += array(
+    'repeat' => 0,
+  );
+  $info['datetime']['settings'] += array(
+    'repeat' => 0,
+  );
+  $info['datestamp']['settings'] += array(
+    'repeat' => 0,
+  );
+}
+
+/**
+ * Implements hook_field_formatter_info_alter().
+ *
+ * This hook lets us add settings to the formatters.
+ */
+function date_repeat_field_field_formatter_info_alter(&$info) {
+
+  if (isset($info['date_default'])) {
+    $info['date_default']['settings'] += array(
+      'show_repeat_rule' => 'show',
+    );
+  }
+}
+
+/**
+ * Implements hook_field_widget_info_alter().
+ *
+ * This Field API hook lets us add a new setting to the widgets.
+ */
+function date_repeat_field_field_widget_info_alter(&$info) {
+
+  $info['date_text']['settings'] += array(
+    'repeat_collapsed' => 0,
+  );
+  $info['date_select']['settings'] += array(
+    'repeat_collapsed' => 0,
+  );
+  if (module_exists('date_popup')) {
+    $info['date_popup']['settings'] += array(
+      'repeat_collapsed' => 0,
+    );
+  }
+}
+
+/**
+ * Implements hook_date_field_settings_form_alter().
+ *
+ * This hook lets us alter the field settings form.
+ */
+function date_repeat_field_date_field_settings_form_alter(&$form, $context) {
+
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $has_data = $context['has_data'];
+
+  $form['repeat'] = array(
+    '#type' => 'select',
+    '#title' => t('Repeating date'),
+    '#default_value' => $field['settings']['repeat'],
+    '#options' => array(0 => t('No'), 1 => t('Yes')),
+    '#attributes' => array('class' => array('container-inline')),
+    '#description' => t("Repeating dates use an 'Unlimited' number of values. Instead of the 'Add more' button, they include a form to select when and how often the date should repeat."),
+    '#disabled' => $has_data,
+  );
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for field_ui_field_edit_form().
+ */
+function date_repeat_field_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
+  $field = $form['#field'];
+  $instance = $form['#instance'];
+
+  if (!in_array($field['type'], array('date', 'datetime', 'datestamp'))) {
+    return;
+  }
+
+  // If using repeating dates, override the Field module's handling of the multiple values option.
+  if (date_is_repeat_field($field, $instance)) {
+    $form['field']['cardinality']['#disabled'] = TRUE;
+    $form['field']['cardinality']['#value'] = FIELD_CARDINALITY_UNLIMITED;
+  }
+}
+
+/**
+ * Implements hook_date_field_instance_settings_form_alter().
+ *
+ * This hook lets us alter the field instance settings form.
+ */
+function date_repeat_field_date_field_instance_settings_form_alter(&$form, $context) {
+  // Just a placeholder for now.
+}
+
+/**
+ * Implements hook_date_field_widget_settings_form_alter().
+ *
+ * This hook lets us alter the field widget settings form.
+ */
+function date_repeat_field_date_field_widget_settings_form_alter(&$form, $context) {
+
+  $field = $context['field'];
+  $instance = $context['instance'];
+
+  if (date_is_repeat_field($field, $instance)) {
+    $form['repeat_collapsed'] = array(
+      '#type' => 'value',
+      '#default_value' => 1,
+      '#options' => array(
+        0 => t('Expanded', array(), array('context' => 'Date repeat')),
+        1 => t('Collapsed', array(), array('context' => 'Date repeat'))
+      ),
+      '#title' => t('Repeat display', array(), array('context' => 'Date repeat')),
+      '#description' => t("Should the repeat options form start out expanded or collapsed? Set to 'Collapsed' to make those options less obtrusive.", array(), array('context' => 'Date repeat')),
+      '#fieldset' => 'date_format',
+      );
+  }
+
+}
+
+/**
+ * Implements hook_date_field_foramatter_settings_form_alter().
+ *
+ * This hook lets us alter the field formatter settings form.
+ */
+function date_repeat_field_date_field_formatter_settings_form_alter(&$form, &$form_state, $context) {
+
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $view_mode = $context['view_mode'];
+  $display = $instance['display'][$view_mode];
+  $formatter = $display['type'];
+  $settings = $display['settings'];
+  if ($formatter == 'date_default') {
+    $form['show_repeat_rule'] = array(
+      '#title' => t('Repeat rule:'),
+      '#type' => 'select',
+      '#options' => array(
+        'show' => t('Show repeat rule'),
+        'hide' => t('Hide repeat rule')),
+      '#default_value' => $settings['show_repeat_rule'],
+      '#access' => $field['settings']['repeat'],
+      '#weight' => 5,
+    );
+  }
+}
+
+/**
+ * Implements hook_date_field_foramatter_settings_summary_alter().
+ *
+ * This hook lets us alter the field formatter settings summary.
+ */
+function date_repeat_field_date_field_formatter_settings_summary_alter(&$summary, $context) {
+
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $view_mode = $context['view_mode'];
+  $display = $instance['display'][$view_mode];
+  $formatter = $display['type'];
+  $settings = $display['settings'];
+  if (isset($settings['show_repeat_rule']) && !empty($field['settings']['repeat'])) {
+    if ($settings['show_repeat_rule'] == 'show') {
+      $summary[] = t('Show repeat rule');
+    }
+    else {
+      $summary[] = t('Hide repeat rule');
+    }
+  }
+}
diff --git a/sites/all/modules/date/date_tools/date_tools.change_type.inc b/sites/all/modules/date/date_tools/date_tools.change_type.inc
new file mode 100644
index 0000000000000000000000000000000000000000..cad2cafdcc0101ff8bb6ab591d1f7f967afc74ba
--- /dev/null
+++ b/sites/all/modules/date/date_tools/date_tools.change_type.inc
@@ -0,0 +1,182 @@
+<?php
+
+/**
+ * @file
+ * A form to change the type of date used in date fields.
+ */
+
+/**
+ * Form constructor for the date type change form.
+ *
+ * @see date_tools_change_type_form_validate()
+ * @see date_tools_change_type_form_submit()
+ */
+function date_tools_change_type_form() {
+  $form = array();
+  // This is broken, still needs to be adjusted for the D6->D7 changes.
+  drupal_set_message(t('This operation does not yet work for the Drupal 7 version.'), 'error');
+  return $form;
+  $fields = content_fields();
+  $date_options = array();
+  $type_options = array();
+
+  $labels = array();
+  foreach (date_field_info() as $type => $info) {
+    $type_options[$type] = $info['label'] . ': ' . $info['description'];
+    $labels[$type] = $info['label'];
+  }
+  // Get the available date fields.
+  foreach ($fields as $field_name => $field) {
+    if ($field['type'] == 'date' || $field['type'] == 'datestamp' || $field['type'] == 'datetime') {
+      $date_options[$labels[$field['type']]][$field_name] = t('Field @label (@field_name)', array('@label' => $field['widget']['label'], '@field_name' => $field_name, '@type' => $labels[$field['type']]));
+    }
+  }
+  if (sizeof($date_options) < 1) {
+    drupal_set_message(t('There are no date fields in this database.'));
+    return $form;
+  }
+  $form['date_field'] = array(
+    '#type' => 'select',
+    '#options' => $date_options,
+    '#title' => t('Date field'),
+    '#default_value' => '',
+    '#description' => t('The date field which whose type should be changed.'),
+  );
+  $form['type'] = array(
+    '#type' => 'radios',
+    '#options' => $type_options,
+    '#default_value' => '',
+    '#required' => TRUE,
+    '#description' => t('The type of date to change the field to.'),
+    '#prefix' => '<strong>' . t('New type:') . '</strong>',
+  );
+  $form['submit'] = array('#type' => 'submit', '#value' => t('Change'));
+  return $form;
+}
+
+/**
+ * Form validation handler for date_tools_change_type_form().
+ *
+ * @see date_tools_change_type_form_submit()
+ */
+function date_tools_change_type_form_validate($form, &$form_state) {
+  $field_name = $form_state['values']['date_field'];
+  $new_type = $form_state['values']['type'];
+  $field = content_fields($field_name);
+  $old_type = $field['type'];
+  if ($new_type == $old_type) {
+    form_set_error('type', t('The current type is the same as the chosen type. There is nothing to change.'));
+  }
+}
+
+/**
+ * Form submission handler for date_tools_change_type_form().
+ *
+ * @see date_tools_change_type_form_validate()
+ */
+function date_tools_change_type_form_submit($form, &$form_state) {
+  $field_name = $form_state['values']['date_field'];
+  $new_type = $form_state['values']['type'];
+  $field = content_fields($field_name);
+  $old_type = $field['type'];
+  if ($new_type == $old_type) {
+    return;
+  }
+  $db_info = content_database_info($field);
+  $table = $db_info['table'];
+  $columns = $db_info['columns'];
+  $labels = array();
+  foreach (date_field_info() as $type => $info) {
+    $labels[$type] = $info['label'];
+  }
+
+  // Is there any data in this field? If not, we can
+  // skip some steps.
+  $has_data = db_query("SELECT COUNT(*) FROM {" . $table . "}")->fetchField();
+
+  // Create a backup copy of the original values.
+  // The values are going to get corrupted when we
+  // change the column type.
+  if ($has_data) {
+    $temp_table = $table . '_temp';
+    db_query("CREATE TABLE {" . $temp_table . "} SELECT * FROM {" . $table . "}");
+  }
+
+  // Change the field definition to the new type.
+  $field['type'] = $new_type;
+  require_once './' . drupal_get_path('module', 'content') . '/includes/content.crud.inc';
+  content_field_instance_update($field, FALSE);
+  content_clear_type_cache();
+
+  // If there's no data to update, we're finished.
+  if (!$has_data) {
+    drupal_set_message(t('The field @field_name has been changed from @old_type to @new_type.', array(
+    '@field_name' => $field['widget']['label'], '@old_type' => $labels[$old_type], '@new_type' => $labels[$new_type])));
+    return;
+  }
+
+  // Replace old values with modified values, massaging the original values as
+  // necessary for the new type.
+  require_once './' . drupal_get_path('module', 'date_api') . '/date_api_sql.inc';
+  $date_handler = new date_sql_handler();
+  $date_handler->granularity = $field['granularity'];
+  $date_handler->date_type = $old_type;
+
+  $new_columns = array();
+  $old_columns = array('nid', 'vid');
+  $new_columns[] = $temp_table . '.nid AS nid';
+  $new_columns[] = $temp_table . '.vid AS vid';
+  if ($field->multiple) {
+    $new_columns[] = $temp_table . '.delta AS delta';
+    $old_columns[] = 'delta';
+  }
+  foreach ($columns as $column => $info) {
+    if ($column != 'value' && $column != 'value2') {
+      continue;
+    }
+    $old_columns[] = $info['column'];
+    $db_field = $date_handler->sql_field($temp_table . '.' . $info['column'], 0);
+    switch ($old_type) {
+      case 'date':
+        switch ($new_type) {
+          case 'datestamp':
+            $new_columns[] = $date_handler->sql_format('U', $db_field) . ' AS ' . $info['column'];
+            break;
+          case 'datetime':
+            $new_columns[] = $date_handler->sql_format('Y-m-d H:i:s', $db_field) . ' AS ' . $info['column'];
+            break;
+        }
+        break;
+      case 'datestamp':
+        switch ($new_type) {
+          case 'date':
+            $new_columns[] = $date_handler->sql_format('Y-m-d/TH:i:s', $db_field) . ' AS ' . $info['column'];
+            break;
+          case 'datetime':
+            $new_columns[] = $date_handler->sql_format('Y-m-d H:i:s', $db_field) . ' AS ' . $info['column'];
+            break;
+        }
+        break;
+      case 'datetime':
+        switch ($new_type) {
+          case 'date':
+            $new_columns[] = $date_handler->sql_format('Y-m-d/TH:i:s', $db_field) . ' AS ' . $info['column'];
+            break;
+          case 'datestamp':
+            $new_columns[] = $date_handler->sql_format('U', $db_field) . ' AS ' . $info['column'];
+            break;
+        }
+        break;
+    }
+  }
+
+  // Make sure database timezone is set to UTC.
+  $date_handler->set_db_timezone();
+
+  // Make the replacement.
+  $sql = 'REPLACE INTO {' . $table . '} (' . implode(', ', $old_columns) . ') ' . ' SELECT ' . implode(', ', $new_columns) . ' FROM {' . $temp_table . '}';
+  db_query($sql);
+  db_query("DROP TABLE {" . $temp_table . "}");
+
+  drupal_set_message(t('The field @field_name has been changed from @old_type to @new_type.', array('@field_name' => $field['widget']['label'], '@old_type' => $labels[$old_type], '@new_type' => $labels[$new_type])));
+}
diff --git a/sites/all/modules/date/date_tools/date_tools.info b/sites/all/modules/date/date_tools/date_tools.info
new file mode 100644
index 0000000000000000000000000000000000000000..a34dcc8339b8eb035e768d0af587a0c4ee14ae99
--- /dev/null
+++ b/sites/all/modules/date/date_tools/date_tools.info
@@ -0,0 +1,14 @@
+name = Date Tools
+description = Tools to import and auto-create dates and calendars.
+dependencies[] = date
+package = Date/Time
+core = 7.x
+configure = admin/config/date/tools
+files[] = tests/date_tools.test
+
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date_tools/date_tools.module b/sites/all/modules/date/date_tools/date_tools.module
new file mode 100644
index 0000000000000000000000000000000000000000..a7ac5f1eb461cc9c1c4dd611a4bf8d90d0378735
--- /dev/null
+++ b/sites/all/modules/date/date_tools/date_tools.module
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * @file
+ * @todo.
+ */
+
+/**
+ * Implements hook_help().
+ */
+function date_tools_help($section, $arg) {
+  switch ($section) {
+    case 'admin/config/date/tools':
+      return '<p>' . t('<h2>Tools for Dates and Calendars</h2>') . '</p>';
+
+    case 'admin/config/date/tools/change':
+      return '<p>' . t('Change a date field from one type to another. Very experimental, use at your own risk!') . '</p>';
+
+    case 'admin/config/date/tools/date_wizard':
+
+      $output = t("Fill out the following form to auto-create a date content type, with a datetime field and matching pre-configured calendar. If the calendar module is enabled and the option to create a calendar is chosen, a calendar and upcoming events block will be created, an ical feed will be added to the calendar. Nodes created from this new content type will include a link to the calendar, and the calendar will have a link to the 'add new date' form. You can also add new date fields to an existing content type by entering the existing content type name instead of creating a new one.") .
+      '</p><p>' .
+      t('Only a limited set of options are displayed here to make this easy to set up. Once the date has been created you will be able to make other changes to the date settings and add other fields to your new content type on the Manage fields screen. You can also make changes to the calendar on the Views edit page.') .
+      '</p>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_permission().
+ */
+function date_tools_permission() {
+  return array(
+    'administer date tools' =>  array(
+      'title' => t('Administer date tools'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function date_tools_menu() {
+
+  $items = array();
+  $items['admin/config/date/tools'] = array(
+    'title'    => 'Date Tools',
+    'description' => 'Date Wizard and other tools to manage and create dates and calendars. ',
+    'access arguments'   => array('administer date tools'),
+    'page callback' => 'date_tools_page',
+  );
+  $items['admin/config/date/tools/about'] = array(
+    'title' => 'About',
+    'description' => 'Date Wizard and other tools to manage and create dates and calendars. ',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -5,
+    'page callback' => 'date_tools_page',
+    'access arguments' => array('administer date tools'),
+  );
+  $items['admin/config/date/tools/date_wizard'] = array(
+    'title' => 'Date wizard',
+    'description' => 'Easy creation of date content types and calendars. ',
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 1,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('date_tools_wizard_form'),
+    'access arguments' => array('administer date tools'),
+    'file' => 'date_tools.wizard.inc',
+  );
+
+  /**
+  $items['admin/config/date/tools/change'] = array(
+    'title'    => 'Change type',
+    'access arguments'   => array('administer date tools'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('date_tools_change_type_form'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 3,
+    'file' => 'date_tools.change_type.inc',
+  );
+  */
+
+  return $items;
+}
+
+/**
+ *  Main Date Tools page
+ */
+function date_tools_page() {
+  $content = '';
+
+  $content .= t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and related calendar. ', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
+
+
+  return $content;
+}
diff --git a/sites/all/modules/date/date_tools/date_tools.wizard.inc b/sites/all/modules/date/date_tools/date_tools.wizard.inc
new file mode 100644
index 0000000000000000000000000000000000000000..034cf3756494507dbdadc360dd4624ec2eade829
--- /dev/null
+++ b/sites/all/modules/date/date_tools/date_tools.wizard.inc
@@ -0,0 +1,392 @@
+<?php
+
+/**
+ * @file
+ * The Date Wizard code.
+ */
+
+/**
+ * @todo.
+ */
+function date_tools_wizard_form() {
+  $form = array();
+  $form['type'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Content type'),
+  );
+  $form['type']['bundle'] = array(
+    '#type' => 'textfield',
+    '#default_value' => 'date',
+    '#title' => t('Content type name'),
+    '#description' => t('Machine-readable name. Allowed values: (a-z, 0-9, _). If this is not an existing content type, the content type will be created.'),
+  );
+  $form['type']['name'] = array(
+    '#type' => 'textfield',
+    '#default_value' => t('Date'),
+    '#title' => t('Content type label'),
+    '#description' => t('The human-readable name for this content type. Only needed when creating a new content type.'),
+  );
+  $form['type']['type_description'] = array(
+    '#type' => 'textarea',
+    '#default_value' => t('A date content type that is linked to a Views calendar.'),
+    '#title' => t('Content type description'),
+    '#description' => t('A description for the content type. Only needed when creating a new content type.'),
+  );
+  $form['field'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Date field'),
+  );
+  $form['field']['field_name'] = array(
+    '#type' => 'textfield',
+    '#default_value' => 'date',
+    '#field_prefix' => 'field_',
+    '#title' => t('Date field name'),
+    '#description' => t('Machine-readable name. Allowed values: (a-z, 0-9, _) Must not be an existing field name.'),
+  );
+  $form['field']['label'] = array(
+    '#tree' => TRUE,
+    '#type' => 'textfield',
+    '#default_value' => t('Date'),
+    '#title' => t('Date field label'),
+    '#description' => t('The human-readable label for this field.'),
+  );
+  $form['field']['widget_type'] = array(
+    '#type' => 'select',
+    '#options' => date_tools_wizard_widget_types(),
+    '#default_value' => 'date_select',
+    '#title' => t('Date widget type'),
+  );
+  $form['field']['repeat'] = array(
+    '#type' => 'select',
+    '#default_value' => 0,
+    '#options' => array(0 => t('No'), 1 => t('Yes')),
+    '#title' => t('Show repeating date options'),
+    '#access' => module_exists('date_repeat_field'),
+  );
+  $form['field']['advanced'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('Advanced options'),
+  );
+  $form['field']['advanced']['todate'] = array(
+    '#type' => 'select',
+    '#default_value' => 'optional',
+    '#options' => array('' => t('Never'), 'optional' => t('Optional'), 'required' => t('Required')),
+    '#title' => t('End Date'),
+    '#description' => t("Display a matching second date field as a 'End date'."),
+  );
+  $form['field']['advanced']['field_type'] = array(
+    '#type' => 'select',
+    '#options' => date_tools_wizard_field_types(),
+    '#default_value' => 'datetime',
+    '#title' => t('Date field type'),
+    '#description' => t("The recommend type is Datetime, except for historical dates or dates with only year or month granularity. Older or incomplete dates should use the Date type (an ISO date)."),
+  );
+  $form['field']['advanced']['granularity'] = array(
+    '#type' => 'select',
+    '#options' => date_granularity_names(),
+    '#default_value' => array('month', 'day', 'year', 'hour', 'minute'),
+    '#title' => t('Granularity'),
+    '#multiple' => TRUE,
+  );
+  $form['field']['advanced']['year_range'] = array(
+    '#type' => 'textfield',
+    '#default_value' => '-1:+1',
+    '#title' => t('Year range'),
+    '#description' => t("Range of allowed years, oldest to newest. '-1:+1 means oldest date is one year back, newest is one year forward from current year."),
+  );
+  $form['field']['advanced']['tz_handling'] = array(
+    '#type' => 'select',
+    '#options' => date_tools_wizard_tz_handling(),
+    '#default_value' => 'site',
+    '#title' => t('Date timezone handling'),
+    '#description' => t("Timezone handling should be set to 'none' for granularity without time elements."),
+  );
+  $form['calendar'] = array(
+    '#type' => 'select',
+    '#default_value' => module_exists('calendar'),
+    '#options' => array(0 => t('No'), 1 => t('Yes')),
+    '#title' => t('Create a calendar for this date field'),
+    '#access' => module_exists('calendar'),
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+  return $form;
+}
+
+/**
+ * @todo.
+ */
+function date_tools_wizard_form_validate(&$form, &$form_state) {
+  $bundle = $form_state['values']['bundle'];
+  $field_name = 'field_' . $form_state['values']['field_name'];
+  $existing_type = db_query("SELECT type FROM {node_type} WHERE type=:bundle", array(':bundle' => $bundle))->fetchField();
+  $existing_instance = db_query("SELECT field_name FROM {field_config_instance} WHERE field_name=:field_name AND bundle=:bundle AND entity_type=:entity_type", array(':field_name' => $field_name, ':bundle' => $bundle, ':entity_type' => 'node'))->fetchField();
+  if ($existing_type) {
+    drupal_set_message(t('This content type name already exists, adding new field to existing content type.'));
+  }
+  if (!preg_match('!^[a-z0-9_]+$!', $bundle)) {
+    form_set_error('bundle', t('The machine-readable name must contain only lowercase letters, numbers, and underscores.'));
+  }
+  if (!empty($form_state['values']['calendar']) && !empty($form_state['values']['blocks']) && strlen($bundle) > 12) {
+    form_set_error('bundle', t('The content type name must be no more than 12 characters long when using it to create a calendar and blocks.'));
+  }
+  if ($existing_instance) {
+    form_set_error('field_name', t('This field name already exists.'));
+  }
+  if (strlen($field_name) > 32) {
+    form_set_error('field_name', t('The field name must be no more than 26 characters long.'));
+  }
+  if (!date_has_time($form_state['values']['granularity']) && $form_state['values']['tz_handling'] != 'none') {
+    form_set_error('tz_handling', t('Timezone handling must be none for granularity without time.'));
+  }
+}
+
+/**
+ * @todo.
+ */
+function date_tools_wizard_form_submit(&$form, &$form_state) {
+  $view_name = date_tools_wizard_build($form_state['values']);
+  menu_rebuild();
+  if (!empty($form_state['values']['calendar']) && !empty($view_name)) {
+    $form_state['redirect'] = 'admin/structure/views/template/' . $view_name . '/add';
+  }
+  else {
+    $form_state['redirect'] = 'admin/structure/types/manage/' . str_replace('_', '-', $form_state['values']['bundle']) . '/fields';
+  }
+}
+
+/**
+ * @todo.
+ */
+function date_tools_wizard_build($form_values) {
+  extract($form_values);
+
+  $field_name = 'field_' . $field_name;
+  $base_table = 'node';
+
+  // Create a node type if it doesn't already exist.
+  // This makes it possible to add additional date fields to
+  // an existing type.
+  $types = node_type_get_names();
+  $type_settings = array();
+  if (!array_key_exists($bundle, $types)) {
+    date_tools_wizard_create_content_type($name, $bundle, $type_description, $type_settings);
+
+    drupal_set_message(t('Your content type @name has been created.', array('@name' => $name)));
+  }
+  else {
+    $types = node_type_get_types();
+    $type = $types[$bundle];
+    if (!empty($type_settings)) {
+      foreach ($type_settings as $key => $setting) {
+        $type->$key = $setting;
+      }
+      node_type_save($type);
+    }
+    $name = $type->name;
+  }
+
+  $field = array(
+    'field_name' => $field_name,
+    'type' => $field_type,
+    'cardinality' => $repeat ? FIELD_CARDINALITY_UNLIMITED : 1,
+    'settings' => array(
+      'granularity' => $granularity,
+      'tz_handling' => $tz_handling,
+      'timezone_db' => date_get_timezone_db($tz_handling),
+      'repeat' => $repeat,
+      'todate' => !empty($todate) ? $todate : 'optional',
+      ),
+  );
+  $instance = array(
+    'entity_type' => 'node',
+    'field_name' => $field_name,
+    'label' => $label,
+    'bundle' => $bundle,
+    // Move the date right below the title.
+    'weight' => -4,
+    'widget' => array(
+      'type' => $widget_type,
+      // Increment for minutes and seconds, can be 1, 5, 10, 15, or 30.
+      'settings' => array(
+        'increment' => 15,
+        // The number of years to go back and forward in drop-down year
+        // selectors.
+        'year_range' => !empty($year_range) ? $year_range : '-0:+1',
+        'input_format' => date_default_format($widget_type),
+        'text_parts' => array(),
+        'label_position' => 'above',
+        'repeat_collapsed' => 0,
+      ),
+      'weight' => -4,
+    ),
+    'settings' => array(
+      'default_value' => 'now',
+      'default_value2' => 'blank',
+    ),
+  );
+
+  $instance['display'] = array(
+    'default' => array(
+      'label' => 'above',
+      'type' => 'date_default',
+      'settings' => array(
+        'format_type' => 'long',
+        'show_repeat_rule' => 'show',
+        'multiple_number' => '',
+        'multiple_from' => '',
+        'multiple_to' => '',
+        'fromto' => 'both',
+      ),
+      'module' => 'date',
+      'weight' => 0 ,
+    ),
+    'teaser' => array(
+      'label' => 'above',
+      'type' => 'date_default',
+      'weight' => 0,
+      'settings' => array(
+        'format_type' => 'long',
+        'show_repeat_rule' => 'show',
+        'multiple_number' => '',
+        'multiple_from' => '',
+        'multiple_to' => '',
+        'fromto' => 'both',
+      ),
+      'module' => 'date',
+    ),
+  );
+
+  $field = field_create_field($field);
+  $instance = field_create_instance($instance);
+  $view_name = 'calendar_' . $field_name;
+
+  field_info_cache_clear(TRUE);
+  field_cache_clear(TRUE);
+
+  drupal_set_message(t('Your date field @name has been created.', array('@name' => $label)));
+
+  return $view_name;
+}
+
+/**
+ * @todo.
+ */
+function date_tools_wizard_include() {
+  module_load_include('inc', 'node', 'content_types');
+  module_load_include('inc', 'node', 'node.pages');
+  module_load_include('inc', 'field', 'field.crud');
+  module_load_include('inc', 'date', 'date_admin');
+}
+
+/**
+ * @todo.
+ */
+function date_tools_wizard_field_types() {
+  $field_types = array();
+  foreach (date_field_info() as $name => $info) {
+    $field_types[$name] = $info['label'];
+  }
+  return $field_types;
+}
+
+/**
+ * @todo.
+ */
+function date_tools_wizard_widget_types() {
+  $widget_types = array();
+  foreach (date_field_widget_info() as $name => $info) {
+    if (!strstr($name, '_repeat')) {
+      $widget_types[$name] = $info['label'];
+    }
+  }
+  return $widget_types;
+}
+
+/**
+ * @todo.
+ */
+function date_tools_wizard_tz_handling() {
+  include_once drupal_get_path('module', 'date') . '/date_admin.inc';
+  return date_timezone_handling_options();
+}
+
+/**
+ * @todo.
+ */
+function date_tools_wizard_create_content_type($name, $bundle, $description, $type_settings = array()) {
+
+  date_tools_wizard_include();
+
+  // Create the content type.
+  $values  = array(
+    'name' => $name,
+    'type' => $bundle,
+    'description' => $description,
+    'title_label' => 'Title',
+    'body_label' => 'Body',
+    'min_word_count' => '0',
+    'help' => '',
+    'node_options' =>
+    array(
+      'status' => 1,
+      'promote' => 1,
+      'sticky' => 0,
+      'revision' => 0,
+    ),
+    'language_content_type' => '0',
+    'old_type' => $bundle,
+    'orig_type' => '',
+    'base' => 'node_content',
+    'custom' => '1',
+    'modified' => '1',
+    'locked' => '0',
+    'url_str' => str_replace('_', '-', $bundle),
+  );
+
+  // Allow overrides of these values.
+  foreach ($type_settings as $key => $value) {
+    $values[$key] = $value;
+  }
+
+  node_type_save((object) $values);
+
+  // Add the body field.
+  $trim_length = variable_get('teaser_length', 600);
+
+  $field = field_info_field('body');
+  $instance = array(
+    'field_name' => 'body',
+    'entity_type' => 'node',
+    'bundle' => $bundle,
+    'label' => t('Description'),
+    'widget' => array(
+      'type' => 'text_textarea_with_summary',
+      'settings' => array(
+        'rows' => 20,
+        'summary_rows' => 5,
+      ),
+      'weight' => -4,
+      'module' => 'text',
+    ),
+    'settings' => array('display_summary' => TRUE),
+     'display' => array(
+      'default' => array(
+        'label' => 'hidden',
+        'type' => 'text_default',
+      ),
+      'teaser' => array(
+        'label' => 'hidden',
+        'type' => 'text_summary_or_trimmed',
+        'trim_length' => $trim_length,
+      ),
+    ),
+  );
+  field_create_instance($instance);
+
+}
diff --git a/sites/all/modules/date/date_tools/tests/date_tools.test b/sites/all/modules/date/date_tools/tests/date_tools.test
new file mode 100644
index 0000000000000000000000000000000000000000..47c056424ed4c0655147f12014572eab8e29f058
--- /dev/null
+++ b/sites/all/modules/date/date_tools/tests/date_tools.test
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @file
+ * Tests for Date Tools.
+ */
+
+class DateToolsTestCase extends DrupalWebTestCase {
+  protected $privileged_user;
+
+  /**
+   * @todo.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Date Tools',
+      'description' => 'Test Date Wizard and other Date Tools.',
+      'group' => 'Date',
+    );
+  }
+
+  /**
+   * @todo.
+   */
+  public function setUp() {
+    // Load the date_api module.
+    parent::setUp('field', 'field_ui', 'date_api', 'date', 'date_popup', 'date_tools');
+
+    // Create and log in our privileged user.
+    $this->privileged_user = $this->drupalCreateUser(
+      array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools')
+    );
+    $this->drupalLogin($this->privileged_user);
+
+    variable_set('date_format_long', 'D, m/d/Y - H:i');
+  }
+
+  /**
+   * Creates a date field using the Date Wizard.
+   */
+  public function testTools() {
+    $form_values = array('label' => 'Test', 'field_type' => 'datetime', 'widget_type' => 'date_select', 'todate' => '');
+    $this->createDateWizard($form_values);
+    $this->dateForm($options = 'select');
+    $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for the Date Wizard datetime field using the date_select widget.');
+    $this->deleteDateField();
+  }
+
+  /**
+   * Tests that date field functions properly.
+   */
+  function dateForm($options) {
+    $edit = array();
+    $edit['title'] = $this->randomName(8);
+    $edit['body[und][0][value]'] = $this->randomName(16);
+    if ($options == 'select') {
+      $edit['field_test[und][0][value][year]'] = '2010';
+      $edit['field_test[und][0][value][month]'] = '10';
+      $edit['field_test[und][0][value][day]'] = '7';
+      $edit['field_test[und][0][value][hour]'] = '10';
+      $edit['field_test[und][0][value][minute]'] = '30';
+    }
+    elseif ($options == 'text') {
+      $edit['field_test[und][0][value][date]'] = '10/07/2010 - 10:30';
+    }
+    elseif ($options == 'popup') {
+      $edit['field_test[und][0][value][date]'] = '10/07/2010';
+      $edit['field_test[und][0][value][time]'] = '10:30';
+    }
+    $this->drupalPost('node/add/story', $edit, t('Save'));
+    $this->assertText($edit['body[und][0][value]'], 'Test node has been created');
+  }
+
+  /**
+   * @todo.
+   */
+  function deleteDateField() {
+    $this->drupalGet('admin/structure/types/manage/story/fields');
+    $this->clickLink('delete');
+    $this->drupalPost(NULL, NULL, t('Delete'));
+    $this->assertText('The field Test has been deleted from the Story content type.', 'Removed date field.');
+  }
+
+  /**
+   * Creates a date field using the Date Wizard.
+   */
+  function createDateWizard($edit) {
+    $edit += array(
+      'bundle' => 'story',
+      'name' => 'Story',
+      'type_description' => 'A test content type.',
+      'field_name' => 'test',
+      'label' => 'Test',
+      'widget_type' => 'date_select',
+      'todate' => 'optional',
+      'field_type' => 'date',
+      'granularity[]' => array('year', 'month', 'day', 'hour', 'minute'),
+      'tz_handling' => 'site',
+      'year_range' => '2010:+2',
+    );
+    $this->drupalPost('admin/config/date/tools/date_wizard', $edit, t('Save'));
+    $this->assertText('Your date field Test has been created.', 'Create a date field using the Date Wizard.');
+  }
+
+}
diff --git a/sites/all/modules/date/date_views/css/date_views.css b/sites/all/modules/date/date_views/css/date_views.css
new file mode 100644
index 0000000000000000000000000000000000000000..a0121ea9bbbc1f9e5538055cf8200e6c404d5cb6
--- /dev/null
+++ b/sites/all/modules/date/date_views/css/date_views.css
@@ -0,0 +1,142 @@
+/* Pager plugin css */
+div.date-views-pager {
+  margin-left: auto;
+  margin-right: auto;
+}
+div.date-views-pager li {
+  float: left;
+  text-align: left;
+  width: 20%;
+}
+
+div.date-views-pager div.current-page {
+  font-weight: bold;
+  text-align: center;
+}
+div.date-views-pager div.next-month,
+div.date-views-pager div.next-year {
+  text-align: right;
+}
+
+
+/* Views filter form css */
+.views-group-box div.date-views-filter-fieldset {
+  margin-left: 0;
+}
+.views-group-box fieldset.date-views-filter-fieldset {
+  padding-top: 0;
+}
+.views-group-box fieldset.date-views-filter-fieldset .container-inline-date > .form-item {
+  border-width: 0;
+  margin: 9px 3px 0 3px;
+  display: block;
+}
+.views-group-box fieldset.date-views-filter-fieldset .container-inline-date .date-padding {
+  padding: 0;
+}
+
+.date-views-filter-wrapper {
+  min-width: 250px;
+}
+.date-views-filter input {
+  float: left !important; /* LTR */
+  margin-right: 2px !important; /* LTR */
+  min-width: 12em;
+  padding: 0 !important;
+  width: 12em;
+}
+
+/**
+ * Style Header
+ */
+/* Give the navigation bar a little extra padding below so it will clear the new contextual links overlay of the teasers below it. */
+.date-nav {
+  clear: both;
+  padding-bottom: 1.5em;
+  width: 100%;
+}
+.date-nav div.date-heading h3 {
+  margin: 0;
+  padding: 0;
+}
+
+.date-nav-wrapper .clear-block {
+  margin-bottom: 10px;
+}
+
+.date-nav-wrapper  {
+  position: relative;
+  margin-top: 5px;
+  width: 100%;
+}
+
+.date-nav-wrapper .date-nav {
+  background-color: transparent;
+  border: 0px;
+  height: 30px;
+  height: auto;
+  min-height: 30px;
+  position: relative;
+  margin-bottom: 10px;
+}
+
+.date-nav-wrapper .date-prev a,
+.date-nav-wrapper .date-next a {
+  text-decoration: none;
+  color: inherit;
+  font-size: 12px;
+}
+
+.date-nav-wrapper.date-nav a:hover {
+  text-decoration: underline;
+}
+
+.date-nav-wrapper .date-prev {
+  padding: 5px 0;
+  position: absolute;
+  left: 0px;
+  text-align: left;
+  top: 0px;
+  width: auto;
+  z-index: 1;
+  font-size: 12px;
+}
+
+.date-nav-wrapper .date-prev {
+  left: 0;
+  right: auto;
+}
+
+.date-nav-wrapper .date-prev a {
+  margin-left: 10px;
+  font-weight: bold;
+}
+
+.date-nav-wrapper .date-heading {
+  position: relative;
+  width: 100%;
+  top: 0px;
+  text-align: center;
+  z-index: 0;
+}
+
+.date-nav-wrapper .date-heading h3 {
+  line-height: 30px;
+  font-size: 1.7em;
+}
+
+.date-nav-wrapper .date-next {
+  padding: 5px 0;
+  position: absolute;
+  right: 0px;
+  text-align: right;
+  top: 0px;
+  width: auto;
+  z-index: 1;
+  font-size: 12px;
+}
+
+.date-nav-wrapper .date-next a {
+  margin-right: 10px;
+  font-weight: bold;
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date_views/date_views.info b/sites/all/modules/date/date_views/date_views.info
new file mode 100644
index 0000000000000000000000000000000000000000..9216f8e01a38d8ea2f3e18e4415ef42e84134576
--- /dev/null
+++ b/sites/all/modules/date/date_views/date_views.info
@@ -0,0 +1,21 @@
+name = Date Views
+description = Views integration for date fields and date functionality.
+package = Date/Time
+dependencies[] = date_api
+dependencies[] = views
+core = 7.x
+php = 5.2
+files[] = includes/date_views_argument_handler.inc
+files[] = includes/date_views_argument_handler_simple.inc
+files[] = includes/date_views_filter_handler.inc
+files[] = includes/date_views_filter_handler_simple.inc
+files[] = includes/date_views.views_default.inc
+files[] = includes/date_views.views.inc
+files[] = includes/date_views_plugin_pager.inc
+
+; Information added by drupal.org packaging script on 2012-04-19
+version = "7.x-2.5"
+core = "7.x"
+project = "date"
+datestamp = "1334835098"
+
diff --git a/sites/all/modules/date/date_views/date_views.module b/sites/all/modules/date/date_views/date_views.module
new file mode 100644
index 0000000000000000000000000000000000000000..03a80dd478017b1de0e7c1e8b4ba5bce59b64b37
--- /dev/null
+++ b/sites/all/modules/date/date_views/date_views.module
@@ -0,0 +1,429 @@
+<?php
+
+/**
+ * Implements hook_views_api().
+ *
+ * This one is used as the base to reduce errors when updating.
+ */
+function date_views_theme() {
+  $path = drupal_get_path('module', 'date_views');
+  $base = array(
+    'file' => 'theme.inc',
+    'path' => "$path/theme",
+  );
+  return array(
+    'date_nav_title' => $base + array('variables' => array('granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL)),
+    'date_views_filter_form' => $base + array('template' => 'date-views-filter-form', 'render element' => 'form'),
+    'date_calendar_day' => $base + array('variables' => array('date' => NULL)),
+
+    'date_views_pager' => $base + array(
+      'variables' => array('plugin' => NULL, 'input' => NULL),
+      // Register a pattern so that it can work like all views templates.
+      'pattern' => 'date_views_pager__',
+      'template' => 'date-views-pager',
+    ),
+  );
+}
+
+function date_views_views_api() {
+  return array(
+    'api' => 3,
+    'path' => drupal_get_path('module', 'date_views') . '/includes',
+  );
+}
+
+/**
+ * Wrapper function to make sure this function will always work.
+ */
+function date_views_views_fetch_fields($base, $type) {
+  if (!module_exists('views')) {
+    return array();
+  }
+  module_load_include('inc', 'views', 'includes/admin');
+  return views_fetch_fields($base, $type);
+}
+
+/**
+ *  Identify all potential date/timestamp fields and cache the data.
+ */
+function date_views_fields($base = 'node', $reset = FALSE) {
+  static $fields = array();
+  $empty = array('name' => array(), 'alias' => array());
+  module_load_include('inc', 'date_views', 'includes/date_views_fields');
+
+  if (empty($fields[$base]) || $reset) {
+    $cid = 'date_views_fields_' . $base;
+    if (!$reset && $cached = cache_get($cid, 'cache_views')) {
+      $fields[$base] = $cached->data;
+    }
+    else {
+      $fields[$base] = _date_views_fields($base);
+    }
+  }
+  // Make sure that empty values will be arrays in he expected format.
+  return !empty($fields) && !empty($fields[$base]) ? $fields[$base] : $empty;
+}
+
+/**
+ * Implements hook_date_views_entities().
+ * Map extra Views tables to the entity that holds its date fields,
+ * needed for Views tables other than the primary tables identified in entity_info().
+ */
+function date_views_date_views_extra_tables() {
+  return array(
+    'node_revision' => 'node',
+  );
+}
+
+/**
+ * Helper function to map entity types to the Views base table they use,
+ * to make it easier to infer the entity type from a base table.
+ *
+ * Views has a new handler called views_handler_field_entity() that loads
+ * entities, and you can use something like the following to get the
+ * entity type from a view, but not all our base tables contain the
+ * entity information we need, (i.e. revisions) so it won't work here
+ * and we resort to creating information from entity_get_info().
+ *
+ *   // A method to get the entity type for a base table.
+ *   $table_data = views_fetch_data($base_table);
+ *   if (!isset($table_data['table']['base']['entity type'])) {
+ *     return FALSE;
+ *   }
+ *   $entity_type = $table_data['table']['base']['entity type'];
+ */
+function date_views_base_tables() {
+  $base_tables = &drupal_static(__FILE__, array());
+
+  if (empty($base_tables)) {
+
+    // First we get the base tables we can learn about from entity_info.
+    $entity_info = entity_get_info();
+    foreach ($entity_info as $entity_type => $info) {
+      if (!empty($info['base table'])) {
+        $base_tables[$info['base table']] = $entity_type;
+      }
+      if (!empty($info['revision table'])) {
+        $base_tables[$info['revision table']] = $entity_type;
+      }
+    }
+
+    // Then we let other modules tell us about other entity tables that hold date fields.
+    $base_tables += module_invoke_all('date_views_extra_tables');
+  }
+
+  return $base_tables;
+}
+
+/**
+ * Implements hook_date_views_fields().
+ *
+ * All modules that create custom fields that use the
+ * 'views_handler_field_date' handler can provide
+ * additional information here about the type of
+ * date they create so the date can be used by
+ * the Date API views date argument and date filter.
+ */
+function date_views_date_views_fields($field) {
+  $values = array(
+    // The type of date: DATE_UNIX, DATE_ISO, DATE_DATETIME.
+    'sql_type' => DATE_UNIX,
+    // Timezone handling options: 'none', 'site', 'date', 'utc' .
+    'tz_handling' => 'site',
+    // Needed only for dates that use 'date' tz_handling.
+    'timezone_field' => '',
+    // Needed only for dates that use 'date' tz_handling.
+    'offset_field' => '',
+    // Array of "table.field" values for related fields that should be
+    // loaded automatically in the Views SQL.
+    'related_fields' => array(),
+    // Granularity of this date field's db data.
+    'granularity' => array('year', 'month', 'day', 'hour', 'minute', 'second'),
+  );
+
+  switch ($field) {
+    case 'users.created':
+    case 'users.access':
+    case 'users.login':
+    case 'node.created':
+    case 'node.changed':
+    case 'node_revision.timestamp':
+    case 'file_managed.timestamp':
+    case 'comment.timestamp':
+      return $values;
+  }
+}
+
+/**
+ * A version of date_real_url that formats links correctly for the new Date pager.
+ */
+function date_pager_url($view, $date_type = NULL, $date_arg = NULL, $force_view_url = FALSE, $absolute = TRUE) {
+
+  // If someone adds a pager without a matching argument, there is not date information to work with.
+  if (empty($view->date_info) || !isset($view->date_info->date_arg_pos)) {
+    return '';
+  }
+
+  $args = $view->args;
+  $pos = $view->date_info->date_arg_pos;
+
+  // The View arguments array is indexed numerically but is not necessarily
+  // in numerical order. Sort the arguments to ensure the correct order.
+  ksort($args);
+
+  // If there are empty arguments before the date argument,
+  // pad them with the wildcard so the date argument will be in
+  // the right position.
+  if (count($args) < $pos) {
+    foreach ($view->argument as $name => $argument) {
+      if ($argument->position == $pos) {
+        break;
+      }
+      $args[] = $argument->options['exception']['value'];
+    }
+  }
+
+  if (!empty($date_type)) {
+    switch ($date_type) {
+      case 'year':
+        $args[$pos] = date_pad($view->date_info->year, 4);
+        break;
+      case 'week':
+        $args[$pos] = date_pad($view->date_info->year, 4) . '-W' . date_pad($view->date_info->week);
+        break;
+      case 'day':
+        $args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month) . '-' . date_pad($view->date_info->day);
+        break;
+      default:
+        $args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month);
+        break;
+    }
+  }
+  elseif (!empty($date_arg)) {
+    $args[$pos] = $date_arg;
+  }
+  else {
+    $args = $view->args;
+  }
+  // Is this an embedded or a block view?
+  // Return the pager query value.
+  if (!$force_view_url &&
+  (!empty($view->preview) || !empty($view->date_info->block_identifier))) {
+
+    $url = $args[$pos];
+    $key = date_block_identifier($view);
+    if (!empty($key)) {
+      return url($_GET['q'], array(
+        'query' => date_views_querystring($view, array($key => $url)),
+        'absolute' => $absolute));
+    }
+  }
+
+  // Normal views may need querystrings appended to them
+  // if they use exposed filters.
+  return url($view->get_url($args), array(
+    'query' => date_views_querystring($view),
+    'absolute' => $absolute));
+}
+
+function date_block_identifier($view) {
+  if (!empty($view->block_identifier)) {
+    return $view->block_identifier;
+  }
+  return isset($view->date_info->block_identifier) ? $view->date_info->block_identifier : NULL;
+}
+
+/**
+ * Implements hook_field_views_data_alter().
+ *
+ * Create a Views field for each date column we care about
+ * to supplement the generic 'entity_id' and 'revision_id'
+ * fields that are automatically created.
+ *
+ * Also use friendlier labels to distinguish the start date
+ * and end date in listings (for fields that use both).
+ */
+function date_views_field_views_data_alter(&$result, $field, $module) {
+  if ($module == 'date') {
+    $has_end_date = !empty($field['settings']['todate']);
+    if ($has_end_date) {
+      $labels = field_views_field_label($field['field_name']);
+      $label = array_shift($labels);
+    }
+    foreach ($result as $table => $data) {
+      $additional = array();
+      $field_name = $field['field_name'];
+      foreach ($data as $column => $value) {
+
+        // The old 'entity_id' and 'revision_id' values got rewritten in Views.
+        // The old values are still there with a 'moved to' key, so ignore them.
+        if (array_key_exists('field', $value) && !array_key_exists('moved to', $value['field'])) {
+          $result[$table][$column]['field']['is date'] = TRUE;
+          // Not sure yet if we still need a custom field handler in D7 now that custom formatters are available.
+          // Might still need it to handle grouping of multiple value dates.
+          //$result[$table][$column]['field']['handler'] = 'date_handler_field_date';
+          //$result[$table][$column]['field']['add fields to query'] = TRUE;
+        }
+
+        // For filters, arguments, and sorts, determine if this column is for
+        // the start date ('value') or the end date ('value2').
+        $this_column = NULL;
+        foreach (array_keys($field['columns']) as $candidate_column) {
+          if ($column == $field['field_name'] . '_' . $candidate_column) {
+            $this_column = $candidate_column;
+            break;
+          }
+        }
+
+        // Only alter the date fields, not timezone, rrule, offset, etc.
+        if ($this_column != 'value' && $this_column != 'value2') {
+          continue;
+        }
+
+        // We will replace the label with a friendlier name in the case of
+        // arguments, filters, and sorts (but only if this field uses an end
+        // date).
+        $replace_label = FALSE;
+        if (array_key_exists('argument', $value)) {
+          $result[$table][$column]['argument']['handler'] = 'date_views_argument_handler_simple';
+          $result[$table][$column]['argument']['empty field name'] = t('Undated');
+          $result[$table][$column]['argument']['is date'] = TRUE;
+          $replace_label = $has_end_date;
+        }
+        if (array_key_exists('filter', $value)) {
+          $result[$table][$column]['filter']['handler'] = 'date_views_filter_handler_simple';
+          $result[$table][$column]['filter']['empty field name'] = t('Undated');
+          $result[$table][$column]['filter']['is date'] = TRUE;
+          $replace_label = $has_end_date;
+        }
+        if (array_key_exists('sort', $value)) {
+          $result[$table][$column]['sort']['is date'] = TRUE;
+          $replace_label = $has_end_date;
+        }
+        if ($replace_label) {
+          // Determine if this column is for the start date ('value') or the
+          // end date ('value2').
+          $this_column = NULL;
+          foreach (array_keys($field['columns']) as $candidate_column) {
+            if ($column == $field['field_name'] . '_' . $candidate_column) {
+              $this_column = $candidate_column;
+              break;
+            }
+          }
+          // Insert the phrase "start date" or "end date" after the label, so
+          // users can distinguish them in listings (compared to the default
+          // behavior of field_views_field_default_views_data(), which only
+          // uses the 'value2' column name to distinguish them).
+          switch ($this_column) {
+            case 'value':
+              // Insert a deliberate double space before 'start date' in the
+              // translatable string. This is a hack to get it to appear right
+              // before 'end date' in the listing (i.e., in a non-alphabetical,
+              // but more user friendly, order).
+              $result[$table][$column]['title'] = t('@label -  start date (!name)', array('@label' => $label, '!name' => $field['field_name']));
+              $result[$table][$column]['title short'] = t('@label -  start date', array('@label' => $label));
+              break;
+            case 'value2':
+              $result[$table][$column]['title'] = t('@label - end date (!name:!column)', array('@label' => $label, '!name' => $field['field_name'], '!column' => $this_column));
+              $result[$table][$column]['title short'] = t('@label - end date:!column', array('@label' => $label, '!column' => $this_column));
+              break;
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for views_ui_edit_form().
+ */
+function date_views_form_views_ui_edit_form_alter(&$form, &$form_state, $form_id) {
+  // This CSS is needed for the configuration form provided by the Date filter
+  // (date_views_filter_handler_simple), but we have to add it here so that
+  // it's already on the edit form the first time a Date filter is being added
+  // to the View. See http://drupal.org/node/1239228#comment-4885288.
+  $form['#attached']['css'][] = drupal_get_path('module', 'date_views') . '/css/date_views.css';
+}
+
+/**
+ * The instanceof function makes this work for any handler that was derived
+ * from 'views_handler_filter_date' or 'views_handler_argument_date',
+ * which includes core date fields like the node updated field.
+ *
+ * The test for $handler->min_date tells us that this is an argument that
+ * not only is derived from the views date handler but also has been processed
+ * by the Date Views filter or argument code.
+*/
+function date_views_handler_is_date($handler, $type = 'argument') {
+  switch ($type) {
+    case 'filter':
+      return $handler instanceof views_handler_filter_date && !empty($handler->min_date);
+    case 'argument':
+      return $handler instanceof views_handler_argument_date && !empty($handler->min_date);
+  }
+  return FALSE;
+}
+
+/**
+ * Validation hook for exposed filters that use the select widget.
+ * This is to ensure the the user completes all parts of the date
+ * not just some parts. Only needed for the select widget.
+ */
+function date_views_select_validate(&$form, &$form_state) {
+  // If there are no values just return.
+  if (empty($form['value']) && empty($form['min'])) {
+    return;
+  }
+  $granularity = (!empty($form['min']['#date_format'])) ? date_format_order($form['min']['#date_format']) : date_format_order($form['value']['#date_format']);
+  $filled = array();
+  $value = drupal_array_get_nested_value($form_state['input'], $form['#parents']);
+  foreach ($granularity as $part) {
+    if (!empty($value['value'][$part])) {
+      $filled[] = $part;
+    }
+  }
+  if (!empty($filled) && count($filled) != count($granularity)) {
+    $unfilled = array_diff($granularity, $filled);
+    foreach ($unfilled as $part) {
+      switch ($part) {
+        case 'year':
+          form_error($form['value'][$part], t('Please choose a year.'), $form_state);
+          break;
+        case 'month':
+          form_error($form['value'][$part], t('Please choose a month.'), $form_state);
+          break;
+        case 'day':
+          form_error($form['value'][$part], t('Please choose a day.'), $form_state);
+          break;
+        case 'hour':
+          form_error($form['value'][$part], t('Please choose an hour.'), $form_state);
+          break;
+        case 'minute':
+          form_error($form['value'][$part], t('Please choose a minute.'), $form_state);
+          break;
+        case 'second':
+          form_error($form['value'][$part], t('Please choose a second.'), $form_state);
+          break;
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_date_formatter_view_alter().
+ *
+ * If we are displaying a date from a view, see if we have information about
+ * which multiple value to display. If so, set the date_id in the entity.
+ */
+function date_views_date_formatter_pre_view_alter(&$entity, &$variables) {
+  // Some views have no row index.
+  if (!empty($entity->view) && isset($entity->view->row_index)) {
+    $field = $variables['field'];
+    $date_id = 'date_id_' . $field['field_name'];
+    $date_delta = 'date_delta_' . $field['field_name'];
+    $date_item = $entity->view->result[$entity->view->row_index];
+    if (!empty($date_item->$date_id)) {
+      $entity->date_id = 'date.' . $date_item->$date_id . '.' . $field['field_name'] . '.' . $date_item->$date_delta . '.0';
+    }
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date_views/includes/date_plugin_display_attachment.inc b/sites/all/modules/date/date_views/includes/date_plugin_display_attachment.inc
new file mode 100644
index 0000000000000000000000000000000000000000..94371f7688a54b1567a1d245259eec56598e5ddc
--- /dev/null
+++ b/sites/all/modules/date/date_views/includes/date_plugin_display_attachment.inc
@@ -0,0 +1,6 @@
+<?php
+/**
+ * @file
+ * Empty file to avoid fatal error if it doesn't exist.
+ * Formerly the attachment for the Date Browser.
+ */
\ No newline at end of file
diff --git a/sites/all/modules/date/date_views/includes/date_views.views.inc b/sites/all/modules/date/date_views/includes/date_views.views.inc
new file mode 100644
index 0000000000000000000000000000000000000000..9ee9e6d11539d9eea498d1485d91a7da62722218
--- /dev/null
+++ b/sites/all/modules/date/date_views/includes/date_views.views.inc
@@ -0,0 +1,198 @@
+<?php
+/**
+ * @file
+ * Defines date-related Views data and plugins:
+ *
+ * Date argument:
+ *   A generic date argument that has an option to select one or more
+ *   Views date fields to filter on, automatically adds them to the view,
+ *   and then filters the view by the value of the selected field(s).
+ *   The flexible argument will accept and evaluate most ISO date
+ *   and period formats, like 2009-05-01, 2008-W25, P1W.
+ *
+ * Date filter:
+ *   A generic date filter that has an option to select a
+ *   Views date field to filter on, with a choice of a widget to use
+ *   for the filter form and an option to set the default value to
+ *   a set date or something like 'now +90 days' . If the operator is
+ *   set to 'between' or 'not between' you can set a default value for
+ *   both the start and end dates.
+ *
+ * Current date argument default
+ *   Adds a default option to set the argument to the current date
+ *   when the argument is empty.
+ *
+ * Date navigation attachment
+ *   Navigation that can be attached to any display to create back/next
+ *   links by date, requires the date argument and uses the current
+ *   date argument default to set a starting point for the view.
+ */
+/**
+ * Implements hook_views_plugins
+ */
+function date_views_views_plugins() {
+  $path = drupal_get_path('module', 'date_views');
+  $views_path = drupal_get_path('module', 'views');
+  module_load_include('inc', 'date_views', 'theme/theme');
+
+  return array(
+    'module' => 'date_views', // This just tells our themes are elsewhere.
+    'display' => array(
+      // Display plugin for date navigation.
+      'date_nav' => array(
+        'title' => t('Date browser'),
+        'help' => t('Date back/next navigation to attach to other displays. Requires the Date argument.'),
+        'handler' => 'date_plugin_display_attachment',
+        'parent' => 'attachment',
+        'path' => "$path/includes",
+        'theme' => 'views_view',
+        'use ajax' => TRUE,
+        'admin' => t('Date browser'),
+        'help topic' => 'date-browser',
+      ),
+    ),
+
+    'pager' => array(
+      'date_views_pager' => array(
+        'title' => t('Page by date'),
+        'help' => t('Page using the value of a date field.'),
+        'handler' => 'date_views_plugin_pager',
+        'path' => "$path/includes",
+        'help topic' => 'date-views-pager',
+        'uses options' => TRUE,
+      ),
+    ),
+
+    'style' => array(
+      'date_nav' => array(
+        'title' => t('Date browser style'),
+        'help' => t('Creates back/next navigation.'),
+        'handler' => 'date_navigation_plugin_style',
+        'path' => "$path/includes",
+        'theme' => 'date_navigation',
+        'theme file' => 'theme.inc',
+        'theme path' => "$path/theme",
+        'uses row plugin' => FALSE,
+        'uses fields' => FALSE,
+        'uses options' => TRUE,
+        'type' => 'date_nav',
+        'even empty' => TRUE,
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_views_data()
+ */
+function date_views_views_data() {
+  $data = array();
+
+  $tables = date_views_base_tables();
+
+  foreach ($tables as $base_table => $entity) {
+    // The flexible date argument.
+    $data[$base_table]['date_argument'] = array(
+      'group' => t('Date'),
+      'title' => t('Date (!base_table)', array('!base_table' => $base_table)),
+      'help' => t('Filter any Views !base_table date field by a date argument, using any common ISO date/period format (i.e. YYYY, YYYY-MM, YYYY-MM-DD, YYYY-W99, YYYY-MM-DD--P3M, P90D, etc). ', array('!base_table' => $base_table)),
+      'argument' => array(
+        'handler' => 'date_views_argument_handler',
+        'empty field name' => t('Undated'),
+        'is date' => TRUE,
+        //'skip base' => $base_table,
+      ),
+    );
+    // The flexible date filter.
+    $data[$base_table]['date_filter'] = array(
+      'group' => t('Date'),
+      'title' => t('Date (!base_table)', array('!base_table' => $base_table)),
+      'help' => t('Filter any Views !base_table date field.', array('!base_table' => $base_table)),
+      'filter' => array(
+        'handler' => 'date_views_filter_handler',
+        'empty field name' => t('Undated'),
+        'is date' => TRUE,
+        //'skip base' => $base_table,
+      ),
+    );
+  }
+
+  return $data;
+}
+
+/**
+ * Implements hook_views_data_alter().
+ */
+function date_views_views_data_alter(&$data) {
+
+  // Mark all the core date handlers as date fields.
+  // This will identify all handlers that directly use the _date handlers,
+  // will not pick up any that extend those handlers.
+  foreach ($data as $module => &$table) {
+    foreach ($table as $id => &$field) {
+      foreach (array('field', 'sort', 'filter', 'argument') as $type) {
+        if (isset($field[$type]) && isset($field[$type]['handler']) && ($field[$type]['handler'] == 'views_handler_' . $type . '_date')) {
+          $field[$type]['is date'] = TRUE;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Central function for setting up the right timezone values
+ * in the SQL date handler.
+ *
+ * The date handler will use this information to decide if the
+ * database value needs a timezone conversion.
+ *
+ * In Views, we will always be comparing to a local date value,
+ * so the goal is to convert the database value to the right
+ * value to compare to the local value.
+ */
+function date_views_set_timezone(&$date_handler, &$view, $field) {
+  switch ($field['tz_handling']) {
+    case 'date' :
+      $date_handler->db_timezone = 'UTC';
+      $date_handler->local_timezone_field = $field['timezone_field'];
+      $date_handler->offset_field = $field['offset_field'];
+      break;
+    case 'none':
+      $date_handler->db_timezone = date_default_timezone();
+      $date_handler->local_timezone = date_default_timezone();
+      break;
+    case 'utc':
+      $date_handler->db_timezone = 'UTC';
+      $date_handler->local_timezone = 'UTC';
+      break;
+    default :
+      $date_handler->db_timezone = 'UTC';
+      $date_handler->local_timezone = date_default_timezone();
+      break;
+  }
+}
+
+function date_views_querystring($view, $extra_params = array()) {
+  $query_params = array_merge($_GET, $extra_params);
+  // Allow NULL params to be removed from the query string.
+  foreach ($extra_params AS $key => $value) {
+    if (!isset($value)) {
+      unset($query_params[$key]);
+    }
+  }
+  // Filter the special "q" and "view" variables out of the query string.
+  $exclude = array('q');
+  // If we don't explicitly add a value for "view", filter it out.
+  if (empty($extra_params['view'])) {
+    $exclude[] = 'view';
+  }
+  // Clear out old date pager settings if not explicitly added.
+  if (!empty($view->date_info->pager_id) && empty($extra_params[$view->date_info->pager_id])) {
+    $exclude[] = $view->date_info->pager_id;
+  }
+
+  $query = drupal_get_query_parameters($query_params, $exclude);
+  // To prevent an empty query string from adding a "?" on to the end of a URL,
+  // we return NULL.
+  return !empty($query) ? $query : NULL;
+}
diff --git a/sites/all/modules/date/date_views/includes/date_views_argument_handler.inc b/sites/all/modules/date/date_views/includes/date_views_argument_handler.inc
new file mode 100644
index 0000000000000000000000000000000000000000..bba39a6be8380d817004ede7eb15fac684e861b4
--- /dev/null
+++ b/sites/all/modules/date/date_views/includes/date_views_argument_handler.inc
@@ -0,0 +1,195 @@
+<?php
+/**
+ * @file
+ * Date API views argument handler.
+ * This argument combines multiple date arguments into a single argument
+ * where all fields are controlled by the same date and can be combined with either AND or OR.
+ */
+
+/**
+ * Date API argument handler.
+ */
+class date_views_argument_handler extends date_views_argument_handler_simple {
+
+  /**
+   * Get granularity and use it to create the formula and a format
+   * for the results.
+   */
+  function init(&$view, &$options) {
+    parent::init($view, $options);
+
+    if (empty($this->view->date_info)) {
+      $this->view->date_info = new stdClass();
+    }
+    if (empty($this->view->date_info->date_fields)) {
+      $this->view->date_info->date_fields = array();
+    }
+    $this->view->date_info->date_fields = array_merge($this->view->date_info->date_fields, $this->options['date_fields']);
+  }
+
+  /**
+   * Default value for the date_fields option.
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['date_fields'] = array('default' => array());
+    $options['date_method'] = array('default' => 'OR');
+    $options['date_group'] = array('default' => 'date');
+    return $options;
+  }
+
+  /**
+   * Add a form element to select date_fields for this argument.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $fields = date_views_fields($this->base_table);
+    $options = array();
+    foreach ($fields['name'] as $name => $field) {
+      $options[$name] = $field['label'];
+    }
+
+    $form['date_fields'] = array(
+      '#title' => t('Date field(s)'),
+      '#type' => 'checkboxes',
+      '#options' => $options,
+      '#default_value' => $this->options['date_fields'],
+      '#multiple' => TRUE,
+      '#description' => t("Select one or more date fields to filter with this argument."),
+    );
+    $form['date_method'] = array(
+      '#title' => t('Method'),
+      '#type' => 'radios',
+      '#options' => array('OR' => t('OR'), 'AND' => t('AND')),
+      '#default_value' => $this->options['date_method'],
+      '#description' => t('Method of handling multiple date fields in the same query. Return items that have any matching date field (date = field_1 OR field_2), or only those with matches in all selected date fields (date = field_1 AND field_2). '),
+      );
+    $form['date_group'] = array(
+      '#type' => 'hidden',
+      '#value' => $this->options['date_group'],
+    );
+  }
+
+  function options_validate(&$form, &$form_state) {
+
+    // Views will whine if we don't have something for the these values even though we removed the option for summaries.
+    $form_state['values']['options']['summary']['format'] = 'none';
+    $form_state['values']['options']['summary']['options']['none'] = array();
+
+    // It is very important to call the parent function here:
+    parent::options_validate($form, $form_state);
+
+    if ($form_state['values']['form_id'] == 'views_ui_config_item_form') {
+      $check_fields = array_filter($form_state['values']['options']['date_fields']);
+      if (empty($check_fields)) {
+        form_error($form['date_fields'], t('You must select at least one date field for this argument.'));
+      }
+    }
+  }
+
+  function options_submit(&$form, &$form_state) {
+    // It is very important to call the parent function here:
+    parent::options_submit($form, $form_state);
+    if ($form_state['values']['form_id'] == 'views_ui_config_item_form') {
+      $form_state['values']['options']['date_fields'] = array_filter($form_state['values']['options']['date_fields']);
+    }
+  }
+
+  // Update the summary values to show selected granularity.
+  function admin_summary() {
+    $fields = date_views_fields($this->base_table);
+    if (!empty($this->options['date_fields'])) {
+      $output = array();
+      foreach ($this->options['date_fields'] as $field) {
+        if (array_key_exists($field, $fields['name'])) {
+          $output[] = $fields['name'][$field]['label'];
+        }
+      }
+      return implode('<br />' . $this->options['date_method'] . ' ', $output);
+    }
+    else {
+      return parent::admin_summary();
+    }
+  }
+
+  /**
+   * Provide a list of default behaviors for this argument if the argument
+   * is not present.
+   *
+   * Override this method to provide additional (or fewer) default behaviors.
+   */
+  function default_actions($which = NULL) {
+    $defaults = parent::default_actions();
+
+    // There is no easy way to do summary queries on multiple fields, so remove that option.
+    unset($defaults['summary']);
+
+    if ($which) {
+      if (!empty($defaults[$which])) {
+        return $defaults[$which];
+      }
+    }
+    else {
+      return $defaults;
+    }
+  }
+
+  /**
+   * Set up the query for this argument.
+   *
+   * The argument sent may be found at $this->argument.
+   */
+  function query($group_by = FALSE) {
+
+    // @TODO Not doing anything with $group_by yet, need to figure out what has to be done.
+
+    if ($this->date_forbid()) {
+      return;
+    }
+    $this->get_query_fields();
+    $this->query->set_where_group($this->options['date_method'], $this->options['date_group']);
+    $this->granularity = $this->date_handler->arg_granularity($this->argument);
+    $format = $this->date_handler->views_formats($this->granularity, 'sql');
+    if (!empty($this->query_fields)) {
+      // Use set_where_group() with the selected date_method
+      // of 'AND' or 'OR' to create the where clause.
+      foreach ($this->query_fields as $count => $query_field) {
+        $field = $query_field['field'];
+        $this->date_handler = $query_field['date_handler'];
+        $this->field = $field['field_name'];
+        $this->real_field = $field['field_name'];
+        $this->table = $field['table_name'];
+        $this->original_table = $field['table_name'];
+        if ($field['table_name'] != $this->table || !empty($this->relationship)) {
+          $this->table = $this->query->queue_table($field['table_name'], $this->relationship);
+        }
+        // $this->table_alias gets set when the first field is processed if otherwise empty.
+        // For subsequent fields, we need to be sure it is emptied again.
+        elseif (empty($this->relationship)) {
+          $this->table_alias = NULL;
+        }
+        parent::query($group_by);
+      }
+    }
+  }
+
+  /**
+   * Collect information about our fields we will need to create the right query.
+   */
+  function get_query_fields() {
+    $fields = date_views_fields($this->base_table);
+    $fields = $fields['name'];
+    $this->query_fields = array();
+    foreach ($this->options['date_fields'] as $delta => $name) {
+      if (array_key_exists($name, $fields) && $field = $fields[$name]) {
+        $date_handler = new date_sql_handler($field['sql_type'], date_default_timezone());
+        $date_handler->granularity = $this->options['granularity'];
+        $date_handler->db_timezone = date_get_timezone_db($field['tz_handling']);
+        $date_handler->local_timezone = date_get_timezone($field['tz_handling']);
+        date_views_set_timezone($date_handler, $this, $field);
+        $this->query_fields[] = array('field' => $field, 'date_handler' => $date_handler);
+      }
+    }
+  }
+
+}
diff --git a/sites/all/modules/date/date_views/includes/date_views_argument_handler_simple.inc b/sites/all/modules/date/date_views/includes/date_views_argument_handler_simple.inc
new file mode 100644
index 0000000000000000000000000000000000000000..faff05a349eb3b51bf59e5433c31d1cda401fc61
--- /dev/null
+++ b/sites/all/modules/date/date_views/includes/date_views_argument_handler_simple.inc
@@ -0,0 +1,345 @@
+<?php
+/**
+ * @file
+ * Date API views argument handler.
+ */
+
+/**
+ * Date API argument handler.
+ */
+class date_views_argument_handler_simple extends views_handler_argument_date {
+
+  /**
+   * Get granularity and use it to create the formula and a format
+   * for the results.
+   */
+  function init(&$view, &$options) {
+    parent::init($view, $options);
+
+    // Add a date handler.
+    module_load_include('inc', 'date_api', 'date_api_sql');
+    $this->date_handler = new date_sql_handler(DATE_UNIX);
+    if (!empty($this->definition['field_name'])) {
+      $field = field_info_field($this->definition['field_name']);
+      if (!empty($field) && !empty($field['type'])) {
+        $this->date_handler->date_type = $field['type'];
+        $this->original_table = $this->definition['table'];
+      }
+      $this->date_handler->db_timezone = date_get_timezone_db($field['settings']['tz_handling']);
+      $this->date_handler->local_timezone = date_get_timezone($field['settings']['tz_handling']);
+    }
+    $this->date_handler->granularity = $this->options['granularity'];
+    // This value needs to be initialized so it exists even if the query doesn't run.
+    $this->date_handler->placeholders = array();
+
+    $this->format = $this->date_handler->views_formats($this->date_handler->granularity, 'display');
+    $this->sql_format = $this->date_handler->views_formats($this->date_handler->granularity, 'sql');
+    // $this->arg_format is the format the parent date handler will use to create a default argument.
+    $this->arg_format = $this->format();
+
+    // Identify the base table for this field.
+    // It will be used to call for the right query field options.
+    $this->base_table = $this->table;
+
+  }
+
+  function format() {
+    if (!empty($this->options['granularity'])) {
+      return $this->date_handler->views_formats($this->options['granularity']);
+    }
+    else {
+      return !empty($this->options[$this->option_name]) ? $this->options[$this->option_name] : 'Y-m';
+    }
+  }
+
+  /**
+   * Set the empty argument value to the current date,
+   * formatted appropriately for this argument.
+   */
+  function get_default_argument($raw = FALSE) {
+    $is_default = FALSE;
+
+    if (!$raw && $this->options['default_argument_type'] == 'date') {
+      $granularity = $this->options['granularity'];
+      if ($granularity == 'week') {
+        $now = date_now();
+        $week = date_week(date_format($now, 'Y-m-d'));
+        $value = date_format($now, 'Y') . '-W' . $week;
+      }
+      else {
+        $value = date($this->arg_format, REQUEST_TIME);
+      }
+      drupal_alter('date_default_argument', $this, $value);
+
+      return $value;
+    }
+
+    // Let the parent argument handle options like node created date.
+    return parent::get_default_argument($raw);
+  }
+
+  /**
+   * Default value for the date_fields option.
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['year_range'] = array('default' => '-3:+3');
+    $options['granularity'] = array('default' => 'month');
+    $options['default_argument_type'] = array('default' => 'date');
+    $options['add_delta'] = array('default' => '');
+    $options['use_fromto'] = array('default' => '');
+    $options['title_format'] = array('default' => '');
+    $options['title_format_custom'] = array('default' => '');
+    return $options;
+  }
+
+  /**
+   * Add a form element to select date_fields for this argument.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Add an option to control the format of the summary.
+    $options = array(
+      '' => t('Default format'),
+      'custom' => t('Custom format'),
+    );
+    $example_month = date_format_date(date_example_date(), 'custom', $this->date_handler->views_formats('month', 'display'));
+    $example_day = date_format_date(date_example_date(), 'custom', $this->date_handler->views_formats('day', 'display'));
+
+    $form['title_format'] = array(
+      '#type' => 'select',
+      '#title' => t('Date format options'),
+      '#default_value' => $this->options['title_format'],
+      '#options' => $options,
+      '#description' => t('The date format used in titles and summary links for this argument. The default format is based on the granularity of the filter, i.e. month: @example_month, day: @example_day.', array('@example_month' => $example_month, '@example_day' => $example_day)),
+      '#attributes' => array('class' => array('dependent-options')),
+      '#states' => array(
+        'visible' => array(
+          ':input[name="options[default_action]"]' => array('value' => 'summary')
+        ),
+      ),
+    );
+
+    $form['title_format_custom'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Custom summary date format'),
+      '#default_value' => $this->options['title_format_custom'],
+      '#description' => t("A custom format for the title and summary date format. Define a php date format string like 'm-d-Y H:i' (see <a href=\"@link\">http://php.net/date</a> for more details).", array('@link' => 'http://php.net/date')),
+      '#attributes' => array('class' => array('dependent-options')),
+      '#states' => array(
+        'visible' => array(
+          ':input[name="options[title_format]"]' => array('value' => 'custom')
+        ),
+      ),
+    );
+
+    $options = $this->date_handler->date_parts();
+    unset($options['second'], $options['minute']);
+    $options += array('week' => t('Week', array(), array('context' => 'datetime')));
+    $form['granularity'] = array(
+      '#title' => t('Granularity'),
+      '#type' => 'radios',
+      '#options' => $options,
+      '#default_value' => $this->options['granularity'],
+      '#multiple' => TRUE,
+      '#description' => t("Select the type of date value to be used in defaults, summaries, and navigation. For example, a granularity of 'month' will set the default date to the current month, summarize by month in summary views, and link to the next and previous month when using date navigation."),
+    );
+
+    $form['year_range'] = array(
+      '#title' => t('Date year range'),
+      '#type' => 'textfield',
+      '#default_value' => $this->options['year_range'],
+      '#description' => t("Set the allowable minimum and maximum year range for this argument, either a -X:+X offset from the current year, like '-3:+3' or an absolute minimum and maximum year, like '2005:2010' . When the argument is set to a date outside the range, the page will be returned as 'Page not found (404)' ."),
+    );
+
+    $form['use_fromto'] = array(
+      '#type' => 'radios',
+      '#title' => t('Dates to compare'),
+      '#default_value' => $this->options['use_fromto'],
+      '#options' => array('' => t('Start/End date range'), 'no' => t('Only this field')),
+      '#description' => t("If selected the view will check if any value starting with the 'Start' date and ending with the 'End' date matches the view criteria. Otherwise the view will be limited to the specifically selected fields. Comparing to the whole Start/End range is the recommended setting when using this filter in a Calendar. When using the Start/End option, it is not necessary to add both the Start and End fields to the filter, either one will do."),
+    );
+
+    $access = TRUE;
+    if (!empty($this->definition['field_name'])) {
+      $field = field_info_field($this->definition['field_name']);
+      $access = $field['cardinality'] != 1;
+    }
+    $form['add_delta'] = array(
+      '#type' => 'radios',
+      '#title' => t('Add multiple value identifier'),
+      '#default_value' => $this->options['add_delta'],
+      '#options' => array('' => t('No'), 'yes' => t('Yes')),
+      '#description' => t('Add an identifier to the view to show which multiple value date fields meet the filter criteria. Note: This option may introduce duplicate values into the view. Required when using multiple value fields in a Calendar or any time you want the node view of multiple value dates to display only the values that match the view filters.'),
+      // Only let mere mortals tweak this setting for multi-value fields
+      '#access' => $access,
+    );
+
+  }
+
+  function options_validate(&$form, &$form_state) {
+    // It is very important to call the parent function here:
+    parent::options_validate($form, $form_state);
+    if (!preg_match('/^(?:\-[0-9]{1,4}|[0-9]{4}):(?:[\+|\-][0-9]{1,4}|[0-9]{4})$/', $form_state['values']['options']['year_range'])) {
+      form_error($form['year_range'], t('Date year range must be in the format -9:+9, 2005:2010, -9:2010, or 2005:+9'));
+    }
+  }
+
+  /**
+   * Provide a link to the next level of the view from the summary.
+   */
+  function summary_name($data) {
+    $value = $data->{$this->name_alias};
+    if (empty($value) && !empty($this->definition['empty field name'])) {
+      return $this->definition['empty field name'];
+    }
+    elseif (empty($value)) {
+      return $this->options['wildcard_substitution'];
+    }
+    $format = !empty($this->options['title_format_custom']) && !empty($this->options['title_format_custom']) ? $this->options['title_format_custom'] : $this->date_handler->views_formats($this->options['granularity'], 'display');
+    $range = $this->date_handler->arg_range($value);
+    return date_format_date($range[0], 'custom', $format);
+  }
+
+  /**
+   * Provide a title for the view based on the argument value.
+   */
+  function title() {
+    $format = !empty($this->options['title_format_custom']) && !empty($this->options['title_format_custom']) ? $this->options['title_format_custom'] : $this->date_handler->views_formats($this->options['granularity'], 'display');
+    $range = $this->date_handler->arg_range($this->argument);
+    return date_format_date($range[0], 'custom', $format);
+ }
+
+  /**
+   * Provide the argument to use to link from the summary to the next level;
+   * this will be called once per row of a summary, and used as part of
+   * $view->get_url().
+   *
+   * @param $data
+   *   The query results for the row.
+   */
+  function summary_argument($data) {
+    $format = $this->date_handler->views_formats($this->options['granularity'], 'sql');
+    $value = $data->{$this->name_alias};
+    if (empty($value)) {
+      return $this->options['exception']['value'];
+    }
+    $range = $this->date_handler->arg_range($value);
+    return date_format_date($range[0], 'custom', $format);
+  }
+
+  /**
+   * Inject a test for valid date range before the summary query.
+   */
+  function summary_query() {
+
+    // @TODO The summary values are computed by the database. Unless the database has
+    // built-in timezone handling it will use a fixed offset, which will not be
+    // right for all dates. The only way I can see to make this work right is to
+    // store the offset for each date in the database so it can be added to the base
+    // date value before the database formats the result. Because this is a huge
+    // architectural change, it won't go in until we start a new branch.
+    $this->formula = $this->date_handler->sql_format($this->sql_format, $this->date_handler->sql_field("***table***.$this->real_field"));
+    $this->ensure_my_table();
+    // Now that our table is secure, get our formula.
+    $formula = $this->get_formula();
+
+    // Add the field, give it an alias that does NOT match the actual field name or grouping won't work right.
+    $this->base_alias = $this->name_alias = $this->query->add_field(NULL, $formula, $this->field . '_summary');
+    $this->query->set_count_field(NULL, $formula, $this->field);
+
+    return $this->summary_basics(FALSE);
+  }
+
+  /**
+   * Inject a test for valid date range before the regular query.
+   * Override the parent query to be able to control the $group.
+   */
+  function query($group_by = FALSE) {
+
+    // @TODO Not doing anything with $group_by yet, need to figure out what has to be done.
+
+    if ($this->date_forbid()) {
+      return;
+    }
+
+    // See if we need to reset granularity based on an argument value.
+    // Make sure we don't try to reset to some bogus value if someone has typed in an unexpected argument.
+    $granularity = $this->date_handler->arg_granularity($this->argument);
+    if (!empty($granularity)) {
+      $this->date_handler->granularity = $granularity;
+      $this->format = $this->date_handler->views_formats($this->date_handler->granularity, 'display');
+      $this->sql_format = $this->date_handler->views_formats($this->date_handler->granularity, 'sql');
+    }
+    $this->granularity = $this->date_handler->granularity;
+    $this->ensure_my_table();
+    $group = !empty($this->options['date_group']) ? $this->options['date_group'] : 0;
+
+    // If requested, add the delta field to the view so we can later find the value that matched our query.
+    if (!empty($this->options['add_delta']) && (substr($this->real_field, -6) == '_value' || substr($this->real_field, -7) == '_value2')) {
+      $this->query->add_field($this->table_alias, 'delta');
+      $real_field_name = str_replace(array('_value', '_value2'), '', $this->real_field);
+      $this->query->add_field($this->table_alias, 'entity_id', 'date_id_' . $real_field_name);
+      $this->query->add_field($this->table_alias, 'delta', 'date_delta_' . $real_field_name);
+    }
+
+    $format = $this->date_handler->granularity == 'week' ? DATE_FORMAT_DATETIME : $this->sql_format;
+    $view_min = date_format($this->min_date, $format);
+    $view_max = date_format($this->max_date, $format);
+    $view_min_placeholder = $this->placeholder();
+    $view_max_placeholder = $this->placeholder();
+    $this->date_handler->placeholders = array($view_min_placeholder => $view_min, $view_max_placeholder => $view_max);
+
+    // Are we comparing this field only or the Start/End date range to the view criteria?
+    if (!empty($this->options['use_fromto'])) {
+
+      // The simple case, match the field to the view range.
+      $field = $this->date_handler->sql_field($this->table_alias . '.' . $this->real_field, NULL, $this->min_date);
+      $field = $this->date_handler->sql_format($format, $field);
+      $this->query->add_where_expression($group, "$field >= $view_min_placeholder AND $field <= $view_max_placeholder", array($view_min_placeholder => $view_min, $view_max_placeholder => $view_max));
+
+    }
+    else {
+
+      // Look for the intersection of the range of the date field with the range of the view.
+      // Get the Start/End values for this field. Retrieve using the original table name.
+      // Swap the current table name (adjusted for relationships) into the query.
+      // @TODO We may be able to use Views substitutions here, investigate that later.
+      $fields = date_views_fields($this->base_table);
+      $fields = $fields['name'];
+      $fromto = $fields[$this->original_table . '.' . $this->real_field]['fromto'];
+
+      $value_min = str_replace($this->original_table, $this->table_alias, $fromto[0]);
+      $value_max = str_replace($this->original_table, $this->table_alias, $fromto[1]);
+      $field_min = $this->date_handler->sql_field($value_min, NULL, $this->min_date);
+      $field_min = $this->date_handler->sql_format($format, $field_min);
+      $field_max = $this->date_handler->sql_field($value_max, NULL, $this->max_date);
+      $field_max = $this->date_handler->sql_format($format, $field_max);
+      $this->query->add_where_expression($group, "$field_max >= $view_min_placeholder AND $field_min <= $view_max_placeholder", array($view_min_placeholder => $view_min, $view_max_placeholder => $view_max));
+    }
+  }
+
+  /**
+   * Add a callback to determine if we have moved outside the valid date range for this argument.
+   */
+  function date_forbid() {
+    if (empty($this->argument)) {
+      return TRUE;
+    }
+    $this->date_range = $this->date_handler->arg_range($this->argument);
+    $this->min_date = $this->date_range[0];
+    $this->max_date = $this->date_range[1];
+    $this->limit = date_range_years($this->options['year_range']);
+    $group = !empty($this->options['date_group']) ? $this->options['date_group'] : 0;
+
+    // See if we're outside the allowed date range for our argument.
+    if (date_format($this->min_date, 'Y') < $this->limit[0] || date_format($this->max_date, 'Y') > $this->limit[1]) {
+      $this->forbid = TRUE;
+      $this->view->build_info['fail'] = TRUE;
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+}
diff --git a/sites/all/modules/date/date_views/includes/date_views_fields.inc b/sites/all/modules/date/date_views/includes/date_views_fields.inc
new file mode 100644
index 0000000000000000000000000000000000000000..a002b08879f92bd320dc414b53fd0c1078e9dc94
--- /dev/null
+++ b/sites/all/modules/date/date_views/includes/date_views_fields.inc
@@ -0,0 +1,169 @@
+<?php
+/**
+ * @file
+ * Helper for identifying Date API fields for views.
+ */
+
+/**
+ *  Identify all potential date/timestamp fields.
+ *
+ *  @return
+ *    array with fieldname, type, and table.
+ *  @see
+ *    date_views_date_views_fields() which implements
+ *    the hook_date_views_fields() for the core date fields.
+ */
+function _date_views_fields($base = 'node') {
+
+  // Make sure $base is never empty.
+  if (empty($base)) {
+    $base = 'node';
+  }
+
+  $cid = 'date_views_fields_' . $base;
+  cache_clear_all($cid, 'cache_views');
+
+  // We use fields that provide filter handlers as our universe of possible
+  // fields of interest.
+  $all_fields = date_views_views_fetch_fields($base, 'filter');
+
+  // Iterate over all the fields that Views knows about.
+  $fields = array();
+  foreach ((array) $all_fields as $alias => $val) {
+    // Set up some default values.
+    $granularity = array('year', 'month', 'day', 'hour', 'minute', 'second');
+    $tz_handling = 'site';
+    $related_fields = array();
+    $timezone_field = '';
+    $offset_field = '';
+    $rrule_field = '';
+    $delta_field = '';
+    $sql_type = DATE_UNIX;
+    $type = '';
+
+    $name = $alias;
+    $tmp = explode('.', $name);
+    $field_name = $tmp[1];
+    $table_name = $tmp[0];
+
+    // Unset the date filter to avoid ugly recursion and broken values.
+    if ($field_name == 'date_filter') {
+      continue;
+    }
+
+    $fromto = array($name, $name);
+
+    // If we don't have a filter handler, we don't need to do anything more.
+    if (!$handler = views_get_handler($table_name, $field_name, 'filter')) {
+      continue;
+    }
+    $handler = views_get_handler($table_name, $field_name, 'filter');
+    $handler_name = $handler->definition['handler'];
+
+    // We don't care about anything but date handlers
+    if (empty($handler->definition['is date'])) {
+      continue;
+    }
+    $is_field = FALSE;
+
+    // For Field module fields, get the date type.
+    $custom = array();
+    if (isset($handler->definition['field_name'])) {
+      $field = field_info_field($handler->definition['field_name']);
+      $is_field = TRUE;
+      switch ($field['type']) {
+       case 'date':
+          $sql_type = DATE_ISO;
+          break;
+        case 'datestamp':
+          break;
+        case 'datetime':
+          $sql_type = DATE_DATETIME;
+          break;
+        default:
+          // If this is not a date field, nothing more to do.
+          continue;
+      }
+
+      $revision = in_array($base, array('node_revision')) ? FIELD_LOAD_REVISION : FIELD_LOAD_CURRENT;
+      $db_info = date_api_database_info($field, $revision);
+      $name = $table_name . "." . $field_name;
+      $granularity = !empty($field['granularity']) ? $field['granularity'] : array('year', 'month', 'day', 'hour', 'minute', 'second');
+
+      $fromto = array(
+        $table_name . '.' . $db_info['columns'][$table_name]['value'],
+        $table_name . '.' . (!empty($field['settings']['todate']) ? $db_info['columns'][$table_name]['value2'] : $db_info['columns'][$table_name]['value']),
+      );
+
+      if (isset($field['settings']['tz_handling'])) {
+        $tz_handling = $field['settings']['tz_handling'];
+        $db_info = date_api_database_info($field, $revision);
+        if ($tz_handling == 'date') {
+          $offset_field = $table_name . '.' . $db_info['columns'][$table_name]['offset'];
+        }
+        $related_fields = array(
+          $table_name . '.' . $db_info['columns'][$table_name]['value']
+        );
+        if (isset($db_info['columns'][$table_name]['value2'])) {
+          $related_fields = array_merge($related_fields, array($table_name . '.' . $db_info['columns'][$table_name]['value2']));
+        }
+        if (isset($db_info['columns'][$table_name]['timezone'])) {
+          $related_fields = array_merge($related_fields, array($table_name . '.' . $db_info['columns'][$table_name]['timezone']));
+          $timezone_field = $table_name . '.' . $db_info['columns'][$table_name]['timezone'];
+        }
+        if (isset($db_info['columns'][$table_name]['rrule'])) {
+          $related_fields = array_merge($related_fields, array($table_name . '.' . $db_info['columns'][$table_name]['rrule']));
+          $rrule_field = $table_name . '.' . $db_info['columns'][$table_name]['rrule'];
+        }
+      }
+      // Get the delta value into the query.
+      if ($field['cardinality'] != 1) {
+        array_push($related_fields, "$table_name.delta");
+        $delta_field = $table_name . '_delta';
+      }
+    }
+
+    // Allow custom modules to provide date fields.
+    else {
+      foreach (module_implements('date_views_fields') as $module) {
+        $function = $module . '_date_views_fields';
+        if ($custom = $function("$table_name.$field_name")) {
+          $type = 'custom';
+          break;
+        }
+      }
+    }
+    // Don't do anything if this is not a date field we can handle.
+    if (!empty($type) || empty($custom)) {
+      $alias = str_replace('.', '_', $alias);
+      $fields['name'][$name] = array(
+        'is_field' => $is_field,
+        'sql_type' => $sql_type,
+        'label' => $val['group'] . ': ' . $val['title'],
+        'granularity' => $granularity,
+        'fullname' => $name,
+        'table_name' => $table_name,
+        'field_name' => $field_name,
+        'query_name' => $alias,
+        'fromto' => $fromto,
+        'tz_handling' => $tz_handling,
+        'offset_field' => $offset_field,
+        'timezone_field' => $timezone_field,
+        'rrule_field' => $rrule_field,
+        'related_fields' => $related_fields,
+        'delta_field' => $delta_field,
+      );
+
+      // Allow the custom fields to over-write values.
+      if (!empty($custom)) {
+        foreach ($custom as $key => $val) {
+          $fields['name'][$name][$key] = $val;
+        }
+      }
+      $fields['name'][$name]['real_field_name'] = $field_name;
+      $fields['alias'][$alias] = $fields['name'][$name];
+    }
+  }
+  cache_set($cid, $fields, 'cache_views');
+  return $fields;
+}
diff --git a/sites/all/modules/date/date_views/includes/date_views_filter_handler.inc b/sites/all/modules/date/date_views/includes/date_views_filter_handler.inc
new file mode 100644
index 0000000000000000000000000000000000000000..63467a2615b1cce2148b00394de3eb64d7b194b3
--- /dev/null
+++ b/sites/all/modules/date/date_views/includes/date_views_filter_handler.inc
@@ -0,0 +1,177 @@
+<?php
+/**
+ * @file
+ * A flexible, configurable date filter.
+ * This filter combines multiple date filters into a single filter
+ * where all fields are controlled by the same date and can be combined with either AND or OR.
+ */
+
+class date_views_filter_handler extends date_views_filter_handler_simple {
+  function init(&$view, &$options) {
+    parent::init($view, $options);
+
+    if (empty($this->view->date_info)) {
+      $this->view->date_info = new stdClass();
+    }
+    if (empty($this->view->date_info->date_fields)) {
+      $this->view->date_info->date_fields = array();
+    }
+    $this->view->date_info->date_fields = array_merge($this->view->date_info->date_fields, $this->options['date_fields']);
+  }
+
+  // Set default values for the date filter.
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['date_fields'] = array('default' => array());
+    $options['date_method'] = array('default' => 'OR');
+    $options['date_group'] = array('default' => 'date');
+    return $options;
+  }
+
+  function op_between($field) {
+    $this->date_combine_conditions('op_between');
+  }
+
+  function op_simple($field) {
+    $this->date_combine_conditions('op_simple');
+  }
+
+  /**
+   * Combines multiple date WHERE expressions into a single WHERE expression.
+   *
+   * @param string $function
+   *   The function name to use to add individual conditions. Either 'op_simple'
+   *   or 'op_between'.
+   */
+  protected function date_combine_conditions($function) {
+    $this->get_query_fields();
+    if (empty($this->query_fields)) {
+      return;
+    }
+
+    // Create a custom filter group for the conditions.
+    $this->query->set_where_group($this->options['date_method'], $this->options['date_group']);
+    // Add each condition to the custom filter group.
+    foreach ((array) $this->query_fields as $query_field) {
+      $field = $query_field['field'];
+      $this->date_handler = $query_field['date_handler'];
+
+      // Respect relationships when determining the table alias.
+      if ($field['table_name'] != $this->table || !empty($this->relationship)) {
+        $this->related_table_alias = $this->query->queue_table($field['table_name'], $this->relationship);
+      }
+      $table_alias = !empty($this->related_table_alias) ? $this->related_table_alias : $field['table_name'];
+      $field_name = $table_alias . '.' . $field['field_name'];
+
+      // Call the appropriate function, either 'op_between' or 'op_simple'.
+      parent::$function($field_name);
+    }
+
+    // Gather all of the condition strings and their placeholders.
+    $conditions = array();
+    $placeholders = array();
+    foreach ($this->query->where[$this->options['date_group']]['conditions'] as $condition) {
+      $conditions[] = $condition['field'];
+      $placeholders += $condition['value'];
+    }
+
+    // Remove the conditions from the custom filter group.
+    unset($this->query->where[$this->options['date_group']]);
+
+    // Combine all of the conditions into one string.
+    $conditions = implode(' ' . $this->options['date_method'] . ' ', $conditions);
+
+    // Add it to the filter group chosen in the Views UI.
+    $this->query->add_where_expression($this->options['group'], $conditions, $placeholders);
+  }
+
+  function extra_options_form(&$form, &$form_state) {
+    parent::extra_options_form($form, $form_state);
+
+    $fields = date_views_fields($this->base_table);
+    $options = array();
+    foreach ($fields['name'] as $name => $field) {
+      $options[$name] = $field['label'];
+    }
+
+    $form['date_fields'] = array(
+      '#title' => t('Date field(s)'),
+      '#type' => 'checkboxes',
+      '#options' => $options,
+      '#default_value' => $this->options['date_fields'],
+      '#multiple' => FALSE,
+      '#description' => t('Select date field(s) to filter.'),
+      '#required' => TRUE,
+    );
+    $form['date_method'] = array(
+      '#title' => t('Method'),
+      '#type' => 'radios',
+      '#options' => array('OR' => t('OR'), 'AND' => t('AND')),
+      '#default_value' => $this->options['date_method'],
+      '#description' => t('Method of handling multiple date fields in the same query. Return items that have any matching date field (date = field_1 OR field_2), or only those with matches in all selected date fields (date = field_1 AND field_2).'),
+      );
+  }
+
+  function extra_options_validate($form, &$form_state) {
+    $check_fields = array_filter($form_state['values']['options']['date_fields']);
+    if (empty($check_fields)) {
+      form_error($form['date_fields'], t('You must select at least one date field for this filter.'));
+    }
+  }
+
+  function extra_options_submit($form, &$form_state) {
+    $form_state['values']['options']['date_fields'] = array_filter($form_state['values']['options']['date_fields']);
+  }
+
+  // Update the summary values to provide
+  // meaningful information for each option.
+  function admin_summary() {
+    if (empty($this->options['date_fields'])) {
+      return t('Missing date fields!');
+    }
+    $handler = $this->date_handler;
+
+    $fields = date_views_fields($this->view->base_table);
+    if (!empty($this->options['date_fields'])) {
+      $output = array();
+      foreach ($this->options['date_fields'] as $field) {
+        if (array_key_exists($field, $fields['name'])) {
+          $output[] = $fields['name'][$field]['label'];
+        }
+      }
+    }
+    $field = implode(' ' . $this->options['date_method'] . ' ', $output);
+    $output = "$field " . check_plain($this->operator) . ' ';
+    $parts = $handler->date_parts();
+    $widget_options = $this->widget_options();
+    // If the filter is exposed, display the granularity.
+    if ($this->options['exposed']) {
+      return t('(@field) <strong>Exposed</strong> @widget @format', array('@field' => $field, '@format' => $parts[$handler->granularity], '@widget' => $widget_options[$this->options['form_type']]));
+    }
+    // If not exposed, display the value.
+    if (in_array($this->operator, $this->operator_values(2))) {
+      $min = check_plain(!empty($this->options['default_date']) ? $this->options['default_date'] : $this->options['value']['min']);
+      $max = check_plain(!empty($this->options['default_to_date']) ? $this->options['default_to_date'] : $this->options['value']['max']);
+      $output .= t('@min and @max', array('@min' => $min, '@max' => $max));
+    }
+    else {
+      $output .= check_plain(!empty($this->options['default_date']) ? $this->options['default_date'] : $this->options['value']['value']);
+    }
+    return $output;
+  }
+
+  function get_query_fields() {
+    $fields = date_views_fields($this->base_table);
+    $fields = $fields['name'];
+    $this->query_fields = array();
+    foreach ((array) $this->options['date_fields'] as $delta => $name) {
+      if (array_key_exists($name, $fields) && $field = $fields[$name]) {
+        $date_handler = new date_sql_handler($field['sql_type'], date_default_timezone());
+        $date_handler->granularity = $this->options['granularity'];
+        $date_handler->db_timezone = date_get_timezone_db($field['tz_handling']);
+        $date_handler->local_timezone = date_get_timezone($field['tz_handling']);
+        $this->query_fields[] = array('field' => $field, 'date_handler' => $date_handler);
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date_views/includes/date_views_filter_handler_simple.inc b/sites/all/modules/date/date_views/includes/date_views_filter_handler_simple.inc
new file mode 100644
index 0000000000000000000000000000000000000000..8a462533e933a5d4ad33c171b2fd9ca50efddd08
--- /dev/null
+++ b/sites/all/modules/date/date_views/includes/date_views_filter_handler_simple.inc
@@ -0,0 +1,494 @@
+<?php
+/**
+ * @file
+ * A standard Views filter for a single date field, using Date API form selectors and sql handling.
+ */
+
+class date_views_filter_handler_simple extends views_handler_filter_date {
+  var $date_handler = NULL;
+  var $offset = NULL;
+
+  function init(&$view, &$options) {
+    parent::init($view, $options);
+    module_load_include('inc', 'date_api', 'date_api_sql');
+    $this->date_handler = new date_sql_handler(DATE_UNIX);
+    if (!empty($this->definition['field_name'])) {
+      $field = field_info_field($this->definition['field_name']);
+      if (!empty($field) && !empty($field['type'])) {
+        $this->date_handler->date_type = $field['type'];
+      }
+      $this->date_handler->db_timezone = date_get_timezone_db($field['settings']['tz_handling']);
+      $this->date_handler->local_timezone = date_get_timezone($field['settings']['tz_handling']);
+    }
+    $this->form_submitted = FALSE;
+    $this->date_handler->granularity = isset($options['granularity']) ? $options['granularity'] : 'day';
+    $this->format = $this->date_handler->views_formats($this->options['granularity'], 'sql');
+
+    // Identify the base table for this field.
+    // It will be used to call for the right query field options.
+    $this->base_table = $this->table;
+
+  }
+
+  // Set default values for the date filter.
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['granularity'] = array('default' => 'day');
+    $options['form_type'] = array('default' => 'date_select');
+    $options['default_date'] = array('default' => '');
+    $options['default_to_date'] = array('default' => '');
+    $options['year_range'] = array('default' => '-3:+3');
+    $options['add_delta'] = array('default' => '');
+    return $options;
+  }
+
+  /**
+   * Helper function to find a default value.
+   */
+  function date_default_value($prefix, $options = NULL) {
+    $default_date = '';
+    if (empty($options)) {
+      $options = $this->options;
+    }
+    // If this is a remembered value, use the value from the SESSION.
+    if (!empty($this->options['expose']['remember'])) {
+      $display_id = ($this->view->display_handler->is_defaulted('filters')) ? 'default' : $this->view->current_display;
+      if (!empty($_SESSION['views'][$this->view->name][$display_id]['date_filter'][$prefix])) {
+        return $_SESSION['views'][$this->view->name][$display_id]['date_filter'][$prefix];
+      }
+    }
+
+    // This is a date that needs to be constructed from options like 'now' .
+    $default_option = $prefix == 'max' ? $options['default_to_date'] : $options['default_date'];
+    if (!empty($default_option)) {
+      str_replace('now', 'today', $default_option);
+      $date = date_create($default_option, date_default_timezone_object());
+      $default_date = !empty($date) ? $date->format($this->format) : '';
+
+      // The format for our filter is in ISO format, but the widget will need it in datetime format.
+      $default_date = str_replace('T', ' ', $default_date);
+    }
+    // This a fixed date.
+    else {
+      $default_date = $options['value'][$prefix];
+    }
+    return $default_date;
+  }
+
+  /**
+   * Helper function to see if we need to swap in the default value.
+   *
+   * Views exposed filters treat everything as submitted, so if it's an empty value we have to
+   * see if anything actually was submitted. If nothing has really been submitted, we need
+   * to swap in our default value logic.
+   */
+  function get_filter_value($prefix, $input) {
+    // All our date widgets provide datetime values but we use ISO in our SQL
+    // for consistency between the way filters and arguments work (arguments
+    // cannot contain spaces).
+    if (empty($input)) {
+      if (empty($this->options['exposed'])) {
+        return str_replace(' ', 'T', $this->date_default_value($prefix));
+      }
+      elseif (isset($this->options['expose']['identifier']) && !isset($_GET[$this->options['expose']['identifier']])) {
+        return str_replace(' ', 'T', $this->date_default_value($prefix));
+      }
+    }
+
+    return str_replace(' ', 'T', $input);
+  }
+
+  function accept_exposed_input($input) {
+    if (!empty($this->options['exposed'])) {
+      $element_input = $input[$this->options['expose']['identifier']];
+      $element_input['value'] = $this->get_filter_value('value', !empty($element_input['value']) ? $element_input['value'] : '');
+      $element_input['min'] = $this->get_filter_value('min', !empty($element_input['min']) ? $element_input['min'] : '');
+      $element_input['max'] = $this->get_filter_value('max', !empty($element_input['max']) ? $element_input['max'] : '');
+      unset($element_input['default_date']);
+      unset($element_input['default_to_date']);
+
+      $input[$this->options['expose']['identifier']] = $element_input;
+    }
+    return parent::accept_exposed_input($input);
+
+  }
+
+  function op_between($field) {
+
+    // Add the delta field to the view so we can later find the value that matched our query.
+    list($table_name, $field_name) = explode('.', $field);
+    if (!empty($this->options['add_delta']) && (substr($field_name, -6) == '_value' || substr($field_name, -7) == '_value2')) {
+      $this->query->add_field($table_name, 'delta');
+      $real_field_name = str_replace(array('_value', '_value2'), '', $this->real_field);
+      $this->query->add_field($table_name, 'entity_id', 'date_id_' . $real_field_name);
+      $this->query->add_field($table_name, 'delta', 'date_delta_' . $real_field_name);
+    }
+
+    $min_value = $this->get_filter_value('min', $this->value['min']);
+    $min_comp_date = new DateObject($min_value, date_default_timezone(), $this->format);
+    $max_value = $this->get_filter_value('max', $this->value['max']);
+    $max_comp_date = new DateObject($max_value, date_default_timezone(), $this->format);
+    $field_min = $this->date_handler->sql_field($field, NULL, $min_comp_date);
+    $field_min = $this->date_handler->sql_format($this->format, $field_min);
+    $field_max = $this->date_handler->sql_field($field, NULL, $max_comp_date);
+    $field_max = $this->date_handler->sql_format($this->format, $field_max);
+    $placeholder_min = $this->placeholder();
+    $placeholder_max = $this->placeholder();
+    $group = !empty($this->options['date_group']) ? $this->options['date_group'] : $this->options['group'];
+    if ($this->operator == 'between') {
+      $this->query->add_where_expression($group, "$field_min >= $placeholder_min AND $field_max <= $placeholder_max", array($placeholder_min => $min_value, $placeholder_max => $max_value));
+    }
+    else {
+      $this->query->add_where_expression($group, "$field_min < $placeholder_min OR $field_max > $placeholder_max", array($placeholder_min => $min_value, $placeholder_max => $max_value));
+    }
+  }
+
+  function op_simple($field) {
+
+    // Add the delta field to the view so we can later find the value that matched our query.
+    list($table_name, $field_name) = explode('.', $field);
+    if (!empty($this->options['add_delta']) && (substr($field_name, -6) == '_value' || substr($field_name, -7) == '_value2')) {
+      $this->query->add_field($table_name, 'delta');
+      $real_field_name = str_replace(array('_value', '_value2'), '', $this->real_field);
+      $this->query->add_field($table_name, 'entity_id', 'date_id_' . $real_field_name);
+      $this->query->add_field($table_name, 'delta', 'date_delta_' . $real_field_name);
+    }
+
+    $value = $this->get_filter_value('value', $this->value['value']);
+    $comp_date = new DateObject($value, date_default_timezone(), $this->format);
+    $field = $this->date_handler->sql_field($field, NULL, $comp_date);
+    $field = $this->date_handler->sql_format($this->format, $field);
+    $placeholder = $this->placeholder();
+    $group = !empty($this->options['date_group']) ? $this->options['date_group'] : $this->options['group'];
+    $this->query->add_where_expression($group, "$field $this->operator $placeholder", array($placeholder => $value));
+  }
+
+  /**
+   * Set the granularity of the date parts to use in the filter.
+    */
+  function has_extra_options() { return TRUE; }
+
+  /**
+   * Date selection options.
+   */
+  function widget_options() {
+    $options = array(
+      'date_select' => t('Select'),
+      'date_text' => t('Text'),
+      'date_popup' => t('Popup'),
+      );
+    if (!module_exists('date_popup')) {
+      unset($options['date_popup']);
+    }
+    return $options;
+  }
+
+  function year_range() {
+    $year_range = explode(':', $this->options['year_range']);
+    if (substr($this->options['year_range'], 0, 1) == '-' || $year_range[0] < 0) {
+      $this_year = date_format(date_now(), 'Y');
+      $year_range[0] = $this_year + $year_range[0];
+      $year_range[1] = $this_year + $year_range[1];
+    }
+    return $year_range;
+  }
+
+  function extra_options_form(&$form, &$form_state) {
+    parent::extra_options_form($form, $form_state);
+    $form['form_type'] = array(
+      '#type' => 'radios',
+      '#title' => t('Date selection form element'),
+      '#default_value' => $this->options['form_type'],
+      '#options' => $this->widget_options(),
+      );
+
+    $form['granularity'] = $this->date_handler->granularity_form($this->options['granularity']);
+    $form['granularity']['#title'] = t('Filter granularity');
+
+    $form['year_range'] = array(
+      '#type' => 'date_year_range',
+      '#default_value' => $this->options['year_range'],
+    );
+
+    if (!empty($this->definition['field_name'])) {
+      $field = field_info_field($this->definition['field_name']);
+    }
+    $form['add_delta'] = array(
+      '#type' => 'radios',
+      '#title' => t('Add multiple value identifier'),
+      '#default_value' => $this->options['add_delta'],
+      '#options' => array('' => t('No'), 'yes' => t('Yes')),
+      '#description' => t('Add an identifier to the view to show which multiple value date fields meet the filter criteria. Note: This option may introduce duplicate values into the view. Required when using multiple value fields in a Calendar or any time you want the node view of multiple value dates to display only the values that match the view filters.'),
+      // Only let mere mortals tweak this setting for multi-value fields
+      '#access' => !empty($field) ? $field['cardinality'] != 1 : 0,
+    );
+  }
+
+  function extra_options_validate($form, &$form_state) {
+    if (!preg_match('/^(?:\-[0-9]{1,4}|[0-9]{4}):(?:[\+|\-][0-9]{1,4}|[0-9]{4})$/', $form_state['values']['options']['year_range'])) {
+      form_error($form['year_range'], t('Date year range must be in the format -9:+9, 2005:2010, -9:2010, or 2005:+9'));
+    }
+  }
+
+  /**
+   * Add the selectors to the value form using the date handler.
+   */
+  function value_form(&$form, &$form_state) {
+    // We use different values than the parent form, so we must
+    // construct our own form element.
+    $form['value'] = array();
+    $form['value']['#tree'] = TRUE;
+
+    // Below section copied from views_handler_filter_numeric.inc.
+    $which = 'all';
+    $source = '';
+    if (!empty($form['operator'])) {
+      $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+    }
+
+    $identifier = $this->options['expose']['identifier'];
+    if (!empty($form_state['exposed'])) {
+
+      if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
+        // exposed and locked.
+        $which = in_array($this->operator, $this->operator_values(2)) ? 'minmax' : 'value';
+      }
+      else {
+        $source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
+      }
+    }
+
+    if ($which == 'all' || $which == 'value') {
+      $form['value'] += $this->date_parts_form($form_state, 'value', $source, $which, $this->operator_values(1), $identifier, 'default_date');
+    }
+
+    if ($which == 'all' || $which == 'minmax') {
+      $form['value'] += $this->date_parts_form($form_state, 'min', $source, $which, $this->operator_values(2), $identifier, 'default_date');
+      $form['value'] += $this->date_parts_form($form_state, 'max', $source, $which, $this->operator_values(2), $identifier, 'default_to_date');
+    }
+
+    // Add some extra validation for the select widget to be sure that
+    // the user inputs all parts of the date.
+    if ($this->options['form_type'] == 'date_select') {
+      $form['value']['#element_validate'] = array('date_views_select_validate');
+    }
+
+  }
+
+  /**
+   * A form element to select date part values.
+   *
+   * @param string $prefix
+   *   A prefix for the date values, 'value', 'min', or 'max' .
+   * @param string $source
+   *   The operator for this element.
+   * @param string $which
+   *   Which element to provide, 'all', 'value', or 'minmax' .
+   * @param array $operator_values
+   *   An array of the allowed operators for this element.
+   * @param array $identifier
+   *   Identifier of the exposed element.
+   * @param array $relative_id
+   *   Form element id to use for the relative date field.
+   *
+   * @return
+   *   The form date part element for this instance.
+   */
+  function date_parts_form($form_state, $prefix, $source, $which, $operator_values, $identifier, $relative_id) {
+    module_load_include('inc', 'date_api', 'date_api_elements');
+    switch ($prefix) {
+      case 'min':
+        $label = t('Start date');
+        $relative_label = t('Relative start date');
+        break;
+      case 'max':
+        $label = t('End date');
+        $relative_label = t('Relative end date');
+        break;
+      default:
+        $label = '';
+        $relative_label = t('Relative date');
+        break;
+    }
+
+    $type = $this->options['form_type'];
+    if ($type == 'date_popup' && !module_exists('date_popup')) {
+      $type = 'date_text';
+    }
+
+    $format = $this->date_handler->views_formats($this->options['granularity'], 'sql');
+    $granularity = array_keys($this->date_handler->date_parts($this->options['granularity']));
+    $relative_value = ($prefix == 'max' ? $this->options['default_to_date'] : $this->options['default_date']);
+
+    if (!empty($form_state['exposed'])) {
+      // UI when the date selector is exposed.
+      $default_date = $this->date_default_value($prefix);
+      $id = 'edit-' . str_replace('_', '-', $this->field) . '-' . $prefix;
+      $form[$prefix] = array(
+        '#title' => check_plain($label),
+        '#type' => $type,
+        '#size' => 20,
+        '#default_value' => !empty($this->value[$prefix]) ? $this->value[$prefix] : $default_date,
+        '#date_format' => date_limit_format($format, $granularity),
+        '#date_label_position' => 'within',
+        '#date_year_range' => $this->options['year_range'],
+        '#process' => array($type . '_element_process'),
+        '#prefix' => '<div id="' . $id . '-wrapper"><div id="' . $id . '">',
+        '#suffix' => '</div></div>',
+      );
+      if ($which == 'all') {
+        $form[$prefix]['#pre_render'][] = 'ctools_dependent_pre_render';
+        $form[$prefix]['#dependency'] = array($source => $operator_values);
+      }
+      if (!isset($form_state['input'][$identifier][$prefix])) {
+        $form_state['input'][$identifier][$prefix] = $this->value[$prefix];
+      }
+    }
+    else {
+      // UI when the date selector is on the views configuration screen.
+      $default_date = '';
+      $id = 'edit-options-value-' . $prefix;
+      $form[$prefix . '_group'] = array(
+        '#type' => 'fieldset',
+        '#attributes' => array('class' => array('date-views-filter-fieldset')),
+      );
+      $form[$prefix . '_group'][$prefix . '_choose_input_type'] = array(
+        '#title' => check_plain($label),
+        '#type' => 'select',
+        '#options' => array('date' => t('Select a date'), 'relative' => ('Enter a relative date')),
+        '#attributes' => array('class' => array($prefix . '-choose-input-type')),
+        '#default_value' => !empty($relative_value) ? 'relative' : 'date',
+      );
+      $form[$prefix . '_group'][$prefix] = array(
+        '#title' => t('Select a date'),
+        '#type' => $type,
+        '#size' => 20,
+        '#default_value' => !empty($this->value[$prefix]) ? $this->value[$prefix] : $default_date,
+        '#date_format' => date_limit_format($format, $granularity),
+        '#date_label_position' => 'within',
+        '#date_year_range' => $this->options['year_range'],
+        '#process' => array($type . '_element_process'),
+        '#prefix' => '<div id="' . $id . '-wrapper"><div id="' . $id . '">',
+        '#suffix' => '</div></div>',
+        '#states' => array(
+          'visible' => array(
+            ":input.{$prefix}-choose-input-type" => array('value' => 'date'),
+          ),
+        ),
+      );
+      $form[$prefix . '_group'][$relative_id] = array(
+        '#type' => 'textfield',
+        '#title' => check_plain($relative_label),
+        '#default_value' => $relative_value,
+        '#description' => t("Relative dates are computed when the view is displayed. Examples: now, now +1 day, 12AM today, Monday next week. <a href=\"@relative_format\">More examples of relative date formats in the PHP documentation</a>.", array('@relative_format' => 'http://www.php.net/manual/en/datetime.formats.relative.php')),
+        '#states' => array(
+          'visible' => array(
+            ":input.{$prefix}-choose-input-type" => array('value' => 'relative'),
+          ),
+        ),
+      );
+      if ($which == 'all') {
+        $form[$prefix . '_group']['#pre_render'][] = 'ctools_dependent_pre_render';
+        $form[$prefix . '_group']['#dependency'] = array($source => $operator_values);
+      }
+    }
+    return $form;
+  }
+
+  /**
+   * Value validation.
+   *
+   * TODO add in more validation.
+   *
+   * We are setting an extra option using a value form
+   * because it makes more sense to set it there.
+   * That's not the normal method, so we have to manually
+   * transfer the selected value back to the option.
+   */
+  function value_validate($form, &$form_state) {
+
+    $options = &$form_state['values']['options'];
+
+    if ($options['operator'] == 'between' || $options['operator'] == 'not between') {
+      if ($options['value']['min_group']['min_choose_input_type'] == 'relative') {
+        if (empty($options['value']['min_group']['default_date'])) {
+          form_set_error('options][value][min_group][default_date', t('Relative start date not specified.'));
+        }
+        else {
+          $this->options['default_date'] = $options['value']['min_group']['default_date'];
+          // NULL out the value field, user wanted the relative value to take hold.
+          $options['value']['min_group']['min'] = NULL;
+        }
+      }
+      // If an absolute date was used, be sure to wipe the relative date.
+      else {
+        $this->options['default_date'] = '';
+      }
+      if ($options['value']['max_group']['max_choose_input_type'] == 'relative') {
+        if (empty($options['value']['max_group']['default_to_date'])) {
+          form_set_error('options][value][max_group][default_to_date', t('Relative end date not specified.'));
+        }
+        else {
+          $this->options['default_to_date'] = $options['value']['max_group']['default_to_date'];
+          // NULL out the value field, user wanted the relative value to take hold.
+          $options['value']['max_group']['max'] = NULL;
+        }
+      }
+      // If an absolute date was used, be sure to wipe the relative date.
+      else {
+        $this->options['default_to_date'] = '';
+      }
+    }
+    elseif (in_array($options['operator'], array('<', '<=', '=', '!=', '>=', '>'))) {
+      if ($options['value']['value_group']['value_choose_input_type'] == 'relative') {
+        if (empty($options['value']['value_group']['default_date'])) {
+          form_set_error('options][value][value_group][default_date', t('Relative date not specified.'));
+        }
+        else {
+          $this->options['default_date'] = $options['value']['value_group']['default_date'];
+          // NULL out the value field, user wanted the relative value to take hold.
+          $options['value']['value_group']['value'] = NULL;
+        }
+      }
+      // If an absolute date was used, be sure to wipe the relative date.
+      else {
+        $this->options['default_date'] = '';
+      }
+    }
+    // Flatten the form structure for views, so the values can be saved.
+    foreach (array('value', 'min', 'max') as $key) {
+      $options['value'][$key] = $options['value'][$key . '_group'][$key];
+    }
+  }
+
+  /**
+   * Validate that the time values convert to something usable.
+   */
+  function validate_valid_time(&$form, $operator, $value) {
+    // Override the core date filter validation.
+    // Our date widgets do their own validation.
+  }
+
+  // Update the summary values to provide
+  // meaningful information for each option.
+  function admin_summary() {
+    $parts = $this->date_handler->date_parts();
+    $widget_options = $this->widget_options();
+    // If the filter is exposed, display the granularity.
+    if ($this->options['exposed']) {
+      return t('<strong>Exposed</strong> @widget @format', array('@format' => $parts[$this->date_handler->granularity], '@widget' => $widget_options[$this->options['form_type']]));
+    }
+    // If not exposed, display the value.
+    $output = '';
+    if (in_array($this->operator, $this->operator_values(2))) {
+      $min = check_plain(!empty($this->options['default_date']) ? $this->options['default_date'] : $this->options['value']['min']);
+      $max = check_plain(!empty($this->options['default_to_date']) ? $this->options['default_to_date'] : $this->options['value']['max']);
+      $output .= t('@min and @max', array('@min' => $min, '@max' => $max));
+    }
+    else {
+      $output .= check_plain(!empty($this->options['default_date']) ? $this->options['default_date'] : $this->options['value']['value']);
+    }
+    return $output;
+  }
+
+}
diff --git a/sites/all/modules/date/date_views/includes/date_views_plugin_pager.inc b/sites/all/modules/date/date_views/includes/date_views_plugin_pager.inc
new file mode 100644
index 0000000000000000000000000000000000000000..10c6581be39c74f5e4c9b6f05768b3dc1b1b3e5f
--- /dev/null
+++ b/sites/all/modules/date/date_views/includes/date_views_plugin_pager.inc
@@ -0,0 +1,233 @@
+<?php
+/**
+ * @file
+ * Date pager.
+ * Works with a Date argument, the argument filters the view and the pager provides back/next navigation.
+ *
+ * USER NOTES:
+ *
+ * To use this, add a pager to a view, and choose the option to 'Page by date'.
+ * There are several settings:
+ * - The pager id: Set an id to be used as the identifier in the url for pager values, defaults to 'date'.
+ * - Pager position: Choose whether to display the date pager above, below, or both above and below the content.
+ * - Link format: Choose whether the pager links will be in the simple 'calendar/2011-12' format or the
+ *   more complex 'calendar/?date=2011-12' pager format. The second one is more likely to work correctly
+ *   if the pager is used in blocks and panels.
+ *
+ * The pager works in combination with a Date argument and it will use the date fields and granularity
+ * set in that argument to create its back/next links. If the view has no Date argument, the pager can
+ * do nothing. The argument can either be a 'Date' argument that lets you select one or more date fields
+ * in the argument, or the simple 'Content' argument for an individual date field. It must be an
+ * argument that uses the date argument handler.
+ *
+ * DEVELOPER NOTES
+ *
+ * The pager could technically create a query of its own rather than depending on the date argument to
+ * set the query, but it has only a limited set of tools to work with because it is a plugin, not a handler:
+ * it has no knowledge about relationships, it cannot use the ensure_my_table() function,
+ * plugins are not even invoked in pre_query(), so can't do anything there.
+ *
+ * My conclusion was that the date pager simply is not powerful enough to create its own queries for
+ * date fields, which require very complex queries. Instead, we can combine this with a date argument and
+ * let the argument create the query and let the pager just provide the back/next links. If there is no
+ * date argument, the pager will do nothing.
+ *
+ * There are still other problems. The pager is not even initialized until after all the handlers
+ * have created their queries, so it has no chance to alter values ahead of that. And the argument
+ * has no knowledge of the pager, so it can't check for pager values before the query is created.
+ *
+ * The solution used here is to let the argument create the original query. The pager query
+ * runs after that, so the pager checks to see if there is a pager value that needs to be used in the query.
+ * The date argument has identified the placeholders it used in the query. So if a change is needed,
+ * we can swap the pager value into the query created by the date argument and adjust the
+ * $view->date_info values set by the argument accordingly so the theme will pick up the new information.
+ */
+
+/**
+ * Example plugin to handle paging by month.
+ */
+class date_views_plugin_pager extends views_plugin_pager {
+
+  /**
+   * This kind of pager does not need to count the number of records.
+   */
+  function use_count_query() {
+    return FALSE;
+  }
+
+  /**
+   * Because we don't know how many pages there are, we never believe there are more records.
+   */
+  function has_more_records() {
+    return FALSE;
+  }
+
+  /*
+   * Tell Views what this pager's setting is.
+   */
+  function summary_title() {
+    return t("Position: @position, format: @format.", array('@position' => $this->options['pager_position'], '@format' => $this->options['link_format']));
+  }
+
+  /**
+   * Tell Views what options this plugin can store.
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['date_id'] = array('default' => 'date');
+    $options['pager_position'] = array('default' => 'top');
+    $options['link_format'] = array('default' => 'pager');
+    $options['date_argument'] = array('default' => 'Unknown');
+    $options['granularity'] = array('default' => 'Unknown');
+    return $options;
+  }
+
+  /*
+   * Provide the form for setting options.
+   */
+  function options_form(&$form, &$form_state) {
+    $form['markup']['#markup'] = t('This pager works together with a Date or Content date field contextual filter. If a Date filter has been added to the view, this pager will provide back/next paging to match the granularity of that filter (i.e. paging by year, month, week, or day). The filter must also be configured to use a DATE default value. If there is no Date contextual filter on this view, or if it has not been set to use a default date, the pager will not appear.');
+    $form['date_id'] = array(
+      '#title' => t('Date identifier'),
+      '#type' => 'textfield',
+      '#description' => t('The query identifier to use when fetching date data from in the URL. Note that if you have more than one display in the same view that uses the date pager (like a page and a block), the pager id must be different for each one or both will change when the pager value changes.'),
+      '#default_value' => $this->options['date_id'],
+      '#required' => TRUE,
+    );
+    $form['pager_position'] = array(
+      '#title' => t('Pager position'),
+      '#type' => 'select',
+      '#options' => array('bottom' => t('Bottom'), 'top' => t('Top'), 'both' => t('Both')),
+      '#description' => t('Where to place the date pager, on the top, bottom, or both top and bottom of the content.'),
+      '#default_value' => $this->options['pager_position'],
+      '#required' => TRUE,
+    );
+    $form['link_format'] = array(
+      '#title' => t('Link format'),
+      '#type' => 'select',
+      '#options' => array('pager' => t('Pager'), 'clean' => t('Clean URL')),
+      '#description' => t("The format for pager link urls. With the Pager format, the links look like 'calendar/?date=2020-05'. The Clean URL format links look like 'calendar/2020-05'. The Clean format links look nicer but the Pager format links are likely to work better if the calendar is used in blocks or panels."),
+      '#default_value' => $this->options['link_format'],
+      '#required' => TRUE,
+    );
+    $form['date_argument']['#type'] = 'hidden';
+    $form['date_argument']['#value'] = $this->options['date_argument'];
+    $form['granularity']['#type'] = 'hidden';
+    $form['granularity']['#value'] = $this->options['granularity'];
+  }
+
+  /**
+   * Transfer date information from the argument to the view so the pager theme can use it
+   * and update the date argument value to whatever is set by the pager.
+   */
+  function query() {
+
+    // By fetching our data from the exposed input, it is possible to
+    // feed pager data through some method other than $_GET.
+    $input = $this->view->get_exposed_input();
+    $value = NULL;
+    if (!empty($input) && !empty($input[$this->options['date_id']])) {
+      $value = $input[$this->options['date_id']];
+    }
+
+    // Bring the argument information into the view so our theme can access it.
+    $i = 0;
+    foreach ($this->view->argument as $id => &$argument) {
+      if (date_views_handler_is_date($argument, 'argument')) {
+
+        // If the argument is empty, nothing to do. This could be from
+        // an argument that does not set a default value.
+        if (empty($argument->argument) || empty($argument->date_handler)) {
+          continue;
+        }
+
+        // Storing this information in the pager so it's available for summary info.
+        // The view argument information is not otherwise accessible to the pager.
+        // Not working right yet, tho.
+        $date_handler = $argument->date_handler;
+        $this->options['date_argument'] = $id;
+        $this->options['granularity'] = $argument->date_handler->granularity;
+
+        // Reset values set by argument if pager requires it.
+        if (!empty($value)) {
+          $argument->argument = $value;
+          $argument->date_range = $argument->date_handler->arg_range($value);
+          $argument->min_date = $argument->date_range[0];
+          $argument->max_date = $argument->date_range[1];
+          // $argument->is_default works correctly for normal arguments, but does not
+          // work correctly if we are swapping in a new value from the pager.
+          $argument->is_default = FALSE;
+        }
+
+        // The pager value might move us into a forbidden range, so test it.
+        if ($this->date_forbid($argument)) {
+          $this->view->build_info['fail'] = TRUE;
+          return;
+        }
+
+        if (empty($this->view->date_info)) $this->view->date_info = new stdClass();
+        $this->view->date_info->granularity = $argument->date_handler->granularity;
+        $format = $this->view->date_info->granularity == 'week' ? DATE_FORMAT_DATETIME : $argument->sql_format;
+        $this->view->date_info->placeholders = $argument->date_handler->placeholders;
+        $this->view->date_info->date_arg = $argument->argument;
+        $this->view->date_info->date_arg_pos = $i;
+        $this->view->date_info->year = date_format($argument->min_date, 'Y');
+        $this->view->date_info->month = date_format($argument->min_date, 'n');;
+        $this->view->date_info->day = date_format($argument->min_date, 'j');
+        $this->view->date_info->week = date_week(date_format($argument->min_date, DATE_FORMAT_DATE));
+        $this->view->date_info->date_range = $argument->date_range;
+        $this->view->date_info->min_date = $argument->min_date;
+        $this->view->date_info->max_date = $argument->max_date;
+        $this->view->date_info->limit = $argument->limit;
+        $this->view->date_info->url = $this->view->get_url();
+        $this->view->date_info->pager_id = $this->options['date_id'];
+        $this->view->date_info->date_pager_position = $this->options['pager_position'];
+        $this->view->date_info->date_pager_format = $this->options['link_format'];
+      }
+      $i++;
+    }
+
+    // Is this a view that needs to be altered based on a pager value?
+    // If there is pager input and the argument has set the placeholders,
+    // swap the pager value in for the placeholder set by the argument.
+    if (!empty($value) && !empty($this->view->date_info->placeholders)) {
+      $placeholders = $this->view->date_info->placeholders;
+      $count = count($placeholders);
+      foreach ($this->view->query->where as $group => $data) {
+        foreach ($data['conditions'] as $delta => $condition) {
+          if (array_key_exists('value', $condition) && is_array($condition['value'])) {
+            foreach ($condition['value'] as $placeholder => $placeholder_value) {
+              if (array_key_exists($placeholder, $placeholders)) {
+                // If we didn't get a match, this is a > $min < $max query that uses the view
+                // min and max dates as placeholders.
+                $date = ($count == 2) ? $this->view->date_info->min_date : $this->view->date_info->max_date;
+                $next_placeholder = array_shift($placeholders);
+                $this->view->query->where[$group]['conditions'][$delta]['value'][$placeholder] = $date->format($format);
+                $count--;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Add a callback to determine if we have moved outside the valid date range for this argument.
+   */
+  function date_forbid($argument) {
+    // See if we're outside the allowed date range for our argument.
+    $limit = date_range_years($argument->options['year_range']);
+    if (date_format($argument->min_date, 'Y') < $limit[0] || date_format($argument->max_date, 'Y') > $limit[1]) {
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+
+  function render($input) {
+    // This adds all of our template suggestions based upon the view name and display id.
+    $pager_theme = views_theme_functions('date_views_pager', $this->view, $this->display);
+    return theme($pager_theme, array('plugin' => $this, 'input' => $input));
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/date/date_views/theme/date-views-filter-form.tpl.php b/sites/all/modules/date/date_views/theme/date-views-filter-form.tpl.php
new file mode 100644
index 0000000000000000000000000000000000000000..ad638c10242b2b25facc4b0d60c074bec4ccff3c
--- /dev/null
+++ b/sites/all/modules/date/date_views/theme/date-views-filter-form.tpl.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Template to display the Views date filter form.
+ *
+ * Values available vary depending on the operator. The availability
+ * of date vs adjustment depending on the filter settings. It can
+ * be date-only, date and adjustment, or adjustment only.
+ *
+ * If the operator is anything but 'Is between' or 'Is not between',
+ * a single date and adjustment field is available.
+ *
+ * $date
+ * $adjustment
+ *
+ * If the operator is 'Is between' or 'Is not between',
+ * two date and adjustment fields are available.
+ *
+ * $mindate
+ * $minadjustment
+ * $maxdate
+ * $maxadjustment
+ *
+ * A description field is also available.
+ *
+ * $description
+ */
+?>
+<div class="date-views-filter-wrapper">
+<div class="container-inline-date date-clear">
+<?php if (!empty($date) || !empty($adjustment)) : ?>
+  <div class="date-clear">
+    <div class="date-views-filter"><?php print $date; ?></div>
+    <div class="date-views-filter"><?php print $adjustment ?></div>
+  </div>
+<?php endif; ?>
+<?php if (!empty($mindate) || !empty($minadjustment)) : ?>
+  <div class="date-clear">
+    <div class="date-views-filter"><?php print $mindate; ?></div>
+    <div class="date-views-filter"><?php print $minadjustment; ?></div>
+  </div>
+<?php endif; ?>
+<?php if (!empty($maxdate) || !empty($maxadjustment)) : ?>
+  <div class="date-clear">
+    <div class="date-views-filter"><?php print $maxdate; ?></div>
+    <div class="date-views-filter"><?php print $maxadjustment; ?></div>
+  </div>
+<?php endif; ?>
+</div>
+<div class="date-clear form-item"><div class="description">
+  <?php print $description; ?>
+</div>
+</div>
+</div>
diff --git a/sites/all/modules/date/date_views/theme/date-views-pager.tpl.php b/sites/all/modules/date/date_views/theme/date-views-pager.tpl.php
new file mode 100644
index 0000000000000000000000000000000000000000..531214cb420af541ddb786930e06c26302e4debc
--- /dev/null
+++ b/sites/all/modules/date/date_views/theme/date-views-pager.tpl.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * @file
+ * Template file for the example display.
+ *
+ * Variables available:
+ * 
+ * $plugin: The pager plugin object. This contains the view.
+ *
+ * $plugin->view
+ *   The view object for this navigation.
+ *
+ * $nav_title
+ *   The formatted title for this view. In the case of block
+ *   views, it will be a link to the full view, otherwise it will
+ *   be the formatted name of the year, month, day, or week.
+ *
+ * $prev_url
+ * $next_url
+ *   Urls for the previous and next calendar pages. The links are
+ *   composed in the template to make it easier to change the text,
+ *   add images, etc.
+ *
+ * $prev_options
+ * $next_options
+ *   Query strings and other options for the links that need to
+ *   be used in the l() function, including rel=nofollow.
+ */
+?>
+<?php if (!empty($pager_prefix)) print $pager_prefix; ?>
+<div class="date-nav-wrapper clearfix<?php if (!empty($extra_classes)) print $extra_classes; ?>">
+  <div class="date-nav item-list">
+    <div class="date-heading">
+      <h3><?php print $nav_title ?></h3>
+    </div>
+    <ul class="pager">
+    <?php if (!empty($prev_url)) : ?>
+      <li class="date-prev">
+        <?php print l('&laquo;' . ($mini ? '' : ' ' . t('Prev', array(), array('context' => 'date_nav'))), $prev_url, $prev_options); ?>
+      &nbsp;</li>
+    <?php endif; ?>
+    <?php if (!empty($next_url)) : ?>
+      <li class="date-next">&nbsp;
+        <?php print l(($mini ? '' : t('Next', array(), array('context' => 'date_nav')) . ' ') . '&raquo;', $next_url, $next_options); ?>
+      </li>
+    <?php endif; ?>
+    </ul>
+  </div>
+</div>
\ No newline at end of file
diff --git a/sites/all/modules/date/date_views/theme/theme.inc b/sites/all/modules/date/date_views/theme/theme.inc
new file mode 100644
index 0000000000000000000000000000000000000000..4a7d4bc5fc5df6f829601e86d7f4a9376a15ad75
--- /dev/null
+++ b/sites/all/modules/date/date_views/theme/theme.inc
@@ -0,0 +1,212 @@
+<?php
+
+/**
+ * @file
+ * Theme files for Date Pager.
+ */
+/**
+ * Jump in and move the pager.
+ */
+function date_views_preprocess_views_view(&$vars) {
+  $view = $vars['view'];
+  if (!empty($view->date_info) && !empty($view->date_info->date_pager_position)) {
+    switch ($view->date_info->date_pager_position) {
+      case 'top':
+        $vars['header'] .= $vars['pager'];
+        $vars['pager'] = '';
+        break;
+      case 'both':
+        $vars['header'] .= $vars['pager'];
+        break;
+      default:
+        // Already on the bottom.
+    }
+  }
+}
+
+/**
+ * Preprocess function for Date pager template.
+ */
+function template_preprocess_date_views_pager(&$vars) {
+  ctools_add_css('date_views', 'date_views');
+
+  $plugin = $vars['plugin'];
+  $input = $vars['input'];
+  $view = $plugin->view;
+
+  $vars['nav_title'] = '';
+  $vars['next_url'] = '';
+  $vars['prev_url'] = '';
+
+  if (empty($view->date_info) || empty($view->date_info->min_date)) {
+    return;
+  }
+  $date_info = $view->date_info;
+  // Make sure we have some sort of granularity.
+  $granularity = !empty($date_info->granularity) ? $date_info->granularity : 'month';
+  $pos = $date_info->date_arg_pos;
+  if (!empty($input)) {
+    $id = $plugin->options['date_id'];
+    if (array_key_exists($id, $input) && !empty($input[$id])) {
+      $view->args[$pos] = $input[$id];
+    }
+  }
+
+  $next_args = $view->args;
+  $prev_args = $view->args;
+  $min_date = $date_info->min_date;
+  $max_date = $date_info->max_date;
+
+  // Set up the pager link format. Setting the block identifier
+  // will force pager style links.
+  if ((isset($date_info->date_pager_format) && $date_info->date_pager_format != 'clean') || !empty($date_info->mini)) {
+    if (empty($date_info->block_identifier)) {
+      $date_info->block_identifier = $date_info->pager_id;
+    }
+  }
+
+  if (empty($date_info->hide_nav)) {
+    $prev_date = clone($min_date);
+    date_modify($prev_date, '-1 ' . $granularity);
+    $next_date = clone($min_date);
+    date_modify($next_date, '+1 ' . $granularity);
+    $format = array('year' => 'Y', 'month' => 'Y-m', 'day' => 'Y-m-d');
+    switch ($granularity) {
+      case 'week':
+        $next_week = date_week(date_format($next_date, 'Y-m-d'));
+        $prev_week = date_week(date_format($prev_date, 'Y-m-d'));
+        $next_arg = date_format($next_date, 'Y-\W') . date_pad($next_week);
+        $prev_arg = date_format($prev_date, 'Y-\W') . date_pad($prev_week);
+        break;
+      default:
+        $next_arg = date_format($next_date, $format[$granularity]);
+        $prev_arg = date_format($prev_date, $format[$granularity]);
+    }
+    $next_path = str_replace($date_info->date_arg, $next_arg, $date_info->url);
+    $prev_path = str_replace($date_info->date_arg, $prev_arg, $date_info->url);
+    $next_args[$pos] = $next_arg;
+    $prev_args[$pos] = $prev_arg;
+    $vars['next_url'] = date_pager_url($view, NULL, $next_arg);
+    $vars['prev_url'] = date_pager_url($view, NULL, $prev_arg);
+    $vars['next_options'] = $vars['prev_options'] = array();
+  }
+  else {
+    $next_path = '';
+    $prev_path = '';
+    $vars['next_url'] = '';
+    $vars['prev_url'] = '';
+    $vars['next_options'] = $vars['prev_options'] = array();
+  }
+
+  // Check whether navigation links would point to
+  // a date outside the allowed range.
+  if (!empty($next_date) && !empty($vars['next_url']) && date_format($next_date, 'Y') > $date_info->limit[1]) {
+    $vars['next_url'] = '';
+  }
+  if (!empty($prev_date) && !empty($vars['prev_url']) && date_format($prev_date, 'Y') < $date_info->limit[0]) {
+    $vars['prev_url'] = '';
+  }
+  $vars['prev_options'] += array('attributes' => array());
+  $vars['next_options'] += array('attributes' => array());
+  $prev_title = '';
+  $next_title = '';
+
+  // Build next/prev link titles.
+  switch ($granularity) {
+    case 'year':
+      $prev_title = t('Navigate to previous year');
+      $next_title = t('Navigate to next year');
+      break;
+    case 'month':
+      $prev_title = t('Navigate to previous month');
+      $next_title = t('Navigate to next month');
+      break;
+    case 'week':
+      $prev_title = t('Navigate to previous week');
+      $next_title = t('Navigate to next week');
+      break;
+    case 'day':
+      $prev_title = t('Navigate to previous day');
+      $next_title = t('Navigate to next day');
+      break;
+  }
+  $vars['prev_options']['attributes'] += array('title' => $prev_title);
+  $vars['next_options']['attributes'] += array('title' => $next_title);
+
+  // Add nofollow for next/prev links.
+  $vars['prev_options']['attributes'] += array('rel' => 'nofollow');
+  $vars['next_options']['attributes'] += array('rel' => 'nofollow');
+
+  // Need this so we can use '&laquo;' or images in the links.
+  $vars['prev_options'] += array('html' => TRUE);
+  $vars['next_options'] += array('html' => TRUE);
+
+  $link = FALSE;
+  // Month navigation titles are used as links in the block view.
+  if (!empty($date_info->mini) && $granularity == 'month') {
+    $link = TRUE;
+  }
+  $params = array(
+    'granularity' => $granularity,
+    'view' => $view,
+    'link' => $link,
+  );
+  $nav_title = theme('date_nav_title', $params);
+  $vars['nav_title'] = $nav_title;
+  $vars['mini'] = !empty($date_info->mini);
+}
+
+/**
+ * Theme the calendar title
+ */
+function theme_date_nav_title($params) {
+  $granularity = $params['granularity'];
+  $view = $params['view'];
+  $date_info = $view->date_info;
+  $link = !empty($params['link']) ? $params['link'] : FALSE;
+  $format = !empty($params['format']) ? $params['format'] : NULL;
+  switch ($granularity) {
+    case 'year':
+      $title = $date_info->year;
+      $date_arg = $date_info->year;
+      break;
+    case 'month':
+      $format = !empty($format) ? $format : (empty($date_info->mini) ? 'F Y' : 'F');
+      $title = date_format_date($date_info->min_date, 'custom', $format);
+      $date_arg = $date_info->year . '-' . date_pad($date_info->month);
+      break;
+    case 'day':
+      $format = !empty($format) ? $format : (empty($date_info->mini) ? 'l, F j, Y' : 'l, F j');
+      $title = date_format_date($date_info->min_date, 'custom', $format);
+      $date_arg = $date_info->year . '-' . date_pad($date_info->month) . '-' . date_pad($date_info->day);
+      break;
+    case 'week':
+      $format = !empty($format) ? $format : (empty($date_info->mini) ? 'F j, Y' : 'F j');
+      $title = t('Week of @date', array('@date' => date_format_date($date_info->min_date, 'custom', $format)));
+      $date_arg = $date_info->year . '-W' . date_pad($date_info->week);
+      break;
+  }
+  if (!empty($date_info->mini) || $link) {
+    // Month navigation titles are used as links in the mini view.
+    $attributes = array('title' => t('View full page month'));
+    $url = date_pager_url($view, $granularity, $date_arg, TRUE);
+    return l($title, $url, array('attributes' => $attributes));
+  }
+  else {
+    return $title;
+  }
+}
+
+/**
+ * Preprocessor for Date Views filter form.
+ */
+function template_preprocess_date_views_filter_form(&$vars) {
+  $form = $vars['form'];
+  $vars['date'] = drupal_render($form['valuedate']);
+  $vars['mindate'] = drupal_render($form['mindate']);
+  $vars['maxdate'] = drupal_render($form['maxdate']);
+  $vars['adjustment'] = drupal_render($form['valueadjustment']);
+  $vars['minadjustment'] = drupal_render($form['minadjustment']);
+  $vars['maxadjustment'] = drupal_render($form['maxadjustment']);
+  $vars['description'] = drupal_render($form['description']) . drupal_render($form);
+}
diff --git a/sites/all/modules/date/tests/README.txt b/sites/all/modules/date/tests/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6bce1e9c4598291ea4d1a5fc82cef7fd572e6f5b
--- /dev/null
+++ b/sites/all/modules/date/tests/README.txt
@@ -0,0 +1,16 @@
+This folder includes files that can be used to test imports of date information.
+To test them, set up FeedAPI and the Feed Element Mapper with Parser iCal
+or Parser CVS and import these files into a date field.
+
+- rrule.ics:
+  Creates repeating dates using a wide variety of RRULEs.
+
+- Yahoo.csv:
+  This file uses the csv export format from Yahoo Calendar, similar to the
+  format created by Outlook's csv export. The sample contains both timed
+  and untimed 'All day' events.
+
+- USHolidays.ics:
+  An ical export of US Holidays in the 'All day' format used by
+  Microsoft and Apple (where the Start date is the date of the event
+  and the End date is the following day).
diff --git a/sites/all/modules/date/tests/USHolidays.ics b/sites/all/modules/date/tests/USHolidays.ics
new file mode 100644
index 0000000000000000000000000000000000000000..cbfa8406911bb0c741bfd4404d4cd943c623c5b3
--- /dev/null
+++ b/sites/all/modules/date/tests/USHolidays.ics
@@ -0,0 +1,2029 @@
+BEGIN:VCALENDAR
+PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN
+VERSION:2.0
+BEGIN:VEVENT
+CREATED:20080827T223540Z
+LAST-MODIFIED:20080827T223609Z
+DTSTAMP:20080901T141914Z
+UID:b8388cae-2125-4614-9801-5fec40a07408
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20000423
+DTEND;VALUE=DATE:20000424
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223613Z
+LAST-MODIFIED:20080827T223631Z
+DTSTAMP:20080901T141914Z
+UID:27198947-51d4-475c-9116-6dd475ab4729
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20010415
+DTEND;VALUE=DATE:20010416
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223633Z
+LAST-MODIFIED:20080827T223647Z
+DTSTAMP:20080901T141914Z
+UID:adebaeec-b7da-4d1e-baff-73e54a5bbe5d
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20020331
+DTEND;VALUE=DATE:20020401
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223650Z
+LAST-MODIFIED:20080827T223703Z
+DTSTAMP:20080901T141914Z
+UID:3378f42f-00f3-42be-888e-8368d5e140b2
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20030420
+DTEND;VALUE=DATE:20030421
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223704Z
+LAST-MODIFIED:20080827T223725Z
+DTSTAMP:20080901T141914Z
+UID:18eae8ac-65e1-4cc0-8bf3-0c287882fbd9
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20040411
+DTEND;VALUE=DATE:20040412
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223726Z
+LAST-MODIFIED:20080827T223740Z
+DTSTAMP:20080901T141914Z
+UID:d0a68adf-3eca-4585-a7a7-853b5d5b03e4
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20050327
+DTEND;VALUE=DATE:20050328
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223741Z
+LAST-MODIFIED:20080827T223755Z
+DTSTAMP:20080901T141914Z
+UID:daf76dce-468b-4f99-8d42-01487f8fafa9
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20060416
+DTEND;VALUE=DATE:20060417
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223757Z
+LAST-MODIFIED:20080827T223811Z
+DTSTAMP:20080901T141914Z
+UID:fa7a1db3-1c5f-472d-9ee4-988d0d0287eb
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20070408
+DTEND;VALUE=DATE:20070409
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223818Z
+LAST-MODIFIED:20080827T223827Z
+DTSTAMP:20080901T141914Z
+UID:69230f5f-f2d2-428d-a90c-a7e1c7deea5e
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20090412
+DTEND;VALUE=DATE:20090413
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223828Z
+LAST-MODIFIED:20080827T223848Z
+DTSTAMP:20080901T141914Z
+UID:0bc494ff-69b5-4dca-8699-c4fe5ea25a13
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20100404
+DTEND;VALUE=DATE:20100405
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223934Z
+LAST-MODIFIED:20080827T223945Z
+DTSTAMP:20080901T141914Z
+UID:44a937c0-f0d8-4458-947c-8a33db7217ef
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20120408
+DTEND;VALUE=DATE:20120409
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223946Z
+LAST-MODIFIED:20080827T223959Z
+DTSTAMP:20080901T141914Z
+UID:734e6d03-ab3c-4693-8c81-f73e3b576c27
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20130331
+DTEND;VALUE=DATE:20130401
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T224000Z
+LAST-MODIFIED:20080827T224011Z
+DTSTAMP:20080901T141914Z
+UID:c4d6a9e0-a5d6-41d4-9297-97e4fdcc85a5
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20140420
+DTEND;VALUE=DATE:20140421
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T224012Z
+LAST-MODIFIED:20080827T224026Z
+DTSTAMP:20080901T141914Z
+UID:b2cab02a-a164-44a4-af66-ccb1b3c253b9
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20150405
+DTEND;VALUE=DATE:20150406
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T224028Z
+LAST-MODIFIED:20080827T224042Z
+DTSTAMP:20080901T141914Z
+UID:763686f7-3ec4-4dfc-9a33-e4c0bae652fa
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20160327
+DTEND;VALUE=DATE:20160328
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T224043Z
+LAST-MODIFIED:20080827T224100Z
+DTSTAMP:20080901T141914Z
+UID:31edb1e8-a064-4a8b-a041-eecd22a4d419
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20170416
+DTEND;VALUE=DATE:20170417
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T224101Z
+LAST-MODIFIED:20080827T224112Z
+DTSTAMP:20080901T141914Z
+UID:d869e442-0b4d-40c4-b34c-6780afce8c46
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20180401
+DTEND;VALUE=DATE:20180402
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T224121Z
+LAST-MODIFIED:20080827T224132Z
+DTSTAMP:20080901T141914Z
+UID:135738b2-b8d5-4e65-bf7c-736e22c6b8b1
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20190421
+DTEND;VALUE=DATE:20190422
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T224133Z
+LAST-MODIFIED:20080827T224147Z
+DTSTAMP:20080901T141914Z
+UID:7606494f-0019-46e6-9d47-ab9498569e5a
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20200412
+DTEND;VALUE=DATE:20200413
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080828T174259Z
+DTSTAMP:20080901T141914Z
+UID:c5c154cc-1dd1-11b2-85c7-e3de2bfad30f
+SUMMARY:Easter Sunday
+STATUS:CONFIRMED
+CLASS:PUBLIC
+DTSTART;VALUE=DATE:20080323
+DTEND;VALUE=DATE:20080324
+CATEGORIES:Holidays
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:2
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T024422Z
+LAST-MODIFIED:20080829T024531Z
+DTSTAMP:20080901T141914Z
+UID:5e604c83-cacc-46fe-bc40-b4f50e2412e7
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20000308
+DTEND;VALUE=DATE:20000309
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T024533Z
+LAST-MODIFIED:20080829T024624Z
+DTSTAMP:20080901T141914Z
+UID:847021ce-03b6-4f2d-abe5-2ba869066b5d
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20010228
+DTEND;VALUE=DATE:20010301
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T024626Z
+LAST-MODIFIED:20080829T024701Z
+DTSTAMP:20080901T141914Z
+UID:0e313bdb-171d-40dd-9ddb-1dfb4a777bb5
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20020213
+DTEND;VALUE=DATE:20020214
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T024822Z
+LAST-MODIFIED:20080829T024839Z
+DTSTAMP:20080901T141914Z
+UID:1577ed41-e8c5-45f9-83e5-86079fe2510b
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20030305
+DTEND;VALUE=DATE:20030306
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T024847Z
+LAST-MODIFIED:20080829T024908Z
+DTSTAMP:20080901T141914Z
+UID:fcbfe576-82e9-4f68-b1ad-5366ff6968ac
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20040225
+DTEND;VALUE=DATE:20040226
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T024911Z
+LAST-MODIFIED:20080829T024923Z
+DTSTAMP:20080901T141914Z
+UID:a403894c-bb2c-4d02-8dca-91c359a54bfe
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20050209
+DTEND;VALUE=DATE:20050210
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T024924Z
+LAST-MODIFIED:20080829T024938Z
+DTSTAMP:20080901T141914Z
+UID:dcc3c2f4-d214-49d8-bb3e-f13c6acf3295
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20060301
+DTEND;VALUE=DATE:20060302
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T024939Z
+LAST-MODIFIED:20080829T024950Z
+DTSTAMP:20080901T141914Z
+UID:b81a6c71-9a3d-49a5-b695-8ac5f1bb013b
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20070221
+DTEND;VALUE=DATE:20070222
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T024951Z
+LAST-MODIFIED:20080829T025002Z
+DTSTAMP:20080901T141914Z
+UID:40090c1d-8669-4d7a-b63a-288006cfac65
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20080206
+DTEND;VALUE=DATE:20080207
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025003Z
+LAST-MODIFIED:20080829T025015Z
+DTSTAMP:20080901T141914Z
+UID:609ce29c-966c-40b4-81c4-8ccac74e98dd
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20090225
+DTEND;VALUE=DATE:20090226
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025017Z
+LAST-MODIFIED:20080829T025031Z
+DTSTAMP:20080901T141914Z
+UID:f96c0bf5-1cf2-4d2e-9955-eb89f4e645d3
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20100217
+DTEND;VALUE=DATE:20100218
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025033Z
+LAST-MODIFIED:20080829T025045Z
+DTSTAMP:20080901T141914Z
+UID:a02038e9-a094-4744-b09d-d7d2ef96bd28
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20110302
+DTEND;VALUE=DATE:20110303
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025046Z
+LAST-MODIFIED:20080829T025057Z
+DTSTAMP:20080901T141914Z
+UID:a0b949a8-2a75-4617-a687-1e7dffc098f5
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20120222
+DTEND;VALUE=DATE:20120223
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025058Z
+LAST-MODIFIED:20080829T025128Z
+DTSTAMP:20080901T141914Z
+UID:8caed879-6158-477c-9901-e1531dc855e8
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20130213
+DTEND;VALUE=DATE:20130214
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025131Z
+LAST-MODIFIED:20080829T025143Z
+DTSTAMP:20080901T141914Z
+UID:69e06d74-9acc-4667-8eb0-7c33299d82c0
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20140305
+DTEND;VALUE=DATE:20140306
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025146Z
+LAST-MODIFIED:20080829T025200Z
+DTSTAMP:20080901T141914Z
+UID:a05d7fa6-4c65-4465-a32a-1b5c2d1189aa
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20150218
+DTEND;VALUE=DATE:20150219
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025202Z
+LAST-MODIFIED:20080829T025218Z
+DTSTAMP:20080901T141914Z
+UID:ce5fe814-c4b3-4aab-8298-86f54e34ffe4
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20160210
+DTEND;VALUE=DATE:20160211
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025220Z
+LAST-MODIFIED:20080829T025231Z
+DTSTAMP:20080901T141914Z
+UID:746c3ee3-3439-41bd-9ee1-7944812a8a29
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20170301
+DTEND;VALUE=DATE:20170302
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025235Z
+LAST-MODIFIED:20080829T025252Z
+DTSTAMP:20080901T141914Z
+UID:6eff84ea-6763-46d3-9c64-b847376f3e34
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20180214
+DTEND;VALUE=DATE:20180215
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025254Z
+LAST-MODIFIED:20080829T025308Z
+DTSTAMP:20080901T141914Z
+UID:e5d798cf-474f-42c3-83b8-0d1186c2c3ad
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20190306
+DTEND;VALUE=DATE:20190307
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025309Z
+LAST-MODIFIED:20080829T025325Z
+DTSTAMP:20080901T141914Z
+UID:9d17488f-12b8-474b-8790-d22e6786735e
+SUMMARY:Ash Wednesday
+DTSTART;VALUE=DATE:20200226
+DTEND;VALUE=DATE:20200227
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025421Z
+LAST-MODIFIED:20080829T025456Z
+DTSTAMP:20080901T141914Z
+UID:1abe0e7a-fa55-42b8-b6cc-bf037ab5c7f4
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20000416
+DTEND;VALUE=DATE:20000417
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025457Z
+LAST-MODIFIED:20080829T025509Z
+DTSTAMP:20080901T141914Z
+UID:ff8dd4a7-0593-4fb6-bcdc-7cd8db41a451
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20010408
+DTEND;VALUE=DATE:20010409
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025510Z
+LAST-MODIFIED:20080829T025521Z
+DTSTAMP:20080901T141914Z
+UID:e403c114-aa09-4dcd-b8cf-b342be833477
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20020324
+DTEND;VALUE=DATE:20020325
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025522Z
+LAST-MODIFIED:20080829T025548Z
+DTSTAMP:20080901T141914Z
+UID:8ebc922a-a220-456f-937b-a943e5df123b
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20030413
+DTEND;VALUE=DATE:20030414
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025549Z
+LAST-MODIFIED:20080829T025601Z
+DTSTAMP:20080901T141914Z
+UID:e03d10c1-ce57-426f-9a08-cd49c25920a9
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20040404
+DTEND;VALUE=DATE:20040405
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025630Z
+LAST-MODIFIED:20080829T025645Z
+DTSTAMP:20080901T141914Z
+UID:8ed86db1-ea90-453a-a1cd-36878811826e
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20070401
+DTEND;VALUE=DATE:20070402
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025646Z
+LAST-MODIFIED:20080829T025708Z
+DTSTAMP:20080901T141914Z
+UID:b45150e2-da4d-477b-aace-b255186d89b1
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20080316
+DTEND;VALUE=DATE:20080317
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025820Z
+LAST-MODIFIED:20080829T025834Z
+DTSTAMP:20080901T141914Z
+UID:96b2e223-1b4f-44e1-80a3-8b57ab7d2f12
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20090405
+DTEND;VALUE=DATE:20090406
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025837Z
+LAST-MODIFIED:20080829T025854Z
+DTSTAMP:20080901T141915Z
+UID:863b0192-787d-4b4b-8550-c7e2db820b0a
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20100328
+DTEND;VALUE=DATE:20100329
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025855Z
+LAST-MODIFIED:20080829T025907Z
+DTSTAMP:20080901T141915Z
+UID:844a3d56-4fab-4df1-92d3-8f4385d8efc9
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20110410
+DTEND;VALUE=DATE:20110411
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025908Z
+LAST-MODIFIED:20080829T025920Z
+DTSTAMP:20080901T141915Z
+UID:ac159587-0a97-4f98-b11c-2193fe61265a
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20120401
+DTEND;VALUE=DATE:20120402
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025922Z
+LAST-MODIFIED:20080829T025938Z
+DTSTAMP:20080901T141915Z
+UID:4dcb5128-64b8-488c-b9ec-6b8c6184c0e9
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20130324
+DTEND;VALUE=DATE:20130325
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025939Z
+LAST-MODIFIED:20080829T025955Z
+DTSTAMP:20080901T141915Z
+UID:0b3db3ec-fa4c-4e71-bf0b-251fde472ef6
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20140413
+DTEND;VALUE=DATE:20140414
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025956Z
+LAST-MODIFIED:20080829T030025Z
+DTSTAMP:20080901T141915Z
+UID:b3ac2edc-39ac-4d09-b45b-9a380ecbb63e
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20150329
+DTEND;VALUE=DATE:20150330
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030027Z
+LAST-MODIFIED:20080829T030041Z
+DTSTAMP:20080901T141915Z
+UID:7af33c57-7711-4581-86e5-221ac5c59ecd
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20160320
+DTEND;VALUE=DATE:20160321
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030042Z
+LAST-MODIFIED:20080829T030100Z
+DTSTAMP:20080901T141915Z
+UID:b372c357-0224-493e-a95c-50f69a9ee376
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20170409
+DTEND;VALUE=DATE:20170410
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030101Z
+LAST-MODIFIED:20080829T030123Z
+DTSTAMP:20080901T141915Z
+UID:2ed9175e-e119-4569-9371-390d70acc0fa
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20180325
+DTEND;VALUE=DATE:20180326
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030124Z
+LAST-MODIFIED:20080829T030149Z
+DTSTAMP:20080901T141915Z
+UID:334646f6-5fef-43a9-83bc-d2dd88c9ebe6
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20190414
+DTEND;VALUE=DATE:20190415
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030150Z
+LAST-MODIFIED:20080829T030206Z
+DTSTAMP:20080901T141915Z
+UID:7f9c6e82-610a-4485-b5fd-dde7f0dba4b8
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20200405
+DTEND;VALUE=DATE:20200406
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030214Z
+LAST-MODIFIED:20080829T030233Z
+DTSTAMP:20080901T141915Z
+UID:af35fdb4-b67e-4b43-887f-c23f58bf9847
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20000421
+DTEND;VALUE=DATE:20000422
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030234Z
+LAST-MODIFIED:20080829T030249Z
+DTSTAMP:20080901T141915Z
+UID:116e335b-4cae-40b1-abf5-4e2f7121a4c0
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20010413
+DTEND;VALUE=DATE:20010414
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030250Z
+LAST-MODIFIED:20080829T030303Z
+DTSTAMP:20080901T141915Z
+UID:7700d32c-2728-439f-b3a2-e458ba1052d7
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20020329
+DTEND;VALUE=DATE:20020330
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030320Z
+LAST-MODIFIED:20080829T030336Z
+DTSTAMP:20080901T141915Z
+UID:2710e06f-c089-40d4-945a-9f8fe125a59c
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20040409
+DTEND;VALUE=DATE:20040410
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030337Z
+LAST-MODIFIED:20080829T030351Z
+DTSTAMP:20080901T141915Z
+UID:1dfafc7f-17b6-4a8d-b1ef-492adb9bd9dc
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20050325
+DTEND;VALUE=DATE:20050326
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030352Z
+LAST-MODIFIED:20080829T030405Z
+DTSTAMP:20080901T141915Z
+UID:8371454e-8dda-4667-81e5-3680dc8cc542
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20060414
+DTEND;VALUE=DATE:20060415
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030406Z
+LAST-MODIFIED:20080829T030421Z
+DTSTAMP:20080901T141915Z
+UID:93b64832-1179-4db9-a8e5-4d3375156294
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20070406
+DTEND;VALUE=DATE:20070407
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030423Z
+LAST-MODIFIED:20080829T030434Z
+DTSTAMP:20080901T141915Z
+UID:ee7bc7d8-d5a8-43f1-b817-54b5458429fa
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20080321
+DTEND;VALUE=DATE:20080322
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030436Z
+LAST-MODIFIED:20080829T030445Z
+DTSTAMP:20080901T141915Z
+UID:98652109-bdda-4451-afd3-9955bfe918c7
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20090410
+DTEND;VALUE=DATE:20090411
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030446Z
+LAST-MODIFIED:20080829T030500Z
+DTSTAMP:20080901T141915Z
+UID:7241d18c-6e4a-4a15-b262-a0415d05e5c0
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20100402
+DTEND;VALUE=DATE:20100403
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030501Z
+LAST-MODIFIED:20080829T030512Z
+DTSTAMP:20080901T141915Z
+UID:6e05d4a1-8b7f-446d-a7fc-566b6837c927
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20110415
+DTEND;VALUE=DATE:20110416
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030513Z
+LAST-MODIFIED:20080829T030524Z
+DTSTAMP:20080901T141915Z
+UID:be42b228-382d-4add-be00-c36fdb2508c7
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20120406
+DTEND;VALUE=DATE:20120407
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030526Z
+LAST-MODIFIED:20080829T030541Z
+DTSTAMP:20080901T141915Z
+UID:db8d6551-0b2d-44c1-8c21-ba96030a445e
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20130329
+DTEND;VALUE=DATE:20130330
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030543Z
+LAST-MODIFIED:20080829T030601Z
+DTSTAMP:20080901T141915Z
+UID:c14a8a90-a69d-44fe-9e34-a28feed1a1c0
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20140418
+DTEND;VALUE=DATE:20140419
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030602Z
+LAST-MODIFIED:20080829T030614Z
+DTSTAMP:20080901T141915Z
+UID:269d06c4-2eed-45de-af47-6668b7e58902
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20150403
+DTEND;VALUE=DATE:20150404
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030616Z
+LAST-MODIFIED:20080829T030629Z
+DTSTAMP:20080901T141915Z
+UID:8e3f7823-a340-4b6e-8b7c-10a539f5db8f
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20160325
+DTEND;VALUE=DATE:20160326
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030630Z
+LAST-MODIFIED:20080829T030647Z
+DTSTAMP:20080901T141915Z
+UID:a6d17884-5c3e-4f4b-9383-7b83814ada9d
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20170414
+DTEND;VALUE=DATE:20170415
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030648Z
+LAST-MODIFIED:20080829T030703Z
+DTSTAMP:20080901T141915Z
+UID:19fb2499-97ae-457f-8d41-6ec76292c77f
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20180330
+DTEND;VALUE=DATE:20180331
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030704Z
+LAST-MODIFIED:20080829T030717Z
+DTSTAMP:20080901T141915Z
+UID:0a125549-300d-4bd9-af20-3fc28935946e
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20190419
+DTEND;VALUE=DATE:20190420
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030718Z
+LAST-MODIFIED:20080829T030730Z
+DTSTAMP:20080901T141915Z
+UID:50de218e-013d-4739-b8d4-f30f74a57168
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20200410
+DTEND;VALUE=DATE:20200411
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030737Z
+LAST-MODIFIED:20080829T030854Z
+DTSTAMP:20080901T141915Z
+UID:af9df15d-af91-4e19-b7d2-e80bf8dfc378
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20000611
+DTEND;VALUE=DATE:20000612
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030855Z
+LAST-MODIFIED:20080829T030906Z
+DTSTAMP:20080901T141915Z
+UID:b5eb3eae-875a-4b50-a10c-b8a487907eac
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20010603
+DTEND;VALUE=DATE:20010604
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030907Z
+LAST-MODIFIED:20080829T030939Z
+DTSTAMP:20080901T141915Z
+UID:c5a9ee90-d177-4ca5-917e-245791f15312
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20020519
+DTEND;VALUE=DATE:20020520
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030942Z
+LAST-MODIFIED:20080829T030958Z
+DTSTAMP:20080901T141915Z
+UID:9bbe68fb-4d23-4d27-9171-26177baf984d
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20030608
+DTEND;VALUE=DATE:20030609
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030959Z
+LAST-MODIFIED:20080829T031012Z
+DTSTAMP:20080901T141915Z
+UID:c4f15038-8df9-475b-bc85-9948f97cddc7
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20040530
+DTEND;VALUE=DATE:20040531
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031013Z
+LAST-MODIFIED:20080829T031024Z
+DTSTAMP:20080901T141915Z
+UID:d54dd907-ba90-4607-88ee-b15d7b79736f
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20050515
+DTEND;VALUE=DATE:20050516
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031027Z
+LAST-MODIFIED:20080829T031041Z
+DTSTAMP:20080901T141915Z
+UID:810562a0-2467-4a43-860d-db69cbf92fdf
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20060604
+DTEND;VALUE=DATE:20060605
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031042Z
+LAST-MODIFIED:20080829T031100Z
+DTSTAMP:20080901T141915Z
+UID:8212e80d-6efa-4e79-bcd0-44fc831a1ecc
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20070527
+DTEND;VALUE=DATE:20070528
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031101Z
+LAST-MODIFIED:20080829T031111Z
+DTSTAMP:20080901T141915Z
+UID:da7b884d-0d0f-48d3-97f7-d13b21cea817
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20080511
+DTEND;VALUE=DATE:20080512
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031112Z
+LAST-MODIFIED:20080829T031122Z
+DTSTAMP:20080901T141915Z
+UID:719c1eff-d26b-4316-86b5-464a4d24bf98
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20090531
+DTEND;VALUE=DATE:20090601
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031123Z
+LAST-MODIFIED:20080829T031142Z
+DTSTAMP:20080901T141915Z
+UID:a61992d7-0747-46db-aa4c-49ddef65de55
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20100523
+DTEND;VALUE=DATE:20100524
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031143Z
+LAST-MODIFIED:20080829T031208Z
+DTSTAMP:20080901T141915Z
+UID:5e614422-74fe-47d6-bf89-dca8c4d7df3a
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20110605
+DTEND;VALUE=DATE:20110606
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031210Z
+LAST-MODIFIED:20080829T031223Z
+DTSTAMP:20080901T141915Z
+UID:09673ae2-e44c-4cac-90de-deaf49b6b875
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20120527
+DTEND;VALUE=DATE:20120528
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031224Z
+LAST-MODIFIED:20080829T031234Z
+DTSTAMP:20080901T141915Z
+UID:1919a739-59f5-46c2-8cb0-b86726b1e72d
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20130519
+DTEND;VALUE=DATE:20130520
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031235Z
+LAST-MODIFIED:20080829T031252Z
+DTSTAMP:20080901T141915Z
+UID:0a4fae5e-4698-427f-bbdf-b6c08fd96053
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20140608
+DTEND;VALUE=DATE:20140609
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031253Z
+LAST-MODIFIED:20080829T031310Z
+DTSTAMP:20080901T141915Z
+UID:3d5c4095-4429-4abe-8a7a-4bbf5236eaa4
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20150524
+DTEND;VALUE=DATE:20150525
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031311Z
+LAST-MODIFIED:20080829T031322Z
+DTSTAMP:20080901T141915Z
+UID:1177a296-0723-4fcb-8d35-e79b1c021330
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20160515
+DTEND;VALUE=DATE:20160516
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031323Z
+LAST-MODIFIED:20080829T031340Z
+DTSTAMP:20080901T141915Z
+UID:452c678d-0b42-4a89-a347-a0b8e12c4fd6
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20170604
+DTEND;VALUE=DATE:20170605
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031341Z
+LAST-MODIFIED:20080829T031400Z
+DTSTAMP:20080901T141915Z
+UID:01fec43b-b371-4f56-97cb-ef454132a74a
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20180520
+DTEND;VALUE=DATE:20180521
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031401Z
+LAST-MODIFIED:20080829T031411Z
+DTSTAMP:20080901T141915Z
+UID:697b8004-261c-4c0b-a15e-06c1af95ab9b
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20190609
+DTEND;VALUE=DATE:20190610
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031412Z
+LAST-MODIFIED:20080829T031427Z
+DTSTAMP:20080901T141915Z
+UID:ac723797-16b2-4fd9-9d5e-2f55cc90dc22
+SUMMARY:Pentecost
+DTSTART;VALUE=DATE:20200531
+DTEND;VALUE=DATE:20200601
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031600Z
+LAST-MODIFIED:20080829T031643Z
+DTSTAMP:20080901T141915Z
+UID:bec77dd4-49e7-46b5-9ea4-7409cc5369e1
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20000618
+DTEND;VALUE=DATE:20000619
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031731Z
+LAST-MODIFIED:20080829T031753Z
+DTSTAMP:20080901T141915Z
+UID:f395a03d-27e2-4214-88c2-20c638c7f99d
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20010610
+DTEND;VALUE=DATE:20010611
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T031843Z
+LAST-MODIFIED:20080829T031908Z
+DTSTAMP:20080901T141915Z
+UID:fb37469f-ba53-4fec-9c65-fb22c59470a8
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20020526
+DTEND;VALUE=DATE:20020527
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T030305Z
+LAST-MODIFIED:20080829T032009Z
+DTSTAMP:20080901T141915Z
+UID:a2eb4297-f3a3-414b-b53a-e7cdaad20ac9
+SUMMARY:Good Friday
+DTSTART;VALUE=DATE:20030418
+DTEND;VALUE=DATE:20030419
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T032035Z
+LAST-MODIFIED:20080829T032044Z
+DTSTAMP:20080901T141915Z
+UID:078f774d-1113-4bad-b7e5-6f4c48100fc4
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20030615
+DTEND;VALUE=DATE:20030616
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T032128Z
+LAST-MODIFIED:20080829T032136Z
+DTSTAMP:20080901T141915Z
+UID:c2df343c-bf38-4e86-9129-010bd55de1b1
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20040606
+DTEND;VALUE=DATE:20040607
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025605Z
+LAST-MODIFIED:20080829T032213Z
+DTSTAMP:20080901T141915Z
+UID:e4891762-ad19-402e-8195-828fb3386d22
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20050320
+DTEND;VALUE=DATE:20050321
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T032246Z
+LAST-MODIFIED:20080829T032255Z
+DTSTAMP:20080901T141915Z
+UID:f14c5274-2112-4470-a3f8-f8a5b4eb8199
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20050522
+DTEND;VALUE=DATE:20050523
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T025617Z
+LAST-MODIFIED:20080829T032333Z
+DTSTAMP:20080901T141915Z
+UID:33a3f736-bd5b-4a87-b983-612e01ea4dbe
+SUMMARY:Palm Sunday
+DTSTART;VALUE=DATE:20060409
+DTEND;VALUE=DATE:20060410
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T032352Z
+LAST-MODIFIED:20080829T032400Z
+DTSTAMP:20080901T141915Z
+UID:43eeeab3-5836-41cc-82b4-d91d922871c4
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20060611
+DTEND;VALUE=DATE:20060612
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T032435Z
+LAST-MODIFIED:20080829T032443Z
+DTSTAMP:20080901T141915Z
+UID:72234667-e98f-4532-b4da-a2cdd2e56ce4
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20070603
+DTEND;VALUE=DATE:20070604
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T032512Z
+LAST-MODIFIED:20080829T032521Z
+DTSTAMP:20080901T141915Z
+UID:a289a44f-5eb2-4f14-b458-e55dcbc00e9d
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20080518
+DTEND;VALUE=DATE:20080519
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T032617Z
+LAST-MODIFIED:20080829T032627Z
+DTSTAMP:20080901T141915Z
+UID:b5d1e103-7807-4049-ac80-df13ab666b5e
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20090607
+DTEND;VALUE=DATE:20090608
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T032717Z
+LAST-MODIFIED:20080829T032725Z
+DTSTAMP:20080901T141915Z
+UID:59ef3b5c-a65f-4a5f-81ec-25d201285670
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20100530
+DTEND;VALUE=DATE:20100531
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T223849Z
+LAST-MODIFIED:20080829T032936Z
+DTSTAMP:20080901T141915Z
+UID:fa0cda04-283e-4b53-95b0-c9903a3f85e2
+SUMMARY:Easter Sunday
+DTSTART;VALUE=DATE:20110417
+DTEND;VALUE=DATE:20110418
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T033004Z
+LAST-MODIFIED:20080829T033014Z
+DTSTAMP:20080901T141915Z
+UID:001f88a2-a3b4-4dff-a577-c9860d01dcbd
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20110612
+DTEND;VALUE=DATE:20110613
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T033236Z
+LAST-MODIFIED:20080829T033243Z
+DTSTAMP:20080901T141915Z
+UID:f931f051-1dec-4a6c-b78b-615474143fd1
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20120603
+DTEND;VALUE=DATE:20120604
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T033315Z
+LAST-MODIFIED:20080829T033325Z
+DTSTAMP:20080901T141915Z
+UID:838f906b-f3c8-4b94-9cdb-ef698d0222b8
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20130526
+DTEND;VALUE=DATE:20130527
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T033425Z
+LAST-MODIFIED:20080829T033433Z
+DTSTAMP:20080901T141915Z
+UID:de98efc2-cd59-41fd-af0d-d2dcb58b23fe
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20140615
+DTEND;VALUE=DATE:20140616
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T033511Z
+LAST-MODIFIED:20080829T033524Z
+DTSTAMP:20080901T141915Z
+UID:139b7040-5cfd-4db4-abf2-8251ae17368e
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20150531
+DTEND;VALUE=DATE:20150601
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T033614Z
+LAST-MODIFIED:20080829T033624Z
+DTSTAMP:20080901T141915Z
+UID:78d6d38a-a0ae-4b75-bcbb-0276d69a430e
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20160522
+DTEND;VALUE=DATE:20160523
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T033655Z
+LAST-MODIFIED:20080829T033706Z
+DTSTAMP:20080901T141915Z
+UID:83608056-f721-4564-88ed-3cc5d12b01fb
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20170611
+DTEND;VALUE=DATE:20170612
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T033759Z
+LAST-MODIFIED:20080829T033812Z
+DTSTAMP:20080901T141915Z
+UID:cc92b242-3a24-471c-b1be-b8918fb8b6de
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20180527
+DTEND;VALUE=DATE:20180528
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T033848Z
+LAST-MODIFIED:20080829T033855Z
+DTSTAMP:20080901T141915Z
+UID:006195b6-8021-4814-9635-f9f5bffa7a36
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20190616
+DTEND;VALUE=DATE:20190617
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T033920Z
+LAST-MODIFIED:20080829T033928Z
+DTSTAMP:20080901T141915Z
+UID:b60896ca-b1eb-4ec1-a9cd-67c7403c6335
+SUMMARY:Trinity Sunday
+DTSTART;VALUE=DATE:20200607
+DTEND;VALUE=DATE:20200608
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T211737Z
+DTSTAMP:20080831T125843Z
+UID:9f3df592-1dd1-11b2-8b51-a8c49a575f97
+SUMMARY:President's Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3MO;BYMONTH=2
+DTSTART;VALUE=DATE:20000221
+DTEND;VALUE=DATE:20000222
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+X-MOZ-GENERATION:1
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T211951Z
+DTSTAMP:20080831T125843Z
+UID:e0d4c156-1dd1-11b2-b6a4-dac750e0163e
+SUMMARY:Mother's Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SU;BYMONTH=5
+DTSTART;VALUE=DATE:20000514
+DTEND;VALUE=DATE:20000515
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+X-MOZ-GENERATION:1
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T212002Z
+DTSTAMP:20080831T125843Z
+UID:c2783248-1dd1-11b2-affa-ee50c39d8083
+SUMMARY:Armed Forces Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3SA;BYMONTH=5
+DTSTART;VALUE=DATE:20000520
+DTEND;VALUE=DATE:20000521
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+X-MOZ-GENERATION:1
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T212012Z
+DTSTAMP:20080831T125843Z
+UID:d9706fa6-1dd1-11b2-a349-e97241bd4740
+SUMMARY:Memorial Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1MO;BYMONTH=5
+DTSTART;VALUE=DATE:20000529
+DTEND;VALUE=DATE:20000530
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+X-MOZ-GENERATION:1
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T212201Z
+DTSTAMP:20080831T125843Z
+UID:46e6845c-1dd2-11b2-bd3d-d8755a1a171f
+SUMMARY:Parents' Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=4SU;BYMONTH=7
+DTSTART;VALUE=DATE:20000723
+DTEND;VALUE=DATE:20000724
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T212326Z
+DTSTAMP:20080831T125843Z
+UID:0726ea42-1dd2-11b2-9fe6-dda3d063fb50
+SUMMARY:Labor Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1MO;BYMONTH=9
+DTSTART;VALUE=DATE:20000904
+DTEND;VALUE=DATE:20000905
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T212648Z
+DTSTAMP:20080831T125843Z
+UID:7d4402f4-1dd2-11b2-9790-b6193cfa4349
+SUMMARY:Halloween
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20001031
+DTEND;VALUE=DATE:20001101
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T212732Z
+DTSTAMP:20080831T125843Z
+UID:2c7ba10c-1dd2-11b2-b0b7-96f89f288199
+SUMMARY:Veteran's Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20001111
+DTEND;VALUE=DATE:20001112
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T212800Z
+DTSTAMP:20080831T125843Z
+UID:4299a358-1dd2-11b2-a228-d062222b6f88
+SUMMARY:Thanksgiving Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=4TH;BYMONTH=11
+DTSTART;VALUE=DATE:20001123
+DTEND;VALUE=DATE:20001124
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T212827Z
+DTSTAMP:20080831T125843Z
+UID:54f392fa-1dd2-11b2-8ecb-9ae0a7fcebd1
+SUMMARY:Christmas Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20001225
+DTEND;VALUE=DATE:20001226
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T212845Z
+DTSTAMP:20080831T125843Z
+UID:b1f194fc-1dd1-11b2-a973-d219c68b95c4
+SUMMARY:New Year's Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000101
+DTEND;VALUE=DATE:20000102
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+X-MOZ-GENERATION:2
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T212853Z
+DTSTAMP:20080831T125843Z
+UID:a2cbca9c-1dd1-11b2-83e2-abab36f0506d
+SUMMARY:New Year's Eve
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20001231
+DTEND;VALUE=DATE:20010101
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T212909Z
+LAST-MODIFIED:20080827T212935Z
+DTSTAMP:20080831T125843Z
+UID:a0486410-f87b-4e09-939a-77121b58b535
+SUMMARY:Christmas Eve
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20081224
+DTEND;VALUE=DATE:20081225
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213107Z
+DTSTAMP:20080831T125843Z
+UID:13f83ed2-1dd2-11b2-a0de-ee8645423959
+SUMMARY:Daylight Savings Time ends
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=11
+DTSTART;VALUE=DATE:20071104
+DTEND;VALUE=DATE:20071105
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213356Z
+DTSTAMP:20080831T125843Z
+UID:f669a974-1dd1-11b2-9fac-f44d91c657af
+SUMMARY:Independence Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000704
+DTEND;VALUE=DATE:20000705
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213430Z
+DTSTAMP:20080831T125843Z
+UID:cb90487e-1dd1-11b2-9e06-d1a12cc963dc
+SUMMARY:Father's Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3SU;BYMONTH=6
+DTSTART;VALUE=DATE:20000618
+DTEND;VALUE=DATE:20000619
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213441Z
+DTSTAMP:20080831T125843Z
+UID:e8022726-1dd1-11b2-aae6-9f73f16c0f01
+SUMMARY:Flag Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000614
+DTEND;VALUE=DATE:20000615
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213535Z
+DTSTAMP:20080831T125843Z
+UID:f1561106-1dd1-11b2-955f-ba14e5210f45
+SUMMARY:Earth Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000422
+DTEND;VALUE=DATE:20000423
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213545Z
+DTSTAMP:20080831T125843Z
+UID:e46086c2-1dd1-11b2-8a16-a2c99f1c525a
+SUMMARY:Tax Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000415
+DTEND;VALUE=DATE:20000416
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213558Z
+DTSTAMP:20080831T125843Z
+UID:c981b858-1dd1-11b2-b69b-94d05f8bda66
+SUMMARY:April Fool's Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000401
+DTEND;VALUE=DATE:20000402
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213629Z
+DTSTAMP:20080831T125843Z
+UID:bd6cfe4c-1dd1-11b2-b3dc-ebaab9302c26
+SUMMARY:St. Patrick's Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000317
+DTEND;VALUE=DATE:20000318
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213700Z
+DTSTAMP:20080831T125843Z
+UID:aff9f3c8-1dd1-11b2-8593-c63469762eb1
+SUMMARY:George Washington's Birthday (actual)
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000222
+DTEND;VALUE=DATE:20000223
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213730Z
+DTSTAMP:20080831T125843Z
+UID:790b86e2-1dd2-11b2-9cb9-c905fa35c6f9
+SUMMARY:Valentine's Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000214
+DTEND;VALUE=DATE:20000215
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213738Z
+DTSTAMP:20080831T125843Z
+UID:4d5b843e-1dd2-11b2-a6c9-8ea942124d1b
+SUMMARY:Abraham Lincoln's Birthday
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000212
+DTEND;VALUE=DATE:20000213
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T213749Z
+DTSTAMP:20080831T125843Z
+UID:0c771532-1dd2-11b2-8dd9-8638db3aef63
+SUMMARY:Groundhog's Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000202
+DTEND;VALUE=DATE:20000203
+CATEGORIES:Holiday
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T220831Z
+LAST-MODIFIED:20080827T220849Z
+DTSTAMP:20080831T125843Z
+UID:8a05b5d3-6b97-4fe1-b26e-b258a073c5e0
+SUMMARY:United Nations Day
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20001024
+DTEND;VALUE=DATE:20001025
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080827T221149Z
+DTSTAMP:20080831T125843Z
+UID:e462881a-20b8-4b70-ab3c-cf38016d3398
+SUMMARY:Daylight Savings Time begins
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SU;BYMONTH=3
+DTSTART;VALUE=DATE:20070311
+DTEND;VALUE=DATE:20070312
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+X-MOZ-GENERATION:2
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T221253Z
+LAST-MODIFIED:20080827T221433Z
+DTSTAMP:20080831T125843Z
+UID:1eb525d5-26cd-43f0-819e-acc3003b35ad
+SUMMARY:Daylight Savings Time begins
+RRULE:FREQ=YEARLY;UNTIL=20060402T000000;INTERVAL=1;BYDAY=1SU;BYMONTH=4
+DTSTART;VALUE=DATE:20000402
+DTEND;VALUE=DATE:20000403
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T221447Z
+LAST-MODIFIED:20080827T221549Z
+DTSTAMP:20080831T125843Z
+UID:05504c5b-5984-4eb0-a60a-c6d5cf083d82
+SUMMARY:Daylight Savings Time ends
+RRULE:FREQ=YEARLY;UNTIL=20061029T000000;INTERVAL=1;BYDAY=-1SU;BYMONTH=10
+DTSTART;VALUE=DATE:20001029
+DTEND;VALUE=DATE:20001030
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T214410Z
+LAST-MODIFIED:20080828T164353Z
+DTSTAMP:20080831T125843Z
+UID:088031d1-abea-47ed-978d-39c6319e8bf2
+SUMMARY:Inauguration Day
+RRULE:FREQ=YEARLY;INTERVAL=4
+DTSTART;VALUE=DATE:20010120
+DTEND;VALUE=DATE:20010121
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080828T164802Z
+LAST-MODIFIED:20080828T164848Z
+DTSTAMP:20080831T125843Z
+UID:d3c521e1-ffab-414c-8cfa-99e76758d8c8
+SUMMARY:Constitution Day\, Citizenship Day
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000917
+DTEND;VALUE=DATE:20000918
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080828T165106Z
+LAST-MODIFIED:20080828T165219Z
+DTSTAMP:20080831T125843Z
+UID:a44b8b6e-7ae4-4120-b7ad-14e91691be2a
+SUMMARY:National Day of Prayer
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1TH;BYMONTH=5
+DTSTART;VALUE=DATE:20000504
+DTEND;VALUE=DATE:20000505
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080828T165839Z
+LAST-MODIFIED:20080828T165925Z
+DTSTAMP:20080831T125843Z
+UID:e20f1b5c-8ac4-4bea-acf4-b4f2bfe95329
+SUMMARY:Arbor Day
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1FR;BYMONTH=4
+DTSTART;VALUE=DATE:20000428
+DTEND;VALUE=DATE:20000429
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080830T011903Z
+LAST-MODIFIED:20080830T012603Z
+DTSTAMP:20080831T125843Z
+UID:feae8f6c-bdce-46c8-aa45-e2d1c0fb9cb0
+SUMMARY:US General Election
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=TU;BYMONTHDAY=2,3,4,5,6,7,8;BYMONTH=11
+DTSTART;VALUE=DATE:20001107
+DTEND;VALUE=DATE:20001108
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080830T021222Z
+LAST-MODIFIED:20080830T021950Z
+DTSTAMP:20080831T125843Z
+UID:60b5ca68-d0a6-4634-9254-16cc300bb12e
+SUMMARY:Black Friday
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=FR;BYMONTHDAY=23,24,25,26,27,28,29;
+ BYMONTH=11
+DTSTART;VALUE=DATE:20001124
+DTEND;VALUE=DATE:20001125
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080901T145133Z
+DTSTAMP:20080831T125843Z
+UID:dd9bfdf4-1dd1-11b2-ab6e-8da990a14639
+SUMMARY:Martin Luther King Jr.'s Day
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3MO;BYMONTH=1
+DTSTART;VALUE=DATE:20000117
+DTEND;VALUE=DATE:20000118
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:years
+X-MOZ-GENERATION:2
+TRANSP:TRANSPARENT
+DESCRIPTION:Traditionally on January 15th.\nObserved on 3rd Monday of 
+ January.
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20070315T171800Z
+LAST-MODIFIED:20080901T150400Z
+DTSTAMP:20080831T125843Z
+UID:175691b0-1dd2-11b2-9596-e9837a6245dd
+SUMMARY:Columbus Day (observed)
+STATUS:CONFIRMED
+CLASS:PUBLIC
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2MO;BYMONTH=10
+DTSTART;VALUE=DATE:20001009
+DTEND;VALUE=DATE:20001010
+X-MOZILLA-ALARM-DEFAULT-LENGTH:0
+X-MOZILLA-RECUR-DEFAULT-INTERVAL:12
+CATEGORIES:Holiday
+X-MOZILLA-RECUR-DEFAULT-UNITS:months
+TRANSP:TRANSPARENT
+DESCRIPTION:Traditionally on October 12th.\nObserved on 2nd Monday of 
+ October.
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T214111Z
+LAST-MODIFIED:20080829T034323Z
+DTSTAMP:20080831T125843Z
+UID:efab1245-c19c-4693-8391-eb5f40cc3743
+SUMMARY:Epiphany
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20000106
+DTEND;VALUE=DATE:20000107
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080827T220608Z
+LAST-MODIFIED:20080829T034349Z
+DTSTAMP:20080831T125843Z
+UID:37f09326-5105-4092-8535-1b4cad9812ac
+SUMMARY:Reformation Day
+RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10
+DTSTART;VALUE=DATE:20001029
+DTEND;VALUE=DATE:20001030
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+BEGIN:VEVENT
+CREATED:20080829T034030Z
+LAST-MODIFIED:20080901T150600Z
+DTSTAMP:20080831T125843Z
+UID:af808fce-8a77-4d15-ad63-c096737303d2
+SUMMARY:All Saints Day
+RRULE:FREQ=YEARLY;INTERVAL=1
+DTSTART;VALUE=DATE:20001101
+DTEND;VALUE=DATE:20001102
+CATEGORIES:Holidays
+TRANSP:TRANSPARENT
+X-MOZ-GENERATION:1
+END:VEVENT
+END:VCALENDAR
diff --git a/sites/all/modules/date/tests/Yahoo.csv b/sites/all/modules/date/tests/Yahoo.csv
new file mode 100644
index 0000000000000000000000000000000000000000..09ec9c6901b44fa5cf93f04dd82e5a206583d54a
--- /dev/null
+++ b/sites/all/modules/date/tests/Yahoo.csv
@@ -0,0 +1,16 @@
+"Subject","Start Date","Start Time","End Date","End Time","All day event","Description"
+"New Year's Day","1/1/2009","","","","true",""
+"Valentine's Day","2/14/2009","","","","true",""
+"St. Patrick's Day","3/17/2009","","","","true",""
+"Memorial Day","5/31/2009","","","","true",""
+"Independence Day","7/4/2009","","","","true",""
+"Labor Day","09/07/2009","","","","true",""
+"Halloween","10/31/2009","","","","true",""
+"Veteran's Day","11/11/2009","","","","true",""
+"Thanksgiving Day","11/26/2009","","","","true",""
+"Christmas Day","12/25/2009","","","","true",""
+"Do It With Drupal","12/10/2008","08:00 AM","12/10/2008","05:00 PM","false",""
+"DrupalCon","03/04/2009","08:00 AM","03/04/2009","05:00 PM","false",""
+"DrupalCon","03/05/2009","08:00 AM","03/05/2009","05:00 PM","false",""
+"DrupalCon","03/06/2009","08:00 AM","03/06/2009","05:00 PM","false",""
+"DrupalCon","03/07/2009","08:00 AM","03/07/2009","05:00 PM","false",""
diff --git a/sites/all/modules/date/tests/date.test b/sites/all/modules/date/tests/date.test
new file mode 100644
index 0000000000000000000000000000000000000000..3b8f35eb6f7fa9fe7b75453c0dafc26879defa77
--- /dev/null
+++ b/sites/all/modules/date/tests/date.test
@@ -0,0 +1,168 @@
+<?php
+
+/**
+ * @file
+ * Test date UI.
+ */
+
+class DateUITestCase extends DrupalWebTestCase {
+  protected $privileged_user;
+
+  /**
+   * @todo.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Field UI',
+      'description' => 'Test creation of various date fields and widgets using Field UI.',
+      'group' => 'Date',
+    );
+  }
+
+  /**
+   * @todo.
+   */
+  public function setUp() {
+    // Load the date_api module.
+    parent::setUp('field', 'field_ui', 'date_api', 'date', 'date_popup', 'date_tools');
+
+    // Create and log in our privileged user.
+    $this->privileged_user = $this->drupalCreateUser(
+      array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools')
+    );
+    $this->drupalLogin($this->privileged_user);
+
+    variable_set('date_format_long', 'D, m/d/Y - H:i');
+  }
+
+  /**
+   * @todo.
+   */
+  public function testFieldUI() {
+    $edit = array();
+    $edit['name'] = 'Story';
+    $edit['type'] = 'story';
+    $this->drupalPost('admin/structure/types/add', $edit, t('Save content type'));
+    $this->assertText('The content type Story has been added.', 'Content type added.');
+
+    // Creates select list field stored as a date with default settings.
+    $this->createDateField($type = 'date', $widget = 'date_select');
+    $edit = array();
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->dateForm($options = 'select');
+    $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a date field using the date_select widget.');
+    $this->deleteDateField();
+    // Creates text field stored as a date with default settings.
+    $this->createDateField($type = 'date', $widget = 'date_text');
+    $edit = array();
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->dateForm($options = 'text');
+    $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a date field using the date_text widget.');
+    $this->deleteDateField();
+    // Creates popup field stored as a date with default settings.
+    $this->createDateField($type = 'date', $widget = 'date_popup');
+    $edit = array();
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->dateForm($options = 'popup');
+    $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a date field using the date_popup widget.');
+    $this->deleteDateField();
+    // Creates select list field stored as a datestamp with default settings.
+    $this->createDateField($type = 'datestamp', $widget = 'date_select');
+    $edit = array();
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->dateForm($options = 'select');
+    $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datestamp field using the date_select widget.');
+    $this->deleteDateField();
+    // Creates text field stored as a datestamp with default settings.
+    $this->createDateField($type = 'datestamp', $widget = 'date_text');
+    $edit = array();
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->dateForm($options = 'text');
+    $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datestamp field using the date_text widget.');
+    $this->deleteDateField();
+    // Creates popup field stored as a datestamp with default settings.
+    $this->createDateField($type = 'datestamp', $widget = 'date_popup');
+    $edit = array();
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->dateForm($options = 'popup');
+    $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datestamp field using the date_popup widget.');
+    $this->deleteDateField();
+    // Creates select list field stored as a datetime with default settings.
+    $this->createDateField($type = 'datetime', $widget = 'date_select');
+    $edit = array();
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->dateForm($options = 'select');
+    $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datetime field using the date_select widget.');
+    $this->deleteDateField();
+    // Creates text field stored as a datetime with default settings.
+    $this->createDateField($type = 'datetime', $widget = 'date_text');
+    $edit = array();
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->dateForm($options = 'text');
+    $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datetime field using the date_text widget.');
+    $this->deleteDateField();
+    // Creates popup field stored as a datetime with default settings.
+    $this->createDateField($type = 'datetime', $widget = 'date_popup');
+    $edit = array();
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->dateForm($options = 'popup');
+    $this->assertText('Thu, 10/07/2010 - 10:30', 'Found the correct date for a datetime field using the date_popup widget.');
+    $this->deleteDateField();
+
+    // Test timezone handling validation on the field settings form.
+    $this->createDateField($type = 'date', $widget = 'date_select');
+    $edit = array('field[settings][granularity][hour]' => FALSE);
+    $this->drupalPost(NULL, $edit, t('Save field settings'));
+    $this->assertText("Dates without hours granularity must not use any timezone handling.", "Dates without hours granularity required to use timezone handling of 'none.'");
+    $this->deleteDateField();
+  }
+
+  /**
+   * @todo.
+   */
+  function dateForm($options) {
+    // Tests that date field functions properly.
+    $edit = array();
+    $edit['title'] = $this->randomName(8);
+    $edit['body[und][0][value]'] = $this->randomName(16);
+    if ($options == 'select') {
+      $edit['field_test[und][0][value][year]'] = '2010';
+      $edit['field_test[und][0][value][month]'] = '10';
+      $edit['field_test[und][0][value][day]'] = '7';
+      $edit['field_test[und][0][value][hour]'] = '10';
+      $edit['field_test[und][0][value][minute]'] = '30';
+    }
+    elseif ($options == 'text') {
+      $edit['field_test[und][0][value][date]'] = '10/07/2010 - 10:30';
+    }
+    elseif ($options == 'popup') {
+      $edit['field_test[und][0][value][date]'] = '10/07/2010';
+      $edit['field_test[und][0][value][time]'] = '10:30';
+    }
+    $this->drupalPost('node/add/story', $edit, t('Save'));
+    $this->assertText($edit['body[und][0][value]'], 'Test node has been created');
+  }
+
+  /**
+   * @todo.
+   */
+  function createDateField($type, $widget) {
+    $edit = array();
+    $edit['fields[_add_new_field][label]'] = 'Test';
+    $edit['fields[_add_new_field][field_name]'] = 'test';
+    $edit['fields[_add_new_field][weight]'] = '-4';
+    $edit['fields[_add_new_field][type]'] = $type;
+    $edit['fields[_add_new_field][widget_type]'] = $widget;
+    $this->drupalPost('admin/structure/types/manage/story/fields', $edit, t('Save'));
+  }
+
+  /**
+   * @todo.
+   */
+  function deleteDateField() {
+    $this->drupalGet('admin/structure/types/manage/story/fields');
+    $this->clickLink('delete');
+    $this->drupalPost(NULL, NULL, t('Delete'));
+    $this->assertText('The field Test has been deleted from the Story content type.', 'Removed date field.');
+  }
+}
diff --git a/sites/all/modules/date/tests/date_api.test b/sites/all/modules/date/tests/date_api.test
new file mode 100644
index 0000000000000000000000000000000000000000..aa39ac319abf32581eda851554b295f6e075df39
--- /dev/null
+++ b/sites/all/modules/date/tests/date_api.test
@@ -0,0 +1,401 @@
+<?php
+
+/**
+ * @file
+ * Test Date API functions
+ */
+
+class DateAPITestCase extends DrupalWebTestCase {
+  /**
+   * @todo.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => t('Date API'),
+      'description' => t('Test Date API functions.') ,
+      'group' => t('Date'),
+    );
+  }
+
+  /**
+   * @todo.
+   */
+  public function setUp() {
+    // Load the date_api module.
+    parent::setUp('date_api');
+    variable_set('date_api_use_iso8601', FALSE);
+    variable_set('date_first_day', 1);
+  }
+
+  /**
+   * @todo.
+   */
+  public function testDateAPI() {
+    // Test date_format_date().
+    $formatters = array(
+      'a',
+      'A',
+      'B',
+      'c',
+      'd',
+      'D',
+      'e',
+      'F',
+      'g',
+      'G',
+      'h',
+      'H',
+      'i',
+      'I',
+      'j',
+      'l',
+      'L',
+      'm',
+      'M',
+      'n',
+      'N',
+      'o',
+      'O',
+      'P',
+      'r',
+      'R',
+      's',
+      'S',
+      't',
+      'T',
+      'u',
+      'U',
+      'w',
+      'W',
+      'y',
+      'Y',
+      'z',
+      'Z',
+    );
+    foreach ($formatters as $formatter) {
+      $date_api_format = date_format_date(date_now(), 'custom', $formatter);
+      $php_format = date_format(date_now(), $formatter);
+      $this->assertEqual($date_api_format, $php_format, 'Test that the "' . $formatter . '" formatter is formatted correctly by date_format_date()');
+    }
+
+    // Test the order of the weeks days for a calendar that starts on Monday and
+    // one that starts on Sunday.
+    variable_set('date_first_day', 1);
+    $expected = array(0 => t('Mon'), 1 => t('Tue'), 2 => t('Wed'), 3 => t('Thu'), 4 => t('Fri'), 5 => t('Sat'), 6 => t('Sun'));
+    $days = date_week_days_ordered(date_week_days_abbr(1));
+    $this->assertEqual($expected, $days, 'Test that date_week_days_ordered() array starts on Monday when the site first day is on Monday.');
+    variable_set('date_first_day', 0);
+    $expected = array(0 => t('Sun'), 1 => t('Mon'), 2 => t('Tue'), 3 => t('Wed'), 4 => t('Thu'), 5 => t('Fri'), 6 => t('Sat'));
+    $days = date_week_days_ordered(date_week_days_abbr(1));
+    $this->assertEqual($expected, $days, 'Test that date_week_days_ordered() array starts on Sunday when the site first day is on Sunday.');
+
+    // Test days in February for a leap year and a non-leap year.
+    $expected = 28;
+    $value = date_days_in_month(2005, 2);
+    $this->assertEqual($expected, $value, "Test date_days_in_month(2, 2005): should be $expected, found $value.");
+    $expected = 29;
+    $value = date_days_in_month(2004, 2);
+    $this->assertEqual($expected, $value, "Test date_days_in_month(2, 2004): should be $expected, found $value.");
+
+    // Test days in year for a leap year and a non-leap year.
+    $expected = 365;
+    $value = date_days_in_year('2005-06-01 00:00:00');
+    $this->assertEqual($expected, $value, "Test date_days_in_year(2005-06-01): should be $expected, found $value.");
+    $expected = 366;
+    $value = date_days_in_year('2004-06-01 00:00:00');
+    $this->assertEqual($expected, $value, "Test date_days_in_year(2004-06-01): should be $expected, found $value.");
+
+    // Test ISO weeks for a leap year and a non-leap year.
+    $expected = 52;
+    $value = date_iso_weeks_in_year('2008-06-01 00:00:00');
+    $this->assertEqual($expected, $value, "Test date_iso_weeks_in_year(2008-06-01): should be $expected, found $value.");
+    $expected = 53;
+    $value = date_iso_weeks_in_year('2009-06-01 00:00:00');
+    $this->assertEqual($expected, $value, "Test date_iso_weeks_in_year(2009-06-01): should be $expected, found $value.");
+
+    // Test day of week for March 1, the day after leap day.
+    $expected = 6;
+    $value = date_day_of_week('2008-03-01 00:00:00');
+    $this->assertEqual($expected, $value, "Test date_day_of_week(2008-03-01): should be $expected, found $value.");
+    $expected = 0;
+    $value = date_day_of_week('2009-03-01 00:00:00');
+    $this->assertEqual($expected, $value, "Test date_day_of_week(2009-03-01): should be $expected, found $value.");
+
+    // Test day of week name for March 1, the day after leap day.
+    $expected = 'Sat';
+    $value = date_day_of_week_name('2008-03-01 00:00:00');
+    $this->assertEqual($expected, $value, "Test date_day_of_week_name(2008-03-01): should be $expected, found $value.");
+    $expected = 'Sun';
+    $value = date_day_of_week_name('2009-03-01 00:00:00');
+    $this->assertEqual($expected, $value, "Test date_day_of_week_name(2009-03-01): should be $expected, found $value.");
+
+    // Test week range with calendar weeks.
+    variable_set('date_first_day', 0);
+    variable_set('date_api_use_iso8601', FALSE);
+    $expected = '2008-01-27 to 2008-02-03';
+    $result = date_week_range(5, 2008);
+    $value = $result[0]->format(DATE_FORMAT_DATE) . ' to ' . $result[1]->format(DATE_FORMAT_DATE);
+    $this->assertEqual($expected, $value, "Test calendar date_week_range(5, 2008): should be $expected, found $value.");
+    $expected = '2009-01-25 to 2009-02-01';
+    $result = date_week_range(5, 2009);
+    $value = $result[0]->format(DATE_FORMAT_DATE) . ' to ' . $result[1]->format(DATE_FORMAT_DATE);
+    $this->assertEqual($expected, $value, "Test calendar date_week_range(5, 2009): should be $expected, found $value.");
+
+    // And now with ISO weeks.
+    variable_set('date_first_day', 1);
+    variable_set('date_api_use_iso8601', TRUE);
+    $expected = '2008-01-28 to 2008-02-04';
+    $result = date_week_range(5, 2008);
+    $value = $result[0]->format(DATE_FORMAT_DATE) . ' to ' . $result[1]->format(DATE_FORMAT_DATE);
+    $this->assertEqual($expected, $value, "Test ISO date_week_range(5, 2008): should be $expected, found $value.");
+    $expected = '2009-01-26 to 2009-02-02';
+    $result = date_week_range(5, 2009);
+    $value = $result[0]->format(DATE_FORMAT_DATE) . ' to ' . $result[1]->format(DATE_FORMAT_DATE);
+    $this->assertEqual($expected, $value, "Test ISO date_week_range(5, 2009): should be $expected, found $value.");
+    variable_set('date_api_use_iso8601', FALSE);
+
+    // Find calendar week for a date.
+    variable_set('date_first_day', 0);
+    $expected = '09';
+    $value = date_week('2008-03-01');
+    $this->assertEqual($expected, $value, "Test date_week(2008-03-01): should be $expected, found $value.");
+    $expected = '10';
+    $value = date_week('2009-03-01');
+    $this->assertEqual($expected, $value, "Test date_week(2009-03-01): should be $expected, found $value.");
+
+    // Create date object from datetime string.
+    $input = '2009-03-07 10:30';
+    $timezone = 'America/Chicago';
+    $date = new dateObject($input, $timezone);
+    $value = $date->format('c');
+    $expected = '2009-03-07T10:30:00-06:00';
+    $this->assertEqual($expected, $value, "Test new dateObject($input, $timezone): should be $expected, found $value.");
+
+    // Same during daylight savings time.
+    $input = '2009-06-07 10:30';
+    $timezone = 'America/Chicago';
+    $date = new dateObject($input, $timezone);
+    $value = $date->format('c');
+    $expected = '2009-06-07T10:30:00-05:00';
+    $this->assertEqual($expected, $value, "Test new dateObject($input, $timezone): should be $expected, found $value.");
+
+    // Create date object from date string.
+    $input = '2009-03-07';
+    $timezone = 'America/Chicago';
+    $date = new dateObject($input, $timezone);
+    $value = $date->format('c');
+    $expected = '2009-03-07T00:00:00-06:00';
+    $this->assertEqual($expected, $value, "Test new dateObject($input, $timezone): should be $expected, found $value.");
+
+    // Same during daylight savings time.
+    $input = '2009-06-07';
+    $timezone = 'America/Chicago';
+    $date = new dateObject($input, $timezone);
+    $value = $date->format('c');
+    $expected = '2009-06-07T00:00:00-05:00';
+    $this->assertEqual($expected, $value, "Test new dateObject($input, $timezone): should be $expected, found $value.");
+
+    // Create date object from date array, date only.
+    $input = array('year' => 2010, 'month' => 2, 'day' => 28);
+    $timezone = 'America/Chicago';
+    $date = new dateObject($input, $timezone);
+    $value = $date->format('c');
+    $expected = '2010-02-28T00:00:00-06:00';
+    $this->assertEqual($expected, $value, "Test new dateObject(array('year' => 2010, 'month' => 2, 'day' => 28), $timezone): should be $expected, found $value.");
+
+    // Create date object from date array with hour.
+    $input = array('year' => 2010, 'month' => 2, 'day' => 28, 'hour' => 10);
+    $timezone = 'America/Chicago';
+    $date = new dateObject($input, $timezone);
+    $value = $date->format('c');
+    $expected = '2010-02-28T10:00:00-06:00';
+    $this->assertEqual($expected, $value, "Test new dateObject(array('year' => 2010, 'month' => 2, 'day' => 28, 'hour' => 10), $timezone): should be $expected, found $value.");
+
+    // 0 = January 1, 1970 00:00:00 (UTC);
+    // 1000000000 = September 9, 2001 01:46:40 (UTC);
+    // Create date object from unix timestamp and convert it to a local date.
+    $input = 0;
+    $timezone = 'UTC';
+    $date = new dateObject($input, $timezone);
+    $value = $date->format('c');
+    $expected = '1970-01-01T00:00:00+00:00';
+    $this->assertEqual($expected, $value, "Test new dateObject($input, $timezone): should be $expected, found $value.");
+
+    $expected = 'UTC';
+    $value = $date->getTimeZone()->getName();
+    $this->assertEqual($expected, $value, "The current timezone is $value: should be $expected.");
+    $expected = 0;
+    $value = $date->getOffset();
+    $this->assertEqual($expected, $value, "The current offset is $value: should be $expected.");
+
+    $timezone = 'America/Los_Angeles';
+    $date->setTimezone(new DateTimeZone($timezone));
+    $value = $date->format('c');
+    $expected = '1969-12-31T16:00:00-08:00';
+    $this->assertEqual($expected, $value, "Test \$date->setTimezone(new DateTimeZone($timezone)): should be $expected, found $value.");
+
+    $expected = 'America/Los_Angeles';
+    $value = $date->getTimeZone()->getName();
+    $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+    $expected = '-28800';
+    $value = $date->getOffset();
+    $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+    // Convert the local version of a timestamp to UTC.
+    $input = 0;
+    $timezone = 'America/Los_Angeles';
+    $date = new dateObject($input, $timezone);
+    $offset = $date->getOffset();
+    $value = $date->format('c');
+    $expected = '1969-12-31T16:00:00-08:00';
+    $this->assertEqual($expected, $value, "Test new dateObject($input, $timezone):  should be $expected, found $value.");
+
+    $expected = 'America/Los_Angeles';
+    $value = $date->getTimeZone()->getName();
+    $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+    $expected = '-28800';
+    $value = $date->getOffset();
+    $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+    $timezone = 'UTC';
+    $date->setTimezone(new DateTimeZone($timezone));
+    $value = $date->format('c');
+    $expected = '1970-01-01T00:00:00+00:00';
+    $this->assertEqual($expected, $value, "Test \$date->setTimezone(new DateTimeZone($timezone)): should be $expected, found $value.");
+
+    $expected = 'UTC';
+    $value = $date->getTimeZone()->getName();
+    $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+    $expected = '0';
+    $value = $date->getOffset();
+    $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+     // Create date object from datetime string and convert it to a local date.
+    $input = '1970-01-01 00:00:00';
+    $timezone = 'UTC';
+    $date = new dateObject($input, $timezone);
+    $value = $date->format('c');
+    $expected = '1970-01-01T00:00:00+00:00';
+    $this->assertEqual($expected, $value, "Test new dateObject('$input', '$timezone'): should be $expected, found $value.");
+
+    $expected = 'UTC';
+    $value = $date->getTimeZone()->getName();
+    $this->assertEqual($expected, $value, "The current timezone is $value: should be $expected.");
+    $expected = 0;
+    $value = $date->getOffset();
+    $this->assertEqual($expected, $value, "The current offset is $value: should be $expected.");
+
+    $timezone = 'America/Los_Angeles';
+    $date->setTimezone(new DateTimeZone($timezone));
+    $value = $date->format('c');
+    $expected = '1969-12-31T16:00:00-08:00';
+    $this->assertEqual($expected, $value, "Test \$date->setTimezone(new DateTimeZone($timezone)): should be $expected, found $value.");
+
+    $expected = 'America/Los_Angeles';
+    $value = $date->getTimeZone()->getName();
+    $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+    $expected = '-28800';
+    $value = $date->getOffset();
+    $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+    // Convert the local version of a datetime string to UTC.
+    $input = '1969-12-31 16:00:00';
+    $timezone = 'America/Los_Angeles';
+    $date = new dateObject($input, $timezone);
+    $offset = $date->getOffset();
+    $value = $date->format('c');
+    $expected = '1969-12-31T16:00:00-08:00';
+    $this->assertEqual($expected, $value, "Test new dateObject('$input', '$timezone'):  should be $expected, found $value.");
+
+    $expected = 'America/Los_Angeles';
+    $value = $date->getTimeZone()->getName();
+    $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+    $expected = '-28800';
+    $value = $date->getOffset();
+    $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+    $timezone = 'UTC';
+    $date->setTimezone(new DateTimeZone($timezone));
+    $value = $date->format('c');
+    $expected = '1970-01-01T00:00:00+00:00';
+    $this->assertEqual($expected, $value, "Test \$date->setTimezone(new DateTimeZone($timezone)): should be $expected, found $value.");
+
+    $expected = 'UTC';
+    $value = $date->getTimeZone()->getName();
+    $this->assertEqual($expected, $value, "The current timezone should be $expected, found $value.");
+    $expected = '0';
+    $value = $date->getOffset();
+    $this->assertEqual($expected, $value, "The current offset should be $expected, found $value.");
+
+     // Create year-only date.
+    $input = '2009';
+    $timezone = NULL;
+    $format = 'Y';
+    $date = new dateObject($input, $timezone, $format);
+    $value = $date->format('Y');
+    $expected = '2009';
+    $this->assertEqual($expected, $value, "Test new dateObject($input, $timezone, $format): should be $expected, found $value.");
+
+     // Create month and year-only date.
+    $input = '2009-10';
+    $timezone = NULL;
+    $format = 'Y-m';
+    $date = new dateObject($input, $timezone, $format);
+    $value = $date->format('Y-m');
+    $expected = '2009-10';
+    $this->assertEqual($expected, $value, "Test new dateObject($input, $timezone, $format): should be $expected, found $value.");
+
+     // Create time-only date.
+    $input = '0000-00-00T10:30:00';
+    $timezone = NULL;
+    $format = 'Y-m-d\TH:i:s';
+    $date = new dateObject($input, $timezone, $format);
+    $value = $date->format('H:i:s');
+    $expected = '10:30:00';
+    $this->assertEqual($expected, $value, "Test new dateObject($input, $timezone, $format): should be $expected, found $value.");
+
+     // Create time-only date.
+    $input = '10:30:00';
+    $timezone = NULL;
+    $format = 'H:i:s';
+    $date = new dateObject($input, $timezone, $format);
+    $value = $date->format('H:i:s');
+    $expected = '10:30:00';
+    $this->assertEqual($expected, $value, "Test new dateObject($input, $timezone, $format): should be $expected, found $value.");
+
+    // Test date ranges.
+    $valid = array(
+      '-20:+20',
+      '-1:+0',
+      '-10:-5',
+      '2000:2020',
+      '-10:2010',
+      '1980:-10',
+      '1920:+20',
+    );
+    $invalid = array(
+      'abc',
+      'abc:+20',
+      '1920:+20a',
+      '+-20:+-30',
+      '12:12',
+      '0:+20',
+      '-20:0',
+    );
+    foreach ($valid as $range) {
+      $this->assertTrue(date_range_valid($range), "$range recognized as a valid date range.");
+    }
+    foreach ($invalid as $range) {
+      $this->assertFalse(date_range_valid($range), "$range recognized as an invalid date range.");
+    }
+  }
+
+  /**
+   * @todo.
+   */
+  public function tearDown() {
+    variable_del('date_first_day');
+    variable_del('date_api_use_iso8601');
+    parent::tearDown();
+  }
+}
diff --git a/sites/all/modules/date/tests/date_field.test b/sites/all/modules/date/tests/date_field.test
new file mode 100644
index 0000000000000000000000000000000000000000..b2a45a0de09d2fa34b645df3d0cb8706fbe85d4d
--- /dev/null
+++ b/sites/all/modules/date/tests/date_field.test
@@ -0,0 +1,264 @@
+<?php
+
+/**
+ * @file
+ * Basic functions for Date tests.
+ */
+abstract class DateFieldBasic extends DrupalWebTestCase {
+  protected $privileged_user;
+
+  /**
+   * @todo.
+   */
+  protected function setUp() {
+    // Load the date_api module.
+    parent::setUp('field', 'field_ui', 'date_api', 'date', 'date_popup', 'date_tools');
+
+    // Create and log in our privileged user.
+    $this->privileged_user = $this->drupalCreateUser(
+      array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools')
+    );
+    $this->drupalLogin($this->privileged_user);
+
+    variable_set('date_popup_timepicker', 'none');
+
+    module_load_include('inc', 'node', 'content_types');
+    module_load_include('inc', 'node', 'node.pages');
+    module_load_include('inc', 'field', 'field.crud');
+    module_load_include('inc', 'date', 'date_admin');
+
+    $edit = array();
+    $edit['name'] = 'Story';
+    $edit['type'] = 'story';
+    $this->drupalPost('admin/structure/types/add', $edit, t('Save content type'));
+    $this->assertText('The content type Story has been added.', 'Content type added.');
+
+  }
+
+  /**
+   * Creates a date field from an array of settings values.
+   *
+   * All values have defaults, only need to specify values that need to be
+   * different.
+   */
+  protected function createDateField($values = array()) {
+    extract($values);
+
+    $field_name = !empty($field_name) ? $field_name : 'field_test';
+    $entity_type = !empty($entity_type) ? $entity_type : 'node';
+    $bundle = !empty($bundle) ? $bundle : 'story';
+    $label = !empty($label) ? $label : 'Test';
+    $field_type = !empty($field_type) ? $field_type : 'datetime';
+    $repeat = !empty($repeat) ? $repeat : 0;
+    $todate = !empty($todate) ? $todate : 'optional';
+    $widget_type = !empty($widget_type) ? $widget_type : 'date_select';
+    $tz_handling = !empty($tz_handing) ? $tz_handling : 'site';
+    $granularity = !empty($granularity) ? $granularity : array('year', 'month', 'day', 'hour', 'minute');
+    $year_range = !empty($year_range) ? $year_range : '2010:+1';
+    $input_format = !empty($input_format) ? $input_format : date_default_format($widget_type);
+    $input_format_custom = !empty($input_format_custom) ? $input_format_custom : '';
+    $text_parts = !empty($text_parts) ? $text_parts : array();
+    $increment = !empty($increment) ? $increment : 15;
+    $default_value = !empty($default_value) ? $default_value : 'now';
+    $default_value2 = !empty($default_value2) ? $default_value2 : 'blank';
+    $default_format = !empty($default_format) ? $default_format : 'long';
+    $cache_enabled = !empty($cache_enabled);
+    $cache_count = !empty($cache_count) ? $cache_count : 4;
+
+    $field = array(
+      'field_name' => $field_name,
+      'type' => $field_type,
+      'cardinality' => !empty($repeat) ? FIELD_CARDINALITY_UNLIMITED : 1,
+      'settings' => array(
+        'granularity' => $granularity,
+        'tz_handling' => $tz_handling,
+        'timezone_db' => date_get_timezone_db($tz_handling),
+        'repeat' => $repeat,
+        'todate' => $todate,
+        'cache_enabled' => $cache_enabled,
+        'cache_count' => $cache_count,
+      ),
+    );
+    $instance = array(
+      'entity_type' => $entity_type,
+      'field_name' => $field_name,
+      'label' => $label,
+      'bundle' => $bundle,
+      // Move the date right below the title.
+      'weight' => -4,
+      'widget' => array(
+        'type' => $widget_type,
+        // Increment for minutes and seconds, can be 1, 5, 10, 15, or 30.
+        'settings' => array(
+          'increment' => $increment,
+          // The number of years to go back and forward in drop-down year
+          // selectors.
+          'year_range' => $year_range,
+          'input_format' => $input_format,
+          'input_format_custom' => $input_format_custom,
+          'text_parts' => $text_parts,
+          'label_position' => 'above',
+          'repeat_collapsed' => 0,
+        ),
+        'weight' => -4,
+      ),
+      'settings' => array(
+        'default_value' => $default_value,
+        'default_value2' => $default_value2,
+      ),
+    );
+
+    $instance['display'] = array(
+      'default' => array(
+        'label' => 'above',
+        'type' => 'date_default',
+        'settings' => array(
+          'format_type' => $default_format,
+          'show_repeat_rule' => 'show',
+          'multiple_number' => '',
+          'multiple_from' => '',
+          'multiple_to' => '',
+          'fromto' => 'both',
+        ),
+        'module' => 'date',
+        'weight' => 0 ,
+      ),
+      'teaser' => array(
+        'label' => 'above',
+        'type' => 'date_default',
+        'weight' => 0,
+        'settings' => array(
+          'format_type' => $default_format,
+          'show_repeat_rule' => 'show',
+          'multiple_number' => '',
+          'multiple_from' => '',
+          'multiple_to' => '',
+          'fromto' => 'both',
+        ),
+        'module' => 'date',
+      ),
+    );
+
+    $field = field_create_field($field);
+    $instance = field_create_instance($instance);
+
+    field_info_cache_clear(TRUE);
+    field_cache_clear(TRUE);
+
+    // Look at how the field got configured.
+    $this->drupalGet("admin/structure/types/manage/$bundle/fields/$field_name");
+    $this->drupalGet("admin/structure/types/manage/$bundle/display");
+
+  }
+
+  /**
+   * @todo.
+   */
+  protected function deleteDateField($label, $bundle = 'story', $bundle_name = 'Story') {
+    $this->drupalGet("admin/structure/types/manage/$bundle/fields");
+    $this->clickLink('delete');
+    $this->drupalPost(NULL, NULL, t('Delete'));
+    $this->assertText("The field $label has been deleted from the $bundle_name content type.", 'Removed date field.');
+  }
+
+}
+
+class DateFieldTestCase extends DateFieldBasic {
+
+  /**
+   * @todo.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Date Field',
+      'description' => 'Test date field settings and Start/End date interaction.',
+      'group' => 'Date',
+    );
+  }
+
+  /**
+   * @todo.
+   */
+  public function testField() {
+    // Create a date fields with simple values.
+    foreach (array('date', 'datestamp', 'datetime') as $field_type) {
+      foreach (array('date_select', 'date_popup', 'date_text') as $widget_type) {
+        $field_name = "field_test_$widget_type";
+        $label = 'Test';
+        $options = array(
+          'label' => $label,
+          'widget_type' => $widget_type,
+          'field_name' => $field_name,
+          'field_type' => $field_type,
+          'input_format' => 'm/d/Y - H:i',
+        );
+        $this->createDateField($options);
+        $this->dateForm($field_name, $field_type, $widget_type);
+        $this->deleteDateField($label);
+      }
+    }
+  }
+
+  /**
+   * @todo.
+   */
+  public function dateForm($field_name, $field_type, $widget_type, $todate = TRUE) {
+    // Tests that date field functions properly.
+    $edit = array();
+    $edit['title'] = $this->randomName(8);
+    if ($widget_type == 'date_select') {
+      $edit[$field_name . '[und][0][value][year]'] = '2010';
+      $edit[$field_name . '[und][0][value][month]'] = '10';
+      $edit[$field_name . '[und][0][value][day]'] = '7';
+      $edit[$field_name . '[und][0][value][hour]'] = '10';
+      $edit[$field_name . '[und][0][value][minute]'] = '30';
+      if ($todate) {
+        $edit[$field_name . '[und][0][show_todate]'] = '1';
+        $edit[$field_name . '[und][0][value2][year]'] = '2010';
+        $edit[$field_name . '[und][0][value2][month]'] = '10';
+        $edit[$field_name . '[und][0][value2][day]'] = '7';
+        $edit[$field_name . '[und][0][value2][hour]'] = '11';
+        $edit[$field_name . '[und][0][value2][minute]'] = '30';
+      }
+    }
+    elseif ($widget_type == 'date_text') {
+      $edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10:30';
+      if ($todate) {
+        $edit[$field_name . '[und][0][show_todate]'] = '1';
+        $edit[$field_name . '[und][0][value2][date]'] = '10/07/2010 - 11:30';
+      }
+    }
+    elseif ($widget_type == 'date_popup') {
+      $edit[$field_name . '[und][0][value][date]'] = '10/07/2010';
+      $edit[$field_name . '[und][0][value][time]'] = '10:30';
+      if ($todate) {
+        $edit[$field_name . '[und][0][show_todate]'] = '1';
+        $edit[$field_name . '[und][0][value2][date]'] = '10/07/2010';
+        $edit[$field_name . '[und][0][value2][time]'] = '11:30';
+      }
+    }
+    // Test that the date is displayed correctly using both the 'short' and
+    // 'long' date types.
+    //
+    // For the short type, save an explicit format and assert that is the one
+    // which is displayed.
+    variable_set('date_format_short', 'l, m/d/Y - H:i:s');
+    $instance = field_info_instance('node', $field_name, 'story');
+    $instance['display']['default']['settings']['format_type'] = 'short';
+    field_update_instance($instance);
+    $this->drupalPost('node/add/story', $edit, t('Save'));
+    $this->assertText($edit['title'], "Node has been created");
+    $should_be = $todate ? 'Thursday, 10/07/2010 - 10:30 to 11:30' : 'Thursday, 10/07/2010 - 10:30';
+    $this->assertText($should_be, "Found the correct date for a $field_type field using the $widget_type widget displayed using the short date format.");
+    // For the long format, do not save anything, and assert that the displayed
+    // date uses the expected default value of this format provided by Drupal
+    // core ('l, F j, Y - H:i').
+    $instance = field_info_instance('node', $field_name, 'story');
+    $instance['display']['default']['settings']['format_type'] = 'long';
+    field_update_instance($instance);
+    $this->drupalPost('node/add/story', $edit, t('Save'));
+    $this->assertText($edit['title'], "Node has been created");
+    $should_be = $todate ? 'Thursday, October 7, 2010 - 10:30 to 11:30' : 'Thursday, October 7, 2010 - 10:30';
+    $this->assertText($should_be, "Found the correct date for a $field_type field using the $widget_type widget displayed using the long date format.");
+  }
+}
diff --git a/sites/all/modules/date/tests/date_timezone.test b/sites/all/modules/date/tests/date_timezone.test
new file mode 100644
index 0000000000000000000000000000000000000000..ddbdcef992d6f7bd51453fd56cba2110ae9d1f97
--- /dev/null
+++ b/sites/all/modules/date/tests/date_timezone.test
@@ -0,0 +1,97 @@
+<?php
+/**
+ * @file
+ * Timezone tests.
+ */
+class DateTimezoneTestCase extends DateFieldBasic {
+
+  /**
+   * @todo.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Timezone & Granularity',
+      'description' => 'Test combinations of date field timezone handling and granularity.',
+      'group' => 'Date',
+    );
+  }
+
+  /**
+   * @todo.
+   */
+  public function testTimezone() {
+    // Create a date fields with combinations of various timezone handling and
+    // granularity.
+    foreach (array('date', 'datestamp', 'datetime') as $field_type) {
+      foreach (array('site', 'none', 'date', 'user', 'utc') as $tz_handling) {
+        foreach (array('year', 'month', 'day', 'hour', 'minute', 'second') as $max_granularity) {
+          // Skip invalid combinations.
+          if (in_array($max_granularity, array('year', 'month', 'day')) && $tz_handling != 'none') {
+            continue;
+          }
+          $field_name = "field_test";
+          $label = 'Test';
+          $granularity = date_granularity_array_from_precision($max_granularity);
+          $options = array(
+            'label' => $label,
+            'widget_type' => 'date_text',
+            'field_name' => $field_name,
+            'field_type' => $field_type,
+            'input_format' => 'custom',
+            'input_format_custom' => 'm/d/Y - H:i:s',
+            'tz_handling' => $tz_handling,
+            'granularity' => $granularity,
+          );
+          $this->createDateField($options);
+          $this->dateForm($field_name, $field_type, $max_granularity, $tz_handling);
+          $this->deleteDateField($label);
+        }
+      }
+    }
+  }
+
+  /**
+   * @todo.
+   */
+  public function dateForm($field_name, $field_type, $max_granularity, $tz_handling) {
+    variable_set('date_format_long', 'D, m/d/Y - H:i:s');
+    $edit = array();
+    $edit['title'] = $this->randomName(8);
+    $edit[$field_name . '[und][0][show_todate]'] = '1';
+    switch ($max_granularity) {
+      case 'year':
+        $edit[$field_name . '[und][0][value][date]'] = '2010';
+        $edit[$field_name . '[und][0][value2][date]'] = '2011';
+        $should_be = '2010 to 2011';
+        break;
+      case 'month':
+        $edit[$field_name . '[und][0][value][date]'] = '07/2010';
+        $edit[$field_name . '[und][0][value2][date]'] = '08/2010';
+        $should_be = '07/2010 to 08/2010';
+        break;
+      case 'day':
+        $edit[$field_name . '[und][0][value][date]'] = '10/07/2010';
+        $edit[$field_name . '[und][0][value2][date]'] = '10/08/2010';
+        $should_be = 'Thu, 10/07/2010 to Fri, 10/08/2010';
+        break;
+      case 'hour':
+        $edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10';
+        $edit[$field_name . '[und][0][value2][date]'] = '10/07/2010 - 11';
+        $should_be = 'Thu, 10/07/2010 - 10 to Thu, 10/07/2010 - 11';
+        break;
+      case 'minute':
+        $edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10:30';
+        $edit[$field_name . '[und][0][value2][date]'] = '10/07/2010 - 11:30';
+        $should_be = 'Thu, 10/07/2010 - 10:30 to 11:30';
+        break;
+      case 'second':
+        $edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10:30:30';
+        $edit[$field_name . '[und][0][value2][date]'] = '10/07/2010 - 11:30:30';
+        $should_be = 'Thu, 10/07/2010 - 10:30:30 to 11:30:30';
+        break;
+    }
+    $this->drupalPost('node/add/story', $edit, t('Save'));
+    $this->assertText($edit['title'], "Node has been created");
+    $this->assertText($should_be, "Found the correct date for a $field_type field using $max_granularity granularity with $tz_handling timezone handling.");
+  }
+}
diff --git a/sites/all/modules/date/tests/date_validation.test b/sites/all/modules/date/tests/date_validation.test
new file mode 100644
index 0000000000000000000000000000000000000000..a32ff805b7fe43b9e56227daff13fb055a678b21
--- /dev/null
+++ b/sites/all/modules/date/tests/date_validation.test
@@ -0,0 +1,151 @@
+<?php
+/**
+ * @file
+ * Date validation tests.
+ */
+class DateValidationTestCase extends DateFieldBasic {
+
+  /**
+   * @todo.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Date Validation',
+      'description' => 'Test date validation.',
+      'group' => 'Date',
+    );
+  }
+
+  /**
+   * @todo.
+   */
+  public function testValidation() {
+    // Attempts to create text date field stored as a date with default settings
+    // (from input which is not valid).
+    foreach (array('date', 'datestamp', 'datetime') as $field_type) {
+      foreach (array('date_select', 'date_popup', 'date_text') as $widget_type) {
+        $field_name = 'field_test';
+        $label = 'Test';
+        $options = array(
+          'label' => $label,
+          'field_name' => $field_name,
+          'field_type' => $field_type,
+          'widget_type' => $widget_type,
+          'input_format' => 'm/d/Y - H:i',
+        );
+        $this->createDateField($options);
+
+        // Malformed date test won't work on date_select, which won't allow
+        // invalid input.
+        if ($widget_type != 'date_select') {
+          $this->malFormedDate($field_name, $field_type, $widget_type);
+        }
+
+        $this->wrongGranularity($field_name, $field_type, $widget_type);
+        $this->deleteDateField($label);
+      }
+    }
+  }
+
+  /**
+   * @todo.
+   */
+  function malFormedDate($field_name, $field_type, $widget_type) {
+    // Tests that date field filters improper dates.
+    $edit = array();
+    $edit['title'] = $this->randomName(8);
+    $edit['body[und][0][value]'] = $this->randomName(16);
+    if ($widget_type == 'date_select') {
+      $edit[$field_name . '[und][0][value][year]'] = '2011';
+      $edit[$field_name . '[und][0][value][month]'] = '15';
+      $edit[$field_name . '[und][0][value][day]'] = '49';
+      $edit[$field_name . '[und][0][value][hour]'] = '10';
+      $edit[$field_name . '[und][0][value][minute]'] = '30';
+    }
+    elseif ($widget_type == 'date_text') {
+      $edit[$field_name . '[und][0][value][date]'] = '15/49/2011 - 10:30';
+    }
+    elseif ($widget_type == 'date_popup') {
+      $edit[$field_name . '[und][0][value][date]'] = '15/49/2011';
+      $edit[$field_name . '[und][0][value][time]'] = '10:30';
+    }
+    $this->drupalPost('node/add/story', $edit, t('Save'));
+    $should_not_be = $edit['title'] . "has been created";
+    $this->assertNoText($should_not_be, "Correctly blocked creation of node with invalid month and day for a $field_type field using the $widget_type widget.");
+    $this->assertText('The month is invalid.', "Correctly blocked invalid month for a $field_type field using the $widget_type widget.");
+    $this->assertText('The day is invalid.', "Correctly blocked invalid day for a $field_type field using the $widget_type widget.");
+
+    // Test two-digit entry for year where 4-digit is expected.
+    if ($widget_type == 'date_select') {
+      $edit[$field_name . '[und][0][value][year]'] = '11';
+      $edit[$field_name . '[und][0][value][month]'] = '12';
+      $edit[$field_name . '[und][0][value][day]'] = '10';
+      $edit[$field_name . '[und][0][value][hour]'] = '10';
+      $edit[$field_name . '[und][0][value][minute]'] = '30';
+    }
+    elseif ($widget_type == 'date_text') {
+      $edit[$field_name . '[und][0][value][date]'] = '12/10/11 - 10:30';
+    }
+    elseif ($widget_type == 'date_popup') {
+      $edit[$field_name . '[und][0][value][date]'] = '12/10/11';
+      $edit[$field_name . '[und][0][value][time]'] = '10:30';
+    }
+    $this->drupalPost('node/add/story', $edit, t('Save'));
+    $should_not_be = $edit['title'] . " has been created";
+    $this->assertNoText($should_not_be, "Correctly blocked creation of node with invalid year for a $field_type field using the $widget_type widget.");
+    $should_be = 'The year is invalid. Please check that entry includes four digits.';
+    $this->assertText($should_be, "Correctly blocked two digit year for a $field_type field using the $widget_type widget.");
+
+    // Test invalid hour/minute entry for time.
+    if ($widget_type == 'date_select') {
+      $edit[$field_name . '[und][0][value][year]'] = '2011';
+      $edit[$field_name . '[und][0][value][month]'] = '12';
+      $edit[$field_name . '[und][0][value][day]'] = '10';
+      $edit[$field_name . '[und][0][value][hour]'] = '29';
+      $edit[$field_name . '[und][0][value][minute]'] = '95';
+    }
+    elseif ($widget_type == 'date_text') {
+      $edit[$field_name . '[und][0][value][date]'] = '12/10/2011 - 29:95';
+    }
+    elseif ($widget_type == 'date_popup') {
+      $edit[$field_name . '[und][0][value][date]'] = '12/10/2011';
+      $edit[$field_name . '[und][0][value][time]'] = '29:95';
+    }
+    $this->drupalPost('node/add/story', $edit, t('Save'));
+    $should_not_be = $edit['title'] . " has been created";
+    $this->assertNoText($should_not_be, "Correctly blocked creation of node with invalid time for a $field_type field using the $widget_type widget.");
+    $should_be = 'The hour is invalid.';
+    $this->assertText($should_be, "Correctly blocked invalid hour for a $field_type field using the $widget_type widget.");
+    $should_be = 'The minute is invalid.';
+    $this->assertText($should_be, "Correctly blocked invalid minute for a $field_type field using the $widget_type widget.");
+
+  }
+
+  /**
+   * @todo.
+   */
+  public function wrongGranularity($field_name, $field_type, $widget_type) {
+    // Create a node with incorrect granularity -- missing time.
+    $edit = array();
+    $edit['title'] = $this->randomName(8);
+    $edit['body[und][0][value]'] = $this->randomName(16);
+    if ($widget_type == 'date_select') {
+      $edit[$field_name . '[und][0][value][year]'] = '2011';
+      $edit[$field_name . '[und][0][value][month]'] = '12';
+      $edit[$field_name . '[und][0][value][day]'] = '10';
+      $edit[$field_name . '[und][0][value][hour]'] = '';
+      $edit[$field_name . '[und][0][value][minute]'] = '';
+    }
+    elseif ($widget_type == 'date_text') {
+      $edit[$field_name . '[und][0][value][date]'] = '12/10/2011';
+    }
+    elseif ($widget_type == 'date_popup') {
+      $edit[$field_name . '[und][0][value][date]'] = '12/10/2011';
+      $edit[$field_name . '[und][0][value][time]'] = '';
+    }
+    $this->drupalPost('node/add/story', $edit, t('Save'));
+    $should_not_be = $edit['title'] . " has been created";
+    $this->assertNoText($should_not_be, "Correctly blocked creation of node with missing time for a $field_type field using the $widget_type widget.");
+    $this->assertText('invalid', "Marked form with missing time as invalid for a $field_type field using the $widget_type widget.");
+  }
+}
diff --git a/sites/all/modules/date/tests/rrule.ics b/sites/all/modules/date/tests/rrule.ics
new file mode 100644
index 0000000000000000000000000000000000000000..285831c97f510be80a6a12f3f3ae674b3417be3e
--- /dev/null
+++ b/sites/all/modules/date/tests/rrule.ics
@@ -0,0 +1,125 @@
+BEGIN:VCALENDAR
+PRODID:-//Test
+VERSION:2.0
+X-WR-CALDESC:Test various iCal RRULEs.
+BEGIN:VEVENT
+UID:iCalRRuleTest1
+SUMMARY:Daily for 10 occurrences
+DTSTART;TZID=US-Eastern:20090702T090000
+RRULE:FREQ=DAILY;COUNT=10
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest2
+SUMMARY:Daily until December 24, 2009
+DTSTART;TZID=US-Eastern:20091202T090000
+RRULE:FREQ=DAILY;UNTIL=20091224T000000Z
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest3
+SUMMARY:Every other day
+DTSTART;TZID=US-Eastern:20090202T090000
+RRULE:FREQ=DAILY;INTERVAL=2
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest4
+SUMMARY:Every 10 days, 5 occurrences
+DTSTART;TZID=US-Eastern:20090302T090000
+RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest5
+SUMMARY:Everyday in January, for 2 years
+DTSTART;TZID=US-Eastern:20090101T090000
+RRULE:FREQ=YEARLY;UNTIL=20110131T090000Z;BYMONTH=1;BYDAY=SU,MO,TU,WE,TH,FR,SA
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest6
+SUMMARY:Weekly for 10 occurrences
+DTSTART;TZID=US-Eastern:20090102T090000
+RRULE:FREQ=WEEKLY;COUNT=10
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest7
+SUMMARY:Weekly on Tuesday and Thursday for 5 weeks
+DTSTART;TZID=US-Eastern:20090902T090000
+RRULE:FREQ=WEEKLY;UNTIL=20091007T000000Z;WKST=SU;BYDAY=TU,TH
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest8
+SUMMARY:Every other week on Monday, Wednesday and Friday until December 24, 2009:
+DTSTART;TZID=US-Eastern:20090502T090000
+RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=20091224T000000Z;WKST=SU;BYDAY=MO,WE,FR
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest9
+SUMMARY:Every other week on Tuesday and Thursday, for 8 occurrences
+DTSTART;TZID=US-Eastern:20090702T090000
+RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest10
+SUMMARY:Monthly on the 1st Friday for ten occurrences
+DTSTART;TZID=US-Eastern:20090905T090000
+RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest11
+SUMMARY:Monthly on the 1st Friday until December 24, 2009
+DTSTART;TZID=US-Eastern:20090905T090000
+RRULE:FREQ=MONTHLY;UNTIL=20091224T000000Z;BYDAY=1FR
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest12
+SUMMARY:Every other month on the 1st and last Sunday of the month for 10 occurrences
+DTSTART;TZID=US-Eastern:20090907T090000
+RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest13
+SUMMARY:Monthly on the second to last Monday of the month for 6 months
+DTSTART;TZID=US-Eastern:20090119T090000
+RRULE:FREQ=MONTHLY;COUNT=6;BYDAY=-2MO
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest14
+SUMMARY:Monthly on the third to the last day of the month
+DTSTART;TZID=US-Eastern:20090928T090000
+RRULE:FREQ=MONTHLY;BYMONTHDAY=-3
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest15
+SUMMARY:Monthly on the 2nd and 15th of the month for 10 occurrences
+DTSTART;TZID=US-Eastern:20090202T090000
+RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest16
+SUMMARY:Monthly on the first and last day of the month for 10 occurrences
+DTSTART;TZID=US-Eastern:20090130T090000
+RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest17
+SUMMARY:Every 3 months on the 10th thru 15th of the month for 10 occurrences
+DTSTART;TZID=US-Eastern:20090410T090000
+RRULE:FREQ=MONTHLY;INTERVAL=3;COUNT=10;BYMONTHDAY=10,11,12,13,14,15
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest18
+SUMMARY:Every Tuesday, every other month
+DTSTART;TZID=US-Eastern:20090602T090000
+RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest19
+SUMMARY:Yearly in June and July for 10 occurrences
+DTSTART;TZID=US-Eastern:20090610T090000
+RRULE:FREQ=YEARLY;COUNT=10;BYMONTH=6,7
+END:VEVENT
+BEGIN:VEVENT
+UID:iCalRRuleTest20
+SUMMARY:Every Thursday in March
+DTSTART;TZID=US-Eastern:20090305T090000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH
+END:VEVENT
+END:VCALENDAR
\ No newline at end of file
diff --git a/sites/all/modules/entity/LICENSE.txt b/sites/all/modules/entity/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1
--- /dev/null
+++ b/sites/all/modules/entity/LICENSE.txt
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/sites/all/modules/entity/README.txt b/sites/all/modules/entity/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..98b599fa230d34ec9c011775fbb3aba6deffcf72
--- /dev/null
+++ b/sites/all/modules/entity/README.txt
@@ -0,0 +1,156 @@
+
+Entity API module
+-----------------
+by Wolfgang Ziegler, nuppla@zites.net
+
+This module extends the entity API of Drupal core in order to provide a unified
+way to deal with entities and their properties. Additionally, it provides an
+entity CRUD controller, which helps simplifying the creation of new entity types.
+
+
+This is an API module. You only need to enable it if a module depends on it or
+you are interested in using it for development.
+
+This README is for interested developers. If you are not interested in
+developing, you may stop reading now.
+
+--------------------------------------------------------------------------------
+                                Entity API
+--------------------------------------------------------------------------------
+
+  * The module provides API functions allowing modules to create, save, delete
+    or to determine access for entities based on any entity type, for which the
+    necessary metadata is available. The module comes with integration for all
+    core entity types, as well as for entities provided via the Entity CRUD API
+    (see below). However, for any other entity type implemented by a contrib
+    module, the module integration has to be provided by the contrib module
+    itself.
+
+  * Thus the module provides API functions like entity_save(), entity_create(),
+    entity_delete(), entity_view() and entity_access() among others.
+    entity_load(), entity_label() and entity_uri() are already provided by
+    Drupal core.
+
+ *  For more information about how to provide this metadata, have a look at the
+    API documentation, i.e. entity_metadata_hook_entity_info().
+
+--------------------------------------------------------------------------------
+               Entity CRUD API - Providing new entity types
+--------------------------------------------------------------------------------
+
+ * This API helps you when defining a new entity type. It provides an entity
+   controller, which implements full CRUD functionality for your entities.
+
+ * To make use of the CRUD functionality you may just use the API functions
+   entity_create(), entity_delete() and entity_save().
+
+   Alternatively you may specify a class to use for your entities, for which the
+   "Entity" class is provided. In particular, it is useful to extend this class
+   in order to easily customize the entity type, e.g. saving.
+
+ * The controller supports fieldable entities, however it does not yet support
+   revisions. There is also a controller which supports implementing exportable
+   entities.
+
+ * The Entity CRUD API helps with providing additional module integration too,
+   e.g. exportable entities are automatically integrated with the Features
+   module. These module integrations are implemented in separate controller
+   classes, which may be overridden and deactivated on their own.
+
+ * There is also an optional ui controller class, which assits with providing an
+   administrative UI for managing entities of a certain type.
+
+ * For more details check out the documentation in the drupal.org handbook
+   http://drupal.org/node/878804 as well as the API documentation, i.e.
+   entity_crud_hook_entity_info().
+
+
+ Basic steps to add a new entity type:
+---------------------------------------
+
+  * You might want to study the code of the "entity_test.module".
+
+  * Describe your entities db table as usual in hook_schema().
+
+  * Just use the "Entity" directly or extend it with your own class.
+    To see how to provide a separate class have a look at the "EntityClass" from
+    the "entity_test.module".
+
+  * Implement hook_entity_info() for your entity. At least specifiy the
+    controller class (EntityAPIController, EntityAPIControllerExportable or your
+    own), your db table and your entity's keys.
+    Again just look at "entity_test.module"'s hook_entity_info() for guidance.
+
+  * If you want your entity to be fieldable just set 'fieldable' in
+    hook_entity_info() to TRUE. The field API attachers are then called
+    automatically in the entity CRUD functions.
+
+  * The entity API is able to deal with bundle objects too (e.g. the node type
+    object). For that just specify another entity type for the bundle objects
+    and set the 'bundle of' property for it.
+    Again just look at "entity_test.module"'s hook_entity_info() for guidance.
+
+  * Schema fields marked as 'serialized' are automatically unserialized upon
+    loading as well as serialized on saving. If the 'merge' attribute is also
+    set to TRUE the unserialized data is automatically "merged" into the entity.
+
+  * Further details can be found at http://drupal.org/node/878804.
+
+
+
+--------------------------------------------------------------------------------
+                Entity Properties & Entity metadata wrappers
+--------------------------------------------------------------------------------
+
+  * This module introduces a unique place for metadata about entity properties:
+    hook_entity_property_info(), whereas hook_entity_property_info() may be
+    placed in your module's {YOUR_MODULE}.info.inc include file. For details
+    have a look at the API documentation, i.e. hook_entity_property_info() and
+    at http://drupal.org/node/878876.
+
+  * The information about entity properties contains the data type and callbacks
+    for how to get and set the data of the property. That way the data of an
+    entity can be easily re-used, e.g. to export it into other data formats like
+    XML.
+
+  * For making use of this information (metadata) the module provides some
+    wrapper classes which ease getting and setting values. The wrapper supports
+    chained usage for retrieving wrappers of entity properties, e.g. to get a
+    node author's mail address one could use:
+
+       $wrapper = entity_metadata_wrapper('node', $node);
+       $wrapper->author->mail->value();
+
+    To update the user's mail address one could use
+
+       $wrapper->author->mail->set('sepp@example.com');
+
+       or
+
+       $wrapper->author->mail = 'sepp@example.com';
+
+    The wrappers always return the data as described in the property
+    information, which may be retrieved directly via entity_get_property_info()
+    or from the wrapper:
+
+       $mail_info = $wrapper->author->mail->info();
+
+    In order to force getting a textual value sanitized for output one can use,
+    e.g.
+
+       $wrapper->title->value(array('sanitize' => TRUE));
+
+    to get the sanitized node title. When a property is already returned
+    sanitized by default, like the node body, one possibly wants to get the
+    not-sanitized data as it would appear in a browser for other use-cases.
+    To do so one can enable the 'decode' option, which ensures for any sanitized
+    data the tags are stripped and HTML entities are decoded before the property
+    is returned:
+
+       $wrapper->body->value->value(array('decode' => TRUE));
+
+    That way one always gets the data as shown to the user. However if you
+    really want to get the raw, unprocessed value, even for sanitized textual
+    data, you can do so via:
+
+      $wrapper->body->value->raw();
diff --git a/sites/all/modules/entity/ctools/content_types/entity_view.inc b/sites/all/modules/entity/ctools/content_types/entity_view.inc
new file mode 100644
index 0000000000000000000000000000000000000000..e5056332848e91f06fb192c74cf2c8eb230d661b
--- /dev/null
+++ b/sites/all/modules/entity/ctools/content_types/entity_view.inc
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * @file
+ * Content type plugin to expose rendered entities, view mode configuration
+ * still available.
+ */
+
+$plugin = array(
+  'title' => t('Rendered entity'),
+  'defaults' => array('view_mode' => 'full'),
+  'content type' => 'entity_entity_view_content_type_info',
+);
+
+/**
+ * Get the entity content type info.
+ */
+function entity_entity_view_content_type_info($entity_type) {
+  $types = entity_entity_view_content_type_content_types();
+  if (isset($types[$entity_type])) {
+    return $types[$entity_type];
+  }
+}
+
+/**
+ * Implements hook_PLUGIN_content_type_content_types().
+ *
+ * Rendered entity use entity types machine name as subtype name.
+ */
+function entity_entity_view_content_type_content_types() {
+  $types = array();
+  $entities = entity_get_info();
+
+  foreach ($entities as $entity_type => $info) {
+    if (entity_type_supports($entity_type, 'view')) {
+      $types[$entity_type] = array(
+        'title' => t('Rendered @entity_type', array('@entity_type' => $info['label'])),
+        'category' => t('Entity'),
+        'required context' => new ctools_context_required(t('Entity'), $entity_type),
+      );
+    }
+  }
+
+  return $types;
+}
+
+/**
+ * Returns an edit form for a entity.
+ *
+ * Rendered entity use entity types machine name as subtype name.
+ *
+ * @see entity_entity_view_get_content_types()
+ */
+function entity_entity_view_content_type_edit_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+  $entity_type = $form_state['subtype_name'];
+  $entity_info = entity_get_info($entity_type);
+
+  $options = array();
+  if (!empty($entity_info['view modes'])) {
+    foreach ($entity_info['view modes'] as $mode => $settings) {
+      $options[$mode] = $settings['label'];
+    }
+  }
+
+  if (count($options) > 1) {
+    $form['view_mode'] = array(
+      '#type' => 'select',
+      '#options' => $options,
+      '#title' => t('View mode'),
+      '#default_value' => $conf['view_mode'],
+    );
+  }
+  else {
+    $form['view_mode_info'] = array(
+      '#type' => 'item',
+      '#title' => t('View mode'),
+      '#description' => t('Only one view mode is available for this entity type.'),
+      '#markup' => $options ? current($options) : t('Default'),
+    );
+
+    $form['view_mode'] = array(
+      '#type' => 'value',
+      '#value' => $options ? key($options) : 'default',
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Save selected view mode.
+ */
+function entity_entity_view_content_type_edit_form_submit(&$form, &$form_state) {
+  if (isset($form_state['values']['view_mode'])) {
+    $form_state['conf']['view_mode'] = $form_state['values']['view_mode'];
+  }
+}
+
+/**
+ * Implements hook_PLUGIN_content_type_render().
+ *
+ * Ctools requires us to return a block.
+ *
+ * @see ctools_content_render()
+ */
+function entity_entity_view_content_type_render($entity_type, $conf, $panel_args, $context) {
+  if ($context->empty) {
+    return;
+  }
+  $block = new stdClass();
+  $block->module = 'entity';
+  $block->delta = $entity_type . '-' . str_replace('-', '_', $conf['view_mode']);
+
+  $entity_id = $context->argument;
+  $entity = entity_load_single($entity_type, $entity_id);
+  $block->content = entity_view($entity_type, array($entity_id => $entity), $conf['view_mode']);
+  return $block;
+}
+
+/**
+ * Implements hook_PLUGIN_content_type_admin_title().
+ *
+ * Returns the administrative title for a type.
+ */
+function entity_entity_view_content_type_admin_title($entity_type, $conf, $contexts) {
+  $entity_info = entity_get_info($entity_type);
+  $view_mode = $conf['view_mode'];
+  if (isset($entity_info['view modes'][$view_mode])) {
+    $view_mode = $entity_info['view modes'][$view_mode]['label'];
+  }
+  return t('Rendered @entity_type using view mode "@view_mode"', array('@entity_type' => $entity_info['label'], '@view_mode' => $view_mode));
+}
diff --git a/sites/all/modules/entity/entity.api.php b/sites/all/modules/entity/entity.api.php
new file mode 100644
index 0000000000000000000000000000000000000000..1dfb0cf0b5796e78d50cb21c4809191072712331
--- /dev/null
+++ b/sites/all/modules/entity/entity.api.php
@@ -0,0 +1,449 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the entity API.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Provide an entity type via the entity CRUD API.
+ *
+ * This is a placeholder for describing further keys for hook_entity_info(),
+ * which are introduced the entity API for providing a new entity type with the
+ * entity CRUD API. For that the entity API provides two controllers:
+ *  - EntityAPIController: A regular CRUD controller.
+ *  - EntityAPIControllerExportable: Extends the regular controller to
+ *    additionally support exportable entities and/or entities making use of a
+ *    name key.
+ * See entity_metadata_hook_entity_info() for the documentation of additional
+ * keys for hook_entity_info() as introduced by the entity API and supported for
+ * any entity type.
+ *
+ * The entity CRUD API supports the following keys:
+ * - entity class: (optional) A class the controller will use for instantiating
+ *   entities. It is suggested to make use of the provided "Entity" class or to
+ *   extend it.
+ * - bundle of: (optional) Entity types can be used as bundles for
+ *   other entity types. To enable this functionality, use the 'bundle of' key
+ *   to indicate which entity type this entity serves as a bundle for. But note
+ *   that the other entity type will still need to declare entities of this
+ *   type as bundles, as described by the documentation of hook_entity_info().
+ *   If the other entity type is fieldable, the entity API controller takes
+ *   care of invoking the field API bundle attachers. Note that
+ *   field_attach_delete_bundle() has to be invoked manually upon module
+ *   uninstallation. See entity_test_entity_info() and entity_test_uninstall()
+ *   for examples.
+ * - module: (optional) The module providing the entity type. This is optional,
+ *   but strongly suggested.
+ * - exportable: (optional) Whether the entity is exportable. Defaults to FALSE.
+ *   If enabled, a name key should be specified and db columns for the module
+ *   and status key as defined by entity_exportable_schema_fields() have to
+ *   exist in the entity's base table. Also see 'entity keys' below.
+ *   This option requires the EntityAPIControllerExportable to work.
+ * - entity keys: An array of keys as defined by Drupal core. The following
+ *   additional keys are used by the entity CRUD API:
+ *   - name: (optional) The key of the entity property containing the unique,
+ *     machine readable name of the entity. If specified, this is used as
+ *     identifier of the entity, while the usual 'id' key is still required and
+ *     may be used when modules deal with entities generically, or to refer to
+ *     the entity internally, i.e. in the database.
+ *     If a name key is given, the name is used as entity identifier by the
+ *     entity API module, metadata wrappers and entity-type specific hooks.
+ *     However note that for consistency all generic entity hooks like
+ *     hook_entity_load() are invoked with the entities keyed by numeric id,
+ *     while entity-type specific hooks like hook_{entity_type}_load() are
+ *     invoked with the entities keyed by name.
+ *     Also, just as entity_load_single() entity_load() may be called
+ *     with names passed as the $ids parameter, while the results of
+ *     entity_load() are always keyed by numeric id. Thus, it is suggested to
+ *     make use of entity_load_multiple_by_name() to implement entity-type
+ *     specific loading functions like {entity_type}_load_multiple(), as this
+ *     function returns the entities keyed by name. See entity_test_get_types()
+ *     for an example.
+ *     For exportable entities, it is strongly recommended to make use of a
+ *     machine name as names are portable across systems.
+ *     This option requires the EntityAPIControllerExportable to work.
+ *   - module: (optional) A key for the module property used by the entity CRUD
+ *     API to save the source module name for exportable entities that have been
+ *     provided in code. Defaults to 'module'.
+ *   - status: (optional) The name of the entity property used by the entity
+ *     CRUD API to save the exportable entity status using defined bit flags.
+ *     Defaults to 'status'. See entity_has_status().
+ * - export: (optional) An array of information used for exporting. For ctools
+ *   exportables compatibility any export-keys supported by ctools may be added
+ *   to this array too.
+ *   - default hook: What hook to invoke to find exportable entities that are
+ *     currently defined. This hook is automatically called by the CRUD
+ *     controller during entity_load(). Defaults to 'default_' . $entity_type.
+ * - admin ui: (optional) An array of optional information used for providing an
+ *   administrative user interface. To enable the UI at least the path must be
+ *   given. Apart from that, the 'access callback' (see below) is required for
+ *   the entity, as well as the 'ENTITY_TYPE_form' for editing, adding and
+ *   cloning. The form gets the entity and the operation ('edit', 'add' or
+ *   'clone') passed. See entity_ui_get_form() for more details.
+ *   Known keys are:
+ *   - path: A path where the UI should show up as expected by hook_menu().
+ *   - controller class: (optional) A controller class name for providing the
+ *     UI. Defaults to EntityDefaultUIController, which implements an admin UI
+ *     suiting for managing configuration entities.
+ *     For customizing the UI inherit from the default class and overide methods
+ *     as suiting and specify your class as controller class.
+ *   - file: (optional) The name of the file in which the entity form resides
+ *     as it is required by hook_menu().
+ *   - file path: (optional) The path to the file as required by hook_menu. If
+ *     not set, it defaults to entity type's module's path, thus the entity
+ *     types 'module' key is required.
+ *   - menu wildcard: The wildcard to use in paths of the hook_menu() items.
+ *     Defaults to %entity_object which is the loader provided by Entity API.
+ * - rules controller class: (optional) A controller class for providing Rules
+ *   integration, or FALSE to disable this feature. The given class has to
+ *   inherit from the class EntityDefaultRulesController, which serves as
+ *   default in case the entity type is not marked as configuration. For
+ *   configuration entities it defaults to FALSE.
+ * - metadata controller class: (optional) A controller class for providing
+ *   entity property info. By default some info is generated out of the
+ *   information provided in your hook_schema() implementation, while only read
+ *   access is granted to that properties by default. Based upon that the
+ *   Entity tokens module also generates token replacements for your entity
+ *   type, once activated.
+ *   Override the controller class to adapt the defaults and to improve and
+ *   complete the generated metadata. Set it to FALSE to disable this feature.
+ *   Defaults to the EntityDefaultMetadataController class.
+ * - features controller class: (optional) A controller class for providing
+ *   Features module integration for exportable entities. The given class has to
+ *   inherit from the default class being EntityDefaultFeaturesController. Set
+ *   it to FALSE to disable this feature.
+ * - i18n controller class: (optional) A controller class for providing
+ *   i18n module integration for (exportable) entities. The given class has to
+ *   inherit from the class EntityDefaultI18nStringController. Defaults to
+ *   FALSE (disabled). See EntityDefaultI18nStringController for more
+ *   information.
+ * - views controller class: (optional) A controller class for providing views
+ *   integration. The given class has to inherit from the class
+ *   EntityDefaultViewsController, which is set as default in case the providing
+ *   module has been specified (see 'module') and the module does not provide
+ *   any views integration. Else it defaults to FALSE, which disables this
+ *   feature. See EntityDefaultViewsController.
+ * - access callback: (optional) Specify a callback that returns access
+ *   permissions for the operations 'create', 'update', 'delete' and 'view'.
+ *   The callback gets optionally the entity and the user account to check for
+ *   passed. See entity_access() for more details on the arguments and
+ *   entity_metadata_no_hook_node_access() for an example.
+ *   This is optional, but suggested for the Rules integration, and required for
+ *   the admin ui (see above).
+ * - form callback: (optional) Specfiy a callback that returns a fully built
+ *   edit form for your entity type. See entity_form().
+ *   In case the 'admin ui' is used, no callback needs to be specified.
+ * - entity cache: (optional) Whether entities should be cached using the cache
+ *   system. Requires the entitycache module to be installed and enabled. As
+ *   cached entities are only retrieved by id key, the cache would not apply to
+ *   exportable entities retrieved by name key. If enabled, 'field cache' is
+ *   obsolete and should be disabled. Defaults to FALSE.
+ *
+ * @see hook_entity_info()
+ * @see entity_metadata_hook_entity_info()
+ */
+function entity_crud_hook_entity_info() {
+  $return = array(
+    'entity_test' => array(
+      'label' => t('Test Entity'),
+      'entity class' => 'Entity',
+      'controller class' => 'EntityAPIController',
+      'base table' => 'entity_test',
+      'module' => 'entity_test',
+      'fieldable' => TRUE,
+      'entity keys' => array(
+        'id' => 'pid',
+        'name' => 'name',
+        'bundle' => 'type',
+      ),
+      'bundles' => array(),
+    ),
+  );
+  foreach (entity_test_get_types() as $name => $info) {
+    $return['entity_test']['bundles'][$name] = array(
+      'label' => $info['label'],
+    );
+  }
+  return $return;
+}
+
+/**
+ * Provide additional metadata for entities.
+ *
+ * This is a placeholder for describing further keys for hook_entity_info(),
+ * which are introduced the entity API in order to support any entity type; e.g.
+ * to make entity_save(), entity_create(), entity_view() and others work.
+ * See entity_crud_hook_entity_info() for the documentation of additional keys
+ * for hook_entity_info() as introduced by the entity API for providing new
+ * entity types with the entity CRUD API.
+ *
+ * Additional keys are:
+ * - plural label: (optional) The human-readable, plural name of the entity
+ *   type. As 'label' it should start capitalized.
+ * - description: (optional) A human-readable description of the entity type.
+ * - access callback: (optional) Specify a callback that returns access
+ *   permissions for the operations 'create', 'update', 'delete' and 'view'.
+ *   The callback gets optionally the entity and the user account to check for
+ *   passed. See entity_access() for more details on the arguments and
+ *   entity_metadata_no_hook_node_access() for an example.
+ * - creation callback: (optional) A callback that creates a new instance of
+ *   this entity type. See entity_metadata_create_node() for an example.
+ * - save callback: (optional) A callback that permanently saves an entity of
+ *   this type.
+ * - deletion callback: (optional) A callback that permanently deletes an
+ *   entity of this type.
+ * - view callback: (optional) A callback to render a list of entities.
+ *   See entity_metadata_view_node() as example.
+ * - form callback: (optional) A callback that returns a fully built edit form
+ *   for the entity type.
+ * - token type: (optional) A type name to use for token replacements. Set it
+ *   to FALSE if there aren't any token replacements for this entity type.
+ * - configuration: (optional) A boolean value that specifies whether the entity
+ *   type should be considered as configuration. Modules working with entities
+ *   may use this value to decide whether they should deal with a certain entity
+ *   type. Defaults to TRUE to for entity types that are exportable, else to
+ *   FALSE.
+ *
+ * @see hook_entity_info()
+ * @see entity_crud_hook_entity_info()
+ * @see entity_access()
+ * @see entity_create()
+ * @see entity_save()
+ * @see entity_delete()
+ * @see entity_view()
+ * @see entity_form()
+ */
+function entity_metadata_hook_entity_info() {
+  return array(
+    'node' => array(
+      'label' => t('Node'),
+      'access callback' => 'entity_metadata_no_hook_node_access',
+      // ...
+    ),
+  );
+}
+
+/**
+ * Allow modules to define metadata about entity properties.
+ *
+ * Modules providing properties for any entities defined in hook_entity_info()
+ * can implement this hook to provide metadata about this properties.
+ * For making use of the metadata have a look at the provided wrappers returned
+ * by entity_metadata_wrapper().
+ * For providing property information for fields see entity_hook_field_info().
+ *
+ * @return
+ *   An array whose keys are entity type names and whose values are arrays
+ *   containing the keys:
+ *   - properties: The array describing all properties for this entity. Entries
+ *     are keyed by the property name and contain an array of metadata for each
+ *     property. The name may only contain alphanumeric lowercase characters
+ *     and underscores. Known keys are:
+ *     - label: A human readable, translated label for the property.
+ *     - description: (optional) A human readable, translated description for
+ *       the property.
+ *     - type: The data type of the property. To make the property actually
+ *       useful it is important to map your properties to one of the known data
+ *       types, which currently are:
+ *        - text: Any text.
+ *        - token: A string containing only lowercase letters, numbers, and
+ *          underscores starting with a letter; e.g. this type is useful for
+ *          machine readable names.
+ *        - integer: A usual PHP integer value.
+ *        - decimal: A PHP float or integer.
+ *        - date: A full date and time, as timestamp.
+ *        - duration: A duration as number of seconds.
+ *        - boolean: A usual PHP boolean value.
+ *        - uri: An absolute URI or URL.
+ *        - entities - You may use the type of each entity known by
+ *          hook_entity_info(), e.g. 'node' or 'user'. Internally entities are
+ *          represented by their identifieres. In case of single-valued
+ *          properties getter callbacks may return full entity objects as well,
+ *          while a value of FALSE is interpreted like a NULL value as "property
+ *          is not set".
+ *        - entity: A special type to be used generically for entities where the
+ *          entity type is not known beforehand. The entity has to be
+ *          represented using an EntityMetadataWrapper.
+ *        - struct: This as well as any else not known type may be used for
+ *          supporting arbitrary data structures. For that additional metadata
+ *          has to be specified with the 'property info' key. New type names
+ *          have to be properly prefixed with the module name.
+ *        - list: A list of values, represented as numerically indexed array.
+ *          The list<TYPE> notation may be used to specify the type of the
+ *          contained items, where TYPE may be any valid type expression.
+ *     - bundle: (optional) If the property is an entity, you may specify the
+ *       bundle of the referenced entity.
+ *     - options list: (optional) A callback that returns a list of possible
+ *       values for the property. The callback has to return an array as
+ *       used by hook_options_list().
+ *       Note that it is possible to return a different set of options depending
+ *       whether they are used in read or in write context. See
+ *       EntityMetadataWrapper::optionsList() for more details on that.
+ *     - getter callback: (optional) A callback used to retrieve the value of
+ *       the property. Defaults to entity_property_verbatim_get().
+ *       It is important that your data is represented, as documented for your
+ *       data type, e.g. a date has to be a timestamp. Thus if necessary, the
+ *       getter callback has to do the necessary conversion. In case of an empty
+ *       or not set value, the callback has to return NULL.
+ *     - setter callback: (optional) A callback used to set the value of the
+ *       property. In many cases entity_property_verbatim_set() can be used.
+ *     - validation callback: (optional) A callback that returns whether the
+ *       passed data value is valid for the property. May be used to implement
+ *       additional validation checks, such as to ensure the value is a valid
+ *       mail address.
+ *     - access callback: (optional) An access callback to allow for checking
+ *       'view' and 'edit' access for the described property. If no callback
+ *       is specified, a 'setter permission' may be specified instead.
+ *     - setter permission: (optional) A permission that describes whether
+ *       a user has permission to set ('edit') this property. This permission
+ *       is only be taken into account, if no 'access callback' is given.
+ *     - schema field: (optional) In case the property is directly based upon
+ *       a field specified in the entity's hook_schema(), the name of the field.
+ *     - queryable: (optional) Whether a property is queryable with
+ *       EntityFieldQuery. Defaults to TRUE if a 'schema field' is specified, or
+ *       if the deprecated 'query callback' is set to
+ *       'entity_metadata_field_query'. Otherwise it defaults to FALSE.
+ *     - query callback: (deprecated) A callback for querying for entities
+ *       having the given property value. See entity_property_query().
+ *       Generally, properties should be queryable via EntityFieldQuery. If
+ *       that is the case, just set 'queryable' to TRUE.
+ *     - required: (optional) Whether this property is required for the creation
+ *       of a new instance of its entity. See
+ *       entity_property_values_create_entity().
+ *     - field: (optional) A boolean indicating whether a property is stemming
+ *       from a field.
+ *     - computed: (optional) A boolean indiciating whether a property is
+ *       computed, i.e. the property value is not stored or loaded by the
+ *       entity's controller but determined on the fly by the getter callback.
+ *       Defaults to FALSE.
+ *     - entity views field: (optional) If enabled, the property is
+ *       automatically exposed as views field available to all views query
+ *       backends listing this entity-type. As the property value will always be
+ *       generated from a loaded entity object, this is particularly useful for
+ *       'computed' properties. Defaults to FALSE.
+ *     - sanitized: (optional) For textual properties only, whether the text is
+ *       already sanitized. In this case you might want to also specify a raw
+ *       getter callback. Defaults to FALSE.
+ *     - sanitize: (optional) For textual properties, that are not sanitized
+ *       yet, specify a function for sanitizing the value. Defaults to
+ *       check_plain().
+ *     - raw getter callback: (optional) For sanitized textual properties, a
+ *       separate callback which can be used to retrieve the raw, unprocessed
+ *       value.
+ *     - clear: (optional) An array of property names, of which the cache should
+ *       be cleared too once this property is updated. As a rule of thumb any
+ *       duplicated properties should be avoided though.
+ *     - property info: (optional) An array of info for an arbitrary data
+ *       structure together with any else not defined type, see data type
+ *       'struct'. Specify metadata in the same way as defined for this hook.
+ *     - property info alter: (optional) A callback for altering the property
+ *       info before it is used by the metadata wrappers.
+ *     - property defaults: (optional) An array of property info defaults for
+ *       each property derived of the wrapped data item (e.g. an entity).
+ *       Applied by the metadata wrappers.
+ *     - auto creation: (optional) Properties of type 'struct' may specify
+ *       this callback which is used to automatically create the data structure
+ *       (e.g. an array) if necessary. This is necessary in order to support
+ *       setting a property of a not yet initialized data structure.
+ *       See entity_metadata_field_file_callback() for an example.
+ *     - translatable: (optional) Whether the property is translatable, defaults
+ *       to FALSE.
+ *     - entity token: (optional) If Entity tokens module is enabled, the
+ *       module provides a token for the property if one does not exist yet.
+ *       Specify FALSE to disable this functionality for the property.
+ *   - bundles: An array keyed by bundle name containing further metadata
+ *     related to the bundles only. This array may contain the key 'properties'
+ *     with an array of info about the bundle specific properties, structured in
+ *     the same way as the entity properties array.
+ *
+ *  @see hook_entity_property_info_alter()
+ *  @see entity_metadata_get_info()
+ *  @see entity_metadata_wrapper()
+ */
+function hook_entity_property_info() {
+  $info = array();
+  $properties = &$info['node']['properties'];
+
+  $properties['nid'] = array(
+    'label' => t("Content ID"),
+    'type' => 'integer',
+    'description' => t("The unique content ID."),
+  );
+  return $info;
+}
+
+/**
+ * Allow modules to alter metadata about entity properties.
+ *
+ * @see hook_entity_property_info()
+ */
+function hook_entity_property_info_alter(&$info) {
+  $properties = &$info['node']['bundles']['poll']['properties'];
+
+  $properties['poll-votes'] = array(
+    'label' => t("Poll votes"),
+    'description' => t("The number of votes that have been cast on a poll node."),
+    'type' => 'integer',
+    'getter callback' => 'entity_property_poll_node_get_properties',
+  );
+}
+
+/**
+ * Provide entity property information for fields.
+ *
+ * This is a placeholder for describing further keys for hook_field_info(),
+ * which are introduced by the entity API.
+ *
+ * For providing entity property info for fields each field type may specify a
+ * property type to map to using the key 'property_type'. With that info in
+ * place useful defaults are generated, which suffice for a lot of field
+ * types.
+ * However it is possible to specify further callbacks that may alter the
+ * generated property info. To do so use the key 'property_callbacks' and set
+ * it to an array of function names. Apart from that any property info provided
+ * for a field instance using the key 'property info' is added in too.
+ *
+ * @see entity_field_info_alter()
+ * @see entity_metadata_field_text_property_callback()
+ */
+function entity_hook_field_info() {
+  return array(
+    'text' => array(
+      'label' => t('Text'),
+      'property_type' => 'text',
+      // ...
+    ),
+  );
+}
+
+/**
+ * Alter the handlers used by the data selection tables provided by this module.
+ *
+ * @param array $field_handlers
+ *   An array of the field handler classes to use for specific types. The keys
+ *   are the types, mapped to their respective classes. Contained types are:
+ *   - All primitive types known by the entity API (see
+ *     hook_entity_property_info()).
+ *   - options: Special type for fields having an options list.
+ *   - field: Special type for Field API fields.
+ *   - entity: Special type for entity-valued fields.
+ *   - relationship: Views relationship handler to use for relationships.
+ *   Values for all specific entity types can be additionally added.
+ *
+ * @see entity_views_field_definition()
+ * @see entity_views_get_field_handlers()
+ */
+function hook_entity_views_field_handlers_alter(array &$field_handlers) {
+  $field_handlers['duration'] = 'example_duration_handler';
+  $field_handlers['node'] = 'example_node_handler';
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/sites/all/modules/entity/entity.features.inc b/sites/all/modules/entity/entity.features.inc
new file mode 100644
index 0000000000000000000000000000000000000000..d856863c8bae6c59a12f52b3e55ffe73def32d8d
--- /dev/null
+++ b/sites/all/modules/entity/entity.features.inc
@@ -0,0 +1,174 @@
+<?php
+
+/**
+ * @file
+ * Provides Features integration for entity types using the CRUD API.
+ */
+
+/**
+ * Returns the configured entity features controller.
+ */
+function entity_features_get_controller($type) {
+  $static = &drupal_static(__FUNCTION__);
+  if (!isset($static[$type])) {
+    $info = entity_get_info($type);
+    $info += array('features controller class' => 'EntityDefaultFeaturesController');
+    $static[$type] = $info['features controller class'] ? new $info['features controller class']($type) : FALSE;
+  }
+  return $static[$type];
+}
+
+/**
+ * Default controller handling features integration.
+ */
+class EntityDefaultFeaturesController {
+
+  protected $type, $info;
+
+  public function __construct($type) {
+    $this->type = $type;
+    $this->info = entity_get_info($type);
+    $this->info['entity keys'] += array('module' => 'module', 'status' => 'status');
+    $this->statusKey = $this->info['entity keys']['status'];
+    $this->moduleKey = $this->info['entity keys']['module'];
+    if (!empty($this->info['bundle of'])) {
+      $entity_info = entity_get_info($this->info['bundle of']);
+      $this->bundleKey = $entity_info['bundle keys']['bundle'];
+    }
+  }
+
+  /**
+   * Defines the result for hook_features_api().
+   */
+  public function api() {
+    return array(
+      // The entity type has to be the features component name.
+      $this->type => array(
+        'name' => $this->info['label'],
+        'feature_source' => TRUE,
+        'default_hook' => isset($this->info['export']['default hook']) ? $this->info['export']['default hook'] : 'default_' . $this->type,
+        // Use the provided component callbacks making use of the controller.
+        'base' => 'entity',
+        'file' => drupal_get_path('module', 'entity') . '/entity.features.inc',
+      ),
+    );
+  }
+
+  /**
+   * Generates the result for hook_features_export_options().
+   */
+  public function export_options() {
+    $options = array();
+    foreach (entity_load_multiple_by_name($this->type, FALSE) as $name => $entity) {
+      $options[$name] = entity_label($this->type, $entity);
+    }
+    return $options;
+  }
+
+  /**
+   * Generates the result for hook_features_export().
+   */
+  public function export($data, &$export, $module_name = '') {
+    $pipe = array();
+    foreach (entity_load_multiple_by_name($this->type, $data) as $name => $entity) {
+      // If this entity is provided by a different module, add it as dependency.
+      if (($entity->{$this->statusKey} & ENTITY_IN_CODE) && $entity->{$this->moduleKey} != $module_name) {
+        $module = $entity->{$this->moduleKey};
+        $export['dependencies'][$module] = $module;
+      }
+      // Otherwise export the entity.
+      else {
+        $export['features'][$this->type][$name] = $name;
+
+        // If this is a bundle of a fieldable entity, add its fields to the pipe.
+        if (!empty($this->info['bundle of'])) {
+          $fields = field_info_instances($this->info['bundle of'], $entity->{$this->bundleKey});
+          foreach ($fields as $name => $field) {
+            $pipe['field'][] = "{$field['entity_type']}-{$field['bundle']}-{$field['field_name']}";
+          }
+        }
+      }
+    }
+    // Add the module providing the entity type as dependency.
+    if ($data && !empty($this->info['module'])) {
+      $export['dependencies'][$this->info['module']] = $this->info['module'];
+      // In case entity is not already an indirect dependency, add it.
+      // We can do so without causing redundant dependencies because,
+      // if entity is an indirect dependency, Features will filter it out.
+      $export['dependencies']['entity'] = 'entity';
+    }
+    return $pipe;
+  }
+
+  /**
+   * Generates the result for hook_features_export_render().
+   */
+  function export_render($module, $data, $export = NULL) {
+    $output = array();
+    $output[] = '  $items = array();';
+    foreach (entity_load_multiple_by_name($this->type, $data) as $name => $entity) {
+      $export  = "  \$items['$name'] = entity_import('{$this->type}', '";
+      // Make sure to escape the characters \ and '.
+      $export .= addcslashes(entity_export($this->type, $entity, '  '), '\\\'');
+      $export .= "');";
+      $output[] = $export;
+    }
+    $output[] = '  return $items;';
+    $output = implode("\n", $output);
+
+    $hook = isset($this->info['export']['default hook']) ? $this->info['export']['default hook'] : 'default_' . $this->type;
+    return array($hook => $output);
+  }
+
+  /**
+   * Generates the result for hook_features_revert().
+   */
+  function revert($module = NULL) {
+    if ($defaults = features_get_default($this->type, $module)) {
+      foreach ($defaults as $name => $entity) {
+        entity_delete($this->type, $name);
+      }
+    }
+  }
+}
+
+/**
+ * Implements of hook_features_api().
+ */
+function entity_features_api() {
+  $items = array();
+  foreach (entity_crud_get_info() as $type => $info) {
+    if (!empty($info['exportable']) && $controller = entity_features_get_controller($type)) {
+      $items += $controller->api();
+    }
+  }
+  return $items;
+}
+
+/**
+ * Features component callback.
+ */
+function entity_features_export_options($entity_type) {
+  return entity_features_get_controller($entity_type)->export_options();
+}
+
+/**
+ * Features component callback.
+ */
+function entity_features_export($data, &$export, $module_name = '', $entity_type) {
+  return entity_features_get_controller($entity_type)->export($data, $export, $module_name);
+}
+
+/**
+ * Features component callback.
+ */
+function entity_features_export_render($module, $data, $export = NULL, $entity_type) {
+  return entity_features_get_controller($entity_type)->export_render($module, $data, $export);
+}
+
+/**
+ * Features component callback.
+ */
+function entity_features_revert($module = NULL, $entity_type) {
+  return entity_features_get_controller($entity_type)->revert($module);
+}
diff --git a/sites/all/modules/entity/entity.i18n.inc b/sites/all/modules/entity/entity.i18n.inc
new file mode 100644
index 0000000000000000000000000000000000000000..8347eaa7c4da3ff5ba0899eac402a56d4e993cb7
--- /dev/null
+++ b/sites/all/modules/entity/entity.i18n.inc
@@ -0,0 +1,210 @@
+<?php
+/**
+ * @file
+ * Internationalization (i18n) integration.
+ */
+
+/**
+ * Gets the i18n controller for a given entity type.
+ *
+ * @return EntityDefaultI18nStringController|array|false
+ *   If a type is given, the controller for the given entity type. Else an array
+ *   of all enabled controllers keyed by entity type is returned.
+ */
+function entity_i18n_controller($type = NULL) {
+  $static = &drupal_static(__FUNCTION__);
+
+  if (!isset($type)) {
+    // Invoke the function for each type to ensure we have fully populated the
+    // static variable.
+    foreach (entity_get_info() as $entity_type => $info) {
+      entity_i18n_controller($entity_type);
+    }
+    return array_filter($static);
+  }
+
+  if (!isset($static[$type])) {
+    $info = entity_get_info($type);
+    // Do not activate it by default. Modules have to explicitly enable it by
+    // specifying EntityDefaultI18nStringController or their customization.
+    $class = isset($info['i18n controller class']) ? $info['i18n controller class'] : FALSE;
+    $static[$type] = $class ? new $class($type, $info) : FALSE;
+  }
+
+  return $static[$type];
+}
+
+/**
+ * Implements hook_i18n_string_info().
+ */
+function entity_i18n_string_info() {
+  $groups = array();
+  foreach (entity_i18n_controller() as $entity_type => $controller) {
+    $groups += $controller->hook_string_info();
+  }
+  return $groups;
+}
+
+/**
+ * Implements hook_i18n_object_info().
+ */
+function entity_i18n_object_info() {
+  $info = array();
+  foreach (entity_i18n_controller() as $entity_type => $controller) {
+    $info += $controller->hook_object_info();
+  }
+  return $info;
+}
+
+/**
+ * Implements hook_i18n_string_objects().
+ */
+function entity_i18n_string_objects($type) {
+  if ($controller = entity_i18n_controller($type)) {
+    return $controller->hook_string_objects();
+  }
+}
+
+/**
+ * Default controller handling i18n integration.
+ *
+ * Implements i18n string translation for all non-field properties marked as
+ * 'translatable' and having the flag 'i18n string' set. This translation
+ * approach fits in particular for translating configuration, i.e. exportable
+ * entities.
+ *
+ * Requirements for the default controller:
+ *  - The entity type providing module must be specified using the 'module' key
+ *    in hook_entity_info().
+ *  - An 'entity class' derived from the provided class 'Entity' must be used.
+ *  - Properties must be declared as 'translatable' and the 'i18n string' flag
+ *    must be set to TRUE using hook_entity_property_info().
+ *  - i18n must be notified about changes manually by calling
+ *    i18n_string_object_update(), i18n_string_object_remove() and
+ *    i18n_string_update_context(). Ideally, this is done in a small integration
+ *    module depending on the entity API and i18n_string. Look at the provided
+ *    testing module "entity_test_i18n" for an example.
+ *  - If the entity API admin UI is used, the "translate" tab will be
+ *    automatically enabled and linked from the UI.
+ *  - There are helpers for getting translated values which work regardless
+ *    whether the i18n_string module is enabled, i.e. entity_i18n_string()
+ *    and Entity::getTranslation().
+ *
+ *  Current limitations:
+ *   - Translatable property values cannot be updated via the metadata wrapper,
+ *     however reading works fine. See Entity::getTranslation().
+ */
+class EntityDefaultI18nStringController {
+
+  protected $entityType, $entityInfo;
+
+  /**
+   * The i18n textgroup we are using.
+   */
+  protected $textgroup;
+
+  public function __construct($type) {
+    $this->entityType = $type;
+    $this->entityInfo = entity_get_info($type);
+    // By default we go with the module name as textgroup.
+    $this->textgroup = $this->entityInfo['module'];
+  }
+
+  /**
+   * Implements hook_i18n_string_info() via entity_i18n_string_info().
+   */
+  public function hook_string_info() {
+    $list = system_list('module_enabled');
+    $info = $list[$this->textgroup]->info;
+
+    $groups[$this->textgroup] = array(
+      'title' => $info['name'],
+      'description' => !empty($info['description']) ? $info['description'] : NULL,
+      'format' => FALSE,
+      'list' => TRUE,
+    );
+    return $groups;
+  }
+
+  /**
+   * Implements hook_i18n_object_info() via entity_i18n_object_info().
+   *
+   * Go with the same default values as the admin UI as far as possible.
+   */
+  public function hook_object_info() {
+    $wildcard = $this->menuWildcard();
+    $id_key = !empty($this->entityInfo['entity keys']['name']) ? $this->entityInfo['entity keys']['name'] : $this->entityInfo['entity keys']['id'];
+
+    $info[$this->entityType] = array(
+      // Generic object title.
+      'title' => $this->entityInfo['label'],
+      // The object key field.
+      'key' => $id_key,
+      // Placeholders for automatic paths.
+      'placeholders' => array(
+        $wildcard => $id_key,
+      ),
+
+      // Properties for string translation.
+      'string translation' => array(
+        // Text group that will handle this object's strings.
+        'textgroup' => $this->textgroup,
+        // Object type property for string translation.
+        'type' => $this->entityType,
+        // Translatable properties of these objects.
+        'properties' => $this->translatableProperties(),
+      ),
+    );
+
+    // Integrate the translate tab into the admin-UI if enabled.
+    if ($base_path = $this->menuBasePath()) {
+      $info[$this->entityType] += array(
+        // To produce edit links automatically.
+        'edit path' => $base_path . '/manage/' . $wildcard,
+        // Auto-generate translate tab.
+        'translate tab' => $base_path . '/manage/' . $wildcard . '/translate',
+      );
+      $info[$this->entityType]['string translation'] += array(
+        // Path to translate strings to every language.
+        'translate path' => $base_path . '/manage/' . $wildcard . '/translate/%i18n_language',
+      );
+    }
+    return $info;
+  }
+
+  /**
+   * Defines the menu base path used by self::hook_object_info().
+   */
+  protected function menuBasePath() {
+    return !empty($this->entityInfo['admin ui']['path']) ? $this->entityInfo['admin ui']['path'] : FALSE;
+  }
+
+  /**
+   * Defines the menu wildcard used by self::hook_object_info().
+   */
+  protected function menuWildcard() {
+    return isset($this->entityInfo['admin ui']['menu wildcard']) ? $this->entityInfo['admin ui']['menu wildcard'] : '%entity_object';
+  }
+
+  /**
+   * Defines translatable properties used by self::hook_object_info().
+   */
+  protected function translatableProperties() {
+    $list = array();
+    foreach (entity_get_all_property_info($this->entityType) as $name => $info) {
+      if (!empty($info['translatable']) && !empty($info['i18n string'])) {
+        $list[$name] = array(
+          'title' => $info['label'],
+        );
+      }
+    }
+    return $list;
+  }
+
+  /**
+   * Implements hook_i18n_string_objects() via entity_i18n_string_objects().
+   */
+  public function hook_string_objects() {
+    return entity_load_multiple_by_name($this->entityType, FALSE);
+  }
+}
diff --git a/sites/all/modules/entity/entity.info b/sites/all/modules/entity/entity.info
new file mode 100644
index 0000000000000000000000000000000000000000..e0a30a65ebc0bc4c38f43b4d7effe7b0af70d807
--- /dev/null
+++ b/sites/all/modules/entity/entity.info
@@ -0,0 +1,33 @@
+name = Entity API
+description = Enables modules to work with any entity type and to provide entities.
+core = 7.x
+files[] = entity.features.inc
+files[] = entity.i18n.inc
+files[] = entity.info.inc
+files[] = entity.rules.inc
+files[] = entity.test
+files[] = includes/entity.inc
+files[] = includes/entity.controller.inc
+files[] = includes/entity.ui.inc
+files[] = includes/entity.wrapper.inc
+files[] = views/entity.views.inc
+files[] = views/handlers/entity_views_field_handler_helper.inc
+files[] = views/handlers/entity_views_handler_area_entity.inc
+files[] = views/handlers/entity_views_handler_field_boolean.inc
+files[] = views/handlers/entity_views_handler_field_date.inc
+files[] = views/handlers/entity_views_handler_field_duration.inc
+files[] = views/handlers/entity_views_handler_field_entity.inc
+files[] = views/handlers/entity_views_handler_field_field.inc
+files[] = views/handlers/entity_views_handler_field_numeric.inc
+files[] = views/handlers/entity_views_handler_field_options.inc
+files[] = views/handlers/entity_views_handler_field_text.inc
+files[] = views/handlers/entity_views_handler_field_uri.inc
+files[] = views/handlers/entity_views_handler_relationship_by_bundle.inc
+files[] = views/handlers/entity_views_handler_relationship.inc
+files[] = views/plugins/entity_views_plugin_row_entity_view.inc
+; Information added by drupal.org packaging script on 2012-05-25
+version = "7.x-1.0-rc3"
+core = "7.x"
+project = "entity"
+datestamp = "1337981155"
+
diff --git a/sites/all/modules/entity/entity.info.inc b/sites/all/modules/entity/entity.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..1f626ccfb5a4b5e161aef9102f91140744ca202e
--- /dev/null
+++ b/sites/all/modules/entity/entity.info.inc
@@ -0,0 +1,181 @@
+<?php
+
+/**
+ * @file
+ * Provides basic entity property info for entities provided via the CRUD API,
+ * as well as property info for all entity types defined by core. For that
+ * the respective modules/MODULE.info.inc files are included.
+ */
+
+/**
+ * Implements hook_entity_property_info().
+ */
+function entity_entity_property_info() {
+  $items = array();
+  // Add in info about entities provided by the CRUD API.
+  foreach (entity_crud_get_info() as $type => $info) {
+    // Automatically enable the controller only if the module does not implement
+    // the hook itself.
+    if (!isset($info['metadata controller class']) && !empty($info['base table']) && (!isset($info['module']) || !module_hook($info['module'], 'entity_property_info'))) {
+      $info['metadata controller class'] = 'EntityDefaultMetadataController';
+    }
+    if (!empty($info['metadata controller class'])) {
+      $controller = new $info['metadata controller class']($type);
+      $items += $controller->entityPropertyInfo();
+    }
+  }
+  // Add in info for all core entities.
+  foreach (_entity_metadata_core_modules() as $module) {
+    module_load_include('inc', 'entity', "modules/$module.info");
+    if (function_exists($function = "entity_metadata_{$module}_entity_property_info")) {
+      if ($return = $function()) {
+        $items = array_merge_recursive($items, $return);
+      }
+    }
+  }
+  return $items;
+}
+
+/**
+ * Implements hook_entity_property_info_alter().
+ */
+function entity_entity_property_info_alter(&$entity_info) {
+  // Add in info for all core entities.
+  foreach (_entity_metadata_core_modules() as $module) {
+    module_load_include('inc', 'entity', "modules/$module.info");
+    if (function_exists($function = "entity_metadata_{$module}_entity_property_info_alter")) {
+      $function($entity_info);
+    }
+  }
+}
+
+function _entity_metadata_core_modules() {
+  return array_filter(array('book', 'comment', 'field', 'locale', 'node', 'taxonomy', 'user', 'system', 'statistics'), 'module_exists');
+}
+
+/**
+ * Default controller for generating some basic metadata for CRUD entity types.
+ */
+class EntityDefaultMetadataController {
+
+  protected $type, $info;
+
+  public function __construct($type) {
+    $this->type = $type;
+    $this->info = entity_get_info($type);
+  }
+
+  public function entityPropertyInfo() {
+    $entity_label = drupal_strtolower($this->info['label']);
+
+    // Provide defaults based on the schema.
+    $info['properties'] = $this->convertSchema();
+    foreach ($info['properties'] as $name => &$property) {
+      // Add a description.
+      $property['description'] = t('@entity "@property" property.', array('@entity' => drupal_ucfirst($entity_label), '@property' => $name));
+    }
+
+    // Set better metadata for known entity keys.
+    $id_key = $this->info['entity keys']['id'];
+
+    if (!empty($this->info['entity keys']['name']) && $key = $this->info['entity keys']['name']) {
+      $info['properties'][$key]['type'] = 'token';
+      $info['properties'][$key]['label'] = t('Machine-readable name');
+      $info['properties'][$key]['description'] = t('The machine-readable name identifying this @entity.', array('@entity' => $entity_label));
+      $info['properties'][$id_key]['label'] = t('Internal, numeric @entity ID', array('@entity' => $entity_label));
+      $info['properties'][$id_key]['description'] = t('The ID used to identify this @entity internally.', array('@entity' => $entity_label));
+    }
+    else {
+      $info['properties'][$id_key]['label'] = t('@entity ID', array('@entity' => drupal_ucfirst($entity_label)));
+      $info['properties'][$id_key]['description'] = t('The unique ID of the @entity.', array('@entity' => $entity_label));
+    }
+    // Care for the bundle.
+    if (!empty($this->info['entity keys']['bundle']) && $key = $this->info['entity keys']['bundle']) {
+      $info['properties'][$key]['type'] = 'token';
+      $info['properties'][$key]['options list'] = array(get_class($this), 'bundleOptionsList');
+    }
+    // Care for the label.
+    if (!empty($this->info['entity keys']['label']) && $key = $this->info['entity keys']['label']) {
+      $info['properties'][$key]['label'] = t('Label');
+      $info['properties'][$key]['description'] = t('The human readable label.');
+    }
+
+    // Add a computed property for the entity URL and expose it to views.
+    if (empty($info['properties']['url']) && !empty($this->info['uri callback'])) {
+      $info['properties']['url'] = array(
+        'label' => t('URL'),
+        'description' => t('The URL of the entity.'),
+        'getter callback' => 'entity_metadata_entity_get_properties',
+        'type' => 'uri',
+        'computed' => TRUE,
+        'entity views field' => TRUE,
+      );
+    }
+
+    return array($this->type => $info);
+  }
+
+  /**
+   * A options list callback returning all bundles for an entity type.
+   */
+  public static function bundleOptionsList($name, $info) {
+    if (!empty($info['parent']) && $type = $info['parent']) {
+      $entity_info = $info['parent']->entityInfo();
+      $options = array();
+      foreach ($entity_info['bundles'] as $name => $bundle_info) {
+        $options[$name] = $bundle_info['label'];
+      }
+      return $options;
+    }
+  }
+
+  /**
+   * Return a set of properties for an entity based on the schema definition
+   */
+  protected function convertSchema() {
+    return entity_metadata_convert_schema($this->info['base table']);
+  }
+}
+
+/**
+ * Converts the schema information available for the given table to property info.
+ *
+ * @param $table
+ *   The name of the table as used in hook_schema().
+ * @return
+ *   An array of property info as suiting for hook_entity_property_info().
+ */
+function entity_metadata_convert_schema($table) {
+  $schema = drupal_get_schema($table);
+  $properties = array();
+  foreach ($schema['fields'] as $name => $info) {
+    if ($type = _entity_metadata_convert_schema_type($info['type'])) {
+      $properties[$name] = array(
+        'type' => $type,
+        'label' => drupal_ucfirst($name),
+        'schema field' => $name,
+        // As we cannot know about any setter access, leave out the setter
+        // callback. For getting usually no further access callback is needed.
+      );
+      if ($info['type'] == 'serial') {
+        $properties[$name]['validation callback'] = 'entity_metadata_validate_integer_positive';
+      }
+    }
+  }
+  return $properties;
+}
+
+function _entity_metadata_convert_schema_type($type) {
+  switch ($type) {
+    case 'int':
+    case 'serial':
+      return 'integer';
+    case 'float':
+    case 'numeric':
+      return 'decimal';
+    case 'char':
+    case 'varchar':
+    case 'text':
+      return 'text';
+  }
+}
diff --git a/sites/all/modules/entity/entity.install b/sites/all/modules/entity/entity.install
new file mode 100644
index 0000000000000000000000000000000000000000..2a992e9665013817cc83be0299fae53622b2593f
--- /dev/null
+++ b/sites/all/modules/entity/entity.install
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Install file for the entity API.
+ */
+
+/**
+ * The entity API modules have been merged into a single module.
+ */
+function entity_update_7000() {
+  // This empty update is required such that all caches are cleared as
+  // necessary.
+}
+
+/**
+ * Remove the deprecated 'entity_defaults_built' variable.
+ */
+function entity_update_7001() {
+  variable_del('entity_defaults_built');
+}
+
+/**
+ * Clear caches and rebuild registry.
+ */
+function entity_update_7002() {
+  // Do nothing, update.php clears cache for us in case there is an update.
+}
diff --git a/sites/all/modules/entity/entity.module b/sites/all/modules/entity/entity.module
new file mode 100644
index 0000000000000000000000000000000000000000..576e0e2fe3bccf1b687995ed2c7509bd0dee4669
--- /dev/null
+++ b/sites/all/modules/entity/entity.module
@@ -0,0 +1,1315 @@
+<?php
+
+/**
+ * @file
+ * Module file for the entity API.
+ */
+
+module_load_include('inc', 'entity', 'modules/callbacks');
+module_load_include('inc', 'entity', 'includes/entity.property');
+
+
+/**
+ * Defines status codes used for exportable entities.
+ */
+
+/**
+ * A bit flag used to let us know if an entity is in the database.
+ */
+
+
+/**
+ * A bit flag used to let us know if an entity has been customly defined.
+ */
+define('ENTITY_CUSTOM', 0x01);
+
+/**
+ * Deprecated, but still here for backward compatibility.
+ */
+define('ENTITY_IN_DB', 0x01);
+
+/**
+ * A bit flag used to let us know if an entity is a 'default' in code.
+ */
+define('ENTITY_IN_CODE', 0x02);
+
+/**
+ * A bit flag used to mark entities as overridden, e.g. they were originally
+ * definded in code and are saved now in the database. Same as
+ * (ENTITY_CUSTOM | ENTITY_IN_CODE).
+ */
+define('ENTITY_OVERRIDDEN', 0x03);
+
+/**
+ * A bit flag used to mark entities as fixed, thus not changeable for any
+ * user.
+ */
+define('ENTITY_FIXED', 0x04 | 0x02);
+
+
+
+/**
+ * Determines whether for the given entity type a given operation is available.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $op
+ *   One of 'create', 'view', 'save', 'delete', 'access' or 'form'.
+ */
+function entity_type_supports($entity_type, $op) {
+  $info = entity_get_info($entity_type);
+  $keys = array(
+    'view' => 'view callback',
+    'create' => 'creation callback',
+    'delete' => 'deletion callback',
+    'save' => 'save callback',
+    'access' => 'access callback',
+    'form' => 'form callback'
+  );
+  if (isset($info[$keys[$op]])) {
+    return TRUE;
+  }
+  if ($op != 'access' && in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return TRUE;
+  }
+  if ($op == 'form' && entity_ui_controller($entity_type)) {
+    return TRUE;
+  }
+}
+
+/**
+ * Menu loader function: load an entity from its path.
+ *
+ * This can be used to load entities of all types in menu paths:
+ *
+ * @code
+ * $items['myentity/%entity_object'] = array(
+ *   'load arguments' => array('myentity'),
+ *   'title' => ...,
+ *   'page callback' => ...,
+ *   'page arguments' => array(...),
+ *   'access arguments' => array(...),
+ * );
+ * @endcode
+ *
+ * @param $entity_id
+ *   The ID of the entity to load, passed by the menu URL.
+ * @param $entity_type
+ *   The type of the entity to load.
+ * @return
+ *   A fully loaded entity object, or FALSE in case of error.
+ */
+function entity_object_load($entity_id, $entity_type) {
+  $entities = entity_load($entity_type, array($entity_id));
+  return reset($entities);
+}
+
+/**
+ * A wrapper around entity_load() to load a single entity by name or numeric id.
+ *
+ * @todo: Re-name entity_load() to entity_load_multiple() in d8 core and this
+ * to entity_load().
+ *
+ * @param $entity_type
+ *   The entity type to load, e.g. node or user.
+ * @param $id
+ *   The entity id, either the numeric id or the entity name. In case the entity
+ *   type has specified a name key, both the numeric id and the name may be
+ *   passed.
+ *
+ * @return
+ *   The entity object, or FALSE.
+ *
+ * @see entity_load()
+ */
+function entity_load_single($entity_type, $id) {
+  $entities = entity_load($entity_type, array($id));
+  return reset($entities);
+}
+
+/**
+ * A wrapper around entity_load() to return entities keyed by name key if existing.
+ *
+ * @param $entity_type
+ *   The entity type to load, e.g. node or user.
+ * @param $names
+ *   An array of entity names or ids, or FALSE to load all entities.
+ * @param $conditions
+ *   (deprecated) An associative array of conditions on the base table, where
+ *   the keys are the database fields and the values are the values those
+ *   fields must have. Instead, it is preferable to use EntityFieldQuery to
+ *   retrieve a list of entity IDs loadable by this function.
+ *
+ * @return
+ *   An array of entity objects indexed by their names (or ids if the entity
+ *   type has no name key).
+ *
+ * @see entity_load()
+ */
+function entity_load_multiple_by_name($entity_type, $names = FALSE, $conditions = array()) {
+  $entities = entity_load($entity_type, $names, $conditions);
+  $info = entity_get_info($entity_type);
+  if (!isset($info['entity keys']['name'])) {
+    return $entities;
+  }
+  return entity_key_array_by_property($entities, $info['entity keys']['name']);
+}
+
+/**
+ * Permanently save an entity.
+ *
+ * In case of failures, an exception is thrown.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   The entity to save.
+ *
+ * @return
+ *   For entity types provided by the CRUD API, SAVED_NEW or SAVED_UPDATED is
+ *   returned depending on the operation performed. If there is no information
+ *   how to save the entity, FALSE is returned.
+ *
+ * @see entity_type_supports()
+ */
+function entity_save($entity_type, $entity) {
+  $info = entity_get_info($entity_type);
+  if (method_exists($entity, 'save')) {
+    return $entity->save();
+  }
+  elseif (isset($info['save callback'])) {
+    $info['save callback']($entity);
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->save($entity);
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Permanently delete the given entity.
+ *
+ * In case of failures, an exception is thrown.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $id
+ *   The uniform identifier of the entity to delete.
+ *
+ * @return
+ *   FALSE, if there were no information how to delete the entity.
+ *
+ * @see entity_type_supports()
+ */
+function entity_delete($entity_type, $id) {
+  return entity_delete_multiple($entity_type, array($id));
+}
+
+/**
+ * Permanently delete multiple entities.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $ids
+ *   An array of entity ids of the entities to delete. In case the entity makes
+ *   use of a name key, both the names or numeric ids may be passed.
+ * @return
+ *   FALSE if the given entity type isn't compatible to the CRUD API.
+ */
+function entity_delete_multiple($entity_type, $ids) {
+  $info = entity_get_info($entity_type);
+  if (isset($info['deletion callback'])) {
+    foreach ($ids as $id) {
+      $info['deletion callback']($id);
+    }
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    entity_get_controller($entity_type)->delete($ids);
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Create a new entity object.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $values
+ *   An array of values to set, keyed by property name. If the entity type has
+ *   bundles the bundle key has to be specified.
+ * @return
+ *   A new instance of the entity type or FALSE if there is no information for
+ *   the given entity type.
+ *
+ * @see entity_type_supports()
+ */
+function entity_create($entity_type, array $values) {
+  $info = entity_get_info($entity_type);
+  if (isset($info['creation callback'])) {
+    return $info['creation callback']($values, $entity_type);
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->create($values);
+  }
+  return FALSE;
+}
+
+/**
+ * Exports an entity.
+ *
+ * Note: Currently, this only works for entity types provided with the entity
+ * CRUD API.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   The entity to export.
+ * @param $prefix
+ *   An optional prefix for each line.
+ * @return
+ *   The exported entity as serialized string. The format is determined by the
+ *   respective entity controller, e.g. it is JSON for the EntityAPIController.
+ *   The output is suitable for entity_import().
+ */
+function entity_export($entity_type, $entity, $prefix = '') {
+  if (method_exists($entity, 'export')) {
+    return $entity->export($prefix);
+  }
+  $info = entity_get_info($entity_type);
+  if (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->export($entity, $prefix);
+  }
+}
+
+/**
+ * Imports an entity.
+ *
+ * Note: Currently, this only works for entity types provided with the entity
+ * CRUD API.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param string $export
+ *   The string containing the serialized entity as produced by
+ *   entity_export().
+ * @return
+ *   The imported entity object not yet saved.
+ */
+function entity_import($entity_type, $export) {
+  $info = entity_get_info($entity_type);
+  if (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->import($export);
+  }
+}
+
+/**
+ * Checks whether an entity type is fieldable.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ *
+ * @return
+ *   TRUE if the entity type is fieldable, FALSE otherwise.
+ */
+function entity_type_is_fieldable($entity_type) {
+  $info = entity_get_info($entity_type);
+  return !empty($info['fieldable']);
+}
+
+/**
+ * Builds a structured array representing the entity's content.
+ *
+ * The content built for the entity will vary depending on the $view_mode
+ * parameter.
+ *
+ * Note: Currently, this only works for entity types provided with the entity
+ * CRUD API.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   An entity object.
+ * @param $view_mode
+ *   A view mode as used by this entity type, e.g. 'full', 'teaser'...
+ * @param $langcode
+ *   (optional) A language code to use for rendering. Defaults to the global
+ *   content language of the current request.
+ * @return
+ *   The renderable array.
+ */
+function entity_build_content($entity_type, $entity, $view_mode = 'full', $langcode = NULL) {
+  $info = entity_get_info($entity_type);
+  if (method_exists($entity, 'buildContent')) {
+    return $entity->buildContent($view_mode, $langcode);
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->buildContent($entity, $view_mode, $langcode);
+  }
+}
+
+/**
+ * Returns the entity identifier, i.e. the entities name or numeric id.
+ *
+ * Unlike entity_extract_ids() this function returns the name of the entity
+ * instead of the numeric id, in case the entity type has specified a name key.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   An entity object.
+ *
+ * @see entity_extract_ids()
+ */
+function entity_id($entity_type, $entity) {
+  if (method_exists($entity, 'identifier')) {
+    return $entity->identifier();
+  }
+  $info = entity_get_info($entity_type);
+  $key = isset($info['entity keys']['name']) ? $info['entity keys']['name'] : $info['entity keys']['id'];
+  return isset($entity->$key) ? $entity->$key : NULL;
+}
+
+/**
+ * Generate an array for rendering the given entities.
+ *
+ * Entities being viewed, are generally expected to be fully-loaded entity
+ * objects, thus have their name or id key set. However, it is possible to
+ * view a single entity without any id, e.g. for generating a preview during
+ * creation.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entities
+ *   An array of entities to render.
+ * @param $view_mode
+ *   A view mode as used by this entity type, e.g. 'full', 'teaser'...
+ * @param $langcode
+ *   (optional) A language code to use for rendering. Defaults to the global
+ *   content language of the current request.
+ * @param $page
+ *   (optional) If set will control if the entity is rendered: if TRUE
+ *   the entity will be rendered without its title, so that it can be embeded
+ *   in another context. If FALSE the entity will be displayed with its title
+ *   in a mode suitable for lists.
+ *   If unset, the page mode will be enabled if the current path is the URI
+ *   of the entity, as returned by entity_uri().
+ *   This parameter is only supported for entities which controller is a
+ *   EntityAPIControllerInterface.
+ * @return
+ *   The renderable array, keyed by the entity type and by entity identifiers,
+ *   for which the entity name is used if existing - see entity_id(). If there
+ *   is no information on how to view an entity, FALSE is returned.
+ */
+function entity_view($entity_type, $entities, $view_mode = 'full', $langcode = NULL, $page = NULL) {
+  $info = entity_get_info($entity_type);
+  if (isset($info['view callback'])) {
+    $entities = entity_key_array_by_property($entities, $info['entity keys']['id']);
+    return $info['view callback']($entities, $view_mode, $langcode, $entity_type);
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->view($entities, $view_mode, $langcode, $page);
+  }
+  return FALSE;
+}
+
+/**
+ * Determines whether the given user has access to an entity.
+ *
+ * @param $op
+ *   The operation being performed. One of 'view', 'update', 'create' or
+ *   'delete'.
+ * @param $entity_type
+ *   The entity type of the entity to check for.
+ * @param $entity
+ *   Optionally an entity to check access for. If no entity is given, it will be
+ *   determined whether access is allowed for all entities of the given type.
+ * @param $account
+ *   The user to check for. Leave it to NULL to check for the global user.
+ *
+ * @return boolean
+ *   Whether access is allowed or not. If the entity type does not specify any
+ *   access information, NULL is returned.
+ *
+ * @see entity_type_supports()
+ */
+function entity_access($op, $entity_type, $entity = NULL, $account = NULL) {
+  if (($info = entity_get_info()) && isset($info[$entity_type]['access callback'])) {
+    return $info[$entity_type]['access callback']($op, $entity, $account, $entity_type);
+  }
+}
+
+/**
+ * Gets the edit form for any entity.
+ *
+ * This helper makes use of drupal_get_form() and the regular form builder
+ * function of the entity type to retrieve and process the form as usual.
+ *
+ * In order to use this helper to show an entity add form, the new entity object
+ * can be created via entity_create() or entity_property_values_create_entity().
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   The entity to show the edit form for.
+ * @return
+ *   The renderable array of the form. If there is no entity form or missing
+ *   metadata, FALSE is returned.
+ *
+ * @see entity_type_supports()
+ */
+function entity_form($entity_type, $entity) {
+  $info = entity_get_info($entity_type);
+  if (isset($info['form callback'])) {
+    return $info['form callback']($entity, $entity_type);
+  }
+  // If there is an UI controller, the providing module has to implement the
+  // entity form using entity_ui_get_form().
+  elseif (entity_ui_controller($entity_type)) {
+    return entity_metadata_form_entity_ui($entity, $entity_type);
+  }
+  return FALSE;
+}
+
+/**
+ * Converts an array of entities to be keyed by the values of a given property.
+ *
+ * @param array $entities
+ *   The array of entities to convert.
+ * @param $property
+ *   The name of entity property, by which the array should be keyed. To get
+ *   reasonable results, the property has to have unique values.
+ *
+ * @return array
+ *   The same entities in the same order, but keyed by their $property values.
+ */
+function entity_key_array_by_property(array $entities, $property) {
+  $ret = array();
+  foreach ($entities as $entity) {
+    $key = isset($entity->$property) ? $entity->$property : NULL;
+    $ret[$key] = $entity;
+  }
+  return $ret;
+}
+
+/**
+ * Get the entity info for the entity types provided via the entity CRUD API.
+ *
+ * @return
+ *  An array in the same format as entity_get_info(), containing the entities
+ *  whose controller class implements the EntityAPIControllerInterface.
+ */
+function entity_crud_get_info() {
+  $types = array();
+  foreach (entity_get_info() as $type => $info) {
+    if (isset($info['controller class']) && in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+      $types[$type] = $info;
+    }
+  }
+  return $types;
+}
+
+/**
+ * Checks if a given entity has a certain exportable status.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   The entity to check the status on.
+ * @param $status
+ *   The constant status like ENTITY_CUSTOM, ENTITY_IN_CODE, ENTITY_OVERRIDDEN
+ *   or ENTITY_FIXED.
+ *
+ * @return
+ *   TRUE if the entity has the status, FALSE otherwise.
+ */
+function entity_has_status($entity_type, $entity, $status) {
+  $info = entity_get_info($entity_type);
+  $status_key = empty($info['entity keys']['status']) ? 'status' : $info['entity keys']['status'];
+  return isset($entity->{$status_key}) && ($entity->{$status_key} & $status) == $status;
+}
+
+/**
+ * Export a variable. Copied from ctools.
+ *
+ * This is a replacement for var_export(), allowing us to more nicely
+ * format exports. It will recurse down into arrays and will try to
+ * properly export bools when it can.
+ */
+function entity_var_export($var, $prefix = '') {
+  if (is_array($var)) {
+    if (empty($var)) {
+      $output = 'array()';
+    }
+    else {
+      $output = "array(\n";
+      foreach ($var as $key => $value) {
+        $output .= "  '$key' => " . entity_var_export($value, '  ') . ",\n";
+      }
+      $output .= ')';
+    }
+  }
+  elseif (is_bool($var)) {
+    $output = $var ? 'TRUE' : 'FALSE';
+  }
+  else {
+    $output = var_export($var, TRUE);
+  }
+
+  if ($prefix) {
+    $output = str_replace("\n", "\n$prefix", $output);
+  }
+  return $output;
+}
+
+/**
+ * Export a variable in pretty formatted JSON.
+ */
+function entity_var_json_export($var, $prefix = '') {
+  if (is_array($var) && $var) {
+    // Defines whether we use a JSON array or object.
+    $use_array = ($var == array_values($var));
+    $output = $use_array ? "[" : "{";
+
+    foreach ($var as $key => $value) {
+      if ($use_array) {
+        $values[] = entity_var_json_export($value, '  ');
+      }
+      else {
+        $values[] = entity_var_json_export((string) $key, '  ') . ' : ' . entity_var_json_export($value, '  ');
+      }
+    }
+    // Use several lines for long content. However for objects with a single
+    // entry keep the key in the first line.
+    if (strlen($content = implode(', ', $values)) > 70 && ($use_array || count($values) > 1)) {
+      $output .= "\n  " . implode(",\n  ", $values) . "\n";
+    }
+    elseif (strpos($content, "\n") !== FALSE) {
+      $output .= " " . $content . "\n";
+    }
+    else {
+      $output .= " " . $content . ' ';
+    }
+    $output .= $use_array ? ']' : '}';
+  }
+  else {
+    $output = drupal_json_encode($var);
+  }
+
+  if ($prefix) {
+    $output = str_replace("\n", "\n$prefix", $output);
+  }
+  return $output;
+}
+
+/**
+ * Rebuild the default entities provided in code.
+ *
+ * Exportable entities provided in code get saved to the database once a module
+ * providing defaults in code is activated. This allows module and entity_load()
+ * to easily deal with exportable entities just by relying on the database.
+ *
+ * The defaults get rebuilt if the cache is cleared or new modules providing
+ * defaults are enabled, such that the defaults in the database are up to date.
+ * A default entity gets updated with the latest defaults in code during rebuild
+ * as long as the default has not been overridden. Once a module providing
+ * defaults is disabled, its default entities get removed from the database
+ * unless they have been overridden. In that case the overridden entity is left
+ * in the database, but its status gets updated to 'custom'.
+ *
+ * @param $entity_types
+ *   (optional) If specified, only the defaults of the given entity types are
+ *   rebuilt.
+ */
+function entity_defaults_rebuild($entity_types = NULL) {
+  if (!isset($entity_types)) {
+    $entity_types = array();
+    foreach (entity_crud_get_info() as $type => $info) {
+      if (!empty($info['exportable'])) {
+        $entity_types[] = $type;
+      }
+    };
+  }
+  foreach ($entity_types as $type) {
+    _entity_defaults_rebuild($type);
+  }
+}
+
+/**
+ * Actually rebuild the defaults of a given entity type.
+ */
+function _entity_defaults_rebuild($entity_type) {
+  if (lock_acquire('entity_rebuild_' . $entity_type)) {
+    $info = entity_get_info($entity_type);
+    $hook = isset($info['export']['default hook']) ? $info['export']['default hook'] : 'default_' . $entity_type;
+    $keys = $info['entity keys'] + array('module' => 'module', 'status' => 'status', 'name' => $info['entity keys']['id']);
+
+    // Check for the existence of the module and status columns.
+    if (!in_array($keys['status'], $info['schema_fields_sql']['base table']) || !in_array($keys['module'], $info['schema_fields_sql']['base table'])) {
+      trigger_error("Missing database columns for the exportable entity $entity_type as defined by entity_exportable_schema_fields(). Update the according module and run update.php!", E_USER_WARNING);
+      return;
+    }
+
+    // Invoke the hook and collect default entities.
+    $entities = array();
+    foreach (module_implements($hook) as $module) {
+      foreach ((array) module_invoke($module, $hook) as $name => $entity) {
+        $entity->{$keys['name']} = $name;
+        $entity->{$keys['module']} = $module;
+        $entities[$name] = $entity;
+      }
+    }
+    drupal_alter($hook, $entities);
+
+    // Check for defaults that disappeared.
+    $existing_defaults = entity_load_multiple_by_name($entity_type, FALSE, array($keys['status'] => array(ENTITY_OVERRIDDEN, ENTITY_IN_CODE, ENTITY_FIXED)));
+
+    foreach ($existing_defaults as $name => $entity) {
+      if (empty($entities[$name])) {
+        $entity->is_rebuild = TRUE;
+        if (entity_has_status($entity_type, $entity, ENTITY_OVERRIDDEN)) {
+          $entity->{$keys['status']} = ENTITY_CUSTOM;
+          entity_save($entity_type, $entity);
+        }
+        else {
+          entity_delete($entity_type, $name);
+        }
+        unset($entity->is_rebuild);
+      }
+    }
+
+    // Load all existing entities.
+    $existing_entities = entity_load_multiple_by_name($entity_type, array_keys($entities));
+
+    foreach ($existing_entities as $name => $entity) {
+      if (entity_has_status($entity_type, $entity, ENTITY_CUSTOM)) {
+        // If the entity already exists but is not yet marked as overridden, we
+        // have to update the status.
+        if (!entity_has_status($entity_type, $entity, ENTITY_OVERRIDDEN)) {
+          $entity->{$keys['status']} |= ENTITY_OVERRIDDEN;
+          $entity->{$keys['module']} = $entities[$name]->{$keys['module']};
+          $entity->is_rebuild = TRUE;
+          entity_save($entity_type, $entity);
+          unset($entity->is_rebuild);
+        }
+
+        // The entity is overridden, so we do not need to save the default.
+        unset($entities[$name]);
+      }
+    }
+
+    // Save defaults.
+    $originals = array();
+    foreach ($entities as $name => $entity) {
+      if (!empty($existing_entities[$name])) {
+        // Make sure we are updating the existing default.
+        $entity->{$keys['id']} = $existing_entities[$name]->{$keys['id']};
+        unset($entity->is_new);
+      }
+      // Pre-populate $entity->original as we already have it. So we avoid
+      // loading it again.
+      $entity->original = !empty($existing_entities[$name]) ? $existing_entities[$name] : FALSE;
+      // Keep original entities for hook_{entity_type}_defaults_rebuild()
+      // implementations.
+      $originals[$name] = $entity->original;
+
+      $entity->{$keys['status']} |= ENTITY_IN_CODE;
+      $entity->is_rebuild = TRUE;
+      entity_save($entity_type, $entity);
+      unset($entity->is_rebuild);
+    }
+
+    // Invoke an entity type-specific hook so modules may apply changes, e.g.
+    // efficiently rebuild caches.
+    module_invoke_all($entity_type . '_defaults_rebuild', $entities, $originals);
+
+    lock_release('entity_rebuild_' . $entity_type);
+  }
+}
+
+/**
+ * Implements hook_modules_enabled().
+ */
+function entity_modules_enabled($modules) {
+  foreach (_entity_modules_get_default_types($modules) as $type) {
+    _entity_defaults_rebuild($type);
+  }
+}
+
+/**
+ * Implements hook_modules_disabled().
+ */
+function entity_modules_disabled($modules) {
+  foreach (_entity_modules_get_default_types($modules) as $entity_type) {
+    $info = entity_get_info($entity_type);
+
+    // Do nothing if the module providing the entity type has been disabled too.
+    if (isset($info['module']) && in_array($info['module'], $modules)) {
+      return;
+    }
+
+    $keys = $info['entity keys'] + array('module' => 'module', 'status' => 'status', 'name' => $info['entity keys']['id']);
+    // Remove entities provided in code by one of the disabled modules.
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $entity_type, '=')
+          ->propertyCondition($keys['module'], $modules, 'IN')
+          ->propertyCondition($keys['status'], array(ENTITY_IN_CODE, ENTITY_FIXED), 'IN');
+    $result = $query->execute();
+    if (isset($result[$entity_type])) {
+      $entities = entity_load($entity_type, array_keys($result[$entity_type]));
+      entity_delete_multiple($entity_type, array_keys($entities));
+    }
+
+    // Update overridden entities to be now custom.
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $entity_type, '=')
+          ->propertyCondition($keys['module'], $modules, 'IN')
+          ->propertyCondition($keys['status'], ENTITY_OVERRIDDEN, '=');
+    $result = $query->execute();
+    if (isset($result[$entity_type])) {
+      foreach (entity_load($entity_type, array_keys($result[$entity_type])) as $name => $entity) {
+        $entity->{$keys['status']} = ENTITY_CUSTOM;
+        $entity->{$keys['module']} = NULL;
+        entity_save($entity_type, $entity);
+      }
+    }
+
+    // Rebuild the remaining defaults so any alterations of the disabled modules
+    // are gone.
+    _entity_defaults_rebuild($entity_type);
+  }
+}
+
+/**
+ * Gets all entity types for which defaults are provided by the $modules.
+ */
+function _entity_modules_get_default_types($modules) {
+  $types = array();
+  foreach (entity_crud_get_info() as $entity_type => $info) {
+    if (!empty($info['exportable'])) {
+      $hook = isset($info['export']['default hook']) ? $info['export']['default hook'] : 'default_' . $entity_type;
+      foreach ($modules as $module) {
+        if (module_hook($module, $hook) || module_hook($module, $hook . '_alter')) {
+          $types[] = $entity_type;
+        }
+      }
+    }
+  }
+  return $types;
+}
+
+/**
+ * Defines schema fields required for exportable entities.
+ *
+ * Warning: Do not call this function in your module's hook_schema()
+ * implementation or update functions. It is not safe to call functions of
+ * dependencies at this point. Instead of calling the function, just copy over
+ * the content.
+ * For more details see the issue http://drupal.org/node/1122812.
+ */
+function entity_exportable_schema_fields($module_col = 'module', $status_col = 'status') {
+  return array(
+    $status_col => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      // Set the default to ENTITY_CUSTOM without using the constant as it is
+      // not safe to use it at this point.
+      'default' => 0x01,
+      'size' => 'tiny',
+      'description' => 'The exportable status of the entity.',
+    ),
+    $module_col => array(
+      'description' => 'The name of the providing module if the entity has been defined in code.',
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => FALSE,
+    ),
+  );
+}
+
+/**
+ * Implements hook_flush_caches().
+ */
+function entity_flush_caches() {
+  entity_property_info_cache_clear();
+  // Re-build defaults in code, however skip it on the admin modules page. In
+  // case of enabling or disabling modules we already rebuild defaults in
+  // entity_modules_enabled() and entity_modules_disabled(), so we do not need
+  // to do it again.
+  if (current_path() != 'admin/modules/list/confirm') {
+    entity_defaults_rebuild();
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function entity_theme() {
+  return array(
+    'entity_status' => array(
+      'variables' => array('status' => NULL, 'html' => TRUE),
+    ),
+    'entity' => array(
+      'render element' => 'elements',
+      'template' => 'entity',
+    ),
+    'entity_ui_overview_item' => array(
+      'variables' => array('label' => NULL, 'entity_type' => NULL, 'url' => FALSE, 'name' => FALSE),
+      'file' => 'includes/entity.ui.inc'
+    ),
+  );
+}
+
+/**
+ * Themes the exportable status of an entity.
+ */
+function theme_entity_status($variables) {
+  $status = $variables['status'];
+  $html = $variables['html'];
+  if (($status & ENTITY_FIXED) == ENTITY_FIXED) {
+    $label = t('Fixed');
+    $help = t('The configuration is fixed and cannot be changed.');
+    return $html ? "<span class='entity-status-fixed' title='$help'>" . $label . "</span>" : $label;
+  }
+  elseif (($status & ENTITY_OVERRIDDEN) == ENTITY_OVERRIDDEN) {
+    $label = t('Overridden');
+    $help = t('This configuration is provided by a module, but has been changed.');
+    return $html ? "<span class='entity-status-overridden' title='$help'>" . $label . "</span>" : $label;
+  }
+  elseif ($status & ENTITY_IN_CODE) {
+    $label = t('Default');
+    $help = t('A module provides this configuration.');
+    return $html ? "<span class='entity-status-default' title='$help'>" . $label . "</span>" : $label;
+  }
+  elseif ($status & ENTITY_CUSTOM) {
+    $label = t('Custom');
+    $help = t('A custom configuration by a user.');
+    return $html ? "<span class='entity-status-custom' title='$help'>" . $label . "</span>" : $label;
+  }
+}
+
+/**
+ * Process variables for entity.tpl.php.
+ */
+function template_preprocess_entity(&$variables) {
+  $variables['view_mode'] = $variables['elements']['#view_mode'];
+  $entity_type = $variables['elements']['#entity_type'];
+  $variables['entity_type'] = $entity_type;
+  $entity = $variables['elements']['#entity'];
+  $variables[$variables['elements']['#entity_type']] = $entity;
+  $info = entity_get_info($entity_type);
+
+  $variables['title'] = check_plain(entity_label($entity_type, $entity));
+  if (isset($variables['elements']['#page'])) {
+    // If set by the caller, respect the page property.
+    $variables['page'] = $variables['elements']['#page'];
+  }
+  else {
+    // Else, try to automatically detect it.
+    $uri = entity_uri($entity_type, $entity);
+    $variables['url'] = $uri ? url($uri['path'], $uri['options']) : FALSE;
+    $variables['page'] = $uri && $uri['path'] == $_GET['q'];
+  }
+
+  // Helpful $content variable for templates.
+  $variables['content'] = array();
+  foreach (element_children($variables['elements']) as $key) {
+    $variables['content'][$key] = $variables['elements'][$key];
+  }
+
+  if (!empty($info['fieldable'])) {
+    // Make the field variables available with the appropriate language.
+    field_attach_preprocess($entity_type, $entity, $variables['content'], $variables);
+  }
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+
+  // Gather css classes.
+  $variables['classes_array'][] = drupal_html_class('entity-' . $entity_type);
+  $variables['classes_array'][] = drupal_html_class($entity_type . '-' . $bundle);
+
+  // Add RDF type and about URI.
+  if (module_exists('rdf')) {
+    $variables['attributes_array']['about'] = empty($uri['path']) ? NULL: url($uri['path']);
+    $variables['attributes_array']['typeof'] = empty($entity->rdf_mapping['rdftype']) ? NULL : $entity->rdf_mapping['rdftype'];
+  }
+
+  // Add suggestions.
+  $variables['theme_hook_suggestions'][] = $entity_type;
+  $variables['theme_hook_suggestions'][] = $entity_type . '__' . $bundle;
+  $variables['theme_hook_suggestions'][] = $entity_type . '__' . $bundle . '__' . $variables['view_mode'];
+  if ($id = entity_id($entity_type, $entity)) {
+    $variables['theme_hook_suggestions'][] = $entity_type . '__' . $id;
+  }
+}
+
+/**
+ * Label callback that refers to the entity classes label method.
+ */
+function entity_class_label($entity) {
+  return $entity->label();
+}
+
+/**
+ * URI callback that refers to the entity classes uri method.
+ */
+function entity_class_uri($entity) {
+  return $entity->uri();
+}
+
+/**
+ * Implements hook_file_download_access() for entity types provided by the CRUD API.
+ */
+function entity_file_download_access($field, $entity_type, $entity) {
+  $info = entity_get_info($entity_type);
+  if (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_access('view', $entity_type, $entity);
+  }
+}
+
+/**
+ * Determines the UI controller class for a given entity type.
+ *
+ * @return EntityDefaultUIController
+ *   If a type is given, the controller for the given entity type. Else an array
+ *   of all enabled UI controllers keyed by entity type is returned.
+ */
+function entity_ui_controller($type = NULL) {
+  $static = &drupal_static(__FUNCTION__);
+
+  if (!isset($type)) {
+    // Invoke the function for each type to ensure we have fully populated the
+    // static variable.
+    foreach (entity_get_info() as $entity_type => $info) {
+      entity_ui_controller($entity_type);
+    }
+    return array_filter($static);
+  }
+
+  if (!isset($static[$type])) {
+    $info = entity_get_info($type);
+    $class = isset($info['admin ui']['controller class']) ? $info['admin ui']['controller class'] : 'EntityDefaultUIController';
+    $static[$type] = (isset($info['admin ui']['path']) && $class) ? new $class($type, $info) : FALSE;
+  }
+
+  return $static[$type];
+}
+
+/**
+ * Implements hook_menu().
+ *
+ * @see EntityDefaultUIController::hook_menu()
+ */
+function entity_menu() {
+  $items = array();
+  foreach (entity_ui_controller() as $controller) {
+    $items += $controller->hook_menu();
+  }
+  return $items;
+}
+
+/**
+ * Implements hook_forms().
+ *
+ * @see EntityDefaultUIController::hook_forms()
+ * @see entity_ui_get_form()
+ */
+function entity_forms($form_id, $args) {
+  // For efficiency only invoke an entity types controller, if a form of it is
+  // requested. Thus if the first (overview and operation form) or the third
+  // argument (edit form) is an entity type name, add in the types forms.
+  if (isset($args[0]) && is_string($args[0]) && entity_get_info($args[0])) {
+    $type = $args[0];
+  }
+  elseif (isset($args[2]) && is_string($args[2]) && entity_get_info($args[2])) {
+    $type = $args[2];
+  }
+  if (isset($type) && $controller = entity_ui_controller($type)) {
+    return $controller->hook_forms();
+  }
+}
+
+/**
+ * A wrapper around drupal_get_form() that helps building entity forms.
+ *
+ * This function may be used by entities to build their entity form. It has to
+ * be used instead of calling drupal_get_form().
+ * Entity forms built with this helper receive useful defaults suiting for
+ * editing a single entity, whereas the special cases of adding and cloning
+ * of entities are supported too.
+ *
+ * While this function is intended to be used to get entity forms for entities
+ * using the entity ui controller, it may be used for entity types not using
+ * the ui controller too.
+ *
+ * @param $entity_type
+ *   The entity type for which to get the form.
+ * @param $entity
+ *   The entity for which to return the form.
+ *   If $op is 'add' the entity has to be either initialized before calling this
+ *   function, or NULL may be passed. If NULL is passed, an entity will be
+ *   initialized with empty values using entity_create(). Thus entities, for
+ *   which this is problematic have to care to pass in an initialized entity.
+ * @param $op
+ *   (optional) One of 'edit', 'add' or 'clone'. Defaults to edit.
+ * @param $form_state
+ *   (optional) A pre-populated form state, e.g. to add in form include files.
+ *   See entity_metadata_form_entity_ui().
+ *
+ * @return
+ *   The fully built and processed form, ready to be rendered.
+ *
+ * @see EntityDefaultUIController::hook_forms()
+ * @see entity_ui_form_submit_build_entity()
+ */
+function entity_ui_get_form($entity_type, $entity, $op = 'edit', $form_state = array()) {
+  if (isset($entity)) {
+    list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  }
+  $form_id = (!isset($bundle) || $bundle == $entity_type) ? $entity_type . '_form' : $entity_type . '_edit_' . $bundle . '_form';
+
+  if (!isset($entity) && $op == 'add') {
+    $entity = entity_create($entity_type, array());
+  }
+
+  // Do not use drupal_get_form(), but invoke drupal_build_form() ourself so
+  // we can prepulate the form state.
+  $form_state['wrapper_callback'] = 'entity_ui_main_form_defaults';
+  $form_state['entity_type'] = $entity_type;
+  form_load_include($form_state, 'inc', 'entity', 'includes/entity.ui');
+
+  // Handle cloning. We cannot do that in the wrapper callback as it is too late
+  // for changing arguments.
+  if ($op == 'clone') {
+    $entity = entity_ui_clone_entity($entity_type, $entity);
+  }
+
+  // We don't pass the entity type as first parameter, as the implementing
+  // module knows the type anyway. However, in order to allow for efficient
+  // hook_forms() implementiations we append the entity type as last argument,
+  // which the module implementing the form constructor may safely ignore.
+  // @see entity_forms()
+  $form_state['build_info']['args'] = array($entity, $op, $entity_type);
+  return drupal_build_form($form_id, $form_state);
+}
+
+/**
+ * Helper for using i18n_string().
+ *
+ * @param $name
+ *   Textgroup and context glued with ':'.
+ * @param $default
+ *   String in default language. Default language may or may not be English.
+ * @param $langcode
+ *   (optional) The code of a certain language to translate the string into.
+ *   Defaults to the i18n_string() default, i.e. the current language.
+ *
+ * @see i18n_string()
+ */
+function entity_i18n_string($name, $default, $langcode = NULL) {
+  return function_exists('i18n_string') ? i18n_string($name, $default, array('langcode' => $langcode)) : $default;
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function entity_views_api() {
+  return array(
+    'api' => '3.0-alpha1',
+    'path' => drupal_get_path('module', 'entity') . '/views',
+  );
+}
+
+/**
+ * Returns a property wrapper for the given data.
+ *
+ * If an entity is wrapped, the wrapper can be used to retrieve further wrappers
+ * for the entitity properties. For that the wrapper support chaining, e.g. you
+ * can use a node wrapper to get the node authors mail address:
+ *
+ * @code
+ *   echo $wrappedNode->author->mail->value();
+ * @endcode
+ *
+ * @param $type
+ *   The type of the passed data.
+ * @param $data
+ *   The data to wrap. It may be set to NULL, so the wrapper can be used
+ *   without any data for getting information about properties.
+ * @param $info
+ *   (optional) Specify additional information for the passed data:
+ *    - langcode: (optional) If the data is language specific, its langauge
+ *      code. Defaults to NULL, what means language neutral.
+ *    - bundle: (optional) If an entity is wrapped but not passed, use this key
+ *      to specify the bundle to return a wrapper for.
+ *    - property info: (optional) May be used to use a wrapper with an arbitrary
+ *      data structure (type 'struct'). Use this key for specifying info about
+ *      properties in the same structure as used by hook_entity_property_info().
+ *    - property info alter: (optional) A callback for altering the property
+ *      info before it is utilized by the wrapper.
+ *    - property defaults: (optional) An array of defaults for the info of
+ *      each property of the wrapped data item.
+ * @return EntityMetadataWrapper
+ *   Dependend on the passed data the right wrapper is returned.
+ */
+function entity_metadata_wrapper($type, $data = NULL, array $info = array()) {
+  if ($type == 'entity' || (($entity_info = entity_get_info()) && isset($entity_info[$type]))) {
+    // If the passed entity is the global $user, we load the user object by only
+    // passing on the user id. The global user is not a fully loaded entity.
+    if ($type == 'user' && is_object($data) && $data == $GLOBALS['user']) {
+      $data = $data->uid;
+    }
+    return new EntityDrupalWrapper($type, $data, $info);
+  }
+  elseif ($type == 'list' || entity_property_list_extract_type($type)) {
+    return new EntityListWrapper($type, $data, $info);
+  }
+  elseif (isset($info['property info'])) {
+    return new EntityStructureWrapper($type, $data, $info);
+  }
+  else {
+    return new EntityValueWrapper($type, $data, $info);
+  }
+}
+
+/**
+ * Returns a metadata wrapper for accessing site-wide properties.
+ *
+ * Although there is no 'site' entity or such, modules may provide info about
+ * site-wide properties using hook_entity_property_info(). This function returns
+ * a wrapper for making use of this properties.
+ *
+ * @return EntityMetadataWrapper
+ *   A wrapper for accessing site-wide properties.
+ *
+ * @see entity_metadata_system_entity_property_info()
+ */
+function entity_metadata_site_wrapper() {
+  $site_info = entity_get_property_info('site');
+  $info['property info'] = $site_info['properties'];
+  return entity_metadata_wrapper('site', FALSE, $info);
+}
+
+/**
+ * Implements hook_module_implements_alter().
+ *
+ * Moves the hook_entity_info_alter() implementation to the bottom so it is
+ * invoked after all modules relying on the entity API.
+ * That way we ensure to run last and clear the field-info cache after the
+ * others added in their bundle information.
+ *
+ * @see entity_entity_info_alter()
+ */
+function entity_module_implements_alter(&$implementations, $hook) {
+  if ($hook == 'entity_info_alter') {
+    // Move our hook implementation to the bottom.
+    $group = $implementations['entity'];
+    unset($implementations['entity']);
+    $implementations['entity'] = $group;
+  }
+}
+
+/**
+ * Implements hook_entity_info_alter().
+ *
+ * @see entity_module_implements_alter()
+ */
+function entity_entity_info_alter(&$entity_info) {
+  _entity_info_add_metadata($entity_info);
+
+  // Modules are using entity_load() in hook_entity_info_alter() to add
+  // their bundle-info. This might trigger the field API cache to be built,
+  // which makes use of the bundle-info. In that case the field-info cache would
+  // have been built with in-complete bundle-info, thus we clear it so it is
+  // rebuilt with complete bundle-info the next time field-info is requested.
+  _field_info_collate_fields(TRUE);
+  // To be sure, also clear the property info cache as it depends on field info.
+  entity_property_info_cache_clear();
+
+  // Populate a default value for the 'configuration' key of all entity types.
+  foreach ($entity_info as $type => $info) {
+    if (!isset($info['configuration'])) {
+      $entity_info[$type]['configuration'] = !empty($info['exportable']);
+    }
+  }
+}
+
+/**
+ * Adds metadata and callbacks for core entities to the entity info.
+ */
+function _entity_info_add_metadata(&$entity_info) {
+  // Set plural labels.
+  $entity_info['node']['plural label'] = t('Nodes');
+  $entity_info['user']['plural label'] = t('Users');
+  $entity_info['file']['plural label'] = t('Files');
+
+  // Set descriptions.
+  $entity_info['node']['description'] = t('Nodes represent the main site content items.');
+  $entity_info['user']['description'] = t('Users who have created accounts on your site.');
+  $entity_info['file']['description'] = t('Uploaded file.');
+
+  // Set access callbacks.
+  $entity_info['node']['access callback'] = 'entity_metadata_no_hook_node_access';
+  $entity_info['user']['access callback'] = 'entity_metadata_user_access';
+
+  // CRUD function callbacks.
+  $entity_info['node']['creation callback'] = 'entity_metadata_create_node';
+  $entity_info['node']['save callback'] = 'node_save';
+  $entity_info['node']['deletion callback'] = 'node_delete';
+  $entity_info['user']['creation callback'] = 'entity_metadata_create_object';
+  $entity_info['user']['save callback'] = 'entity_metadata_user_save';
+  $entity_info['user']['deletion callback'] = 'user_delete';
+  $entity_info['file']['save callback'] = 'file_save';
+  $entity_info['file']['deletion callback'] = 'entity_metadata_delete_file';
+
+  // Form callbacks.
+  $entity_info['node']['form callback'] = 'entity_metadata_form_node';
+  $entity_info['user']['form callback'] = 'entity_metadata_form_user';
+
+  // View callbacks.
+  $entity_info['node']['view callback'] = 'entity_metadata_view_node';
+  $entity_info['user']['view callback'] = 'entity_metadata_view_single';
+
+  if (module_exists('comment')) {
+    $entity_info['comment']['plural label'] = t('Comments');
+    $entity_info['comment']['description'] = t('Remark or note that refers to a node.');
+    $entity_info['comment']['access callback'] = 'entity_metadata_comment_access';
+    $entity_info['comment']['creation callback'] = 'entity_metadata_create_comment';
+    $entity_info['comment']['save callback'] = 'comment_save';
+    $entity_info['comment']['deletion callback'] = 'comment_delete';
+    $entity_info['comment']['view callback'] = 'entity_metadata_view_comment';
+    $entity_info['comment']['form callback'] = 'entity_metadata_form_comment';
+  }
+  if (module_exists('taxonomy')) {
+    $entity_info['taxonomy_term']['plural label'] = t('Taxonomy terms');
+    $entity_info['taxonomy_term']['description'] = t('Taxonomy terms are used for classifying content.');
+    $entity_info['taxonomy_term']['access callback'] = 'entity_metadata_taxonomy_access';
+    $entity_info['taxonomy_term']['creation callback'] = 'entity_metadata_create_object';
+    $entity_info['taxonomy_term']['save callback'] = 'taxonomy_term_save';
+    $entity_info['taxonomy_term']['deletion callback'] = 'taxonomy_term_delete';
+    $entity_info['taxonomy_term']['view callback'] = 'entity_metadata_view_single';
+    $entity_info['taxonomy_term']['form callback'] = 'entity_metadata_form_taxonomy_term';
+
+    $entity_info['taxonomy_vocabulary']['plural label'] = t('Taxonomy vocabularies');
+    $entity_info['taxonomy_vocabulary']['description'] = t('Vocabularies contain related taxonomy terms, which are used for classifying content.');
+    $entity_info['taxonomy_vocabulary']['access callback'] = 'entity_metadata_taxonomy_access';
+    $entity_info['taxonomy_vocabulary']['creation callback'] = 'entity_metadata_create_object';
+    $entity_info['taxonomy_vocabulary']['save callback'] = 'taxonomy_vocabulary_save';
+    $entity_info['taxonomy_vocabulary']['deletion callback'] = 'taxonomy_vocabulary_delete';
+    $entity_info['taxonomy_vocabulary']['form callback'] = 'entity_metadata_form_taxonomy_vocabulary';
+    // Token type mapping.
+    $entity_info['taxonomy_term']['token type'] = 'term';
+    $entity_info['taxonomy_vocabulary']['token type'] = 'vocabulary';
+  }
+}
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function entity_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'ctools' && $plugin == 'content_types') {
+    return 'ctools/content_types';
+  }
+}
diff --git a/sites/all/modules/entity/entity.rules.inc b/sites/all/modules/entity/entity.rules.inc
new file mode 100644
index 0000000000000000000000000000000000000000..c3ec8dc87220874cf3c9a26a58b693567c788f58
--- /dev/null
+++ b/sites/all/modules/entity/entity.rules.inc
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * @file
+ * Provides Rules integration for entities provided via the CRUD API.
+ *
+ * Rules automatically provides us with actions for CRUD and a suiting entity
+ * data type. For events the controller automatically invokes Rules events once
+ * Rules is active, so we just have to provide the appropriate info.
+ */
+
+/**
+ * Default controller for generating Rules integration.
+ */
+class EntityDefaultRulesController {
+
+  protected $type, $info;
+
+  public function __construct($type) {
+    $this->type = $type;
+    $this->info = entity_get_info($type);
+  }
+
+  public function eventInfo() {
+    $info = $this->info;
+    $type = $this->type;
+
+    $label = $info['label'];
+    $defaults = array(
+      'module' => isset($info['module']) ? $info['module'] : 'entity',
+      'group' => $label,
+      'access callback' => 'entity_rules_integration_event_access',
+    );
+
+    $items[$type . '_insert'] = $defaults + array(
+      'label' => t('After saving a new @entity', array('@entity' => drupal_strtolower($label))),
+      'variables' => entity_rules_events_variables($type, t('created @entity', array('@entity' => drupal_strtolower($label)))),
+    );
+    $items[$type . '_update'] = $defaults + array(
+      'label' => t('After updating an existing @entity', array('@entity' => drupal_strtolower($label))),
+      'variables' => entity_rules_events_variables($type, t('updated @entity', array('@entity' => drupal_strtolower($label))), TRUE),
+    );
+    $items[$type . '_presave'] = $defaults + array(
+      'label' => t('Before saving a @entity', array('@entity' => drupal_strtolower($label))),
+      'variables' => entity_rules_events_variables($type, t('saved @entity', array('@entity' => drupal_strtolower($label))), TRUE),
+    );
+    $items[$type . '_delete'] = $defaults + array(
+      'label' => t('After deleting a @entity', array('@entity' => drupal_strtolower($label))),
+      'variables' => entity_rules_events_variables($type, t('deleted @entity', array('@entity' => drupal_strtolower($label)))),
+    );
+    if (count($info['view modes'])) {
+      $items[$type . '_view'] = $defaults + array(
+        'label' => t('@entity is viewed', array('@entity' => $label)),
+        'variables' => entity_rules_events_variables($type, t('viewed @entity', array('@entity' => drupal_strtolower($label)))) + array(
+          'view_mode' => array(
+            'type' => 'text',
+            'label' => t('view mode'),
+            'options list' => 'rules_get_entity_view_modes',
+             // Add the entity-type for the options list callback.
+            'options list entity type' => $type,
+          ),
+        ),
+      );
+    }
+    // Specify that on presave the entity is saved anyway.
+    $items[$type . '_presave']['variables'][$type]['skip save'] = TRUE;
+    return $items;
+  }
+
+}
+
+/**
+ * Returns some parameter info suiting for the specified entity type.
+ */
+function entity_rules_events_variables($type, $label, $update = FALSE) {
+  $args = array(
+    $type => array('type' => $type, 'label' => $label),
+  );
+  if ($update) {
+    $args += array(
+      $type . '_unchanged' => array(
+        'type' => $type,
+        'label' => t('unchanged entity'),
+        'handler' => 'rules_events_entity_unchanged',
+      ),
+    );
+  }
+  return $args;
+}
+
+/**
+ * Implements hook_rules_event_info().
+ */
+function entity_rules_event_info() {
+  $items = array();
+  foreach (entity_crud_get_info() as $type => $info) {
+    // By default we enable the controller only for non-configuration.
+    $configuration = !empty($info['configuration']) || !empty($info['exportable']);
+    $info += array('rules controller class' => $configuration ? FALSE : 'EntityDefaultRulesController');
+    if ($info['rules controller class']) {
+      $controller = new $info['rules controller class']($type);
+      $items += $controller->eventInfo();
+    }
+  }
+  return $items;
+}
+
+/**
+ * Rules integration access callback.
+ */
+function entity_rules_integration_event_access($type, $event_name) {
+  // Cut of _insert/_update/.. from the event name.
+  $entity_type = substr($event_name, 0, strrpos($event_name, '_'));
+
+  $result = entity_access('view', $entity_type);
+  // If no access callback is given, just grant access for viewing.
+  return isset($result) ? $result : TRUE;
+}
diff --git a/sites/all/modules/entity/entity.test b/sites/all/modules/entity/entity.test
new file mode 100644
index 0000000000000000000000000000000000000000..aaebc619bbda99934354b8d2b99b54e5c5647499
--- /dev/null
+++ b/sites/all/modules/entity/entity.test
@@ -0,0 +1,1514 @@
+<?php
+
+/**
+ * @file
+ * Entity CRUD API tests.
+ */
+
+/**
+ * Common parent class containing common helpers.
+ */
+abstract class EntityWebTestCase extends DrupalWebTestCase {
+
+  /**
+   * Creates a new vocabulary.
+   */
+  protected function createVocabulary() {
+    $vocab = entity_create('taxonomy_vocabulary', array(
+      'name' => $this->randomName(),
+      'machine_name' => drupal_strtolower($this->randomName()),
+      'description' => $this->randomName(),
+    ));
+    entity_save('taxonomy_vocabulary', $vocab);
+    return $vocab;
+  }
+
+  /**
+   * Creates a random file of the given type.
+   */
+  protected function createFile($file_type = 'text') {
+    // Create a managed file.
+    $file = current($this->drupalGetTestFiles($file_type));
+
+    // Set additional file properties and save it.
+    $file->filemime = file_get_mimetype($file->filename);
+    $file->uid = 1;
+    $file->timestamp = REQUEST_TIME;
+    $file->filesize = filesize($file->uri);
+    $file->status = 0;
+    file_save($file);
+    return $file;
+  }
+}
+
+/**
+ * Test basic API.
+ */
+class EntityAPITestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity CRUD',
+      'description' => 'Tests basic CRUD API functionality.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity', 'entity_test');
+  }
+
+  /**
+   * Tests CRUD.
+   */
+  function testCRUD() {
+    module_enable(array('entity_feature'));
+
+    $user1 = $this->drupalCreateUser();
+    // Create test entities for the user1 and unrelated to a user.
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
+    $entity->save();
+    $entity = entity_create('entity_test', array('name' => 'test2', 'uid' => $user1->uid));
+    $entity->save();
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => NULL));
+    $entity->save();
+
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test')));
+
+    $this->assertEqual($entities[0]->name, 'test', 'Created and loaded entity.');
+    $this->assertEqual($entities[1]->name, 'test', 'Created and loaded entity.');
+
+    $results = entity_test_load_multiple(array($entity->pid));
+    $loaded = array_pop($results);
+    $this->assertEqual($loaded->pid, $entity->pid, 'Loaded the entity unrelated to a user.');
+
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
+    $entities[0]->delete();
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
+    $this->assertEqual($entities, array(), 'Entity successfully deleted.');
+
+    $entity->save();
+    $this->assertEqual($entity->pid, $loaded->pid, 'Entity successfully updated.');
+
+    // Try deleting multiple test entities by deleting all.
+    $pids = array_keys(entity_test_load_multiple(FALSE));
+    entity_test_delete_multiple($pids);
+  }
+
+  /**
+   * Tests CRUD API functions: entity_(create|delete|save)
+   */
+  function testCRUDAPIfunctions() {
+    module_enable(array('entity_feature'));
+
+    $user1 = $this->drupalCreateUser();
+    // Create test entities for the user1 and unrelated to a user.
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
+    entity_save('entity_test', $entity);
+    $entity = entity_create('entity_test', array('name' => 'test2', 'uid' => $user1->uid));
+    entity_save('entity_test', $entity);
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => NULL));
+    entity_save('entity_test', $entity);
+
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test')));
+    $this->assertEqual($entities[0]->name, 'test', 'Created and loaded entity.');
+    $this->assertEqual($entities[1]->name, 'test', 'Created and loaded entity.');
+
+    // Test getting the entity label, which is the used test-type's label.
+    $label = entity_label('entity_test', $entities[0]);
+    $this->assertEqual($label, 'label', 'Default label returned.');
+
+    $results = entity_test_load_multiple(array($entity->pid));
+    $loaded = array_pop($results);
+    $this->assertEqual($loaded->pid, $entity->pid, 'Loaded the entity unrelated to a user.');
+
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
+
+    entity_delete('entity_test', $entities[0]->pid);
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
+    $this->assertEqual($entities, array(), 'Entity successfully deleted.');
+
+    entity_save('entity_test', $entity);
+    $this->assertEqual($entity->pid, $loaded->pid, 'Entity successfully updated.');
+
+    // Try deleting multiple test entities by deleting all.
+    $pids = array_keys(entity_test_load_multiple(FALSE));
+    entity_delete_multiple('entity_test', $pids);
+  }
+
+  /**
+   * Test loading entities defined in code.
+   */
+  function testExportables() {
+    module_enable(array('entity_feature'));
+
+    $types = entity_load_multiple_by_name('entity_test_type', array('test2', 'test'));
+
+    $this->assertEqual(array_keys($types), array('test2', 'test'), 'Entities have been loaded in the order as specified.');
+    $this->assertEqual($types['test']->label, 'label', 'Default type loaded.');
+    $this->assertTrue($types['test']->status & ENTITY_IN_CODE && !($types['test']->status & ENTITY_CUSTOM), 'Default type status is correct.');
+
+    // Test using a condition, which has to be applied on the defaults.
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'label'));
+    $this->assertEqual($types['test']->label, 'label', 'Condition to default type applied.');
+
+    $types['test']->label = 'modified';
+    $types['test']->save();
+
+    // Ensure loading the changed entity works.
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'modified'));
+    $this->assertEqual($types['test']->label, 'modified', 'Modified type loaded.');
+
+    // Clear the cache to simulate a new page load.
+    entity_get_controller('entity_test_type')->resetCache();
+
+    // Test loading using a condition again, now they default may not appear any
+    // more as it's overridden by an entity with another label.
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'label'));
+    $this->assertTrue(empty($types), 'Conditions are applied to the overridden entity only.');
+
+    // But the overridden entity has to appear with another condition.
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'modified'));
+    $this->assertEqual($types['test']->label, 'modified', 'Modified default type loaded by condition.');
+
+    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
+    $this->assertEqual($types['test']->label, 'modified', 'Modified default type loaded by id.');
+    $this->assertTrue(entity_has_status('entity_test_type', $types['test'], ENTITY_OVERRIDDEN), 'Status of overridden type is correct.');
+
+    // Test rebuilding the defaults and make sure overridden entities stay.
+    entity_defaults_rebuild();
+    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
+    $this->assertEqual($types['test']->label, 'modified', 'Overridden entity is still overridden.');
+    $this->assertTrue(entity_has_status('entity_test_type', $types['test'], ENTITY_OVERRIDDEN), 'Status of overridden type is correct.');
+
+    // Test reverting.
+    $types['test']->delete();
+    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
+    $this->assertEqual($types['test']->label, 'label', 'Entity has been reverted.');
+
+    // Test loading an exportable by its numeric id.
+    $result = entity_load_multiple_by_name('entity_test_type', array($types['test']->id));
+    $this->assertTrue(isset($result['test']), 'Exportable entity loaded by the numeric id.');
+
+    // Test exporting an entity to JSON.
+    $serialized_string = $types['test']->export();
+    $data = drupal_json_decode($serialized_string);
+    $this->assertNotNull($data, 'Exported entity is valid JSON.');
+    $import = entity_import('entity_test_type', $serialized_string);
+    $this->assertTrue(get_class($import) == get_class($types['test']) && $types['test']->label == $import->label, 'Successfully exported entity to code.');
+    $this->assertTrue(!isset($import->status), 'Exportable status has not been exported to code.');
+
+    // Test disabling the module providing the defaults in code.
+    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
+    $types['test']->label = 'modified';
+    $types['test']->save();
+
+    module_disable(array('entity_feature'));
+
+    // Make sure the overridden entity stays and the other one is deleted.
+    entity_get_controller('entity_test_type')->resetCache();
+    $test = entity_load_single('entity_test_type', 'test');
+    $this->assertTrue(!empty($test) && $test->label == 'modified', 'Overidden entity is still available.');
+    $this->assertTrue(!empty($test) && !entity_has_status('entity_test_type', $test, ENTITY_IN_CODE) && entity_has_status('entity_test_type', $test, ENTITY_CUSTOM), 'Overidden entity is now marked as custom.');
+
+    $test2 = entity_load_single('entity_test_type', 'test2');
+    $this->assertFalse($test2, 'Default entity has disappeared.');
+  }
+
+  /**
+   * Make sure insert() and update() hooks for exportables are invoked.
+   */
+  function testExportableHooks() {
+    $_SESSION['entity_hook_test'] = array();
+    // Enabling the module should invoke the enabled hook for the other
+    // entities provided in code.
+    module_enable(array('entity_feature'));
+
+    $insert = array('main', 'test', 'test2');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_insert'] == $insert, 'Hook entity_insert has been invoked.');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_insert'] == $insert, 'Hook entity_test_type_insert has been invoked.');
+
+    // Load a default entity and make sure the rebuilt logic only ran once.
+    entity_load_single('entity_test_type', 'test');
+    $this->assertTrue(!isset($_SESSION['entity_hook_test']['entity_test_type_update']), '"Entity-test-type" defaults have been rebuilt only once.');
+
+    // Add a new test entity in DB and make sure the hook is invoked too.
+    $test3 = entity_create('entity_test_type', array(
+      'name' => 'test3',
+      'label' => 'label',
+      'weight' => 0,
+    ));
+    $test3->save();
+
+    $insert[] = 'test3';
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_insert'] == $insert, 'Hook entity_insert has been invoked.');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_insert'] == $insert, 'Hook entity_test_type_insert has been invoked.');
+
+    // Now override the 'test' entity and make sure it invokes the update hook.
+    $result = entity_load_multiple_by_name('entity_test_type', array('test'));
+    $result['test']->label = 'modified';
+    $result['test']->save();
+
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_update'] == array('test'), 'Hook entity_update has been invoked.');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_update'] == array('test'), 'Hook entity_test_type_update has been invoked.');
+
+    // 'test' has to remain enabled, as it has been overridden.
+    $delete = array('main', 'test2');
+    module_disable(array('entity_feature'));
+
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_delete'] == $delete, 'Hook entity_deleted has been invoked.');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_delete'] == $delete, 'Hook entity_test_type_deleted has been invoked.');
+
+    // Now make sure 'test' is not overridden any more, but custom.
+    $result = entity_load_multiple_by_name('entity_test_type', array('test'));
+    $this->assertTrue(!$result['test']->hasStatus(ENTITY_OVERRIDDEN), 'Entity is not marked as overridden any more.');
+    $this->assertTrue(entity_has_status('entity_test_type', $result['test'], ENTITY_CUSTOM), 'Entity is marked as custom.');
+
+    // Test deleting the remaining entities from DB.
+    entity_delete_multiple('entity_test_type', array('test', 'test3'));
+    $delete[] = 'test';
+    $delete[] = 'test3';
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_delete'] == $delete, 'Hook entity_deleted has been invoked.');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_delete'] == $delete, 'Hook entity_test_type_deleted has been invoked.');
+  }
+
+  /**
+   * Tests determining changes.
+   */
+  function testChanges() {
+    module_enable(array('entity_feature'));
+    $types = entity_load_multiple_by_name('entity_test_type');
+
+    // Override the default entity, such it gets saved in the DB.
+    $types['test']->label ='test_changes';
+    $types['test']->save();
+
+    // Now test an update without applying any changes.
+    $types['test']->save();
+    $this->assertEqual($types['test']->label, 'test_changes', 'No changes have been determined.');
+
+    // Apply changes.
+    $types['test']->label = 'updated';
+    $types['test']->save();
+
+    // The hook implementations entity_test_entity_test_type_presave() and
+    // entity_test_entity_test_type_update() determine changes and change the
+    // label.
+    $this->assertEqual($types['test']->label, 'updated_presave_update', 'Changes have been determined.');
+
+    // Test the static load cache to be cleared.
+    $types = entity_load_multiple_by_name('entity_test_type');
+    $this->assertEqual($types['test']->label, 'updated_presave', 'Static cache has been cleared.');
+  }
+
+
+  /**
+   * Tests viewing entites.
+   */
+  function testRendering() {
+    module_enable(array('entity_feature'));
+
+    $user1 = $this->drupalCreateUser();
+    // Create test entities for the user1 and unrelated to a user.
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
+
+    $render = $entity->view();
+    $output = drupal_render($render);
+    // The entity class adds the user name to the output. Verify it is there.
+    $this->assertTrue(strpos($output, format_username($user1)) !== FALSE, 'Entity has been rendered');
+  }
+
+  /**
+   * Test uninstall of the entity_test module.
+   */
+  function testUninstall() {
+    // Add a test type and add a field instance, uninstall, then re-install and
+    // make sure the field instance can be re-created.
+    $test_type = entity_create('entity_test_type', array(
+      'name' => 'test',
+      'label' => 'label',
+      'weight' => 0,
+    ));
+    $test_type->save();
+
+    $field = array(
+      'field_name' => 'field_test_fullname',
+      'type' => 'text',
+      'cardinality' => 1,
+      'translatable' => FALSE,
+    );
+    field_create_field($field);
+
+    $instance = array(
+      'entity_type' => 'entity_test',
+      'field_name' => 'field_test_fullname',
+      'bundle' => 'test',
+      'label' => 'Full name',
+      'description' => 'Specify your first and last name.',
+      'widget' => array(
+        'type' => 'text_textfield',
+        'weight' => 0,
+      ),
+    );
+    field_create_instance($instance);
+
+    // Uninstallation has to remove all bundles, thus also field instances.
+    module_disable(array('entity_test'));
+    require_once DRUPAL_ROOT . '/includes/install.inc';
+    drupal_uninstall_modules(array('entity_test'));
+
+    // Make sure the instance has been deleted.
+    $instance_read = field_read_instance('entity_test', 'field_test_fullname', 'test', array('include_inactive' => 1));
+    $this->assertFalse((bool) $instance_read, 'Field instance has been deleted.');
+
+    // Ensure re-creating the same instance now works.
+    module_enable(array('entity_test'));
+    $test_type = entity_create('entity_test_type', array(
+      'name' => 'test',
+      'label' => 'label',
+      'weight' => 0,
+    ));
+    $test_type->save();
+    field_create_field($field);
+    field_create_instance($instance);
+
+    $instance_read = field_info_instance('entity_test', 'field_test_fullname', 'test');
+    $this->assertTrue((bool) $instance_read, 'Field instance has been re-created.');
+  }
+}
+
+/**
+ * Test the generated Rules integration.
+ */
+class EntityAPIRulesIntegrationTestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity CRUD Rules integration',
+      'description' => 'Tests the Rules integration provided by the Entity CRUD API.',
+      'group' => 'Entity API',
+      'dependencies' => array('rules'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity', 'entity_test', 'rules');
+    // Make sure the logger is enabled so the debug log is saved.
+    variable_set('rules_debug_log', 1);
+  }
+
+  /**
+   * Test the events.
+   */
+  function testEvents() {
+    $rule = rules_reaction_rule();
+    $rule->event('entity_test_presave');
+    $rule->event('entity_test_insert');
+    $rule->event('entity_test_update');
+    $rule->event('entity_test_delete');
+    $rule->action('drupal_message', array('message' => 'hello!'));
+    $rule->save();
+    rules_clear_cache(TRUE);
+
+    // Let the events occur.
+    $user1 = $this->drupalCreateUser();
+    RulesLog::logger()->clear();
+
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
+    $entity->save();
+    $entity->name = 'update';
+    $entity->save();
+    $entity->delete();
+
+    // Now there should have been 5 events, 2 times presave and once insert,
+    // update and delete.
+    $count = substr_count(RulesLog::logger()->render(), '0 ms Reacting on event');
+    $this->assertTrue($count == 5, 'Events have been properly invoked.');
+    RulesLog::logger()->checkLog();
+  }
+}
+
+/**
+ * Test the i18n integration.
+ */
+class EntityAPIi18nItegrationTestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity CRUD i18n integration',
+      'description' => 'Tests the i18n integration provided by the Entity CRUD API.',
+      'group' => 'Entity API',
+      'dependencies' => array('i18n_string'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity_test_i18n');
+    $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages'));
+    $this->drupalLogin($this->admin_user);
+    $this->addLanguage('de');
+  }
+
+  /**
+   * Copied from i18n module (class Drupali18nTestCase).
+   *
+   * We cannot extend from Drupali18nTestCase as else the test-bot would die.
+   */
+  public function addLanguage($language_code) {
+    // Check to make sure that language has not already been installed.
+    $this->drupalGet('admin/config/regional/language');
+
+    if (strpos($this->drupalGetContent(), 'enabled[' . $language_code . ']') === FALSE) {
+      // Doesn't have language installed so add it.
+      $edit = array();
+      $edit['langcode'] = $language_code;
+      $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+      // Make sure we are not using a stale list.
+      drupal_static_reset('language_list');
+      $languages = language_list('language');
+      $this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.'));
+
+      if (array_key_exists($language_code, $languages)) {
+        $this->assertRaw(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => $languages[$language_code]->name, '@locale-help' => url('admin/help/locale'))), t('Language has been created.'));
+      }
+    }
+    elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'enabled[' . $language_code . ']'))) {
+      // It's installed and enabled. No need to do anything.
+      $this->assertTrue(true, 'Language [' . $language_code . '] already installed and enabled.');
+    }
+    else {
+      // It's installed but not enabled. Enable it.
+      $this->assertTrue(true, 'Language [' . $language_code . '] already installed.');
+      $this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
+      $this->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
+    }
+  }
+
+  /**
+   * Tests the provided default controller.
+   */
+  function testDefaultController() {
+    // Create test entities for the user1 and unrelated to a user.
+    $entity = entity_create('entity_test_type', array(
+      'name' => 'test',
+      'uid' => $GLOBALS['user']->uid,
+      'label' => 'label-en',
+    ));
+    $entity->save();
+
+    // Add a translation.
+    i18n_string_textgroup('entity_test')->update_translation("entity_test_type:{$entity->name}:label", 'de', 'label-de');
+
+    $default = entity_i18n_string("entity_test:entity_test_type:{$entity->name}:label", 'label-en');
+    $translation = entity_i18n_string("entity_test:entity_test_type:{$entity->name}:label", 'label-en', 'de');
+
+    $this->assertEqual($translation, 'label-de', 'Label has been translated.');
+    $this->assertEqual($default, 'label-en', 'Default label retrieved.');
+
+    // Test the helper method.
+    $translation = $entity->getTranslation('label', 'de');
+    $default = $entity->getTranslation('label');
+    $this->assertEqual($translation, 'label-de', 'Label has been translated via the helper method.');
+    $this->assertEqual($default, 'label-en', 'Default label retrieved via the helper method.');
+
+    // Test updating and make sure the translation stays.
+    $entity->name = 'test2';
+    $entity->save();
+    $translation = $entity->getTranslation('label', 'de');
+    $this->assertEqual($translation, 'label-de', 'Translation survives a name change.');
+
+    // Test using the wrapper to retrieve a translation.
+    $wrapper = entity_metadata_wrapper('entity_test_type', $entity);
+    $translation = $wrapper->language('de')->label->value();
+    $this->assertEqual($translation, 'label-de', 'Translation retrieved via the wrapper.');
+
+    // Test deleting.
+    $entity->delete();
+    $translation = entity_i18n_string("entity_test:entity_test_type:{$entity->name}:label", 'label-en', 'de');
+    $this->assertEqual($translation, 'label-en', 'Translation has been deleted.');
+  }
+}
+
+/**
+ * Tests metadata wrappers.
+ */
+class EntityMetadataTestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Metadata Wrapper',
+      'description' => 'Makes sure metadata wrapper are working right.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity', 'entity_test', 'locale');
+    // Create a field having 4 values for testing multiple value support.
+    $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
+    $this->field = array('field_name' => $this->field_name, 'type' => 'text', 'cardinality' => 4);
+    $this->field = field_create_field($this->field);
+    $this->field_id = $this->field['id'];
+    $this->instance = array(
+      'field_name' => $this->field_name,
+      'entity_type' => 'node',
+      'bundle' => 'page',
+      'label' => $this->randomName() . '_label',
+      'description' => $this->randomName() . '_description',
+      'weight' => mt_rand(0, 127),
+      'settings' => array(
+        'text_processing' => FALSE,
+      ),
+      'widget' => array(
+        'type' => 'text_textfield',
+        'label' => 'Test Field',
+        'settings' => array(
+          'size' => 64,
+        )
+      )
+    );
+    field_create_instance($this->instance);
+
+    // Make the body field and the node type 'page' translatable.
+    $field = field_info_field('body');
+    $field['translatable'] = TRUE;
+    field_update_field($field);
+    variable_set('language_content_type_page', 1);
+  }
+
+  /**
+   * Creates a user and a node, then tests getting the properties.
+   */
+  function testEntityMetadataWrapper() {
+    $account = $this->drupalCreateUser();
+    // For testing sanitizing give the user a malicious user name
+    $account = user_save($account, array('name' => '<b>BadName</b>'));
+    $title = '<b>Is it bold?<b>';
+    $body[LANGUAGE_NONE][0] = array('value' => '<b>The body & nothing.</b>', 'summary' => '<b>The body.</b>');
+    $node = $this->drupalCreateNode(array('uid' => $account->uid, 'name' => $account->name, 'body' => $body, 'title' => $title, 'summary' => '', 'type' => 'page'));
+
+    // First test without sanitizing.
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual('<b>Is it bold?<b>', $wrapper->title->value(), 'Getting a field value.');
+    $this->assertEqual($node->title, $wrapper->title->raw(), 'Getting a raw property value.');
+
+    // Test chaining.
+    $this->assertEqual($account->mail, $wrapper->author->mail->value(), 'Testing chained usage.');
+    $this->assertEqual($account->name, $wrapper->author->name->value(), 'Testing chained usage with callback and sanitizing.');
+
+    // Test sanitized output.
+    $options = array('sanitize' => TRUE);
+    $this->assertEqual(check_plain('<b>Is it bold?<b>'), $wrapper->title->value($options), 'Getting sanitized field.');
+    $this->assertEqual(filter_xss($node->name), $wrapper->author->name->value($options), 'Getting sanitized property with getter callback.');
+
+    // Test getting an not existing property.
+    try {
+      echo $wrapper->dummy;
+      $this->fail('Getting an not existing property.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Getting an not existing property.');
+    }
+
+    // Test setting.
+    $wrapper->author = 0;
+    $this->assertEqual(0, $wrapper->author->uid->value(), 'Setting a property.');
+    try {
+      $wrapper->url = 'dummy';
+      $this->fail('Setting an unsupported property.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Setting an unsupported property.');
+    }
+
+    // Test value validation.
+    $this->assertFalse($wrapper->author->name->validate(array(3)), 'Validation correctly checks for valid data types.');
+    try {
+      $wrapper->author->mail = 'foo';
+      $this->fail('An invalid mail address has been set.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Setting an invalid mail address throws exception.');
+    }
+    // Test unsetting a required property.
+    try {
+      $wrapper->author = NULL;
+      $this->fail('The required node author has been unset.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Unsetting the required node author throws an exception.');
+    }
+
+    // Test setting a referenced entity by id.
+    $wrapper->author->set($GLOBALS['user']->uid);
+    $this->assertEqual($wrapper->author->getIdentifier(), $GLOBALS['user']->uid, 'Get the identifier of a referenced entity.');
+    $this->assertEqual($wrapper->author->uid->value(), $GLOBALS['user']->uid, 'Successfully set referenced entity using the identifier.');
+    // Set by object.
+    $wrapper->author->set($GLOBALS['user']);
+    $this->assertEqual($wrapper->author->uid->value(), $GLOBALS['user']->uid, 'Successfully set referenced entity using the entity.');
+
+
+    // Test getting by the field API processed values like the node body.
+    $body_value = $wrapper->body->value;
+    $this->assertEqual("<p>The body &amp; nothing.</p>\n", $body_value->value(), "Getting processed value.");
+    $this->assertEqual("The body & nothing.\n", $body_value->value(array('decode' => TRUE)), "Decoded value.");
+    $this->assertEqual("<b>The body & nothing.</b>", $body_value->raw(), "Raw body returned.");
+
+    // Test getting the summary.
+    $this->assertEqual("<p>The body.</p>\n", $wrapper->body->summary->value(), "Getting body summary.");
+
+    $wrapper->body->set(array('value' => "<b>The second body.</b>"));
+    $this->assertEqual("<p>The second body.</p>\n", $wrapper->body->value->value(), "Setting a processed field value and reading it again.");
+    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], "<b>The second body.</b>", 'Update appears in the wrapped entity.');
+    $this->assert(isset($node->body[LANGUAGE_NONE][0]['safe_value']), 'Formatted text has been processed.');
+
+    // Test translating the body on an English node.
+    locale_add_language('de');
+    $body['en'][0] = array('value' => '<b>English body.</b>', 'summary' => '<b>The body.</b>');
+    $node = $this->drupalCreateNode(array('body' => $body, 'language' => 'en', 'type' => 'page'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->language('de');
+
+    $languages = language_list();
+    $this->assertEqual($wrapper->getPropertyLanguage(), $languages['de'], 'Wrapper language has been set to German');
+    $this->assertEqual($wrapper->body->value->value(), "<p>English body.</p>\n", 'Language fallback on default language.');
+
+    // Set a German text using the wrapper.
+    $wrapper->body->set(array('value' => "<b>Der zweite Text.</b>"));
+    $this->assertEqual($wrapper->body->value->value(), "<p>Der zweite Text.</p>\n", 'German body set and retrieved.');
+
+    $wrapper->language(LANGUAGE_NONE);
+    $this->assertEqual($wrapper->body->value->value(), "<p>English body.</p>\n", 'Default language text is still there.');
+
+    // Test iterator.
+    $type_info = entity_get_property_info('node');
+    $this->assertFalse(array_diff_key($type_info['properties'], iterator_to_array($wrapper->getIterator())), 'Iterator is working.');
+    foreach ($wrapper as $property) {
+      $this->assertTrue($property instanceof EntityMetadataWrapper, 'Iterate over wrapper properties.');
+    }
+
+    // Test setting a new node.
+    $node->title = 'foo';
+    $wrapper->set($node);
+    $this->assertEqual($wrapper->title->value(), 'foo', 'Changed the wrapped node.');
+
+    // Test getting options lists.
+    $this->assertEqual($wrapper->type->optionsList(), node_type_get_names(), 'Options list returned.');
+
+    // Test making use of a generic 'entity' reference property the
+    // 'entity_test' module provides. The property defaults to the node author.
+    $this->assertEqual($wrapper->reference->uid->value(), $wrapper->author->getIdentifier(), 'Used generic entity reference property.');
+    // Test updating a property of the generic entity reference.
+    $wrapper->reference->name->set('foo');
+    $this->assertEqual($wrapper->reference->name->value(), 'foo', 'Updated property of generic entity reference');
+    // For testing, just point the reference to the node itself now.
+    $wrapper->reference->set($wrapper);
+    $this->assertEqual($wrapper->reference->nid->value(), $wrapper->getIdentifier(), 'Correctly updated the generic entity referenced property.');
+
+    // Test saving and deleting.
+    $wrapper->save();
+    $wrapper->delete();
+    $return = node_load($wrapper->getIdentifier());
+    $this->assertFalse($return, "Node has been successfully deleted.");
+
+    // Ensure changing the bundle changes available wrapper properties.
+    $wrapper->type->set('article');
+    $this->assertTrue(isset($wrapper->field_tags), 'Changing bundle changes available wrapper properties.');
+
+    // Test labels.
+    $user = $this->drupalCreateUser();
+    user_save($user, array('roles' => array()));
+    $wrapper->author = $user->uid;
+    $this->assertEqual($wrapper->label(), $node->title, 'Entity label returned.');
+    $this->assertEqual($wrapper->author->roles[0]->label(), t('authenticated user'), 'Label from options list returned');
+    $this->assertEqual($wrapper->author->roles->label(), t('authenticated user'), 'Label for a list from options list returned');
+  }
+
+  /**
+   * Test supporting multi-valued fields.
+   */
+  function testListMetadataWrappers() {
+    $property = $this->field_name;
+    $values = array();
+    $values[LANGUAGE_NONE][0] = array('value' => '<b>2009-09-05</b>');
+    $values[LANGUAGE_NONE][1] = array('value' => '2009-09-05');
+    $values[LANGUAGE_NONE][2] = array('value' => '2009-08-05');
+
+    $node = $this->drupalCreateNode(array('type' => 'page', $property => $values));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual('<b>2009-09-05</b>', $wrapper->{$property}[0]->value(), 'Getting array entry.');
+    $this->assertEqual('2009-09-05', $wrapper->{$property}->get(1)->value(), 'Getting array entry.');
+    $this->assertEqual(3, count($wrapper->{$property}->value()), 'Getting the whole array.');
+
+    // Test sanitizing
+    $this->assertEqual(check_plain('<b>2009-09-05</b>'), $wrapper->{$property}[0]->value(array('sanitize' => TRUE)), 'Getting array entry.');
+
+    // Test iterator
+    $this->assertEqual(array_keys(iterator_to_array($wrapper->$property->getIterator())), array_keys($wrapper->$property->value()), 'Iterator is working.');
+    foreach ($wrapper->$property as $p) {
+      $this->assertTrue($p instanceof EntityMetadataWrapper, 'Iterate over list wrapper properties.');
+    }
+
+    // Make sure changing the array changes the actual entity property.
+    $wrapper->{$property}[0] = '2009-10-05';
+    unset($wrapper->{$property}[1], $wrapper->{$property}[2]);
+    $this->assertEqual($wrapper->{$property}->value(), array('2009-10-05'), 'Setting multiple property values.');
+
+    // Test setting an arbitrary list item.
+    $list = array(0 => REQUEST_TIME);
+    $wrapper = entity_metadata_wrapper('list<date>', $list);
+    $wrapper[1] = strtotime('2009-09-05');
+    $this->assertEqual($wrapper->value(), array(REQUEST_TIME, strtotime('2009-09-05')), 'Setting a list item.');
+    $this->assertEqual($wrapper->count(), 2, 'List count is correct.');
+
+    // Test using a list wrapper without data.
+    $wrapper = entity_metadata_wrapper('list<date>');
+    $info = array();
+    foreach ($wrapper as $item) {
+      $info[] = $item->info();
+    }
+    $this->assertTrue($info[0]['type'] == 'date', 'Iterated over empty list wrapper.');
+
+    // Test using a list of entities with a list of term objects.
+    $list = array();
+    $list[] = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => 'term 1',
+      'vocabulary' => 1,
+    ))->save()->value();
+    $list[] = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => 'term 2',
+      'vocabulary' => 1,
+    ))->save()->value();
+    $wrapper = entity_metadata_wrapper('list<taxonomy_term>', $list);
+    $this->assertTrue($wrapper[0]->name->value() == 'term 1', 'Used a list of entities.');
+    // Test getting a list of identifiers.
+    $ids = $wrapper->value(array('identifier' => TRUE));
+    $this->assertTrue(!is_object($ids[0]), 'Get a list of entity ids.');
+
+    $wrapper = entity_metadata_wrapper('list<taxonomy_term>', $ids);
+    $this->assertTrue($wrapper[0]->name->value() == 'term 1', 'Created a list of entities with ids.');
+
+    // Test with a list of generic entities. The list is expected to be a list
+    // of entity wrappers, otherwise the entity type is unknown.
+    $node = $this->drupalCreateNode(array('title' => 'node 1'));
+    $list = array();
+    $list[] = entity_metadata_wrapper('node', $node);
+    $wrapper = entity_metadata_wrapper('list<entity>', $list);
+    $this->assertEqual($wrapper[0]->title->value(), 'node 1', 'Wrapped node was found in generic list of entities.');
+  }
+
+  /**
+   * Tests using the wrapper without any data.
+   */
+  function testWithoutData() {
+    $wrapper = entity_metadata_wrapper('node', NULL, array('bundle' => 'page'));
+    $this->assertTrue(isset($wrapper->title), 'Bundle properties have been added.');
+    $info = $wrapper->author->mail->info();
+    $this->assertTrue(!empty($info) && is_array($info) && isset($info['label']), 'Property info returned.');
+  }
+
+  /**
+   * Test using access() method.
+   */
+  function testAccess() {
+    // Test without data.
+    $account = $this->drupalCreateUser(array('bypass node access'));
+    $this->assertTrue(entity_access('view', 'node', NULL, $account), 'Access without data checked.');
+
+    // Test with actual data.
+    $values[LANGUAGE_NONE][0] = array('value' => '<b>2009-09-05</b>');
+    $values[LANGUAGE_NONE][1] = array('value' => '2009-09-05');
+    $node = $this->drupalCreateNode(array('type' => 'page', $this->field_name => $values));
+    $this->assertTrue(entity_access('delete', 'node', $node, $account), 'Access with data checked.');
+
+    // Test per property access without data.
+    $account2 = $this->drupalCreateUser(array('bypass node access', 'administer nodes'));
+    $wrapper = entity_metadata_wrapper('node', NULL, array('bundle' => 'page'));
+    $this->assertTrue($wrapper->access('edit', $account), 'Access to node granted.');
+    $this->assertFalse($wrapper->status->access('edit', $account), 'Access for admin property denied.');
+    $this->assertTrue($wrapper->status->access('edit', $account2), 'Access for admin property allowed for the admin.');
+
+    // Test per property access with data.
+    $wrapper = entity_metadata_wrapper('node', $node, array('bundle' => 'page'));
+    $this->assertFalse($wrapper->status->access('edit', $account), 'Access for admin property denied.');
+    $this->assertTrue($wrapper->status->access('edit', $account2), 'Access for admin property allowed for the admin.');
+
+    // Test field level access.
+    $this->assertTrue($wrapper->{$this->field_name}->access('view'), 'Field access granted.');
+  }
+
+  /**
+   * Tests using a data structure with passed in metadata.
+   */
+  function testDataStructureWrapper() {
+    $log_entry = array(
+      'type'        => 'entity',
+      'message'     => $this->randomName(8),
+      'variables'   => array(),
+      'severity'    => WATCHDOG_NOTICE,
+      'link'        => '',
+      'user'        => $GLOBALS['user'],
+    );
+    $info['property info'] = array(
+      'type' => array('type' => 'text', 'label' => 'The category to which this message belongs.'),
+      'message' => array('type' => 'text', 'label' => 'The log message.'),
+      'user' => array('type' => 'user', 'label' => 'The user causing the log entry.'),
+    );
+    $wrapper = entity_metadata_wrapper('log_entry', $log_entry, $info);
+    $this->assertEqual($wrapper->user->name->value(), $GLOBALS['user']->name, 'Wrapped custom entity.');
+  }
+
+  /**
+   * Tests using entity_property_query().
+   */
+  function testEntityQuery() {
+    // Creat a test node.
+    $title = '<b>Is it bold?<b>';
+    $values[LANGUAGE_NONE][0] = array('value' => 'foo');
+    $node = $this->drupalCreateNode(array($this->field_name => $values, 'title' => $title, 'uid' => $GLOBALS['user']->uid));
+
+    $results = entity_property_query('node', 'title', $title);
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given title.');
+
+    $results = entity_property_query('node', $this->field_name, 'foo');
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given field value.');
+
+    $results = entity_property_query('node', $this->field_name, array('foo', 'bar'));
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a list of possible values.');
+
+    $results = entity_property_query('node', 'author', $GLOBALS['user']);
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given auhtor.');
+
+    // Create another test node and try querying for tags.
+    $tag = entity_property_values_create_entity('taxonomy_term', array(
+          'name' => $this->randomName(),
+          'vocabulary' => 1,
+    ))->save();
+    $field_tag_value[LANGUAGE_NONE][0]['tid'] = $tag->getIdentifier();
+    $node = $this->drupalCreateNode(array('type' => 'article', 'field_tags' => $field_tag_value));
+
+    // Try query-ing with a single value.
+    $results = entity_property_query('node', 'field_tags', $tag->getIdentifier());
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given term id.');
+
+    $results = entity_property_query('node', 'field_tags', $tag->value());
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given term object.');
+
+    // Try query-ing with a list of possible values.
+    $results = entity_property_query('node', 'field_tags', array($tag->getIdentifier()));
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a list of term ids.');
+  }
+
+  /**
+   * Tests serializing data wrappers, in particular for EntityDrupalWrapper.
+   */
+  function testWrapperSerialization() {
+    $node = $this->drupalCreateNode();
+    $wrapper = entity_metadata_wrapper('node', $node);
+    $this->assertTrue($wrapper->value() == $node, 'Data correctly wrapped.');
+
+    // Test serializing and make sure only the node id is stored.
+    $this->assertTrue(strpos(serialize($wrapper), $node->title) === FALSE, 'Node has been correctly serialized.');
+    $this->assertEqual(unserialize(serialize($wrapper))->title->value(), $node->title, 'Serializing works right.');
+
+    $wrapper2 = unserialize(serialize($wrapper));
+    // Test serializing the unloaded wrapper.
+    $this->assertEqual(unserialize(serialize($wrapper2))->title->value(), $node->title, 'Serializing works right.');
+
+    // Test loading a not more existing node.
+    $s = serialize($wrapper2);
+    node_delete($node->nid);
+    $this->assertFalse(node_load($node->nid), 'Node deleted.');
+
+    $value = unserialize($s)->value();
+    $this->assertNull($value, 'Tried to load not existing node.');
+  }
+}
+
+/**
+ * Tests provided entity property info of the core modules.
+ */
+class EntityTokenTestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity tokens',
+      'description' => 'Tests provided tokens for entity properties.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity_token');
+  }
+
+  /**
+   * Tests whether token support is basically working.
+   */
+  function testTokenSupport() {
+    // Test basic tokens.
+    $node = $this->drupalCreateNode(array('sticky' => TRUE, 'promote' => FALSE));
+    $text = "Sticky: [node:sticky] Promote: [node:promote] User: [site:current-user:name]";
+    $true = t('true');
+    $false = t('false');
+    $user_name = $GLOBALS['user']->name;
+    $target = "Sticky: $true Promote: $false User: $user_name";
+    $replace = token_replace($text, array('node' => $node));
+    $this->assertEqual($replace, $target, 'Provided tokens basically work.');
+
+    // Test multiple-value tokens using the tags field of articles.
+    for ($i = 0; $i < 4; $i++) {
+      $tags[$i] = entity_property_values_create_entity('taxonomy_term', array(
+        'name' => $this->randomName(),
+        'vocabulary' => 1,
+      ))->save();
+      $field_value[LANGUAGE_NONE][$i]['tid'] = $tags[$i]->getIdentifier();
+      $labels[$i] = $tags[$i]->label();
+    }
+    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article', 'field_tags' => $field_value));
+
+    $text = "Tags: [node:field-tags] First: [node:field-tags:0] 2nd name: [node:field-tags:1:name] 1st vocab [node:field-tags:0:vocabulary]";
+    $tag_labels = implode(', ', $labels);
+    $target = "Tags: $tag_labels First: $labels[0] 2nd name: $labels[1] 1st vocab {$tags[0]->vocabulary->label()}";
+    $replace = token_replace($text, array('node' => $node));
+    $this->assertEqual($replace, $target, 'Multiple-value token replacements have been replaced.');
+
+    // Make sure not existing values are not handled.
+    $replace = token_replace("[node:field-tags:43]", array('node' => $node));
+    $this->assertEqual($replace, "[node:field-tags:43]", 'Not existing values are not replaced.');
+
+    // Test data-structure tokens like [site:current-page:url].
+    $replace = token_replace("[site:current-page:url]", array());
+    $this->assertEqual($replace, $GLOBALS['base_root'] . request_uri(), 'Token replacements of data structure properties replaced.');
+
+    // Test chaining of data-structure tokens using an image-field.
+    $file = $this->createFile('image');
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_image = array('fid' => $file->fid);
+    $replace = token_replace("[node:field-image:file:name]", array('node' => $node));
+    $this->assertEqual($replace, $wrapper->field_image->file->name->value(), 'Token replacements of an image field have been replaced.');
+  }
+}
+
+/**
+ * Tests provided entity property info of the core modules.
+ */
+class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Property info core integration',
+      'description' => 'Tests using metadata wrapper for drupal core.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity', 'book', 'statistics', 'locale');
+  }
+
+  protected function assertException($wrapper, $name, $text = NULL) {
+    $this->assertTrue(isset($wrapper->$name), 'Property wrapper ' . check_plain($name) . ' exists.');
+    $text = isset($text) ? $text : 'Getting the not existing property ' . $name . ' throws exception.';
+    try {
+      $wrapper->$name->value();
+      $this->fail($text);
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass($text);
+    }
+  }
+
+  protected function assertEmpty($wrapper, $name) {
+    $this->assertTrue(isset($wrapper->$name), 'Property ' . check_plain($name) . ' exists.');
+    $this->assertTrue($wrapper->$name->value() === NULL, 'Property ' . check_plain($name) . ' is empty.');
+  }
+
+  protected function assertValue($wrapper, $key) {
+    $this->assertTrue($wrapper->$key->value() !== NULL, check_plain($key) . ' property returned.');
+    $info = $wrapper->$key->info();
+    if (!empty($info['raw getter callback'])) {
+      // Also test getting the raw value
+      $this->assertTrue($wrapper->$key->raw() !== NULL, check_plain($key) . ' raw value returned.');
+    }
+  }
+
+  /**
+   * Test book module integration.
+   */
+  function testBookModule() {
+    $title = 'Book 1';
+    $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'book'));
+    $node2 = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => $node->nid)));
+    $node3 = $this->drupalCreateNode(array('type' => 'page'));
+
+    // Test whether the properties work.
+    $wrapper = entity_metadata_wrapper('node', $node2);
+    $this->assertEqual("Book 1", $wrapper->book->title->value(), "Book title returned.");
+    $this->assertEqual($node->nid, $wrapper->book->nid->value(), "Book id returned.");
+
+    // Try using book properties for no book nodes.
+    $wrapper = entity_metadata_wrapper('node', $node3);
+    $this->assertException($wrapper, 'book');
+  }
+
+  /**
+   * Test properties of a comment.
+   */
+  function testComments() {
+    $title = 'Node 1';
+    $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'page'));
+    $account = $this->drupalCreateUser();
+    $comment = (object)array(
+      'subject' => 'topic',
+      'nid' => $node->nid,
+      'uid' => $account->uid,
+      'cid' => FALSE,
+      'pid' => 0,
+      'homepage' => '',
+      'language' => LANGUAGE_NONE,
+      'hostname' => ip_address(),
+    );
+    $comment->comment_body[LANGUAGE_NONE][0] = array('value' => 'text', 'format' => 0);
+    comment_save($comment);
+    $wrapper = entity_metadata_wrapper('comment', $comment);
+    foreach ($wrapper as $key => $value) {
+      if ($key != 'parent') {
+        $this->assertValue($wrapper, $key);
+      }
+    }
+    $this->assertEmpty($wrapper, 'parent');
+  }
+
+  /**
+   * Test all properties of a node.
+   */
+  function testNodeProperties() {
+    $title = 'Book 1';
+    $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'page'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+    foreach ($wrapper as $key => $value) {
+      if ($key != 'book' && $key != 'source' && $key != 'last_view') {
+        $this->assertValue($wrapper, $key);
+      }
+    }
+    $this->assertException($wrapper, 'book');
+    $this->assertEmpty($wrapper, 'source');
+    $this->assertException($wrapper->source, 'title');
+    $this->assertEmpty($wrapper, 'last_view');
+  }
+
+  /**
+   * Tests properties provided by the taxonomy module.
+   */
+  function testTaxonomyProperties() {
+    $vocab = $this->createVocabulary();
+    $term_parent = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => $vocab,
+    ))->save()->value();
+    $term_parent2 = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => $vocab,
+    ))->save()->value();
+    $term = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => $vocab,
+      'description' => $this->randomString(),
+      'weight' => mt_rand(0, 10),
+      'parent' => array($term_parent->tid),
+    ))->save()->value();
+
+    $wrapper = entity_metadata_wrapper('taxonomy_term', $term);
+    foreach ($wrapper as $key => $value) {
+      $this->assertValue($wrapper, $key);
+    }
+    // Test setting another parent using the full object.
+    $wrapper->parent[] = $term_parent2;
+    $this->assertEqual($wrapper->parent[1]->getIdentifier(), $term_parent2->tid, 'Term parent added.');
+
+    $parents = $wrapper->parent->value();
+    $tids = $term_parent->tid . ':' . $term_parent2->tid;
+    $this->assertEqual($parents[0]->tid . ':' . $parents[1]->tid, $tids, 'Parents returned.');
+    $this->assertEqual(implode(':', $wrapper->parent->value(array('identifier' => TRUE))), $tids, 'Parent ids returned.');
+
+    // Test vocabulary.
+    foreach ($wrapper->vocabulary as $key => $value) {
+      $this->assertValue($wrapper->vocabulary, $key);
+    }
+    // Test field integration.
+    $tags[LANGUAGE_NONE][0]['tid'] = $term->tid;
+    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article', 'field_tags' => $tags));
+    $wrapper = entity_metadata_wrapper('node', $node);
+    $this->assertEqual($wrapper->field_tags[0]->name->value(), $term->name, 'Get an associated tag of a node with the wrapper.');
+
+    $wrapper->field_tags[1] = $term_parent;
+    $tags = $wrapper->field_tags->value();
+    $this->assertEqual($tags[1]->tid, $term_parent->tid, 'Associated a new tag with a node.');
+    $this->assertEqual($tags[0]->tid, $term->tid, 'Previsous set association kept.');
+
+    // Test getting a list of identifiers.
+    $tags = $wrapper->field_tags->value(array('identifier' => TRUE));
+    $this->assertEqual($tags, array($term->tid, $term_parent->tid), 'List of referenced term identifiers returned.');
+
+    // Test setting tags by using ids.
+    $wrapper->field_tags->set(array(2));
+    $this->assertEqual($wrapper->field_tags[0]->tid->value(), 2, 'Specified tags by a list of term ids.');
+
+    // Test unsetting all tags.
+    $wrapper->field_tags = NULL;
+    $this->assertFalse($wrapper->field_tags->value(), 'Unset all tags from a node.');
+
+    // Test setting entity references to NULL.
+    // Create a taxonomy term field for that purpose.
+    $field_name = drupal_strtolower($this->randomName() . '_field_name');
+    $field = array('field_name' => $field_name, 'type' => 'taxonomy_term_reference', 'cardinality' => 1);
+    $field = field_create_field($field);
+    $field_id = $field['id'];
+    $field_instance = array(
+      'field_name' => $field_name,
+      'entity_type' => 'node',
+      'bundle' => 'article',
+      'label' => $this->randomName() . '_label',
+      'description' => $this->randomName() . '_description',
+      'weight' => mt_rand(0, 127),
+      'widget' => array(
+        'type' => 'options_select',
+        'label' => 'Test term field',
+      )
+    );
+    field_create_instance($field_instance);
+    $term_field[LANGUAGE_NONE][0]['tid'] = $term->tid;
+    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article', $field_name => $term_field));
+    $wrapper = entity_metadata_wrapper('node', $node);
+    $wrapper->$field_name->set(NULL);
+    $termref = $wrapper->$field_name->value();
+    $this->assertNull($termref, 'Unset of a term reference successful.');
+  }
+
+  /**
+   * Test all properties of a user.
+   */
+  function testUserProperties() {
+    $account = $this->drupalCreateUser();
+    $account->login = REQUEST_TIME;
+    $account->access = REQUEST_TIME;
+    $wrapper = entity_metadata_wrapper('user', $account);
+    foreach ($wrapper as $key => $value) {
+      $this->assertValue($wrapper, $key);
+    }
+  }
+
+  /**
+   * Test properties provided by system module.
+   */
+  function testSystemProperties() {
+    $wrapper = entity_metadata_site_wrapper();
+    foreach ($wrapper as $key => $value) {
+      $this->assertValue($wrapper, $key);
+    }
+    // Test page request related properties.
+    foreach ($wrapper->current_page as $key => $value) {
+      $this->assertValue($wrapper->current_page, $key);
+    }
+
+    // Test files.
+    $file = $this->createFile();
+
+    $wrapper = entity_metadata_wrapper('file', $file);
+    foreach ($wrapper as $key => $value) {
+      $this->assertValue($wrapper, $key);
+    }
+  }
+
+  /**
+   * Runs some generic tests on each entity.
+   */
+  function testCRUDfunctions() {
+    $info = entity_get_info();
+    foreach ($info as $entity_type => $entity_info) {
+      // Test using access callback.
+      entity_access('view', $entity_type);
+      entity_access('update', $entity_type);
+      entity_access('create', $entity_type);
+      entity_access('delete', $entity_type);
+
+      // Test creating the entity.
+      if (!isset($entity_info['creation callback'])) {
+        continue;
+      }
+
+      // Populate $values with all values that are setable. They will be set
+      // with an metadata wrapper, so we also test setting that way.
+      $values = array();
+      foreach (entity_metadata_wrapper($entity_type) as $name => $wrapper) {
+        $info = $wrapper->info();
+        if (!empty($info['setter callback'])) {
+          $values[$name] = $this->createValue($wrapper);
+        }
+      }
+      $entity = entity_property_values_create_entity($entity_type, $values)->value();
+      $this->assertTrue($entity, "Created $entity_type and set all setable values.");
+
+      // Save the new entity.
+      $return = entity_save($entity_type, $entity);
+      if ($return === FALSE) {
+        continue; // No support for saving.
+      }
+      $id = entity_metadata_wrapper($entity_type, $entity)->getIdentifier();
+      $this->assertTrue($id, "$entity_type has been successfully saved.");
+
+      // And delete it.
+      $return = entity_delete($entity_type, $id);
+      if ($return === FALSE) {
+        continue; // No support for deleting.
+      }
+      $return = entity_load_single($entity_type, $id);
+      $this->assertFalse($return, "$entity_type has been successfully deleted.");
+    }
+  }
+
+  /**
+   * Test making use of a text fields.
+   */
+  function testTextFields() {
+    // Create a simple text field without text processing.
+    $field = array(
+      'field_name' => 'field_text',
+      'type' => 'text',
+      'cardinality' => 2,
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => 'field_text',
+      'entity_type' => 'node',
+      'label' => 'test',
+      'bundle' => 'article',
+      'widget' => array(
+        'type' => 'text_textfield',
+        'weight' => -1,
+      ),
+    );
+    field_create_instance($instance);
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_text[0] = 'the text';
+
+    // Try saving the node and make sure the information is still there after
+    // loading the node again, thus the correct data structure has been written.
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual('the text', $wrapper->field_text[0]->value(), 'Text has been specified.');
+
+    // Now activate text processing.
+    $instance['settings']['text_processing'] = 1;
+    field_update_instance($instance);
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_text[0]->set(array('value' => "<b>The second body.</b>"));
+    $this->assertEqual("<p>The second body.</p>\n", $wrapper->field_text[0]->value->value(), "Setting a processed text field value and reading it again.");
+
+    // Assert the summary property is correctly removed.
+    $this->assertFalse(isset($wrapper->field_text[0]->summary), 'Processed text has no summary.');
+
+    // Create a text field with summary but without text processing.
+    $field = array(
+      'field_name' => 'field_text2',
+      'type' => 'text_with_summary',
+      'cardinality' => 1,
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => 'field_text2',
+      'entity_type' => 'node',
+      'label' => 'test',
+      'bundle' => 'article',
+      'settings' => array('text_processing' => 0),
+      'widget' => array(
+        'type' => 'text_textarea_with_summary',
+        'weight' => -1,
+      ),
+    );
+    field_create_instance($instance);
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_text2->summary = 'the summary';
+    $wrapper->field_text2->value = 'the text';
+
+    // Try saving the node and make sure the information is still there after
+    // loading the node again, thus the correct data structure has been written.
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual('the text', $wrapper->field_text2->value->value(), 'Text has been specified.');
+    $this->assertEqual('the summary', $wrapper->field_text2->summary->value(), 'Summary has been specified.');
+  }
+
+  /**
+   * Test making use of a file field.
+   */
+  function testFileFields() {
+    $file = $this->createFile();
+
+    // Create a file field.
+    $field = array(
+      'field_name' => 'field_file',
+      'type' => 'file',
+      'cardinality' => 2,
+      'settings' => array('display_field' => TRUE),
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => 'field_file',
+      'entity_type' => 'node',
+      'label' => 'File',
+      'bundle' => 'article',
+      'settings' => array('description_field' => TRUE),
+      'required' => FALSE,
+      'widget' => array(
+        'type' => 'file_generic',
+        'weight' => -1,
+      ),
+    );
+    field_create_instance($instance);
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_file[0] = array('fid' => $file->fid, 'display' => FALSE);
+    $this->assertEqual($file->filename, $wrapper->field_file[0]->file->name->value(), 'File has been specified.');
+
+    $wrapper->field_file[0]->description = 'foo';
+    $wrapper->field_file[0]->display = TRUE;
+
+    $this->assertEqual($wrapper->field_file[0]->description->value(), 'foo', 'File description has been correctly set.');
+
+    // Try saving the node and make sure the information is still there after
+    // loading the node again, thus the correct data structure has been written.
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual($wrapper->field_file[0]->description->value(), 'foo', 'File description has been correctly set.');
+    $this->assertEqual($wrapper->field_file[0]->display->value(), TRUE, 'File display value has been correctly set.');
+
+    // Test adding a new file, the display-property has to be created
+    // automatically.
+    $wrapper->field_file[1]->file = $file;
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertEqual($file->fid, $wrapper->field_file[1]->file->getIdentifier(), 'New file has been added.');
+
+    // Test adding an invalid file-field item, i.e. without any file.
+    try {
+      $wrapper->field_file[] = array('description' => 'test');
+      $this->fail('Exception not thrown.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Not valid file-field item has thrown an exception.');
+    }
+
+    // Test remove all file-field items.
+    $wrapper->field_file = NULL;
+    $this->assertFalse($wrapper->field_file->value(), 'Removed multiple file-field items.');
+  }
+
+  /**
+   * Test making use of an image field.
+   */
+  function testImageFields() {
+    $file = $this->createFile('image');
+
+    // Just use the image field on the article node.
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_image = array('fid' => $file->fid);
+    $this->assertEqual($file->filename, $wrapper->field_image->file->name->value(), 'File has been specified.');
+
+    $wrapper->field_image->alt = 'foo';
+    $this->assertEqual($wrapper->field_image->alt->value(), 'foo', 'Image alt attribute has been correctly set.');
+
+    // Try saving the node and make sure the information is still there after
+    // loading the node again, thus the correct data structure has been written.
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual($wrapper->field_image->alt->value(), 'foo', 'File description has been correctly set.');
+
+    // Test adding a new image.
+    $wrapper->field_image->file = $file;
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertEqual($file->fid, $wrapper->field_image->file->getIdentifier(), 'New file has been added.');
+
+    // Test adding an invalid image-field item, i.e. without any file.
+    try {
+      $wrapper->field_image = array();
+      $this->fail('Exception not thrown.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Not valid image-field item has thrown an exception.');
+    }
+  }
+
+  /**
+   * Creates a value for the given property.
+   */
+  protected function createValue($wrapper) {
+    if (!isset($this->node)) {
+      $this->node = $this->drupalCreateNode(array('type' => 'page'));
+      $this->user = $this->drupalCreateUser();
+      $this->taxonomy_vocabulary = $this->createVocabulary();
+    }
+
+    if ($options = $wrapper->optionsList()) {
+      $options = entity_property_options_flatten($options);
+      return $wrapper instanceof EntityListWrapper ? array(key($options)) : key($options);
+    }
+
+    // For mail addresses properly pass an mail address.
+    $info = $wrapper->info();
+    if ($info['name'] == 'mail') {
+      return 'webmaster@example.com';
+    }
+
+    switch ($wrapper->type()) {
+      case 'decimal':
+      case 'integer':
+      case 'duration':
+        return 1;
+      case 'date':
+        return REQUEST_TIME;
+      case 'boolean':
+        return TRUE;
+      case 'token':
+        return drupal_strtolower($this->randomName(8));
+      case 'text':
+        return $this->randomName(32);
+      case 'text_formatted':
+        return array('value' => $this->randomName(16));
+      case 'list<taxonomy_term>':
+        return array();
+
+      default:
+        return $this->{$wrapper->type()};
+    }
+  }
+}
diff --git a/sites/all/modules/entity/entity.tpl.php b/sites/all/modules/entity/entity.tpl.php
new file mode 100644
index 0000000000000000000000000000000000000000..cfe94dd7e5f2cd095c75ad22cf04a22e62ce4be4
--- /dev/null
+++ b/sites/all/modules/entity/entity.tpl.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Default theme implementation for entities.
+ *
+ * Available variables:
+ * - $content: An array of comment items. Use render($content) to print them all, or
+ *   print a subset such as render($content['field_example']). Use
+ *   hide($content['field_example']) to temporarily suppress the printing of a
+ *   given element.
+ * - $title: The (sanitized) entity label.
+ * - $url: Direct url of the current entity if specified.
+ * - $page: Flag for the full page state.
+ * - $classes: String of classes that can be used to style contextually through
+ *   CSS. It can be manipulated through the variable $classes_array from
+ *   preprocess functions. By default the following classes are available, where
+ *   the parts enclosed by {} are replaced by the appropriate values:
+ *   - entity-{ENTITY_TYPE}
+ *   - {ENTITY_TYPE}-{BUNDLE}
+ *
+ * Other variables:
+ * - $classes_array: Array of html class attribute values. It is flattened
+ *   into a string within the variable $classes.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_entity()
+ * @see template_process()
+ */
+?>
+<div class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
+
+  <?php if (!$page): ?>
+    <h2<?php print $title_attributes; ?>>
+      <?php if ($url): ?>
+        <a href="<?php print $url; ?>"><?php print $title; ?></a>
+      <?php else: ?>
+        <?php print $title; ?>
+      <?php endif; ?>
+    </h2>
+  <?php endif; ?>
+
+  <div class="content"<?php print $content_attributes; ?>>
+    <?php
+      print render($content);
+    ?>
+  </div>
+</div>
diff --git a/sites/all/modules/entity/entity_token.info b/sites/all/modules/entity/entity_token.info
new file mode 100644
index 0000000000000000000000000000000000000000..74ffec06b7fbee244ec7a546ac0962c55929ce60
--- /dev/null
+++ b/sites/all/modules/entity/entity_token.info
@@ -0,0 +1,13 @@
+name = Entity tokens
+description = Provides token replacements for all properties that have no tokens and are known to the entity API.
+core = 7.x
+files[] = entity_token.tokens.inc
+files[] = entity_token.module
+dependencies[] = entity
+
+; Information added by drupal.org packaging script on 2012-05-25
+version = "7.x-1.0-rc3"
+core = "7.x"
+project = "entity"
+datestamp = "1337981155"
+
diff --git a/sites/all/modules/entity/entity_token.module b/sites/all/modules/entity/entity_token.module
new file mode 100644
index 0000000000000000000000000000000000000000..f0abe59e38517d3af3fa59d7b184bf66a77675ce
--- /dev/null
+++ b/sites/all/modules/entity/entity_token.module
@@ -0,0 +1,6 @@
+<?php
+
+/**
+ * @file
+ * Module file for the entity tokens module. Drupal needs this file.
+ */
diff --git a/sites/all/modules/entity/entity_token.tokens.inc b/sites/all/modules/entity/entity_token.tokens.inc
new file mode 100644
index 0000000000000000000000000000000000000000..f9ec7f7e15c46cb0eb642e32723a9e67b40cd276
--- /dev/null
+++ b/sites/all/modules/entity/entity_token.tokens.inc
@@ -0,0 +1,341 @@
+<?php
+
+/**
+ * @file
+ * Provides tokens for entity properties which have no token yet.
+ */
+
+/**
+ * Defines the types of properties to be added as token.
+ *
+ * @return
+ *   An array mapping token types to the usual (entity) type names.
+ */
+function entity_token_types() {
+  $return = entity_token_types_chained();
+  return $return + drupal_map_assoc(array('text', 'integer', 'decimal', 'duration', 'boolean', 'uri'));
+}
+
+/**
+ * Defines a list of token types that need to be chained.
+ *
+ * @return
+ *   If a (token) type is given, whether the given type needs to be chained.
+ *   Else a full list of token types to be chained as returned by
+ *   entity_token_token_types().
+ */
+function entity_token_types_chained($type = NULL) {
+  // This functions gets called rather often when replacing tokens, thus
+  // we statically cache $types using the advanced drupal static pattern.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['types'] = &drupal_static(__FUNCTION__, array());
+  }
+  $types = &$drupal_static_fast['types'];
+
+  if (!$types) {
+    // Add entities.
+    foreach (entity_get_info() as $entity_type => $info) {
+      if ($token_type = isset($info['token type']) ? $info['token type'] : $entity_type) {
+        $types[$token_type] = $entity_type;
+      }
+    }
+    // Add 'date' and 'site' tokens.
+    $types['date'] = 'date';
+    $types['site'] = 'site';
+    // Add a 'struct' type.
+    $types['struct'] = 'struct';
+  }
+
+  if (isset($type)) {
+    return isset($types[$type]) || entity_property_list_extract_type($type);
+  }
+  return $types;
+}
+
+/**
+ * Gets the right token type for a given property info array.
+ */
+function _entity_token_map_to_token_type($property_info) {
+  $lookup = &drupal_static(__FUNCTION__);
+
+  if (!$lookup) {
+    // Initialize a lookup array mapping property types to token types.
+    $lookup = array_flip(entity_token_types());
+  }
+
+  $type = isset($property_info['type']) ? $property_info['type'] : 'text';
+  // Just use the type 'struct' for all structures.
+  if (!empty($property_info['property info'])) {
+    $type = 'struct';
+  }
+
+  if ($item_type = entity_property_list_extract_type($type)) {
+    return isset($lookup[$item_type]) ? "list<$lookup[$item_type]>" : FALSE;
+  }
+  return isset($lookup[$type]) ? $lookup[$type] : FALSE;
+}
+
+/**
+ * Implements hook_token_info_alter().
+ */
+function entity_token_token_info_alter(&$info) {
+  $entity_info = entity_get_info();
+  $token_types = entity_token_types_chained();
+
+  // Loop over all chain-able token types, as those may contain further tokens,
+  // e.g. entity types or 'site'.
+  foreach ($token_types as $token_type => $type) {
+    // Just add all properties regardless whether it's in a bundle, but only if
+    // there is no token of the property yet.
+    foreach (entity_get_all_property_info($type) as $name => $property) {
+      $name = str_replace('_', '-', $name);
+      $property += array('type' => 'text', 'description' => $property['label']);
+      $property_token_type = _entity_token_map_to_token_type($property);
+
+      if (!isset($info['tokens'][$token_type][$name]) && $property_token_type) {
+
+        $info['tokens'][$token_type][$name] = array(
+          'name' => $property['label'],
+          'description' => $property['description'],
+          'type' => $property_token_type,
+          // Mark the token so we know we have to provide the value afterwards.
+          'entity-token' => TRUE,
+        );
+      }
+      if ($property_token_type == 'struct' && !empty($property['property info'])) {
+        $info['tokens'][$token_type][$name]['dynamic'] = TRUE;
+        $help = array();
+        foreach ($property['property info'] as $key => $property_info) {
+          $help[] = $key . ' (' . $property_info['label'] . ')';
+        }
+        $info['tokens'][$token_type][$name]['description'] .= ' ' . t('The following properties may be appended to the token: @keys',
+          array('@keys' => implode(', ', $help))
+        );
+      }
+    }
+  }
+
+  // Make sure all chain-able token types we support are registered.
+  foreach ($token_types as $token_type => $type) {
+
+    if (!empty($info['tokens'][$token_type]) && !isset($info['types'][$token_type])) {
+      if (isset($entity_info[$type])) {
+        $info['types'][$token_type] = array(
+          'name' => $entity_info[$type]['label'],
+          'description' => t('Tokens related to the "@name" entities.', array('@name' => $entity_info[$type]['label'])),
+          'needs-data' => $token_type,
+        );
+      }
+      else {
+        $info['types'][$token_type] = array(
+          'name' => drupal_strtoupper($token_type),
+          'description' => t('@name tokens.', array('@name' => drupal_strtoupper($token_type))),
+          'needs-data' => $token_type,
+        );
+      }
+    }
+    if (!empty($info['tokens'][$token_type]) && !isset($info['types']["list<$token_type>"]) && $token_type != 'site') {
+      if (isset($entity_info[$type])) {
+        $info['types']["list<$token_type>"] = array(
+          'name' => t('List of @entities', array('@entities' => isset($entity_info[$type]['plural label']) ? $entity_info[$type]['plural label'] : $entity_info[$type]['label'] . 's')),
+          'description' => t('Tokens related to the "@name" entities.', array('@name' => $entity_info[$type]['label'])),
+          'needs-data' => "list<$token_type>",
+        );
+      }
+      else {
+        $info['types']["list<$token_type>"] = array(
+          'name' => t('List of @type values', array('@type' => $token_type)),
+          'description' => t('Tokens for lists of @type values.', array('@type' => $token_type)),
+          'needs-data' => "list<$token_type>",
+        );
+      }
+      // Also add some basic token replacements for lists...
+      for ($i = 0; $i < 4; $i++) {
+        $info['tokens']["list<$token_type>"][$i] = array(
+          'name' => t('@type with delta @delta', array('@delta' => $i, '@type' => $info['types'][$token_type]['name'])),
+          'description' => t('The list item with delta @delta. Delta values start from 0 and are incremented by one per list item.', array('@delta' => $i)),
+          'type' => $token_type,
+        );
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function entity_token_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  $token_types = entity_token_types_chained();
+  $replacements = array();
+
+  if (isset($token_types[$type]) && (!empty($data[$type]) || $type == 'site')) {
+    $data += array($type => FALSE);
+
+    // Make use of token module's token cache if available.
+    $info = module_exists('token') ? token_get_info() : token_info();
+    foreach ($tokens as $name => $original) {
+      // Provide the token for all properties marked to stem from us.
+      if (!empty($info['tokens'][$type][$name]['entity-token']) || $type == 'struct') {
+        $wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, $token_types[$type], $data[$type], $options) : $wrapper;
+        $property_name = str_replace('-', '_', $name);
+        try {
+          $replacement = _entity_token_get_token($wrapper->$property_name, $options);
+          if (isset($replacement)) {
+            $replacements[$original] = $replacement;
+          }
+        }
+        catch (EntityMetadataWrapperException $e) {
+          // If tokens for not existing values are requested, just do nothing.
+        }
+      }
+    }
+
+    // Properly chain everything of a type marked as needs chaining.
+    $info['tokens'] += array($type => array());
+    foreach ($info['tokens'][$type] as $name => $token_info) {
+      if (!empty($token_info['entity-token']) && isset($token_info['type']) && entity_token_types_chained($token_info['type'])) {
+
+        if ($chained_tokens = token_find_with_prefix($tokens, $name)) {
+          $wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, $token_types[$type], $data[$type], $options) : $wrapper;
+          $property_name = str_replace('-', '_', $name);
+
+          try {
+            // Pass on 'struct' properties wrapped, else un-wrap the data.
+            $value = ($token_info['type'] == 'struct') ? $wrapper->$property_name : $wrapper->$property_name->value();
+            $replacements += token_generate($token_info['type'], $chained_tokens, array($token_info['type'] => $value), $options);
+          }
+          catch (EntityMetadataWrapperException $e) {
+            // If tokens for not existing values are requested, just do nothing.
+          }
+        }
+      }
+    }
+  }
+  // Add support for evaluating tokens for "list<type"> types.
+  elseif ($item_token_type = entity_property_list_extract_type($type)) {
+    foreach ($tokens as $name => $original) {
+      // Care about getting entries of a list.
+      if (is_numeric($name)) {
+        $wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, "list<$token_types[$item_token_type]>", $data[$type], $options) : $wrapper;
+        try {
+          $replacement = _entity_token_get_token($wrapper->get($name), $options);
+          if (isset($replacement)) {
+            $replacements[$original] = $replacement;
+          }
+        }
+        catch (EntityMetadataWrapperException $e) {
+          // If tokens for not existing values are requested, just do nothing.
+        }
+      }
+      // Care about generating chained tokens for list-items.
+      else {
+        $parts = explode(':', $name, 2);
+        $delta = $parts[0];
+
+        if (is_numeric($delta) && $chained_tokens = token_find_with_prefix($tokens, $delta)) {
+          $wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, "list<$token_types[$item_token_type]>", $data[$type], $options) : $wrapper;
+          try {
+            $replacements += token_generate($item_token_type, $chained_tokens, array($item_token_type => $wrapper->get($delta)->value()), $options);
+          }
+          catch (EntityMetadataWrapperException $e) {
+            // If tokens for not existing values are requested, just do nothing.
+          }
+        }
+      }
+    }
+  }
+
+  // Add support for chaining struct data. As struct data has no registered
+  // tokens, we have to chain based upon wrapper property info.
+  if ($type == 'struct') {
+    $wrapper = $data[$type];
+    foreach ($wrapper as $name => $property) {
+      $token_type = _entity_token_map_to_token_type($property->info());
+
+      if (entity_token_types_chained($token_type) && $chained_tokens = token_find_with_prefix($tokens, $name)) {
+        try {
+          // Pass on 'struct' properties wrapped, else un-wrap the data.
+          $value = ($token_type == 'struct') ? $property : $property->value();
+          $replacements += token_generate($token_type, $chained_tokens, array($token_type => $value), $options);
+        }
+        catch (EntityMetadataWrapperException $e) {
+          // If tokens for not existing values are requested, just do nothing.
+        }
+      }
+    }
+  }
+
+  return $replacements;
+}
+
+/**
+ * Wraps the given data by correctly obeying the options.
+ */
+function _entity_token_wrap_data($token_type, $type, $data, $options) {
+  if ($type == 'site') {
+    $wrapper = entity_metadata_site_wrapper();
+  }
+  elseif ($type == 'struct') {
+    // 'struct' data items are passed on wrapped.
+    $wrapper = $data;
+  }
+  else {
+    $wrapper = entity_metadata_wrapper($type, $data);
+  }
+  if (isset($options['language']) && $wrapper instanceof EntityStructureWrapper) {
+    $wrapper->language($options['language']->language);
+  }
+  return $wrapper;
+}
+
+/**
+ * Gets the token replacement by correctly obeying the options.
+ */
+function _entity_token_get_token($wrapper, $options) {
+
+  if ($wrapper->value() === NULL) {
+    // Do not provide a replacement if there is no value.
+    return NULL;
+  }
+
+  if (empty($options['sanitize'])) {
+    // When we don't need sanitized tokens decode already sanitizied texts.
+    $options['decode'] = TRUE;
+  }
+  $langcode = isset($options['language']) ? $options['language']->language : NULL;
+
+  // If there is a label for a property, e.g. defined by an options list or an
+  // entity label, make use of it.
+  if ($label = $wrapper->label()) {
+    return empty($options['sanitize']) ? $label : check_plain($label);
+  }
+
+  switch ($wrapper->type()) {
+    case 'integer':
+      return $wrapper->value();
+    case 'decimal':
+      return number_format($wrapper->value(), 2);
+    case 'date':
+      return format_date($wrapper->value(), 'medium', '', NULL, $langcode);
+    case 'duration':
+      return format_interval($wrapper->value(), 2, $langcode);
+    case 'boolean':
+      return $wrapper->value() ? t('true') : t('false');
+    case 'uri':
+    case 'text':
+      return $wrapper->value($options);
+  }
+
+  // Care for outputing list values.
+  if ($wrapper instanceof EntityListWrapper) {
+    $output = array();
+    foreach ($wrapper as $item) {
+      $output[] = _entity_token_get_token($item, $options);
+    }
+    return implode(', ', $output);
+  }
+  // Else we do not have a good string to output, e.g. for struct values. Just
+  // output the string representation of the wrapper.
+  return (string) $wrapper;
+}
diff --git a/sites/all/modules/entity/includes/entity.controller.inc b/sites/all/modules/entity/includes/entity.controller.inc
new file mode 100644
index 0000000000000000000000000000000000000000..1a2812e9c330c4376512c17e508d6c95d7e2b95b
--- /dev/null
+++ b/sites/all/modules/entity/includes/entity.controller.inc
@@ -0,0 +1,799 @@
+<?php
+
+/**
+ * @file
+ * Provides a controller building upon the core controller but providing more
+ * features like full CRUD functionality.
+ */
+
+/**
+ * Interface for EntityControllers compatible with the entity API.
+ */
+interface EntityAPIControllerInterface extends DrupalEntityControllerInterface {
+
+  /**
+   * Delete permanently saved entities.
+   *
+   * In case of failures, an exception is thrown.
+   *
+   * @param $ids
+   *   An array of entity IDs.
+   */
+  public function delete($ids);
+
+  /**
+   * Invokes a hook on behalf of the entity. For hooks that have a respective
+   * field API attacher like insert/update/.. the attacher is called too.
+   */
+  public function invoke($hook, $entity);
+
+  /**
+   * Permanently saves the given entity.
+   *
+   * In case of failures, an exception is thrown.
+   *
+   * @param $entity
+   *   The entity to save.
+   *
+   * @return
+   *   SAVED_NEW or SAVED_UPDATED is returned depending on the operation
+   *   performed.
+   */
+  public function save($entity);
+
+  /**
+   * Create a new entity.
+   *
+   * @param array $values
+   *   An array of values to set, keyed by property name.
+   * @return
+   *   A new instance of the entity type.
+   */
+  public function create(array $values = array());
+
+  /**
+   * Exports an entity as serialized string.
+   *
+   * @param $entity
+   *   The entity to export.
+   * @param $prefix
+   *   An optional prefix for each line.
+   *
+   * @return
+   *   The exported entity as serialized string. The format is determined by
+   *   the controller and has to be compatible with the format that is accepted
+   *   by the import() method.
+   */
+  public function export($entity, $prefix = '');
+
+  /**
+   * Imports an entity from a string.
+   *
+   * @param string $export
+   *   An exported entity as serialized string.
+   *
+   * @return
+   *   An entity object not yet saved.
+   */
+  public function import($export);
+
+  /**
+   * Builds a structured array representing the entity's content.
+   *
+   * The content built for the entity will vary depending on the $view_mode
+   * parameter.
+   *
+   * @param $entity
+   *   An entity object.
+   * @param $view_mode
+   *   View mode, e.g. 'full', 'teaser'...
+   * @param $langcode
+   *   (optional) A language code to use for rendering. Defaults to the global
+   *   content language of the current request.
+   * @return
+   *   The renderable array.
+   */
+  public function buildContent($entity, $view_mode = 'full', $langcode = NULL);
+
+  /**
+   * Generate an array for rendering the given entities.
+   *
+   * @param $entities
+   *   An array of entities to render.
+   * @param $view_mode
+   *   View mode, e.g. 'full', 'teaser'...
+   * @param $langcode
+   *   (optional) A language code to use for rendering. Defaults to the global
+   *   content language of the current request.
+   * @param $page
+   *   (optional) If set will control if the entity is rendered: if TRUE
+   *   the entity will be rendered without its title, so that it can be embeded
+   *   in another context. If FALSE the entity will be displayed with its title
+   *   in a mode suitable for lists.
+   *   If unset, the page mode will be enabled if the current path is the URI
+   *   of the entity, as returned by entity_uri().
+   *   This parameter is only supported for entities which controller is a
+   *   EntityAPIControllerInterface.
+   * @return
+   *   The renderable array, keyed by entity name or numeric id.
+   */
+  public function view($entities, $view_mode = 'full', $langcode = NULL, $page = NULL);
+}
+
+/**
+ * A controller implementing EntityAPIControllerInterface for the database.
+ */
+class EntityAPIController extends DrupalDefaultEntityController implements EntityAPIControllerInterface {
+
+  protected $cacheComplete = FALSE;
+  protected $bundleKey;
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController#__construct()
+   */
+  public function __construct($entityType) {
+    parent::__construct($entityType);
+    // If this is the bundle of another entity, set the bundle key.
+    if (isset($this->entityInfo['bundle of'])) {
+      $info = entity_get_info($this->entityInfo['bundle of']);
+      $this->bundleKey = $info['bundle keys']['bundle'];
+    }
+  }
+
+  /**
+   * Builds and executes the query for loading.
+   *
+   * @return The results in a Traversable object.
+   */
+  public function query($ids, $conditions, $revision_id = FALSE) {
+    // Build the query.
+    $query = $this->buildQuery($ids, $conditions, $revision_id);
+    $result = $query->execute();
+    if (!empty($this->entityInfo['entity class'])) {
+      $result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['entity class'], array(array(), $this->entityType));
+    }
+    return $result;
+  }
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController#load($ids, $conditions)
+   *
+   * In contrast to the parent implementation we factor out query execution, so
+   * fetching can be further customized easily.
+   */
+  public function load($ids = array(), $conditions = array()) {
+    $entities = array();
+
+    // Revisions are not statically cached, and require a different query to
+    // other conditions, so separate the revision id into its own variable.
+    if ($this->revisionKey && isset($conditions[$this->revisionKey])) {
+      $revision_id = $conditions[$this->revisionKey];
+      unset($conditions[$this->revisionKey]);
+    }
+    else {
+      $revision_id = FALSE;
+    }
+
+    // Create a new variable which is either a prepared version of the $ids
+    // array for later comparison with the entity cache, or FALSE if no $ids
+    // were passed. The $ids array is reduced as items are loaded from cache,
+    // and we need to know if it's empty for this reason to avoid querying the
+    // database when all requested entities are loaded from cache.
+    $passed_ids = !empty($ids) ? array_flip($ids) : FALSE;
+
+    // Try to load entities from the static cache.
+    if ($this->cache && !$revision_id) {
+      $entities = $this->cacheGet($ids, $conditions);
+      // If any entities were loaded, remove them from the ids still to load.
+      if ($passed_ids) {
+        $ids = array_keys(array_diff_key($passed_ids, $entities));
+      }
+    }
+
+    // Support the entitycache module if activated.
+    if (!empty($this->entityInfo['entity cache']) && !$revision_id && $ids && !$conditions) {
+      $cached_entities = EntityCacheControllerHelper::entityCacheGet($this, $ids, $conditions);
+      // If any entities were loaded, remove them from the ids still to load.
+      $ids = array_diff($ids, array_keys($cached_entities));
+      $entities += $cached_entities;
+
+      // Add loaded entities to the static cache if we are not loading a
+      // revision.
+      if ($this->cache && !empty($cached_entities) && !$revision_id) {
+        $this->cacheSet($cached_entities);
+      }
+    }
+
+    // Load any remaining entities from the database. This is the case if $ids
+    // is set to FALSE (so we load all entities), if there are any ids left to
+    // load or if loading a revision.
+    if (!($this->cacheComplete && $ids === FALSE && !$conditions) && ($ids === FALSE || $ids || $revision_id)) {
+      $queried_entities = array();
+      foreach ($this->query($ids, $conditions, $revision_id) as $record) {
+        // Skip entities already retrieved from cache.
+        if (isset($entities[$record->{$this->idKey}])) {
+          continue;
+        }
+
+        // For DB-based entities take care of serialized columns.
+        if (!empty($this->entityInfo['base table'])) {
+          $schema = drupal_get_schema($this->entityInfo['base table']);
+
+          foreach ($schema['fields'] as $field => $info) {
+            if (!empty($info['serialize']) && isset($record->$field)) {
+              $record->$field = unserialize($record->$field);
+              // Support automatic merging of 'data' fields into the entity.
+              if (!empty($info['merge']) && is_array($record->$field)) {
+                foreach ($record->$field as $key => $value) {
+                  $record->$key = $value;
+                }
+                unset($record->$field);
+              }
+            }
+          }
+        }
+
+        $queried_entities[$record->{$this->idKey}] = $record;
+      }
+    }
+
+    // Pass all entities loaded from the database through $this->attachLoad(),
+    // which attaches fields (if supported by the entity type) and calls the
+    // entity type specific load callback, for example hook_node_load().
+    if (!empty($queried_entities)) {
+      $this->attachLoad($queried_entities, $revision_id);
+      $entities += $queried_entities;
+    }
+
+    // Entitycache module support: Add entities to the entity cache if we are
+    // not loading a revision.
+    if (!empty($this->entityInfo['entity cache']) && !empty($queried_entities) && !$revision_id) {
+      EntityCacheControllerHelper::entityCacheSet($this, $queried_entities);
+    }
+
+    if ($this->cache) {
+      // Add entities to the cache if we are not loading a revision.
+      if (!empty($queried_entities) && !$revision_id) {
+        $this->cacheSet($queried_entities);
+
+        // Remember if we have cached all entities now.
+        if (!$conditions && $ids === FALSE) {
+          $this->cacheComplete = TRUE;
+        }
+      }
+    }
+    // Ensure that the returned array is ordered the same as the original
+    // $ids array if this was passed in and remove any invalid ids.
+    if ($passed_ids && $passed_ids = array_intersect_key($passed_ids, $entities)) {
+      foreach ($passed_ids as $id => $value) {
+        $passed_ids[$id] = $entities[$id];
+      }
+      $entities = $passed_ids;
+    }
+    return $entities;
+  }
+
+  public function resetCache(array $ids = NULL) {
+    $this->cacheComplete = FALSE;
+    parent::resetCache($ids);
+    // Support the entitycache module.
+    if (!empty($this->entityInfo['entity cache'])) {
+      EntityCacheControllerHelper::resetEntityCache($this, $ids);
+    }
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   */
+  public function invoke($hook, $entity) {
+    if (!empty($this->entityInfo['fieldable']) && function_exists($function = 'field_attach_' . $hook)) {
+      $function($this->entityType, $entity);
+    }
+
+    if (!empty($this->entityInfo['bundle of']) && entity_type_is_fieldable($this->entityInfo['bundle of'])) {
+      $type = $this->entityInfo['bundle of'];
+      // Call field API bundle attachers for the entity we are a bundle of.
+      if ($hook == 'insert') {
+        field_attach_create_bundle($type, $entity->{$this->bundleKey});
+      }
+      elseif ($hook == 'delete') {
+        field_attach_delete_bundle($type, $entity->{$this->bundleKey});
+      }
+      elseif ($hook == 'update' && $entity->original->{$this->bundleKey} != $entity->{$this->bundleKey}) {
+        field_attach_rename_bundle($type, $entity->original->{$this->bundleKey}, $entity->{$this->bundleKey});
+      }
+    }
+    // Invoke the hook.
+    module_invoke_all($this->entityType . '_' . $hook, $entity);
+    // Invoke the respective entity level hook.
+    if ($hook == 'presave' || $hook == 'insert' || $hook == 'update' || $hook == 'delete') {
+      module_invoke_all('entity_' . $hook, $entity, $this->entityType);
+    }
+    // Invoke rules.
+    if (module_exists('rules')) {
+      rules_invoke_event($this->entityType . '_' . $hook, $entity);
+    }
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @param $transaction
+   *   Optionally a DatabaseTransaction object to use. Allows overrides to pass
+   *   in their transaction object.
+   */
+  public function delete($ids, DatabaseTransaction $transaction = NULL) {
+    $entities = $ids ? $this->load($ids) : FALSE;
+    if (!$entities) {
+      // Do nothing, in case invalid or no ids have been passed.
+      return;
+    }
+    // This transaction causes troubles on MySQL, see
+    // http://drupal.org/node/1007830. So we deactivate this by default until
+    // is shipped in a point release.
+    // $transaction = isset($transaction) ? $transaction : db_transaction();
+
+    try {
+      $ids = array_keys($entities);
+
+      db_delete($this->entityInfo['base table'])
+        ->condition($this->idKey, $ids, 'IN')
+        ->execute();
+      // Reset the cache as soon as the changes have been applied.
+      $this->resetCache($ids);
+
+      foreach ($entities as $id => $entity) {
+        $this->invoke('delete', $entity);
+      }
+      // Ignore slave server temporarily.
+      db_ignore_slave();
+    }
+    catch (Exception $e) {
+      if (isset($transaction)) {
+        $transaction->rollback();
+      }
+      watchdog_exception($this->entityType, $e);
+      throw $e;
+    }
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @param $transaction
+   *   Optionally a DatabaseTransaction object to use. Allows overrides to pass
+   *   in their transaction object.
+   */
+  public function save($entity, DatabaseTransaction $transaction = NULL) {
+    $transaction = isset($transaction) ? $transaction : db_transaction();
+    try {
+      // Load the stored entity, if any.
+      if (!empty($entity->{$this->idKey}) && !isset($entity->original)) {
+        // In order to properly work in case of name changes, load the original
+        // entity using the id key if it is available.
+        $entity->original = entity_load_unchanged($this->entityType, $entity->{$this->idKey});
+      }
+
+      $this->invoke('presave', $entity);
+
+      if (!empty($entity->{$this->idKey}) && empty($entity->is_new)) {
+        $return = drupal_write_record($this->entityInfo['base table'], $entity, $this->idKey);
+        $this->resetCache(array($entity->{$this->idKey}));
+        $this->invoke('update', $entity);
+      }
+      else {
+        $return = drupal_write_record($this->entityInfo['base table'], $entity);
+        $this->invoke('insert', $entity);
+      }
+      // Ignore slave server temporarily.
+      db_ignore_slave();
+      unset($entity->is_new);
+      unset($entity->original);
+
+      return $return;
+    }
+    catch (Exception $e) {
+      $transaction->rollback();
+      watchdog_exception($this->entityType, $e);
+      throw $e;
+    }
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   */
+  public function create(array $values = array()) {
+    // Add is_new property if it is not set.
+    $values += array('is_new' => TRUE);
+    if (isset($this->entityInfo['entity class']) && $class = $this->entityInfo['entity class']) {
+      return new $class($values, $this->entityType);
+    }
+    return (object) $values;
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @return
+   *   A serialized string in JSON format suitable for the import() method.
+   */
+  public function export($entity, $prefix = '') {
+    $vars = get_object_vars($entity);
+    unset($vars['is_new']);
+    return entity_var_json_export($vars, $prefix);
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @param $export
+   *   A serialized string in JSON format as produced by the export() method.
+   */
+  public function import($export) {
+    $vars = drupal_json_decode($export);
+    if (is_array($vars)) {
+      return $this->create($vars);
+    }
+    return FALSE;
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @param $content
+   *   Optionally. Allows pre-populating the built content to ease overridding
+   *   this method.
+   */
+  public function buildContent($entity, $view_mode = 'full', $langcode = NULL, $content = array()) {
+    // Remove previously built content, if exists.
+    $entity->content = $content;
+    $langcode = isset($langcode) ? $langcode : $GLOBALS['language_content']->language;
+
+    // Add in fields.
+    if (!empty($this->entityInfo['fieldable'])) {
+      // Perform the preparation tasks if they have not been performed yet.
+      // An internal flag prevents the operation from running twice.
+      $key = isset($entity->{$this->idKey}) ? $entity->{$this->idKey} : NULL;
+      field_attach_prepare_view($this->entityType, array($key => $entity), $view_mode);
+      $entity->content += field_attach_view($this->entityType, $entity, $view_mode, $langcode);
+    }
+    // Invoke hook_ENTITY_view() to allow modules to add their additions.
+    if (module_exists('rules')) {
+      rules_invoke_all($this->entityType . '_view', $entity, $view_mode, $langcode);
+    }
+    else {
+      module_invoke_all($this->entityType . '_view', $entity, $view_mode, $langcode);
+    }
+    module_invoke_all('entity_view', $entity, $this->entityType, $view_mode, $langcode);
+    $build = $entity->content;
+    unset($entity->content);
+    return $build;
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   */
+  public function view($entities, $view_mode = 'full', $langcode = NULL, $page = NULL) {
+    // For Field API and entity_prepare_view, the entities have to be keyed by
+    // (numeric) id.
+    $entities = entity_key_array_by_property($entities, $this->idKey);
+    if (!empty($this->entityInfo['fieldable'])) {
+      field_attach_prepare_view($this->entityType, $entities, $view_mode);
+    }
+    entity_prepare_view($this->entityType, $entities);
+    $langcode = isset($langcode) ? $langcode : $GLOBALS['language_content']->language;
+
+    $view = array();
+    foreach ($entities as $entity) {
+      $build = entity_build_content($this->entityType, $entity, $view_mode, $langcode);
+      $build += array(
+        // If the entity type provides an implementation, use this instead the
+        // generic one.
+        // @see template_preprocess_entity()
+        '#theme' => 'entity',
+        '#entity_type' => $this->entityType,
+        '#entity' => $entity,
+        '#view_mode' => $view_mode,
+        '#language' => $langcode,
+        '#page' => $page,
+      );
+      // Allow modules to modify the structured entity.
+      drupal_alter(array($this->entityType . '_view', 'entity_view'), $build, $this->entityType);
+      $key = isset($entity->{$this->idKey}) ? $entity->{$this->idKey} : NULL;
+      $view[$this->entityType][$key] = $build;
+    }
+    return $view;
+  }
+}
+
+/**
+ * A controller implementing exportables stored in the database.
+ */
+class EntityAPIControllerExportable extends EntityAPIController {
+
+  protected $entityCacheByName = array();
+  protected $nameKey, $statusKey, $moduleKey;
+
+  /**
+   * Overridden.
+   *
+   * Allows specifying a name key serving as uniform identifier for this entity
+   * type while still internally we are using numeric identifieres.
+   */
+  public function __construct($entityType) {
+    parent::__construct($entityType);
+    // Use the name key as primary identifier.
+    $this->nameKey = isset($this->entityInfo['entity keys']['name']) ? $this->entityInfo['entity keys']['name'] : $this->idKey;
+    if (!empty($this->entityInfo['exportable'])) {
+      $this->statusKey = isset($this->entityInfo['entity keys']['status']) ? $this->entityInfo['entity keys']['status'] : 'status';
+      $this->moduleKey = isset($this->entityInfo['entity keys']['module']) ? $this->entityInfo['entity keys']['module'] : 'module';
+    }
+  }
+
+  /**
+   * Support loading by name key.
+   */
+  protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
+    // Add the id condition ourself, as we might have a separate name key.
+    $query = parent::buildQuery(array(), $conditions, $revision_id);
+    if ($ids) {
+      // Support loading by numeric ids as well as by machine names.
+      $key = is_numeric(reset($ids)) ? $this->idKey : $this->nameKey;
+      $query->condition("base.$key", $ids, 'IN');
+    }
+    return $query;
+  }
+
+  /**
+   * Overridden to support passing numeric ids as well as names as $ids.
+   */
+  public function load($ids = array(), $conditions = array()) {
+    $entities = array();
+
+    // Only do something if loaded by names.
+    if (!$ids || $this->nameKey == $this->idKey || is_numeric(reset($ids))) {
+      return parent::load($ids, $conditions);
+    }
+
+    // Revisions are not statically cached, and require a different query to
+    // other conditions, so separate the revision id into its own variable.
+    if ($this->revisionKey && isset($conditions[$this->revisionKey])) {
+      $revision_id = $conditions[$this->revisionKey];
+      unset($conditions[$this->revisionKey]);
+    }
+    else {
+      $revision_id = FALSE;
+    }
+    $passed_ids = !empty($ids) ? array_flip($ids) : FALSE;
+
+    // Care about the static cache.
+    if ($this->cache && !$revision_id) {
+      $entities = $this->cacheGetByName($ids, $conditions);
+    }
+    // If any entities were loaded, remove them from the ids still to load.
+    if ($entities) {
+      $ids = array_keys(array_diff_key($passed_ids, $entities));
+    }
+
+    $entities_by_id = parent::load($ids, $conditions);
+    $entities += entity_key_array_by_property($entities_by_id, $this->nameKey);
+
+    // Ensure that the returned array is keyed by numeric id and ordered the
+    // same as the original $ids array and remove any invalid ids.
+    $return = array();
+    foreach ($passed_ids as $name => $value) {
+      if (isset($entities[$name])) {
+        $return[$entities[$name]->{$this->idKey}] = $entities[$name];
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController::cacheGet()
+   */
+  protected function cacheGet($ids, $conditions = array()) {
+    if (!empty($this->entityCache) && $ids !== array()) {
+      $entities = $ids ? array_intersect_key($this->entityCache, array_flip($ids)) : $this->entityCache;
+      return $this->applyConditions($entities, $conditions);
+    }
+    return array();
+  }
+
+  /**
+   * Like cacheGet() but keyed by name.
+   */
+  protected function cacheGetByName($names, $conditions = array()) {
+    if (!empty($this->entityCacheByName) && $names !== array() && $names) {
+      // First get the entities by ids, then apply the conditions.
+      // Generally, we make use of $this->entityCache, but if we are loading by
+      // name, we have to use $this->entityCacheByName.
+      $entities = array_intersect_key($this->entityCacheByName, array_flip($names));
+      return $this->applyConditions($entities, $conditions);
+    }
+    return array();
+  }
+
+  protected function applyConditions($entities, $conditions = array()) {
+    if ($conditions) {
+      foreach ($entities as $key => $entity) {
+        $entity_values = (array) $entity;
+        if (array_diff_assoc($conditions, $entity_values)) {
+          unset($entities[$key]);
+        }
+      }
+    }
+    return $entities;
+  }
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController::cacheSet()
+   */
+  protected function cacheSet($entities) {
+    $this->entityCache += $entities;
+    // If we have a name key, also support static caching when loading by name.
+    if ($this->nameKey != $this->idKey) {
+      $this->entityCacheByName += entity_key_array_by_property($entities, $this->nameKey);
+    }
+  }
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController::attachLoad()
+   *
+   * Changed to call type-specific hook with the entities keyed by name if they
+   * have one.
+   */
+  protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
+    // Attach fields.
+    if ($this->entityInfo['fieldable']) {
+      if ($revision_id) {
+        field_attach_load_revision($this->entityType, $queried_entities);
+      }
+      else {
+        field_attach_load($this->entityType, $queried_entities);
+      }
+    }
+
+    // Call hook_entity_load().
+    foreach (module_implements('entity_load') as $module) {
+      $function = $module . '_entity_load';
+      $function($queried_entities, $this->entityType);
+    }
+    // Call hook_TYPE_load(). The first argument for hook_TYPE_load() are
+    // always the queried entities, followed by additional arguments set in
+    // $this->hookLoadArguments.
+    // For entities with a name key, pass the entities keyed by name to the
+    // specific load hook.
+    if ($this->nameKey != $this->idKey) {
+      $entities_by_name = entity_key_array_by_property($queried_entities, $this->nameKey);
+    }
+    else {
+      $entities_by_name = $queried_entities;
+    }
+    $args = array_merge(array($entities_by_name), $this->hookLoadArguments);
+    foreach (module_implements($this->entityInfo['load hook']) as $module) {
+      call_user_func_array($module . '_' . $this->entityInfo['load hook'], $args);
+    }
+  }
+
+  public function resetCache(array $ids = NULL) {
+    $this->cacheComplete = FALSE;
+    if (isset($ids)) {
+      foreach (array_intersect_key($this->entityCache, array_flip($ids)) as $id => $entity) {
+        unset($this->entityCacheByName[$this->entityCache[$id]->{$this->nameKey}]);
+        unset($this->entityCache[$id]);
+      }
+    }
+    else {
+      $this->entityCache = array();
+      $this->entityCacheByName = array();
+    }
+  }
+
+  /**
+   * Overridden to care about reverted entities.
+   */
+  public function delete($ids, DatabaseTransaction $transaction = NULL) {
+    $entities = $ids ? $this->load($ids) : FALSE;
+    if ($entities) {
+      parent::delete($ids, $transaction);
+
+      foreach ($entities as $id => $entity) {
+        if (entity_has_status($this->entityType, $entity, ENTITY_IN_CODE)) {
+          entity_defaults_rebuild(array($this->entityType));
+          break;
+        }
+      }
+    }
+  }
+
+  /**
+   * Overridden to care about reverted bundle entities and to skip Rules.
+   */
+  public function invoke($hook, $entity) {
+    if ($hook == 'delete') {
+      // To ease figuring out whether this is a revert, make sure that the
+      // entity status is updated in case the providing module has been
+      // disabled.
+      if (entity_has_status($this->entityType, $entity, ENTITY_IN_CODE) && !module_exists($entity->{$this->moduleKey})) {
+        $entity->{$this->statusKey} = ENTITY_CUSTOM;
+      }
+      $is_revert = entity_has_status($this->entityType, $entity, ENTITY_IN_CODE);
+    }
+
+    if (!empty($this->entityInfo['fieldable']) && function_exists($function = 'field_attach_' . $hook)) {
+      $function($this->entityType, $entity);
+    }
+
+    if (isset($this->entityInfo['bundle of']) && $type = $this->entityInfo['bundle of']) {
+      // Call field API bundle attachers for the entity we are a bundle of.
+      if ($hook == 'insert') {
+        field_attach_create_bundle($type, $entity->{$this->bundleKey});
+      }
+      elseif ($hook == 'delete' && !$is_revert) {
+        field_attach_delete_bundle($type, $entity->{$this->bundleKey});
+      }
+      elseif ($hook == 'update' && $id = $entity->{$this->nameKey}) {
+        if ($entity->original->{$this->bundleKey} != $entity->{$this->bundleKey}) {
+          field_attach_rename_bundle($type, $entity->original->{$this->bundleKey}, $entity->{$this->bundleKey});
+        }
+      }
+    }
+    // Invoke the hook.
+    module_invoke_all($this->entityType . '_' . $hook, $entity);
+    // Invoke the respective entity level hook.
+    if ($hook == 'presave' || $hook == 'insert' || $hook == 'update' || $hook == 'delete') {
+      module_invoke_all('entity_' . $hook, $entity, $this->entityType);
+    }
+  }
+
+  /**
+   * Overridden to care exportables that are overridden.
+   */
+  public function save($entity, DatabaseTransaction $transaction = NULL) {
+    // Preload $entity->original by name key if necessary.
+    if (!empty($entity->{$this->nameKey}) && empty($entity->{$this->idKey}) && !isset($entity->original)) {
+      $entity->original = entity_load_unchanged($this->entityType, $entity->{$this->nameKey});
+    }
+    // Update the status for entities getting overridden.
+    if (entity_has_status($this->entityType, $entity, ENTITY_IN_CODE) && empty($entity->is_rebuild)) {
+      $entity->{$this->statusKey} |= ENTITY_CUSTOM;
+    }
+    return parent::save($entity, $transaction);
+  }
+
+  /**
+   * Overridden.
+   */
+  public function export($entity, $prefix = '') {
+    $vars = get_object_vars($entity);
+    unset($vars[$this->statusKey], $vars[$this->moduleKey], $vars['is_new']);
+    if ($this->nameKey != $this->idKey) {
+      unset($vars[$this->idKey]);
+    }
+    return entity_var_json_export($vars, $prefix);
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   */
+  public function view($entities, $view_mode = 'full', $langcode = NULL, $page = NULL) {
+    $view = parent::view($entities, $view_mode, $langcode, $page);
+
+    if ($this->nameKey != $this->idKey) {
+      // Re-key the view array to be keyed by name.
+      $return = array();
+      foreach ($view[$this->entityType] as $id => $content) {
+        $key = isset($content['#entity']->{$this->nameKey}) ? $content['#entity']->{$this->nameKey} : NULL;
+        $return[$this->entityType][$key] = $content;
+      }
+      $view = $return;
+    }
+    return $view;
+  }
+}
diff --git a/sites/all/modules/entity/includes/entity.inc b/sites/all/modules/entity/includes/entity.inc
new file mode 100644
index 0000000000000000000000000000000000000000..90a53c48b5ff205f6f7f595e675b0a1e5125b881
--- /dev/null
+++ b/sites/all/modules/entity/includes/entity.inc
@@ -0,0 +1,295 @@
+<?php
+
+/**
+ * @file
+ * Provides a base class for entities.
+ */
+
+/**
+ * A common class for entities.
+ *
+ * It's suggested, but not required, to extend this class and to override
+ * __construct() in order to specify a fixed entity type.
+ *
+ * For providing an entity label and URI it is suggested to override the
+ * defaultLabel() and defaultUri() methods, and to specify the
+ * entity_class_label() and entity_class_uri() as respective callbacks in
+ * hook_entity_info(). That way modules are able to override your defaults
+ * by altering the hook_entity_info() callbacks, while $entity->label() and
+ * $entity->uri() reflect this changes as well.
+ *
+ * Defaults for entity properties can be easily defined by adding class
+ * properties, e.g.:
+ * @code
+ *   public $name = '';
+ *   public $count = 0;
+ * @endcode
+ */
+class Entity {
+
+  protected $entityType;
+  protected $entityInfo;
+  protected $idKey, $nameKey, $statusKey;
+
+  /**
+   * Creates a new entity.
+   *
+   * @see entity_create()
+   */
+  public function __construct(array $values = array(), $entityType = NULL) {
+    if (empty($entityType)) {
+      throw new Exception('Cannot create an instance of Entity without a specified entity type.');
+    }
+    $this->entityType = $entityType;
+    $this->setUp();
+    // Set initial values.
+    foreach ($values as $key => $value) {
+      $this->$key = $value;
+    }
+  }
+
+  /**
+   * Set up the object instance on construction or unserializiation.
+   */
+  protected function setUp() {
+    $this->entityInfo = entity_get_info($this->entityType);
+    $this->idKey = $this->entityInfo['entity keys']['id'];
+    $this->nameKey = isset($this->entityInfo['entity keys']['name']) ? $this->entityInfo['entity keys']['name'] : $this->idKey;
+    $this->statusKey = empty($info['entity keys']['status']) ? 'status' : $info['entity keys']['status'];
+  }
+
+  /**
+   * Returns the internal, numeric identifier.
+   *
+   * Returns the numeric identifier, even if the entity type has specified a
+   * name key. In the latter case, the numeric identifier is supposed to be used
+   * when dealing generically with entities or internally to refer to an entity,
+   * i.e. in a relational database. If unsure, use Entity:identifier().
+   */
+  public function internalIdentifier() {
+    return isset($this->{$this->idKey}) ? $this->{$this->idKey} : NULL;
+  }
+
+  /**
+   * Returns the entity identifier, i.e. the entities name or numeric id.
+   *
+   * @return
+   *   The identifier of the entity. If the entity type makes use of a name key,
+   *   the name is returned, else the numeric id.
+   *
+   * @see entity_id()
+   */
+  public function identifier() {
+    return isset($this->{$this->nameKey}) ? $this->{$this->nameKey} : NULL;
+  }
+
+  /**
+   * Returns the info of the type of the entity.
+   *
+   * @see entity_get_info()
+   */
+  public function entityInfo() {
+    return $this->entityInfo;
+  }
+
+  /**
+   * Returns the type of the entity.
+   */
+  public function entityType() {
+    return $this->entityType;
+  }
+
+  /**
+   * Returns the bundle of the entity.
+   *
+   * @return
+   *   The bundle of the entity. Defaults to the entity type if the entity type
+   *   does not make use of different bundles.
+   */
+  public function bundle() {
+    return !empty($this->entityInfo['entity keys']['bundle']) ? $this->{$this->entityInfo['entity keys']['bundle']} : $this->entityType;
+  }
+
+  /**
+   * Returns the label of the entity.
+   *
+   * Modules may alter the label by specifying another 'label callback' using
+   * hook_entity_info_alter().
+   *
+   * @see entity_label()
+   */
+  public function label() {
+    if (isset($this->entityInfo['label callback']) && $this->entityInfo['label callback'] == 'entity_class_label') {
+      return $this->defaultLabel();
+    }
+    return entity_label($this->entityType, $this);
+  }
+
+  /**
+   * Defines the entity label if the 'entity_class_label' callback is used.
+   *
+   * Specify 'entity_class_label' as 'label callback' in hook_entity_info() to
+   * let the entity label point to this method. Override this in order to
+   * implement a custom default label.
+   */
+  protected function defaultLabel() {
+    // Add in the translated specified label property.
+    return $this->getTranslation($this->entityInfo['entity keys']['label']);
+  }
+
+  /**
+   * Returns the uri of the entity just as entity_uri().
+   *
+   * Modules may alter the uri by specifying another 'uri callback' using
+   * hook_entity_info_alter().
+   *
+   * @see entity_uri()
+   */
+  public function uri() {
+    if (isset($this->entityInfo['uri callback']) && $this->entityInfo['uri callback'] == 'entity_class_uri') {
+      return $this->defaultUri();
+    }
+    return entity_uri($this->entityType, $this);
+  }
+
+  /**
+   * Override this in order to implement a custom default URI and specify
+   * 'entity_class_uri' as 'uri callback' hook_entity_info().
+   */
+  protected function defaultUri() {
+    return array('path' => 'default/' . $this->identifier());
+  }
+
+  /**
+   * Checks if the entity has a certain exportable status.
+   *
+   * @param $status
+   *   A status constant, i.e. one of ENTITY_CUSTOM, ENTITY_IN_CODE,
+   *   ENTITY_OVERRIDDEN or ENTITY_FIXED.
+   *
+   * @return
+   *   For exportable entities TRUE if the entity has the status, else FALSE.
+   *   In case the entity is not exportable, NULL is returned.
+   *
+   * @see entity_has_status()
+   */
+  public function hasStatus($status) {
+    if (!empty($this->entityInfo['exportable'])) {
+      return isset($this->{$this->statusKey}) && ($this->{$this->statusKey} & $status) == $status;
+    }
+  }
+
+  /**
+   * Permanently saves the entity.
+   *
+   * @see entity_save()
+   */
+  public function save() {
+    return entity_get_controller($this->entityType)->save($this);
+  }
+
+  /**
+   * Permanently deletes the entity.
+   *
+   * @see entity_delete()
+   */
+  public function delete() {
+    $id = $this->identifier();
+    if (isset($id)) {
+      entity_get_controller($this->entityType)->delete(array($id));
+    }
+  }
+
+  /**
+   * Exports the entity.
+   *
+   * @see entity_export()
+   */
+  public function export($prefix = '') {
+    return entity_get_controller($this->entityType)->export($this, $prefix);
+  }
+
+  /**
+   * Generate an array for rendering the entity.
+   *
+   * @see entity_view()
+   */
+  public function view($view_mode = 'full', $langcode = NULL, $page = NULL) {
+    return entity_get_controller($this->entityType)->view(array($this), $view_mode, $langcode, $page);
+  }
+
+  /**
+   * Builds a structured array representing the entity's content.
+   *
+   * @see entity_build_content()
+   */
+  public function buildContent($view_mode = 'full', $langcode = NULL) {
+    return entity_get_controller($this->entityType)->buildContent($this, $view_mode, $langcode);
+  }
+
+  /**
+   * Gets the raw, translated value of a property or field.
+   *
+   * Supports retrieving field translations as well as i18n string translations.
+   *
+   * Note that this returns raw data values, which might not reflect what
+   * has been declared for hook_entity_property_info() as no 'getter callbacks'
+   * are invoked or no referenced entities are loaded. For retrieving values
+   * reflecting the property info make use of entity metadata wrappers, see
+   * entity_metadata_wrapper().
+   *
+   * @param $property_name
+   *   The name of the property to return; e.g., 'title'.
+   * @param $langcode
+   *   (optional) The language code of the language to which the value should
+   *   be translated. If set to NULL, the default display language is being
+   *   used.
+   *
+   * @return
+   *   The raw, translated property value; or the raw, un-translated value if no
+   *   translation is available.
+   *
+   * @todo Implement an analogous setTranslation() method for updating.
+   */
+  public function getTranslation($property, $langcode = NULL) {
+    $all_info = entity_get_all_property_info($this->entityType);
+    $property_info = $all_info[$property];
+
+    if (!empty($property_info['translatable'])) {
+      if (!empty($property_info['field'])) {
+        return field_get_items($this->entityType, $this, $property, $langcode);
+      }
+      elseif (!empty($property_info['i18n string'])) {
+        $name = $this->entityInfo['module'] . ':' . $this->entityType . ':' . $this->identifier() . ':' . $property;
+        return entity_i18n_string($name, $this->$property, $langcode);
+      }
+    }
+    return $this->$property;
+  }
+
+  /**
+   * Magic method to only serialize what's necessary.
+   */
+  public function __sleep() {
+    $vars = get_object_vars($this);
+    unset($vars['entityInfo'], $vars['idKey'], $vars['nameKey'], $vars['statusKey']);
+    // Also key the returned array with the variable names so the method may
+    // be easily overridden and customized.
+    return drupal_map_assoc(array_keys($vars));
+  }
+
+  /**
+   * Magic method to invoke setUp() on unserialization.
+   */
+  public function __wakeup() {
+    $this->setUp();
+  }
+}
+
+/**
+ * These classes are deprecated by "Entity" and are only here for backward
+ * compatibility reasons.
+ */
+class EntityDB extends Entity {}
+class EntityExtendable extends Entity {}
+class EntityDBExtendable extends Entity {}
diff --git a/sites/all/modules/entity/includes/entity.property.inc b/sites/all/modules/entity/includes/entity.property.inc
new file mode 100644
index 0000000000000000000000000000000000000000..7b1dac7053e9434ad0e2ece6f4134163c8f3c038
--- /dev/null
+++ b/sites/all/modules/entity/includes/entity.property.inc
@@ -0,0 +1,646 @@
+<?php
+
+/**
+ * @file
+ * Provides API functions around hook_entity_property_info(). Also see
+ * entity.info.inc, which cares for providing entity property info for all core
+ * entity types.
+ */
+
+/**
+ * Get the entity property info array of an entity type.
+ *
+ * @param $entity_type
+ *   The entity type, e.g. node, for which the info shall be returned, or NULL
+ *   to return an array with info about all types.
+ *
+ * @see hook_entity_property_info()
+ * @see hook_entity_property_info_alter()
+ */
+function entity_get_property_info($entity_type = NULL) {
+  // Use the advanced drupal_static() pattern, since this is called very often.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['info'] = &drupal_static(__FUNCTION__);
+  }
+  $info = &$drupal_static_fast['info'];
+
+  // hook_entity_property_info() includes translated strings, so each language
+  // is cached separately.
+  $langcode = $GLOBALS['language']->language;
+
+  if (empty($info)) {
+    if ($cache = cache_get("entity_property_info:$langcode")) {
+      $info = $cache->data;
+    }
+    else {
+      $info = module_invoke_all('entity_property_info');
+      // Let other modules alter the entity info.
+      drupal_alter('entity_property_info', $info);
+      cache_set("entity_property_info:$langcode", $info);
+    }
+  }
+  return empty($entity_type) ? $info : (isset($info[$entity_type]) ? $info[$entity_type] : array());
+}
+
+/**
+ * Returns the default information for an entity property.
+ *
+ * @return
+ *   An array of optional property information keys mapped to their defaults.
+ *
+ * @see hook_entity_property_info()
+ */
+function entity_property_info_defaults() {
+  return array(
+    'type' => 'text',
+    'getter callback' => 'entity_property_verbatim_get',
+  );
+}
+
+/**
+ * Gets an array of info about all properties of a given entity type.
+ *
+ * In contrast to entity_get_property_info(), this function returns info about
+ * all properties the entity might have, thus it adds an all properties assigned
+ * to entity bundles.
+ *
+ * @param $entity_type
+ *   (optiona) The entity type to return properties for.
+ *
+ * @return
+ *   An array of info about properties. If the type is ommitted, all known
+ *   properties are returned.
+ */
+function entity_get_all_property_info($entity_type = NULL) {
+  if (!isset($entity_type)) {
+    // Retrieve all known properties.
+    $properties = array();
+    foreach (entity_get_info() as $entity_type => $info) {
+      $properties += entity_get_all_property_info($entity_type);
+    }
+    return $properties;
+  }
+  // Else retrieve the properties of the given entity type only.
+  $info = entity_get_property_info($entity_type);
+  $info += array('properties' => array(), 'bundles' => array());
+  // Add all bundle properties.
+  foreach ($info['bundles'] as $bundle => $bundle_info) {
+    $bundle_info += array('properties' => array());
+    $info['properties'] += $bundle_info['properties'];
+  }
+  return $info['properties'];
+}
+
+/**
+ * Queries for entities having the given property value.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $property
+ *   The name of the property to query for.
+ * @param $value
+ *   A single property value or an array of possible values to query for.
+ * @param $limit
+ *   Limit the numer of results. Defaults to 30.
+ *
+ * @return
+ *   An array of entity ids or NULL if there is no information how to query for
+ *   the given property.
+ */
+function entity_property_query($entity_type, $property, $value, $limit = 30) {
+  $properties = entity_get_all_property_info($entity_type);
+  $info = $properties[$property] + array('type' => 'text', 'queryable' => !empty($properties[$property]['schema field']));
+
+  // We still support the deprecated query callback, so just add in EFQ-based
+  // callbacks in case 'queryable' is set to TRUE and make use of the callback.
+  if ($info['queryable'] && empty($info['query callback'])) {
+    $info['query callback'] = !empty($info['field']) ? 'entity_metadata_field_query' : 'entity_metadata_table_query';
+  }
+
+  $type = $info['type'];
+  // Make sure an entity or a list of entities are passed on as identifiers
+  // with the help of the wrappers. For that ensure the data type matches the
+  // passed on value(s).
+  if (is_array($value) && !entity_property_list_extract_type($type)) {
+    $type = 'list<' . $type . '>';
+  }
+  elseif (!is_array($value) && entity_property_list_extract_type($type)) {
+    $type = entity_property_list_extract_type($type);
+  }
+
+  $wrapper = entity_metadata_wrapper($type, $value);
+  $value = $wrapper->value(array('identifier' => TRUE));
+
+  if (!empty($info['query callback'])) {
+    return $info['query callback']($entity_type, $property, $value, $limit);
+  }
+}
+
+/**
+ * Resets the cached information of hook_entity_property_info().
+ */
+function entity_property_info_cache_clear() {
+  drupal_static_reset('entity_get_property_info');
+  // Clear all languages.
+  cache_clear_all('entity_property_info:', 'cache', TRUE);
+}
+
+/**
+ * Implements hook_hook_info().
+ */
+function entity_hook_info() {
+  $hook_info['entity_property_info'] = array(
+    'group' => 'info',
+  );
+  $hook_info['entity_property_info_alter'] = array(
+    'group' => 'info',
+  );
+  return $hook_info;
+}
+
+/**
+ * Implements hook_field_info_alter().
+ * Defines default property types for core field types.
+ */
+function entity_field_info_alter(&$field_info) {
+  if (module_exists('number')) {
+    $field_info['number_integer']['property_type'] = 'integer';
+    $field_info['number_decimal']['property_type'] = 'decimal';
+    $field_info['number_float']['property_type'] = 'decimal';
+  }
+  if (module_exists('text')) {
+    $field_info['text']['property_type'] = 'text';
+    $field_info['text']['property_callbacks'][] = 'entity_metadata_field_text_property_callback';
+    $field_info['text_long']['property_type'] = 'text';
+    $field_info['text_long']['property_callbacks'][] = 'entity_metadata_field_text_property_callback';
+    $field_info['text_with_summary']['property_type'] = 'field_item_textsummary';
+    $field_info['text_with_summary']['property_callbacks'][] = 'entity_metadata_field_text_property_callback';
+  }
+  if (module_exists('list')) {
+    $field_info['list_integer']['property_type'] = 'integer';
+    $field_info['list_boolean']['property_type'] = 'boolean';
+    $field_info['list_float']['property_type'] = 'decimal';
+    $field_info['list_text']['property_type'] = 'text';
+  }
+  if (module_exists('taxonomy')) {
+    $field_info['taxonomy_term_reference']['property_type'] = 'taxonomy_term';
+    $field_info['taxonomy_term_reference']['property_callbacks'][] = 'entity_metadata_field_term_reference_callback';
+  }
+  if (module_exists('file')) {
+    // The callback specifies a custom data structure matching the file field
+    // items. We introduce a custom type name for this data structure.
+    $field_info['file']['property_type'] = 'field_item_file';
+    $field_info['file']['property_callbacks'][] = 'entity_metadata_field_file_callback';
+  }
+  if (module_exists('image')) {
+    // The callback specifies a custom data structure matching the image field
+    // items. We introduce a custom type name for this data structure.
+    $field_info['image']['property_type'] = 'field_item_image';
+    $field_info['image']['property_callbacks'][] = 'entity_metadata_field_file_callback';
+    $field_info['image']['property_callbacks'][] = 'entity_metadata_field_image_callback';
+  }
+}
+
+/**
+ * Implements hook_field_create_instance().
+ * Clear the cache when a field instance changed.
+ */
+function entity_field_create_instance() {
+  entity_property_info_cache_clear();
+}
+
+/**
+ * Implements hook_field_delete_instance().
+ * Clear the cache when a field instance changed.
+ */
+function entity_field_delete_instance() {
+  entity_property_info_cache_clear();
+}
+
+/**
+ * Implements hook_field_update_instance().
+ * Clear the cache when a field instance changed.
+ */
+function entity_field_update_instance() {
+  entity_property_info_cache_clear();
+}
+
+/**
+ * Verifies that the given data can be safely used as the given type regardless
+ * of the PHP variable type of $data. Example: the string "15" is a valid
+ * integer, but "15nodes" is not.
+ *
+ * @return
+ *   Whether the data is valid for the given type.
+ */
+function entity_property_verify_data_type($data, $type) {
+  // As this may be called very often statically cache the entity info using
+  // the fast pattern.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    // Make use of the same static as entity info.
+    entity_get_info();
+    $drupal_static_fast['entity_info'] = &drupal_static('entity_get_info');
+  }
+  $info = &$drupal_static_fast['entity_info'];
+
+  // First off check for entities, which may be represented by their ids too.
+  if (isset($info[$type])) {
+    if (is_object($data)) {
+      return TRUE;
+    }
+    elseif (isset($info[$type]['entity keys']['name'])) {
+      return entity_property_verify_data_type($data, 'token');
+    }
+    return entity_property_verify_data_type($data, empty($info[$type]['fieldable']) ? 'text' : 'integer');
+  }
+
+  switch ($type) {
+    case 'site':
+    case 'unknown':
+      return TRUE;
+    case 'date':
+    case 'duration':
+    case 'integer':
+      return is_numeric($data) && strpos($data, '.') === FALSE;
+    case 'decimal':
+      return is_numeric($data);
+    case 'text':
+      return is_scalar($data);
+    case 'token':
+      return is_scalar($data) && preg_match('!^[a-z][a-z0-9_]*$!', $data);
+    case 'boolean':
+      return is_scalar($data) && (is_bool($data) || $data == 0 || $data == 1);
+    case 'uri':
+      return valid_url($data, TRUE);
+    case 'list':
+      return (is_array($data) && array_values($data) == $data) || (is_object($data) && $data instanceof EntityMetadataArrayObject);
+    case 'entity':
+      return is_object($data) && $data instanceof EntityDrupalWrapper;
+    default:
+    case 'struct':
+      return is_object($data) || is_array($data);
+  }
+}
+
+/**
+ * Creates the entity object for an array of given property values.
+ *
+ * @param $entity_type
+ *   The entity type to create an entity for.
+ * @param $values
+ *   An array of values as described by the entity's property info. All entity
+ *   properties of the given entity type that are marked as required, must be
+ *   present.
+ *   If the passed values have no matching property, their value will be
+ *   assigned to the entity directly, without the use of the metadata-wrapper
+ *   property.
+ *
+ * @return EntityDrupalWrapper
+ *   An EntityDrupalWrapper wrapping the newly created entity or FALSE, if
+ *   there were no information how to create the entity.
+ */
+function entity_property_values_create_entity($entity_type, $values = array()) {
+  if (entity_type_supports($entity_type, 'create')) {
+    $info = entity_get_info($entity_type);
+    // Create the initial entity by passing the values for all 'entity keys'
+    // to entity_create().
+    $entity_keys = array_filter($info['entity keys']);
+    $creation_values = array_intersect_key($values, array_flip($entity_keys));
+
+    // In case the bundle key does not match the property that sets it, ensure
+    // the bundle key is initialized somehow, so entity_extract_ids()
+    // does not bail out during wrapper creation.
+    if (!empty($info['entity keys']['bundle'])) {
+      $creation_values += array($info['entity keys']['bundle'] => FALSE);
+    }
+    $entity = entity_create($entity_type, $creation_values);
+
+    // Now set the remaining values using the wrapper.
+    $wrapper = entity_metadata_wrapper($entity_type, $entity);
+    foreach ($values as $key => $value) {
+      if (!in_array($key, $info['entity keys'])) {
+        if (isset($wrapper->$key)) {
+          $wrapper->$key->set($value);
+        }
+        else {
+          $entity->$key = $value;
+        }
+      }
+    }
+    // @todo: Once we require Drupal 7.7 or later, verify the entity has
+    // now a valid bundle and throw the EntityMalformedException if not.
+    return $wrapper;
+  }
+  return FALSE;
+}
+
+
+/**
+ * Extracts the contained type for a list type string like list<date>.
+ *
+ * @return
+ *   The contained type or FALSE, if the given type string is no list.
+ */
+function entity_property_list_extract_type($type) {
+  if (strpos($type, 'list<') === 0 && $type[strlen($type)-1] == '>') {
+    return substr($type, 5, -1);
+  }
+  return FALSE;
+}
+
+/**
+ * Extracts the innermost type for a type string like list<list<date>>.
+ *
+ * @param $type
+ *   The type to examine.
+ *
+ * @return
+ *   For list types, the innermost type. The type itself otherwise.
+ */
+function entity_property_extract_innermost_type($type) {
+  while (strpos($type, 'list<') === 0 && $type[strlen($type)-1] == '>') {
+    $type = substr($type, 5, -1);
+  }
+  return $type;
+}
+
+/**
+ * Gets the property just as it is set in the data.
+ */
+function entity_property_verbatim_get($data, array $options, $name, $type, $info) {
+  $name = isset($info['schema field']) ? $info['schema field'] : $name;
+  if ((is_array($data) || (is_object($data) && $data instanceof ArrayAccess)) && isset($data[$name])) {
+    return $data[$name];
+  }
+  elseif (is_object($data) && isset($data->$name)) {
+    // Incorporate i18n_string translations. We may rely on the entity class
+    // here as its usage is required by the i18n integration.
+    if (isset($options['language']) && !empty($info['i18n string'])) {
+      return $data->getTranslation($name, $options['language']->language);
+    }
+    else {
+      return $data->$name;
+    }
+  }
+  return NULL;
+}
+
+/**
+ * Date values are converted from ISO strings to timestamp if needed.
+ */
+function entity_property_verbatim_date_get($data, array $options, $name, $type, $info) {
+  $name = isset($info['schema field']) ? $info['schema field'] : $name;
+  return is_numeric($data[$name]) ? $data[$name] : strtotime($data[$name], REQUEST_TIME);
+}
+
+/**
+ * Sets the property to the given value. May be used as 'setter callback'.
+ */
+function entity_property_verbatim_set(&$data, $name, $value, $langcode, $type, $info) {
+  $name = isset($info['schema field']) ? $info['schema field'] : $name;
+  if (is_array($data) || (is_object($data) && $data instanceof ArrayAccess)) {
+    $data[$name] = $value;
+  }
+  elseif (is_object($data)) {
+    $data->$name = $value;
+  }
+}
+
+/**
+ * Gets the property using the getter method (named just like the property).
+ */
+function entity_property_getter_method($object, array $options, $name) {
+  // Remove any underscores as classes are expected to use CamelCase.
+  $method = strtr($name, array('_' => ''));
+  return $object->$method();
+}
+
+/**
+ * Sets the property to the given value using the setter method. May be used as
+ * 'setter callback'.
+ */
+function entity_property_setter_method($object, $name, $value) {
+  // Remove any underscores as classes are expected to use CamelCase.
+  $method = 'set' . strtr($name, array('_' => ''));
+  // Invoke the setProperty() method where 'Property' is the property name.
+  $object->$method($value);
+}
+
+/**
+ * Getter callback for getting an array. Makes sure it's numerically indexed.
+ */
+function entity_property_get_list($data, array $options, $name) {
+  return isset($data->$name) ? array_values($data->$name) : array();
+}
+
+/**
+ * A validation callback ensuring the passed integer is positive.
+ */
+function entity_property_validate_integer_positive($value) {
+  return $value > 0;
+}
+
+/**
+ * A validation callback ensuring the passed integer is non-negative.
+ */
+function entity_property_validate_integer_non_negative($value) {
+  return $value >= 0;
+}
+
+/**
+ * A simple auto-creation callback for array based data structures.
+ */
+function entity_property_create_array($property_name, $context) {
+  return array();
+}
+
+/**
+ * Flattens the given options in single dimensional array.
+ * We don't depend on options module, so we cannot use options_array_flatten().
+ *
+ * @see options_array_flatten()
+ */
+function entity_property_options_flatten($options) {
+  $result = array();
+  foreach ($options as $key => $value) {
+    if (is_array($value)) {
+      $result += $value;
+    }
+    else {
+      $result[$key] = $value;
+    }
+  }
+  return $result;
+}
+
+/**
+ * Defines info for the properties of the text_formatted data structure.
+ */
+function entity_property_text_formatted_info() {
+  return array(
+    'value' => array(
+      'type' => 'text',
+      'label' => t('Text'),
+      'sanitized' => TRUE,
+      'getter callback' => 'entity_metadata_field_text_get',
+      'setter callback' => 'entity_property_verbatim_set',
+      'setter permission' => 'administer nodes',
+      'raw getter callback' => 'entity_property_verbatim_get',
+    ),
+    'summary' => array(
+      'type' => 'text',
+      'label' => t('Summary'),
+      'sanitized' => TRUE,
+      'getter callback' => 'entity_metadata_field_text_get',
+      'setter callback' => 'entity_property_verbatim_set',
+      'setter permission' => 'administer nodes',
+      'raw getter callback' => 'entity_property_verbatim_get',
+    ),
+    'format' => array(
+      'type' => 'token',
+      'label' => t('Text format'),
+      'options list' => 'entity_metadata_field_text_formats',
+      'getter callback' => 'entity_property_verbatim_get',
+    ),
+  );
+}
+
+/**
+ * Defines info for the properties of the field_item_textsummary data structure.
+ */
+function entity_property_field_item_textsummary_info() {
+  return array(
+    'value' => array(
+      'type' => 'text',
+      'label' => t('Text'),
+      'setter callback' => 'entity_property_verbatim_set',
+    ),
+    'summary' => array(
+      'type' => 'text',
+      'label' => t('Summary'),
+      'setter callback' => 'entity_property_verbatim_set',
+    ),
+  );
+}
+
+/**
+ * Defines info for the properties of the file-field item data structure.
+ */
+function entity_property_field_item_file_info() {
+  $properties['file'] = array(
+    'type' => 'file',
+    'label' => t('The file.'),
+    'getter callback' => 'entity_metadata_field_file_get',
+    'setter callback' => 'entity_metadata_field_file_set',
+    'required' => TRUE,
+  );
+  $properties['description'] = array(
+    'type' => 'text',
+    'label' => t('The file description'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  $properties['display'] = array(
+    'type' => 'boolean',
+    'label' => t('Whether the file is being displayed.'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  return $properties;
+}
+
+/**
+ * Defines info for the properties of the image-field item data structure.
+ */
+function entity_property_field_item_image_info() {
+  $properties['file'] = array(
+    'type' => 'file',
+    'label' => t('The image file.'),
+    'getter callback' => 'entity_metadata_field_file_get',
+    'setter callback' => 'entity_metadata_field_file_set',
+    'required' => TRUE,
+  );
+  $properties['alt'] = array(
+    'type' => 'text',
+    'label' => t('The "Alt" attribute text'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  $properties['title'] = array(
+    'type' => 'text',
+    'label' => t('The "Title" attribute text'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  return $properties;
+}
+
+
+/**
+ * Previously, hook_entity_property_info() has been provided by the removed
+ * entity metadata module. To provide backward compatibility for provided
+ * helpers that may be specified in hook_entity_property_info(), the following
+ * (deprecated) functions are provided.
+ */
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_verbatim_get($data, array $options, $name) {
+  return entity_property_verbatim_get($data, $options, $name);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_verbatim_set($data, $name, $value) {
+  return entity_property_verbatim_set($data, $name, $value);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_getter_method($object, array $options, $name) {
+  return entity_property_getter_method($object, $options, $name);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_setter_method($object, $name, $value) {
+  entity_property_setter_method($object, $name, $value);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_get_list($data, array $options, $name) {
+  return entity_property_get_list($data, $options, $name);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_validate_integer_positive($value) {
+  return entity_property_validate_integer_positive($value);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_validate_integer_non_negative($value) {
+  return entity_property_validate_integer_non_negative($value);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_text_formatted_properties() {
+  return entity_property_text_formatted_info();
+}
diff --git a/sites/all/modules/entity/includes/entity.ui.inc b/sites/all/modules/entity/includes/entity.ui.inc
new file mode 100644
index 0000000000000000000000000000000000000000..a449b25a09468a1504bf5a270d0520e8a65e9b41
--- /dev/null
+++ b/sites/all/modules/entity/includes/entity.ui.inc
@@ -0,0 +1,672 @@
+<?php
+
+/**
+ * @file
+ * Provides a controller for building an entity overview form.
+ */
+
+/**
+ * Default controller for providing UI.
+ */
+class EntityDefaultUIController {
+
+  protected $entityType;
+  protected $entityInfo, $path;
+
+  /**
+   * Defines the number of entries to show per page in overview table.
+   */
+  public $overviewPagerLimit = 25;
+
+  public function __construct($entity_type, $entity_info) {
+    $this->entityType = $entity_type;
+    $this->entityInfo = $entity_info;
+    $this->path = $this->entityInfo['admin ui']['path'];
+    $this->statusKey = empty($this->entityInfo['entity keys']['status']) ? 'status' : $this->entityInfo['entity keys']['status'];
+  }
+
+  /**
+   * Provides definitions for implementing hook_menu().
+   */
+  public function hook_menu() {
+    $items = array();
+    $id_count = count(explode('/', $this->path));
+    $wildcard = isset($this->entityInfo['admin ui']['menu wildcard']) ? $this->entityInfo['admin ui']['menu wildcard'] : '%entity_object';
+    $plural_label = isset($this->entityInfo['plural label']) ? $this->entityInfo['plural label'] : $this->entityInfo['label'] . 's';
+
+    $items[$this->path] = array(
+      'title' => $plural_label,
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array($this->entityType . '_overview_form', $this->entityType),
+      'description' => 'Manage ' . $plural_label . '.',
+      'access callback' => 'entity_access',
+      'access arguments' => array('view', $this->entityType),
+      'file' => 'includes/entity.ui.inc',
+    );
+    $items[$this->path . '/list'] = array(
+      'title' => 'List',
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+      'weight' => -10,
+    );
+    $items[$this->path . '/add'] = array(
+      'title callback' => 'entity_ui_get_action_title',
+      'title arguments' => array('add', $this->entityType),
+      'page callback' => 'entity_ui_get_form',
+      'page arguments' => array($this->entityType, NULL, 'add'),
+      'access callback' => 'entity_access',
+      'access arguments' => array('create', $this->entityType),
+      'type' => MENU_LOCAL_ACTION,
+    );
+    $items[$this->path . '/manage/' . $wildcard] = array(
+      'title' => 'Edit',
+      'title callback' => 'entity_label',
+      'title arguments' => array($this->entityType, $id_count + 1),
+      'page callback' => 'entity_ui_get_form',
+      'page arguments' => array($this->entityType, $id_count + 1),
+      'load arguments' => array($this->entityType),
+      'access callback' => 'entity_access',
+      'access arguments' => array('update', $this->entityType, $id_count + 1),
+    );
+    $items[$this->path . '/manage/' . $wildcard . '/edit'] = array(
+      'title' => 'Edit',
+      'load arguments' => array($this->entityType),
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+    );
+
+    // Clone form, a special case for the edit form.
+    $items[$this->path . '/manage/' . $wildcard . '/clone'] = array(
+      'title' => 'Clone',
+      'page callback' => 'entity_ui_get_form',
+      'page arguments' => array($this->entityType, $id_count + 1, 'clone'),
+      'load arguments' => array($this->entityType),
+      'access callback' => 'entity_access',
+      'access arguments' => array('create', $this->entityType),
+    );
+    // Menu item for operations like revert and delete.
+    $items[$this->path . '/manage/' . $wildcard . '/%'] = array(
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array($this->entityType . '_operation_form', $this->entityType, $id_count + 1, $id_count + 2),
+      'load arguments' => array($this->entityType),
+      'access callback' => 'entity_access',
+      'access arguments' => array('delete', $this->entityType, $id_count + 1),
+      'file' => 'includes/entity.ui.inc',
+    );
+
+    if (!empty($this->entityInfo['exportable'])) {
+      // Menu item for importing an entity.
+      $items[$this->path . '/import'] = array(
+        'title callback' => 'entity_ui_get_action_title',
+        'title arguments' => array('import', $this->entityType),
+        'page callback' => 'drupal_get_form',
+        'page arguments' => array($this->entityType . '_operation_form', $this->entityType, NULL, 'import'),
+        'access callback' => 'entity_access',
+        'access arguments' => array('create', $this->entityType),
+        'file' => 'includes/entity.ui.inc',
+        'type' => MENU_LOCAL_ACTION,
+      );
+    }
+
+    if (!empty($this->entityInfo['admin ui']['file'])) {
+      // Add in the include file for the entity form.
+      foreach (array("/manage/$wildcard", "/manage/$wildcard/clone", '/add') as $path_end) {
+        $items[$this->path . $path_end]['file'] = $this->entityInfo['admin ui']['file'];
+        $items[$this->path . $path_end]['file path'] = isset($this->entityInfo['admin ui']['file path']) ? $this->entityInfo['admin ui']['file path'] : drupal_get_path('module', $this->entityInfo['module']);
+      }
+    }
+    return $items;
+  }
+
+  /**
+   * Provides definitions for implementing hook_forms().
+   *
+   * Use per bundle form ids if possible, such that easy per bundle alterations
+   * are supported too.
+   *
+   * Note that for performance reasons, this method is only invoked for forms,
+   * which receive the entity_type as first argument. Thus any forms added, must
+   * follow that pattern.
+   *
+   * @see entity_forms()
+   */
+  public function hook_forms() {
+    // The overview and the operation form are implemented by the controller,
+    // the callback and validation + submit handlers just invoke the controller.
+    $forms[$this->entityType . '_overview_form'] = array(
+      'callback' => 'entity_ui_overview_form',
+      'wrapper_callback' => 'entity_ui_form_defaults',
+    );
+    $forms[$this->entityType . '_operation_form'] = array(
+      'callback' => 'entity_ui_operation_form',
+      'wrapper_callback' => 'entity_ui_form_defaults',
+    );
+
+    // The entity form (ENTITY_TYPE_form) handles editing, adding and cloning.
+    // For that form, the wrapper callback entity_ui_main_form_defaults() gets
+    // directly invoked via entity_ui_get_form().
+    // If there are bundles though, we use form ids that include the bundle name
+    // (ENTITY_TYPE_edit_BUNDLE_NAME_form) to enable per bundle alterations
+    // as well as alterations based upon the base form id (ENTITY_TYPE_form).
+    if (!(count($this->entityInfo['bundles']) == 1 && isset($this->entityInfo['bundles'][$this->entityType]))) {
+      foreach ($this->entityInfo['bundles'] as $bundle => $bundle_info) {
+        $forms[$this->entityType . '_edit_' . $bundle . '_form']['callback'] = $this->entityType . '_form';
+        // Again the wrapper callback is invoked by entity_ui_get_form() anyway.
+      }
+    }
+    return $forms;
+  }
+
+  /**
+   * Builds the entity overview form.
+   */
+  public function overviewForm($form, &$form_state) {
+    // By default just show a simple overview for all entities.
+    $form['table'] = $this->overviewTable();
+    $form['pager'] = array('#theme' => 'pager');
+    return $form;
+  }
+
+  /**
+   * Overview form validation callback.
+   *
+   * @param $form
+   *   The form array of the overview form.
+   * @param $form_state
+   *   The overview form state which will be used for validating.
+   */
+  public function overviewFormValidate($form, &$form_state) {}
+
+  /**
+   * Overview form submit callback.
+   *
+   * @param $form
+   *   The form array of the overview form.
+   * @param $form_state
+   *   The overview form state which will be used for submitting.
+   */
+  public function overviewFormSubmit($form, &$form_state) {}
+
+
+  /**
+   * Generates the render array for a overview table for arbitrary entities
+   * matching the given conditions.
+   *
+   * @param $conditions
+   *   An array of conditions as needed by entity_load().
+
+   * @return Array
+   *   A renderable array.
+   */
+  public function overviewTable($conditions = array()) {
+
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $this->entityType);
+
+    // Add all conditions to query.
+    foreach ($conditions as $key => $value) {
+      $query->propertyCondition($key, $value);
+    }
+
+    if ($this->overviewPagerLimit) {
+      $query->pager($this->overviewPagerLimit);
+    }
+
+    $results = $query->execute();
+
+    $ids = isset($results[$this->entityType]) ? array_keys($results[$this->entityType]) : array();
+    $entities = $ids ? entity_load($this->entityType, $ids) : array();
+    ksort($entities);
+
+    $rows = array();
+    foreach ($entities as $entity) {
+      $rows[] = $this->overviewTableRow($conditions, entity_id($this->entityType, $entity), $entity);
+    }
+
+    $render = array(
+      '#theme' => 'table',
+      '#header' => $this->overviewTableHeaders($conditions, $rows),
+      '#rows' => $rows,
+      '#empty' => t('None.'),
+    );
+    return $render;
+  }
+
+  /**
+   * Generates the table headers for the overview table.
+   */
+  protected function overviewTableHeaders($conditions, $rows, $additional_header = array()) {
+    $header = $additional_header;
+    array_unshift($header, t('Label'));
+    if (!empty($this->entityInfo['exportable'])) {
+      $header[] = t('Status');
+    }
+    // Add operations with the right colspan.
+    $header[] = array('data' => t('Operations'), 'colspan' => $this->operationCount());
+    return $header;
+  }
+
+  /**
+   * Returns the operation count for calculating colspans.
+   */
+  protected function operationCount() {
+    $count = 3;
+    $count += !empty($this->entityInfo['bundle of']) && entity_type_is_fieldable($this->entityInfo['bundle of']) && module_exists('field_ui') ? 2 : 0;
+    $count += !empty($this->entityInfo['exportable']) ? 1 : 0;
+    $count += !empty($this->entityInfo['i18n controller class']) ? 1 : 0;
+    return $count;
+  }
+
+  /**
+   * Generates the row for the passed entity and may be overridden in order to
+   * customize the rows.
+   *
+   * @param $additional_cols
+   *   Additional columns to be added after the entity label column.
+   */
+  protected function overviewTableRow($conditions, $id, $entity, $additional_cols = array()) {
+    $entity_uri = entity_uri($this->entityType, $entity);
+
+    $row[] = array('data' => array(
+      '#theme' => 'entity_ui_overview_item',
+      '#label' => entity_label($this->entityType, $entity),
+      '#name' => !empty($this->entityInfo['exportable']) ? entity_id($this->entityType, $entity) : FALSE,
+      '#url' => $entity_uri ? $entity_uri : FALSE,
+      '#entity_type' => $this->entityType),
+    );
+
+    // Add in any passed additional cols.
+    foreach ($additional_cols as $col) {
+      $row[] = $col;
+    }
+
+    // Add a row for the exportable status.
+    if (!empty($this->entityInfo['exportable'])) {
+      $row[] = array('data' => array(
+        '#theme' => 'entity_status',
+        '#status' => $entity->{$this->statusKey},
+      ));
+    }
+    // In case this is a bundle, we add links to the field ui tabs.
+    $field_ui = !empty($this->entityInfo['bundle of']) && entity_type_is_fieldable($this->entityInfo['bundle of']) && module_exists('field_ui');
+    // For exportable entities we add an export link.
+    $exportable = !empty($this->entityInfo['exportable']);
+    // If i18n integration is enabled, add a link to the translate tab.
+    $i18n = !empty($this->entityInfo['i18n controller class']);
+
+    // Add operations depending on the status.
+    if (entity_has_status($this->entityType, $entity, ENTITY_FIXED)) {
+      $row[] = array('data' => l(t('clone'), $this->path . '/manage/' . $id . '/clone'), 'colspan' => $this->operationCount());
+    }
+    else {
+      $row[] = l(t('edit'), $this->path . '/manage/' . $id);
+
+      if ($field_ui) {
+        $row[] = l(t('manage fields'), $this->path . '/manage/' . $id . '/fields');
+        $row[] = l(t('manage display'), $this->path . '/manage/' . $id . '/display');
+      }
+      if ($i18n) {
+        $row[] = l(t('translate'), $this->path . '/manage/' . $id . '/translate');
+      }
+      if ($exportable) {
+        $row[] = l(t('clone'), $this->path . '/manage/' . $id . '/clone');
+      }
+
+      if (empty($this->entityInfo['exportable']) || !entity_has_status($this->entityType, $entity, ENTITY_IN_CODE)) {
+        $row[] = l(t('delete'), $this->path . '/manage/' . $id . '/delete', array('query' => drupal_get_destination()));
+      }
+      elseif (entity_has_status($this->entityType, $entity, ENTITY_OVERRIDDEN)) {
+        $row[] = l(t('revert'), $this->path . '/manage/' . $id . '/revert', array('query' => drupal_get_destination()));
+      }
+      else {
+        $row[] = '';
+      }
+    }
+    if ($exportable) {
+      $row[] = l(t('export'), $this->path . '/manage/' . $id . '/export');
+    }
+    return $row;
+  }
+
+
+  /**
+   * Builds the operation form.
+   *
+   * For the export operation a serialized string of the entity is directly
+   * shown in the form (no submit function needed).
+   */
+  public function operationForm($form, &$form_state, $entity, $op) {
+    switch ($op) {
+      case 'revert':
+        $label = entity_label($this->entityType, $entity);
+        $confirm_question = t('Are you sure you want to revert the %entity %label?', array('%entity' => $this->entityInfo['label'], '%label' => $label));
+        return confirm_form($form, $confirm_question, $this->path);
+
+      case 'delete':
+        $label = entity_label($this->entityType, $entity);
+        $confirm_question = t('Are you sure you want to delete the %entity %label?', array('%entity' => $this->entityInfo['label'], '%label' => $label));
+        return confirm_form($form, $confirm_question, $this->path);
+
+      case 'export':
+        if (!empty($this->entityInfo['exportable'])) {
+          $export = entity_export($this->entityType, $entity);
+          $form['export'] = array(
+            '#type' => 'textarea',
+            '#title' => t('Export'),
+            '#description' => t('For importing copy the content of the text area and paste it into the import page.'),
+            '#rows' => 25,
+            '#default_value' => $export,
+          );
+          return $form;
+        }
+
+      case 'import':
+        $form['import'] = array(
+          '#type' => 'textarea',
+          '#title' => t('Import'),
+          '#description' => t('Paste an exported %entity_type here.', array('%entity_type' => $this->entityInfo['label'])),
+          '#rows' => 20,
+        );
+        $form['overwrite'] = array(
+          '#title' => t('Overwrite'),
+          '#type' => 'checkbox',
+          '#description' => t('If checked, any existing %entity with the same identifier will be replaced by the import.', array('%entity' => $this->entityInfo['label'])),
+          '#default_value' => FALSE,
+        );
+        $form['submit'] = array(
+          '#type' => 'submit',
+          '#value' => t('Import'),
+        );
+        return $form;
+    }
+    drupal_not_found();
+    exit;
+  }
+
+  /**
+   * Operation form validation callback.
+   */
+  public function operationFormValidate($form, &$form_state) {
+    if ($form_state['op'] == 'import') {
+      if ($entity = entity_import($this->entityType, $form_state['values']['import'])) {
+        // Store the successfully imported entity in $form_state.
+        $form_state[$this->entityType] = $entity;
+        if (!$form_state['values']['overwrite']) {
+          // Check for existing entities with the same identifier.
+          $id = entity_id($this->entityType, $entity);
+          $entities = entity_load($this->entityType, array($id));
+          if (!empty($entities)) {
+            $label = entity_label($this->entityType, $entity);
+            $vars = array('%entity' => $this->entityInfo['label'], '%label' => $label);
+            form_set_error('import', t('Import of %entity %label failed, a %entity with the same machine name already exists. Check the overwrite option to replace it.', $vars));
+          }
+        }
+      }
+      else {
+        form_set_error('import', t('Import failed.'));
+      }
+    }
+  }
+
+  /**
+   * Operation form submit callback.
+   */
+  public function operationFormSubmit($form, &$form_state) {
+    $msg = $this->applyOperation($form_state['op'], $form_state[$this->entityType]);
+    drupal_set_message($msg);
+    $form_state['redirect'] = $this->path;
+  }
+
+  /**
+   * Applies an operation to the given entity.
+   *
+   * Note: the export operation is directly carried out by the operationForm()
+   * method.
+   *
+   * @param string $op
+   *   The operation (revert, delete or import).
+   * @param $entity
+   *   The entity to manipulate.
+   *
+   * @return
+   *   The status message of what has been applied.
+   */
+  public function applyOperation($op, $entity) {
+    $label = entity_label($this->entityType, $entity);
+    $vars = array('%entity' => $this->entityInfo['label'], '%label' => $label);
+    $id = entity_id($this->entityType, $entity);
+    $edit_link = l(t('edit'), $this->path . '/manage/' . $id . '/edit');
+
+    switch ($op) {
+      case 'revert':
+        entity_delete($this->entityType, $id);
+        watchdog($this->entityType, 'Reverted %entity %label to the defaults.', $vars, WATCHDOG_NOTICE, $edit_link);
+        return t('Reverted %entity %label to the defaults.', $vars);
+
+      case 'delete':
+        entity_delete($this->entityType, $id);
+        watchdog($this->entityType, 'Deleted %entity %label.', $vars);
+        return t('Deleted %entity %label.', $vars);
+
+      case 'import':
+        // First check if there is any existing entity with the same ID.
+        $id = entity_id($this->entityType, $entity);
+        $entities = entity_load($this->entityType, array($id));
+        if ($existing_entity = reset($entities)) {
+          // Copy DB id and remove the new indicator to overwrite the DB record.
+          $idkey = $this->entityInfo['entity keys']['id'];
+          $entity->{$idkey} = $existing_entity->{$idkey};
+          unset($entity->is_new);
+        }
+        entity_save($this->entityType, $entity);
+        watchdog($this->entityType, 'Imported %entity %label.', $vars);
+        return t('Imported %entity %label.', $vars);
+
+      default:
+        return FALSE;
+    }
+  }
+
+  /**
+   * Entity submit builder invoked via entity_ui_form_submit_build_entity().
+   *
+   * Extracts the form values and updates the entity.
+   *
+   * The provided implementation makes use of the helper function
+   * entity_form_submit_build_entity() provided by core, which already invokes
+   * the field API attacher for fieldable entities.
+   *
+   * @return
+   *   The updated entity.
+   *
+   * @see entity_ui_form_submit_build_entity()
+   */
+  public function entityFormSubmitBuildEntity($form, &$form_state) {
+    // Add the bundle property to the entity if the entity type supports bundles
+    // and the form provides a value for the bundle key. Especially new entities
+    // need to have their bundle property pre-populated before we invoke
+    // entity_form_submit_build_entity().
+    if (!empty($this->entityInfo['entity keys']['bundle']) && isset($form_state['values'][$this->entityInfo['entity keys']['bundle']])) {
+      $form_state[$this->entityType]->{$this->entityInfo['entity keys']['bundle']} = $form_state['values'][$this->entityInfo['entity keys']['bundle']];
+    }
+    entity_form_submit_build_entity($this->entityType, $form_state[$this->entityType], $form, $form_state);
+    return $form_state[$this->entityType];
+  }
+}
+
+/**
+ * Form builder function for the overview form.
+ *
+ * @see EntityDefaultUIController::overviewForm()
+ */
+function entity_ui_overview_form($form, &$form_state, $entity_type) {
+  return entity_ui_controller($entity_type)->overviewForm($form, $form_state);
+}
+
+/**
+ * Form builder for the entity operation form.
+ *
+ * @see EntityDefaultUIController::operationForm()
+ */
+function entity_ui_operation_form($form, &$form_state, $entity_type, $entity, $op) {
+  $form_state['op'] = $op;
+  return entity_ui_controller($entity_type)->operationForm($form, $form_state, $entity, $op);
+}
+
+/**
+ * Form wrapper the main entity form.
+ *
+ * @see entity_ui_form_defaults()
+ */
+function entity_ui_main_form_defaults($form, &$form_state, $entity = NULL, $op = NULL) {
+  // Now equals entity_ui_form_defaults() but is still here to keep backward
+  // compatability.
+  return entity_ui_form_defaults($form, $form_state, $form_state['entity_type'], $entity, $op);
+}
+
+/**
+ * Clones the entity object and makes sure it will get saved as new entity.
+ *
+ * @return
+ *   The cloned entity object.
+ */
+function entity_ui_clone_entity($entity_type, $entity) {
+  // Clone the entity and make sure it will get saved as a new entity.
+  $entity = clone $entity;
+
+  $entity_info = entity_get_info($entity_type);
+  $entity->{$entity_info['entity keys']['id']} = FALSE;
+  if (!empty($entity_info['entity keys']['name'])) {
+    $entity->{$entity_info['entity keys']['name']} = FALSE;
+  }
+  $entity->is_new = TRUE;
+
+  // Make sure the status of a cloned exportable is custom.
+  if (!empty($entity_info['exportable'])) {
+    $status_key = isset($entity_info['entity keys']['status']) ? $entity_info['entity keys']['status'] : 'status';
+    $entity->$status_key = ENTITY_CUSTOM;
+  }
+  return $entity;
+}
+
+/**
+ * Form wrapper callback for all entity ui forms.
+ *
+ * This callback makes sure the form state is properly initialized and sets
+ * some useful default titles.
+ *
+ * @see EntityDefaultUIController::hook_forms()
+ */
+function entity_ui_form_defaults($form, &$form_state, $entity_type, $entity = NULL, $op = NULL) {
+  $defaults = array(
+    'entity_type' => $entity_type,
+  );
+  if (isset($entity)) {
+    $defaults[$entity_type] = $entity;
+  }
+  if (isset($op)) {
+    $defaults['op'] = $op;
+  }
+  $form_state += $defaults;
+  if (isset($op)) {
+    drupal_set_title(entity_ui_get_page_title($op, $entity_type, $entity), PASS_THROUGH);
+  }
+  // Add in handlers pointing to the controller for the forms implemented by it.
+  if (isset($form_state['build_info']['base_form_id']) && $form_state['build_info']['base_form_id'] != $entity_type . '_form') {
+    $form['#validate'][] = 'entity_ui_controller_form_validate';
+    $form['#submit'][] = 'entity_ui_controller_form_submit';
+  }
+  return $form;
+}
+
+/**
+ * Validation callback for forms implemented by the UI controller.
+ */
+function entity_ui_controller_form_validate($form, &$form_state) {
+  // Remove 'entity_ui_' prefix and the '_form' suffix.
+  $base = substr($form_state['build_info']['base_form_id'], 10, -5);
+  $method = $base . 'FormValidate';
+  entity_ui_controller($form_state['entity_type'])->$method($form, $form_state);
+}
+
+/**
+ * Submit callback for forms implemented by the UI controller.
+ */
+function entity_ui_controller_form_submit($form, &$form_state) {
+  // Remove 'entity_ui_' prefix and the '_form' suffix.
+  $base = substr($form_state['build_info']['base_form_id'], 10, -5);
+  $method = $base . 'FormSubmit';
+  entity_ui_controller($form_state['entity_type'])->$method($form, $form_state);
+}
+
+/**
+ * Gets the page title for the passed operation.
+ */
+function entity_ui_get_page_title($op, $entity_type, $entity = NULL) {
+  $label = entity_label($entity_type, $entity);
+  switch ($op) {
+    case 'edit':
+      return t('Edit @label', array('@label' => $label));
+    case 'clone':
+      return t('Clone @label', array('@label' => $label));
+    case 'revert':
+      return t('Revert @label', array('@label' => $label));
+    case 'delete':
+      return t('Delete @label', array('@label' => $label));
+    case 'export':
+      return t('Export @label', array('@label' => $label));
+  }
+  return entity_ui_get_action_title($op, $entity_type);
+}
+
+/**
+ * Gets the page/menu title for local action operations.
+ */
+function entity_ui_get_action_title($op, $entity_type) {
+  $info = entity_get_info($entity_type);
+  switch ($op) {
+    case 'add':
+      return t('Add @entity_type', array('@entity_type' => drupal_strtolower($info['label'])));
+    case 'import':
+      return t('Import @entity_type', array('@entity_type' => drupal_strtolower($info['label'])));
+  }
+}
+
+/**
+ * Submit builder for the main entity form, which extracts the form values and updates the entity.
+ *
+ * This is a helper function for entities making use of the entity UI
+ * controller.
+ *
+ * @return
+ *   The updated entity.
+ *
+ * @see EntityDefaultUIController::hook_forms()
+ * @see EntityDefaultUIController::entityFormSubmitBuildEntity()
+ */
+function entity_ui_form_submit_build_entity($form, &$form_state) {
+  return entity_ui_controller($form_state['entity_type'])->entityFormSubmitBuildEntity($form, $form_state);
+}
+
+/**
+ * Validation callback for machine names of exportables.
+ *
+ * We don't allow numeric machine names, as entity_load() treats them as the
+ * numeric identifier and they are easily confused with ids in general.
+ */
+function entity_ui_validate_machine_name($element, &$form_state) {
+  if (is_numeric($element['#value'])) {
+    form_error($element, t('Machine-readable names must not consist of numbers only.'));
+  }
+}
+
+/**
+ * Returns HTML for an entity on the entity overview listing.
+ *
+ * @ingroup themeable
+ */
+function theme_entity_ui_overview_item($variables) {
+  $output = $variables['url'] ? l($variables['label'], $variables['url']['path'], $variables['url']['options']) : check_plain($variables['label']);
+  if ($variables['name']) {
+    $output .= ' <small> (' . t('Machine name') . ': ' . check_plain($variables['name']) . ')</small>';
+  }
+  return $output;
+}
diff --git a/sites/all/modules/entity/includes/entity.wrapper.inc b/sites/all/modules/entity/includes/entity.wrapper.inc
new file mode 100644
index 0000000000000000000000000000000000000000..e4d31098c278c6b7c8e9f44df16005bc0eecbd35
--- /dev/null
+++ b/sites/all/modules/entity/includes/entity.wrapper.inc
@@ -0,0 +1,1185 @@
+<?php
+
+/**
+ * @file
+ * Provides wrappers allowing easy usage of the entity metadata.
+ */
+
+/**
+ * A common base class for all wrappers.
+ */
+abstract class EntityMetadataWrapper {
+
+  protected $type;
+  protected $data;
+  protected $info;
+  protected $cache = array();
+
+  /**
+   * Construct a new wrapper object.
+   *
+   * @param $type
+   *   The type of the passed data.
+   * @param $data
+   *   Optional. The data to wrap.
+   * @param $info
+   *   Optional. Used internally to pass info about properties down the tree.
+   */
+  public function __construct($type, $data = NULL, $info = array()) {
+    $this->type = $type;
+    $this->info = $info + array(
+      'langcode' => NULL,
+    );
+    $this->info['type'] = $type;
+    if (isset($data)) {
+      $this->set($data);
+    }
+  }
+
+  /**
+   * Gets info about the wrapped data.
+   *
+   * @return Array
+   *   Keys set are all keys as specified for a property in hook_entity_info()
+   *   as well as possible the following keys:
+   *    - name: If this wraps a property, the name of the property.
+   *    - parent: The parent wrapper, if any.
+   *    - langcode: The language code, if this data is language specific.
+   */
+  public function info() {
+    return $this->info;
+  }
+
+  /**
+   * Gets the (entity)type of the wrapped data.
+   */
+  public function type() {
+    return $this->type;
+  }
+
+  /**
+   * Returns the wrapped data. If no options are given the data is returned as
+   * described in the info.
+   *
+   * @param $options
+   *   (optional) A keyed array of options:
+   *   - sanitize: A boolean flag indicating that textual properties should be
+   *     sanitized for display to a web browser. Defaults to FALSE.
+   *   - decode: If set to TRUE and some textual data is already sanitized, it
+   *     strips HTML tags and decodes HTML entities. Defaults to FALSE.
+   *
+   *  @return
+   *    The value of the wrapped data. If the data property is not set, NULL
+   *    is returned.
+   *
+   *  @throws EntityMetadataWrapperException
+   *    In case there are no data values available to the wrapper, an exception
+   *    is thrown. E.g. if the value for an entity property is to be retrieved
+   *    and there is no entity available, the exception is thrown. However, if
+   *    an entity is available but the property is not set, NULL is returned.
+   */
+  public function value(array $options = array()) {
+    if (!$this->dataAvailable() && isset($this->info['parent'])) {
+      throw new EntityMetadataWrapperException('Missing data values.');
+    }
+    if (!isset($this->data) && isset($this->info['name'])) {
+      $this->data = $this->info['parent']->getPropertyValue($this->info['name'], $this->info);
+    }
+    return $this->data;
+  }
+
+  /**
+   * Returns the raw, unprocessed data. Most times this is the same as returned
+   * by value(), however for already processed and sanitized textual data, this
+   * will return the unprocessed data in contrast to value().
+   */
+  public function raw() {
+    if (!$this->dataAvailable()) {
+      throw new EntityMetadataWrapperException('Missing data values.');
+    }
+    if (isset($this->info['name']) && isset($this->info['parent'])) {
+      return $this->info['parent']->getPropertyRaw($this->info['name'], $this->info);
+    }
+    // Else return the usual value, which should be raw in this case.
+    return $this->value();
+  }
+
+  /**
+   * Returns whether data is available to work with.
+   *
+   * @return
+   *   If we operate without any data FALSE, else TRUE.
+   */
+  protected function dataAvailable() {
+    return isset($this->data) || (isset($this->info['parent']) && $this->info['parent']->dataAvailable());
+  }
+
+  /**
+   * Set a new data value.
+   */
+  public function set($value) {
+    if (!$this->validate($value)) {
+      throw new EntityMetadataWrapperException('Invalid data value given. Be sure it matches the required data type and format.');
+    }
+    $this->clear();
+    $this->data = $value;
+    $this->updateParent($value);
+    return $this;
+  }
+
+  /**
+   * Updates the parent data structure of a data property with the latest data value.
+   */
+  protected function updateParent($value) {
+    if (isset($this->info['parent'])) {
+      $this->info['parent']->setProperty($this->info['name'], $value);
+    }
+  }
+
+  /**
+   * Returns whether $value is a valid value to set.
+   */
+  public function validate($value) {
+    if (isset($value) && !entity_property_verify_data_type($value, $this->type)) {
+      return FALSE;
+    }
+    // Only proceed with further checks if this is not a list item. If this is
+    // a list item, the checks are performed on the list property level.
+    if (isset($this->info['parent']) && $this->info['parent'] instanceof EntityListWrapper) {
+      return TRUE;
+    }
+    if (!isset($value) && !empty($this->info['required'])) {
+      // Do not allow NULL values if the property is required.
+      return FALSE;
+    }
+    return !isset($this->info['validation callback']) || call_user_func($this->info['validation callback'], $value, $this->info);
+  }
+
+  public function __toString() {
+    return isset($this->info) ? 'Property ' . $this->info['name'] : $this->type;
+  }
+
+  /**
+   * Clears the data value and the wrapper cache.
+   */
+  protected function clear() {
+    $this->data = NULL;
+    foreach ($this->cache as $wrapper) {
+      $wrapper->clear();
+    }
+  }
+
+  /**
+   * Returns the options list specifying possible values for the property, if
+   * defined.
+   *
+   * @param $op
+   *   (optional) One of 'edit' or 'view'. In case the list of possible values
+   *   a user could set for a property differs from the list of values a
+   *   property could have, $op determines which options should be returned.
+   *   Defaults to 'edit'.
+   *   E.g. all possible roles a user could have include the anonymous and the
+   *   authenticated user roles, while those roles cannot be added to a user
+   *   account. So their options would be included for 'view', but for 'edit'
+   *   not.
+   *
+   * @return
+   *   An array as used by hook_options_list() or FALSE.
+   */
+  public function optionsList($op = 'edit') {
+    if (isset($this->info['options list']) && is_callable($this->info['options list'])) {
+      $name = isset($this->info['name']) ? $this->info['name'] : NULL;
+      return call_user_func($this->info['options list'], $name, $this->info, $op);
+    }
+    return FALSE;
+  }
+
+  /**
+   * Returns the label for the currently set property value if there is one
+   * available, i.e. if an options list has been specified.
+   */
+  public function label() {
+    if ($options = $this->optionsList('view')) {
+      $options = entity_property_options_flatten($options);
+      $value = $this->value();
+      if (is_scalar($value) && isset($options[$value])) {
+        return $options[$value];
+      }
+    }
+  }
+
+  /**
+   * Determines whether the given user has access to view or edit this property.
+   * Apart from relying on access metadata of properties, this takes into
+   * account information about entity level access, if available:
+   *  - Referenced entities can only be viewed, when the user also has
+   *    permission to view the entity.
+   *  - A property may be only edited, if the user has permission to update the
+   *    entity containing the property.
+   *
+   * @param $op
+   *   The operation being performed. One of 'view' or 'edit.
+   * @param $account
+   *   The user to check for. Leave it to NULL to check for the global user.
+   * @return boolean
+   *   Whether access to entity property is allowed for the given operation.
+   *   However if we wrap no data, it returns whether access is allowed to the
+   *   property of all entities of this type.
+   *   If there is no access information for this property, TRUE is returned.
+   */
+  public function access($op, $account = NULL) {
+    if (empty($this->info['parent']) && $this instanceof EntityDrupalWrapper) {
+      // If there is no parent just incorporate entity based access.
+      return $this->entityAccess($op == 'edit' ? 'update' : 'view', $account);
+    }
+    return !empty($this->info['parent']) ? $this->info['parent']->propertyAccess($this->info['name'], $op, $account) : TRUE;
+  }
+
+  /**
+   * Prepare for serializiation.
+   */
+  public function __sleep() {
+    $vars = get_object_vars($this);
+    unset($vars['cache']);
+    return drupal_map_assoc(array_keys($vars));
+  }
+}
+
+/**
+ * Wraps a single value.
+ */
+class EntityValueWrapper extends EntityMetadataWrapper {
+
+  /**
+   * Overrides EntityMetadataWrapper#value().
+   * Sanitizes or decode textual data if necessary.
+   */
+  public function value(array $options = array()) {
+    $data = parent::value();
+    if ($this->type == 'text' && isset($data)) {
+      $info = $this->info + array('sanitized' => FALSE, 'sanitize' => 'check_plain');
+      $options += array('sanitize' => FALSE, 'decode' => FALSE);
+      if ($options['sanitize'] && !$info['sanitized']) {
+        return call_user_func($info['sanitize'], $data);
+      }
+      elseif ($options['decode'] && $info['sanitized']) {
+        return decode_entities(strip_tags($data));
+      }
+    }
+    return $data;
+  }
+}
+
+/**
+ * Provides a general wrapper for any data structure. For this to work the
+ * metadata has to be passed during construction.
+ */
+class EntityStructureWrapper extends EntityMetadataWrapper implements IteratorAggregate {
+
+  protected $propertyInfo = array(), $propertyInfoAltered = FALSE;
+  protected $langcode = LANGUAGE_NONE;
+
+  protected $propertyInfoDefaults = array(
+    'type' => 'text',
+    'getter callback' => 'entity_property_verbatim_get',
+    'clear' => array(),
+  );
+
+  /**
+   * Construct a new EntityStructureWrapper object.
+   *
+   * @param $type
+   *   The type of the passed data.
+   * @param $data
+   *   Optional. The data to wrap.
+   * @param $info
+   *   Used to for specifying metadata about the data and internally to pass
+   *   info about properties down the tree. For specifying metadata known keys
+   *   are:
+   *   - property info: An array of info about the properties of the wrapped
+   *     data structure. It has to contain an array of property info in the same
+   *     structure as used by hook_entity_property_info().
+   */
+  public function __construct($type, $data = NULL, $info = array()) {
+    parent::__construct($type, $data, $info);
+    $this->info += array('property defaults' => array());
+    $info += array('property info' => array());
+    $this->propertyInfo['properties'] = $info['property info'];
+  }
+
+  /**
+   * May be used to lazy-load additional info about the data, depending on the
+   * concrete passed data.
+   */
+  protected function spotInfo() {
+    // Apply the callback if set, such that the caller may alter the info.
+    if (!empty($this->info['property info alter']) && !$this->propertyInfoAltered) {
+      $this->propertyInfo = call_user_func($this->info['property info alter'], $this, $this->propertyInfo);
+      $this->propertyInfoAltered = TRUE;
+    }
+  }
+
+  /**
+   * Gets the info about the given property.
+   *
+   * @param $name
+   *   The name of the property. If not given, info about all properties will
+   *   be returned.
+   * @throws EntityMetadataWrapperException
+   *   If there is no such property.
+   * @return
+   *   An array of info about the property.
+   */
+  public function getPropertyInfo($name = NULL) {
+    $this->spotInfo();
+    if (!isset($name)) {
+      return $this->propertyInfo['properties'];
+    }
+    if (!isset($this->propertyInfo['properties'][$name])) {
+      throw new EntityMetadataWrapperException('Unknown data property ' . check_plain($name) . '.');
+    }
+    return $this->propertyInfo['properties'][$name] + $this->info['property defaults'] + $this->propertyInfoDefaults;
+  }
+
+  /**
+   * Returns a reference on the property info.
+   *
+   * If possible, use the property info alter callback for spotting metadata.
+   * The reference may be used to alter the property info for any remaining
+   * cases, e.g. if additional metadata has been asserted.
+   */
+  public function &refPropertyInfo() {
+    return $this->propertyInfo;
+  }
+
+  /**
+   * Sets a new language to use for retrieving properties.
+   *
+   * @param $langcode
+   *   The language code of the language to set.
+   * @return EntityWrapper
+   */
+  public function language($langcode = LANGUAGE_NONE) {
+    if ($langcode != $this->langcode) {
+      $this->langcode = $langcode;
+      $this->cache = array();
+    }
+    return $this;
+  }
+
+  /**
+   * Gets the language used for retrieving properties.
+   *
+   * @return String
+   *   The language object of the language or NULL for the default language.
+   *
+   * @see EntityStructureWrapper::language()
+   */
+  public function getPropertyLanguage() {
+    if ($this->langcode != LANGUAGE_NONE && $list = language_list()) {
+      if (isset($list[$this->langcode])) {
+        return $list[$this->langcode];
+      }
+    }
+    return NULL;
+  }
+
+  /**
+   * Get the wrapper for a property.
+   *
+   * @return
+   *   An instance of EntityMetadataWrapper.
+   */
+  public function get($name) {
+    // Look it up in the cache if possible.
+    if (!array_key_exists($name, $this->cache)) {
+      if ($info = $this->getPropertyInfo($name)) {
+        $info += array('parent' => $this, 'name' => $name, 'langcode' => $this->langcode, 'property defaults' => array());
+        $info['property defaults'] += $this->info['property defaults'];
+        $this->cache[$name] = entity_metadata_wrapper($info['type'], NULL, $info);
+      }
+      else {
+        throw new EntityMetadataWrapperException('There is no property ' . check_plain($name) . " for this entity.");
+      }
+    }
+    return $this->cache[$name];
+  }
+
+  /**
+   * Magic method: Get a wrapper for a property.
+   */
+  public function __get($name) {
+    if (strpos($name, 'krumo') === 0) {
+      // #914934 Ugly workaround to allow krumo to write its recursion property.
+      // This is necessary to make dpm() work without throwing exceptions.
+      return NULL;
+    }
+    $get = $this->get($name);
+    return $get;
+  }
+
+  /**
+   * Magic method: Set a property.
+   */
+  public function __set($name, $value) {
+    if (strpos($name, 'krumo') === 0) {
+      // #914934 Ugly workaround to allow krumo to write its recursion property.
+      // This is necessary to make dpm() work without throwing exceptions.
+      $this->$name = $value;
+    }
+    else {
+      $this->get($name)->set($value);
+    }
+  }
+
+  /**
+   * Gets the value of a property.
+   */
+  protected function getPropertyValue($name, &$info) {
+    $options = array('language' => $this->getPropertyLanguage(), 'absolute' => TRUE);
+    $data = $this->value();
+    if (!isset($data)) {
+      throw new EntityMetadataWrapperException('Unable to get the data property ' . check_plain($name) . ' as the parent data structure is not set.');
+    }
+    return $info['getter callback']($data, $options, $name, $this->type, $info);
+  }
+
+  /**
+   * Gets the raw value of a property.
+   */
+  protected function getPropertyRaw($name, &$info) {
+    if (!empty($info['raw getter callback'])) {
+      $options = array('language' => $this->getPropertyLanguage(), 'absolute' => TRUE);
+      $data = $this->value();
+      if (!isset($data)) {
+        throw new EntityMetadataWrapperException('Unable to get the data property ' . check_plain($name) . ' as the parent data structure is not set.');
+      }
+      return $info['raw getter callback']($data, $options, $name, $this->type, $info);
+    }
+    return $this->getPropertyValue($name, $info);
+  }
+
+  /**
+   * Sets a property.
+   */
+  protected function setProperty($name, $value) {
+    $info = $this->getPropertyInfo($name);
+    if (!empty($info['setter callback'])) {
+      $data = $this->value();
+
+      // In case the data structure is not set, support simple auto-creation
+      // for arrays. Else an exception is thrown.
+      if (!isset($data)) {
+        if (!empty($this->info['auto creation']) && !($this instanceof EntityDrupalWrapper)) {
+          $data = $this->info['auto creation']($name, $this->info);
+        }
+        else {
+          throw new EntityMetadataWrapperException('Unable to set the data property ' . check_plain($name) . ' as the parent data structure is not set.');
+        }
+      }
+
+      // Invoke the setter callback for updating our data.
+      $info['setter callback']($data, $name, $value, $this->langcode, $this->type, $info);
+
+      // If the setter has not thrown any exceptions, proceed and apply the
+      // update to the current and any parent wrappers as necessary.
+      $data = $this->info['type'] == 'entity' ? $this : $data;
+      $this->set($data);
+
+      // Clear the cache of properties dependent on this value.
+      foreach ($info['clear'] as $name) {
+        if (isset($this->cache[$name])) {
+          $this->cache[$name]->clear();
+        }
+      }
+    }
+    else {
+      throw new EntityMetadataWrapperException('Entity property ' . check_plain($name) . " doesn't support writing.");
+    }
+  }
+
+  protected function propertyAccess($name, $op, $account = NULL) {
+    $info = $this->getPropertyInfo($name);
+    // If the property should be accessed and it's an entity, make sure the user
+    // is allowed to view that entity.
+    if ($op == 'view' && $this->$name instanceof EntityDrupalWrapper && !$this->$name->entityAccess($op, $account)) {
+      return FALSE;
+    }
+    // If a property should be edited and this is an entity, make sure the user
+    // has update access for this entity.
+    if ($op == 'edit') {
+      $entity = $this;
+      while (!($entity instanceof EntityDrupalWrapper) && isset($entity->info['parent'])) {
+        $entity = $entity->info['parent'];
+      }
+      if ($entity instanceof EntityDrupalWrapper && !$entity->entityAccess('update', $account)) {
+        return FALSE;
+      }
+    }
+    if (!empty($info['access callback'])) {
+      $data = $this->dataAvailable() ? $this->value() : NULL;
+      return call_user_func($info['access callback'], $op, $name, $data, $account, $this->type);
+    }
+    elseif ($op == 'edit' && isset($info['setter permission'])) {
+      return user_access($info['setter permission'], $account);
+    }
+    return TRUE;
+  }
+
+  /**
+   * Magic method: Can be used to check if a property is known.
+   */
+  public function __isset($name) {
+    $this->spotInfo();
+    return isset($this->propertyInfo['properties'][$name]);
+  }
+
+  public function getIterator() {
+    $this->spotInfo();
+    return new EntityMetadataWrapperIterator($this, array_keys($this->propertyInfo['properties']));
+  }
+
+  /**
+   * Returns the identifier of the data structure. If there is none, NULL is
+   * returned.
+   */
+  public function getIdentifier() {
+    return isset($this->id) && $this->dataAvailable() ? $this->id->value() : NULL;
+  }
+
+  /**
+   * Prepare for serializiation.
+   */
+  public function __sleep() {
+    $vars = parent::__sleep();
+    unset($vars['propertyInfoDefaults']);
+    return $vars;
+  }
+
+  public function clear() {
+    $this->propertyInfoAltered = FALSE;
+    parent::clear();
+  }
+}
+
+/**
+ * Provides a wrapper for entities registrered in hook_entity_info().
+ *
+ * The wrapper eases applying getter and setter callbacks of entity properties
+ * specified in hook_entity_property_info().
+ */
+class EntityDrupalWrapper extends EntityStructureWrapper {
+
+  /**
+   * Contains the entity id.
+   */
+  protected $id = FALSE;
+  protected $bundle;
+  protected $entityInfo;
+
+  /**
+   * Construct a new EntityDrupalWrapper object.
+   *
+   * @param $type
+   *   The type of the passed data.
+   * @param $data
+   *   Optional. The entity to wrap or its identifier.
+   * @param $info
+   *   Optional. Used internally to pass info about properties down the tree.
+   */
+  public function __construct($type, $data = NULL, $info = array()) {
+    parent::__construct($type, $data, $info);
+    $this->setUp();
+  }
+
+  protected function setUp() {
+    $this->propertyInfo = entity_get_property_info($this->type) + array('properties' => array());
+    $info = $this->info + array('property info' => array(), 'bundle' => NULL);
+    $this->propertyInfo['properties'] += $info['property info'];
+    $this->bundle = $info['bundle'];
+    $this->entityInfo = entity_get_info($this->type);
+    if (isset($this->bundle)) {
+      $this->spotBundleInfo(FALSE);
+    }
+  }
+
+  /**
+   * Sets the entity internally accepting both the entity id and object.
+   */
+  protected function setEntity($data) {
+    // For entities we allow getter callbacks to return FALSE, which we
+    // interpret like NULL values as unset properties.
+    if (isset($data) && $data !== FALSE && !is_object($data)) {
+      $this->id = $data;
+      $this->data = FALSE;
+    }
+    elseif (is_object($data) && $data instanceof EntityDrupalWrapper) {
+      // We got a wrapped entity passed, so take over its values.
+      $this->id = $data->id;
+      $this->data = $data->data;
+      // For generic entity references, also update the entity type accordingly.
+      if ($this->info['type'] == 'entity') {
+        $this->type = $data->type;
+      }
+    }
+    elseif (is_object($data)) {
+      // We got the entity object passed.
+      $this->data = $data;
+      $id = entity_id($this->type, $data);
+      $this->id = isset($id) ? $id : FALSE;
+    }
+    else {
+      $this->id = FALSE;
+      $this->data = NULL;
+    }
+  }
+
+  /**
+   * Used to lazy-load bundle info. So the wrapper can be loaded e.g. just
+   * for setting without the data being loaded.
+   */
+  protected function spotInfo() {
+    if (!$this->propertyInfoAltered) {
+      if ($this->info['type'] == 'entity' && $this->dataAvailable() && $this->value()) {
+        // Add in entity-type specific details.
+        $this->setUp();
+      }
+      $this->spotBundleInfo(TRUE);
+      parent::spotInfo();
+      $this->propertyInfoAltered = TRUE;
+    }
+  }
+
+  /**
+   * Tries to determine the bundle and adds in the according property info.
+   *
+   * @param $load
+   *   Whether the entity should be loaded to spot the info if necessary.
+   */
+  protected function spotBundleInfo($load = TRUE) {
+    // Like entity_extract_ids() assume the entity type if no key is given.
+    if (empty($this->entityInfo['entity keys']['bundle']) && $this->type != 'entity') {
+      $this->bundle = $this->type;
+    }
+    // Detect the bundle if not set yet and add in properties from the bundle.
+    elseif (!$this->bundle && !empty($this->entityInfo['fieldable']) && $load && $this->dataAvailable()) {
+      try {
+        if ($entity = $this->value()) {
+          list($id, $vid, $bundle) = entity_extract_ids($this->type, $entity);
+          $this->bundle = $bundle;
+        }
+      }
+      catch (EntityMetadataWrapperException $e) {
+        // Loading data failed, so we cannot derive the used bundle.
+      }
+    }
+
+    if ($this->bundle && isset($this->propertyInfo['bundles'][$this->bundle])) {
+      $bundle_info = (array) $this->propertyInfo['bundles'][$this->bundle] + array('properties' => array());
+      // Allow bundles to re-define existing properties, such that the bundle
+      // can add in more bundle-specific details like the bundle of a referenced
+      // entity.
+      $this->propertyInfo['properties'] = $bundle_info['properties'] + $this->propertyInfo['properties'];
+    }
+  }
+
+  /**
+   * Returns the identifier of the wrapped entity.
+   *
+   * @see entity_id()
+   */
+  public function getIdentifier() {
+    return $this->dataAvailable() ? $this->value(array('identifier' => TRUE)) : NULL;
+  }
+
+  /**
+   * Returns the bundle of an entity, or FALSE if it has no bundles.
+   */
+  public function getBundle() {
+    if ($this->dataAvailable()) {
+      $this->spotInfo();
+      return $this->bundle;
+    }
+  }
+
+  /**
+   * Overridden.
+   *
+   * @param $options
+   *   An array of options. Known keys:
+   *   - identifier: If set to TRUE, the entity identifier is returned.
+   */
+  public function value(array $options = array()) {
+    // Try loading the data via the getter callback if there is none yet.
+    if (!isset($this->data)) {
+      $this->setEntity(parent::value());
+    }
+    if (!empty($options['identifier'])) {
+      return $this->id;
+    }
+    elseif (!$this->data && !empty($this->id)) {
+      // Lazy load the entity if necessary.
+      $return = entity_load($this->type, array($this->id));
+      // In case the entity cannot be loaded, we return NULL just as for empty
+      // properties.
+      $this->data = $return ? reset($return) : NULL;
+    }
+    return $this->data;
+  }
+
+  /**
+   * Overridden to support setting the entity by either the object or the id.
+   */
+  public function set($value) {
+    if (!$this->validate($value)) {
+      throw new EntityMetadataWrapperException('Invalid data value given. Be sure it matches the required data type and format.');
+    }
+    if ($this->info['type'] == 'entity' && $value === $this) {
+      // Nothing to do.
+      return $this;
+    }
+    $previous_id = $this->id;
+    $previous_type = $this->type;
+    // Set value, so we get the identifier and pass it to the normal setter.
+    $this->clear();
+    $this->setEntity($value);
+    // Generally, we have to update the parent only if the entity reference
+    // has changed. In case of a generic entity reference, we pass the entity
+    // wrapped. Else we just pass the id of the entity to the setter callback.
+    if ($this->info['type'] == 'entity' && ($previous_id != $this->id || $previous_type != $this->type)) {
+      // We need to clone the wrapper we pass through as value, so it does not
+      // get cleared when the current wrapper instance gets cleared.
+      $this->updateParent(clone $this);
+    }
+    // In case the entity has been unset, we cannot properly detect changes as
+    // the previous id defaults to FALSE for unloaded entities too. So in that
+    // case we just always update the parent.
+    elseif ($this->id === FALSE && !$this->data) {
+      $this->updateParent(NULL);
+    }
+    elseif ($previous_id != $this->id) {
+      $this->updateParent($this->id);
+    }
+    return $this;
+  }
+
+  /**
+   * Overridden.
+   */
+  public function clear() {
+    $this->id = NULL;
+    $this->bundle = isset($this->info['bundle']) ? $this->info['bundle'] : NULL;
+    if ($this->type != $this->info['type']) {
+      // Reset entity info / property info based upon the info provided during
+      // the creation of the wrapper.
+      $this->type = $this->info['type'];
+      $this->setUp();
+    }
+    parent::clear();
+  }
+
+  /**
+   * Overridden.
+   */
+  public function type() {
+    // In case of a generic entity wrapper, load the data first to determine
+    // the type of the concrete entity.
+    if ($this->dataAvailable() && $this->info['type'] == 'entity') {
+      try {
+        $this->value(array('identifier' => TRUE));
+      }
+      catch (EntityMetadataWrapperException $e) {
+        // If loading data fails, we cannot determine the concrete entity type.
+      }
+    }
+    return $this->type;
+  }
+
+  /**
+   * Checks whether the operation $op is allowed on the entity.
+   *
+   * @see entity_access()
+   */
+  public function entityAccess($op, $account = NULL) {
+    $entity = $this->dataAvailable() ? $this->value() : NULL;
+    return entity_access($op, $this->type, $entity, $account);
+  }
+
+  /**
+   * Permanently save the wrapped entity.
+   *
+   * @throws EntityMetadataWrapperException
+   *   If the entity type does not support saving.
+   *
+   * @return EntityDrupalWrapper
+   */
+  public function save() {
+    if ($this->data) {
+      if (!entity_type_supports($this->type, 'save')) {
+        throw new EntityMetadataWrapperException("There is no information about how to save entities of type " . check_plain($this->type) . '.');
+      }
+      entity_save($this->type, $this->data);
+      // On insert, update the identifier afterwards.
+      if (!$this->id) {
+        list($this->id, , ) = entity_extract_ids($this->type, $this->data);
+      }
+    }
+    // If the entity hasn't been loaded yet, don't bother saving it.
+    return $this;
+  }
+
+  /**
+   * Permanently delete the wrapped entity.
+   *
+   * @return EntityDrupalWrapper
+   */
+  public function delete() {
+    if ($this->dataAvailable() && $this->value()) {
+      $return = entity_delete($this->type, $this->id);
+      if ($return === FALSE) {
+        throw new EntityMetadataWrapperException("There is no information about how to delete entities of type " . check_plain($this->type) . '.');
+      }
+    }
+    return $this;
+  }
+
+  /**
+   * Gets the info about the wrapped entity.
+   */
+  public function entityInfo() {
+    return $this->entityInfo;
+  }
+
+  /**
+   * Returns the name of the key used by the entity for given entity key.
+   *
+   * @param $name
+   *   One of 'id', 'name', 'bundle' or 'revision'.
+   * @return
+   *   The name of the key used by the entity.
+   */
+  public function entityKey($name) {
+    return isset($this->entityInfo['entity keys'][$name]) ? $this->entityInfo['entity keys'][$name] : FALSE;
+  }
+
+  /**
+   * Returns the entity label.
+   *
+   * @see entity_label()
+   */
+  public function label() {
+    if ($entity = $this->value()) {
+      return entity_label($this->type, $entity);
+    }
+  }
+
+  /**
+   * Prepare for serializiation.
+   */
+  public function __sleep() {
+    $vars = parent::__sleep();
+    // Don't serialize the loaded entity and its property info.
+    unset($vars['data'], $vars['propertyInfo'], $vars['propertyInfoAltered'], $vars['entityInfo']);
+    // In case the entity is not saved yet, serialize the unsaved data.
+    if ($this->dataAvailable() && $this->id === FALSE) {
+      $vars['data'] = 'data';
+    }
+    return $vars;
+  }
+
+  public function __wakeup() {
+    $this->setUp();
+    if ($this->id !== FALSE) {
+      // Make sure data is set, so the entity will be loaded when needed.
+      $this->data = FALSE;
+    }
+  }
+}
+
+/**
+ * Wraps a list of values.
+ *
+ * If the wrapped data is a list of data, its numerical indexes may be used to
+ * retrieve wrappers for the list items. For that this wrapper implements
+ * ArrayAccess so it may be used like a usual numerically indexed array.
+ */
+class EntityListWrapper extends EntityMetadataWrapper implements IteratorAggregate, ArrayAccess, Countable {
+
+  /**
+   * The type of contained items.
+   */
+  protected $itemType;
+
+  /**
+   * Whether this is a list of entities with a known entity type, i.e. for
+   * generic list of entities (list<entity>) this is FALSE.
+   */
+  protected $isEntityList;
+
+
+  public function __construct($type, $data = NULL, $info = array()) {
+    parent::__construct($type, NULL, $info);
+
+    $this->itemType = entity_property_list_extract_type($this->type);
+    if (!$this->itemType) {
+      $this->itemType = 'unknown';
+    }
+    $this->isEntityList = (bool) entity_get_info($this->itemType);
+
+    if (isset($data)) {
+      $this->set($data);
+    }
+  }
+
+  /**
+   * Get the wrapper for a single item.
+   *
+   * @return
+   *   An instance of EntityMetadataWrapper.
+   */
+  public function get($delta) {
+    // Look it up in the cache if possible.
+    if (!array_key_exists($delta, $this->cache)) {
+      if (!isset($delta)) {
+        // The [] operator has been used so point at a new entry.
+        $values = parent::value();
+        $delta = $values ? max(array_keys($values)) + 1 : 0;
+      }
+      if (is_numeric($delta)) {
+        $info = array('parent' => $this, 'name' => $delta) + $this->info;
+        $this->cache[$delta] = entity_metadata_wrapper($this->itemType, NULL, $info);
+      }
+      else {
+        throw new EntityMetadataWrapperException('There can be only numerical keyed items in a list.');
+      }
+    }
+    return $this->cache[$delta];
+  }
+
+  protected function getPropertyValue($delta) {
+    // Make use parent::value() to easily by-pass any entity-loading.
+    $data = parent::value();
+    if (isset($data[$delta])) {
+      return $data[$delta];
+    }
+  }
+
+  protected function getPropertyRaw($delta) {
+    return $this->getPropertyValue($delta);
+  }
+
+  protected function setProperty($delta, $value) {
+    $data = parent::value();
+    if (is_numeric($delta)) {
+      $data[$delta] = $value;
+      $this->set($data);
+    }
+  }
+
+  protected function propertyAccess($delta, $op, $account = NULL) {
+    return $this->access($op, $account);
+  }
+
+  /**
+   * Returns the list as numerically indexed array.
+   *
+   * Note that a list of entities might contain stale entity references. In
+   * that case the wrapper and the identifier of a stale reference would be
+   * still accessible, however the entity object value would be NULL. That way,
+   * there may be NULL values in lists of entity objects due to stale entity
+   * references.
+   *
+   * @param $options
+   *   An array of options. Known keys:
+   *   - identifier: If set to TRUE for a list of entities, it won't be returned
+   *     as list of fully loaded entity objects, but as a list of entity ids.
+   *     Note that this list may contain ids of stale entity references.
+   */
+  public function value(array $options = array()) {
+    // For lists of entities fetch full entity objects before returning.
+    // Generic entity-wrappers need to be handled separately though.
+    if ($this->isEntityList && empty($options['identifier']) && $this->dataAvailable()) {
+      $list = parent::value();
+      $entities = $list ? entity_load($this->get(0)->type, $list) : array();
+      // Make sure to keep the array keys as present in the list.
+      foreach ($list as $key => $id) {
+        // In case the entity cannot be loaded, we return NULL just as for empty
+        // properties.
+        $list[$key] = isset($entities[$id]) ? $entities[$id] : NULL;
+      }
+      return $list;
+    }
+    return parent::value();
+  }
+
+  public function set($values) {
+    // Support setting lists of fully loaded entities.
+    if ($this->isEntityList && $values && is_object(reset($values))) {
+      foreach ($values as $key => $value) {
+        list($id, $vid, $bundle) = entity_extract_ids($this->itemType, $value);
+        $values[$key] = $id;
+      }
+    }
+    return parent::set($values);
+  }
+
+  /**
+   * If we wrap a list, we return an iterator over the data list.
+   */
+  public function getIterator() {
+    // In case there is no data available, just iterate over the first item.
+    return new EntityMetadataWrapperIterator($this, $this->dataAvailable() ? array_keys(parent::value()) : array(0));
+  }
+
+  /**
+   * Implements the ArrayAccess interface.
+   */
+  public function offsetGet($delta) {
+    return $this->get($delta);
+  }
+
+  public function offsetExists($delta) {
+    return $this->dataAvailable() && ($data = $this->value()) && array_key_exists($delta, $data);
+  }
+
+  public function offsetSet($delta, $value) {
+    $this->get($delta)->set($value);
+  }
+
+  public function offsetUnset($delta) {
+    if ($this->offsetExists($delta)) {
+      unset($this->data[$delta]);
+      $this->set($this->data);
+    }
+  }
+
+  public function count() {
+    return $this->dataAvailable() ? count($this->value()) : 0;
+  }
+
+  /**
+   * Overridden.
+   */
+  public function validate($value) {
+    // Required lists may not be empty or unset.
+    if (!empty($this->info['required']) && empty($value)) {
+      return FALSE;
+    }
+    return parent::validate($value);
+  }
+
+  /**
+   * Returns the label for the list of set values if available.
+   */
+  public function label() {
+    if ($options = $this->optionsList('view')) {
+      $options = entity_property_options_flatten($options);
+      $labels = array_intersect_key($options, array_flip((array) parent::value()));
+    }
+    else {
+      // Get each label on its own, e.g. to support getting labels of a list
+      // of entities.
+      $labels = array();
+      foreach ($this as $key => $property) {
+        $label = $property->label();
+        if (!$label) {
+          return NULL;
+        }
+        $labels[] = $label;
+      }
+    }
+    return isset($labels) ? implode(', ', $labels) : NULL;
+  }
+}
+
+/**
+ * Provide a separate Exception so it can be caught separately.
+ */
+class EntityMetadataWrapperException extends Exception { }
+
+
+/**
+ * Allows to easily iterate over existing child wrappers.
+ */
+class EntityMetadataWrapperIterator implements RecursiveIterator {
+
+  protected $position = 0;
+  protected $wrapper, $keys;
+
+  public function __construct(EntityMetadataWrapper $wrapper, array $keys) {
+    $this->wrapper = $wrapper;
+    $this->keys = $keys;
+  }
+
+  function rewind() {
+    $this->position = 0;
+  }
+
+  function current() {
+    return $this->wrapper->get($this->keys[$this->position]);
+  }
+
+  function key() {
+    return $this->keys[$this->position];
+  }
+
+  function next() {
+    $this->position++;
+  }
+
+  function valid() {
+    return isset($this->keys[$this->position]);
+  }
+
+  public function hasChildren() {
+    return $this->current() instanceof IteratorAggregate;
+  }
+
+  public function getChildren() {
+    return $this->current()->getIterator();
+  }
+}
+
+/**
+ * An array object implementation keeping the reference on the given array so
+ * changes to the object are reflected in the passed array.
+ */
+class EntityMetadataArrayObject implements ArrayAccess, Countable, IteratorAggregate {
+
+  protected $data;
+
+  public function __construct(&$array) {
+    $this->data =& $array;
+  }
+
+  public function &getArray() {
+    return $this->data;
+  }
+
+  /**
+   * Implements the ArrayAccess interface.
+   */
+  public function offsetGet($delta) {
+    return $this->data[$delta];
+  }
+
+  public function offsetExists($delta) {
+    return array_key_exists($delta, $this->data);
+  }
+
+  public function offsetSet($delta, $value) {
+    $this->data[$delta] = $value;
+  }
+
+  public function offsetUnset($delta) {
+    unset($this->data[$delta]);
+  }
+
+  public function count() {
+    return count($this->data);
+  }
+
+  public function getIterator() {
+    return new ArrayIterator($this->data);
+  }
+}
diff --git a/sites/all/modules/entity/modules/book.info.inc b/sites/all/modules/entity/modules/book.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..3803ec81783389e1bc9d95b71208aa5c7ed4e7da
--- /dev/null
+++ b/sites/all/modules/entity/modules/book.info.inc
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @file
+ * Provides info about book nodes.
+ */
+
+/**
+ * Implements hook_entity_property_info_alter() on top of book module.
+ *
+ * @see entity_entity_property_info_alter()
+ */
+function entity_metadata_book_entity_property_info_alter(&$info) {
+  // Add meta-data about the added node properties.
+  $properties = &$info['node']['properties'];
+
+  $properties['book'] = array(
+    'label' => t("Book"),
+    'type' => 'node',
+    'description' => t("If part of a book, the book to which this book page belongs."),
+    'getter callback' => 'entity_metadata_book_get_properties',
+  );
+}
\ No newline at end of file
diff --git a/sites/all/modules/entity/modules/callbacks.inc b/sites/all/modules/entity/modules/callbacks.inc
new file mode 100644
index 0000000000000000000000000000000000000000..bfcc4362afa1d62aed076750f49e493d25d37a44
--- /dev/null
+++ b/sites/all/modules/entity/modules/callbacks.inc
@@ -0,0 +1,921 @@
+<?php
+
+/**
+ * @file
+ * Provides various callbacks for the whole core module integration.
+ */
+
+/**
+ * Callback for getting properties of an entity.
+ */
+function entity_metadata_entity_get_properties($entity, array $options, $name, $entity_type) {
+  if ($name == 'url') {
+    $return = entity_uri($entity_type, $entity);
+    return url($return['path'], $return['options'] + $options);
+  }
+}
+
+/**
+ * Callback for getting book node properties.
+ * @see entity_metadata_book_entity_info_alter()
+ */
+function entity_metadata_book_get_properties($node, array $options, $name, $entity_type) {
+  if (!isset($node->book['bid'])) {
+    throw new EntityMetadataWrapperException('This node is no book page.');
+  }
+  return $node->book['bid'];
+}
+
+/**
+ * Callback for getting comment properties.
+ * @see entity_metadata_comment_entity_info_alter()
+ */
+function entity_metadata_comment_get_properties($comment, array $options, $name) {
+  switch ($name) {
+    case 'name':
+      return $name = ($comment->uid == 0) ? variable_get('anonymous', t('Anonymous')) : $comment->name;
+
+    case 'mail':
+      if ($comment->uid != 0) {
+        $account = user_load($comment->uid);
+        return $account->mail;
+      }
+      return $comment->mail;
+
+    case 'edit_url':
+      return url('comment/edit/' . $comment->cid, $options);
+
+    case 'parent':
+      if (!empty($comment->pid)) {
+        return $comment->pid;
+      }
+      // There is no parent comment.
+      return NULL;
+  }
+}
+
+/**
+ * Callback for setting comment properties.
+ * @see entity_metadata_comment_entity_info_alter()
+ */
+function entity_metadata_comment_setter($comment, $name, $value) {
+  switch ($name) {
+    case 'node':
+      $comment->nid = $value;
+      // Also set the bundle name.
+      $node = node_load($value);
+      $comment->node_type = 'comment_node_' . $node->type;
+      break;
+  }
+}
+
+/**
+ * Callback for getting comment related node properties.
+ * @see entity_metadata_comment_entity_info_alter()
+ */
+function entity_metadata_comment_get_node_properties($node, array $options, $name, $entity_type) {
+  switch ($name) {
+    case 'comment_count':
+      return isset($node->comment_count) ? $node->comment_count : 0;
+
+    case 'comment_count_new':
+      return comment_num_new($node->nid);
+  }
+}
+
+/**
+ * Getter callback for getting global languages.
+ */
+function entity_metadata_locale_get_languages($data, array $options, $name) {
+  return isset($GLOBALS[$name]) ? $GLOBALS[$name]->language : NULL;
+}
+
+/**
+ * Getter callback for getting the preferred user language.
+ */
+function entity_metadata_locale_get_user_language($account, array $options, $name) {
+  return user_preferred_language($account)->language;
+}
+
+/**
+ * Return the options lists for the node and comment status property.
+ */
+function entity_metadata_status_options_list() {
+  return array(
+    NODE_PUBLISHED => t('Published'),
+    NODE_NOT_PUBLISHED => t('Unpublished'),
+  );
+}
+
+/**
+ * Callback for getting node properties.
+ *
+ * @see entity_metadata_node_entity_info_alter()
+ */
+function entity_metadata_node_get_properties($node, array $options, $name, $entity_type) {
+  switch ($name) {
+    case 'is_new':
+      return empty($node->nid) || !empty($node->is_new);
+
+    case 'source':
+      if (!empty($node->tnid) && $source = node_load($node->tnid)) {
+        return $source;
+      }
+      return NULL;
+
+    case 'edit_url':
+      return url('node/' . $node->nid . '/edit', $options);
+  }
+}
+
+/**
+ * Callback for determing access for node revision related properties.
+ */
+function entity_metadata_node_revision_access($op, $name, $entity = NULL, $account = NULL) {
+  return $op == 'view' ? user_access('view revisions', $account) : user_access('administer nodes', $account);
+}
+
+/**
+ * Callback for getting poll properties.
+ * @see entity_metadata_poll_entity_info_alter()
+ */
+function entity_metadata_poll_node_get_properties($node, array $options, $name) {
+  $total_votes = $highest_votes = 0;
+  foreach ($node->choice as $choice) {
+    if ($choice['chvotes'] > $highest_votes) {
+      $winner = $choice;
+      $highest_votes = $choice['chvotes'];
+    }
+    $total_votes = $total_votes + $choice['chvotes'];
+  }
+
+  if ($name == 'poll_duration') {
+    return $node->runtime;
+  }
+  elseif ($name == 'poll_votes') {
+    return $total_votes;
+  }
+  elseif (!isset($winner)) {
+    // There is no poll winner yet.
+    return NULL;
+  }
+  switch ($name) {
+    case 'poll_winner_votes':
+        return $winner['chvotes'];
+
+    case 'poll_winner':
+        return $winner['chtext'];
+
+    case 'poll_winner_percent':
+        return ($winner['chvotes'] / $total_votes) * 100;
+  }
+}
+
+/**
+ * Callback for getting statistics properties.
+ * @see entity_metadata_statistics_entity_info_alter()
+ */
+function entity_metadata_statistics_node_get_properties($node, array $options, $name) {
+  $statistics = (array) statistics_get($node->nid);
+  $statistics += array('totalcount' => 0, 'daycount' => 0, 'timestamp' => NULL);
+
+  switch ($name) {
+    case 'views':
+      return $statistics['totalcount'];
+
+    case 'day_views':
+      return $statistics['daycount'];
+
+    case 'last_view':
+      return $statistics['timestamp'];
+  }
+}
+
+/**
+ * Callback for getting site-wide properties.
+ * @see entity_metadata_system_entity_info_alter()
+ */
+function entity_metadata_system_get_properties($data = FALSE, array $options, $name) {
+  switch ($name) {
+    case 'name':
+      return variable_get('site_name', 'Drupal');
+
+    case 'url':
+      return url('<front>', $options);
+
+    case 'login_url':
+      return url('user', $options);
+
+    case 'current_user':
+      return $GLOBALS['user']->uid ? $GLOBALS['user']->uid : drupal_anonymous_user();
+
+    case 'current_date':
+      return REQUEST_TIME;
+
+    case 'current_page':
+      // Subsequent getters of the struct retrieve the actual values.
+      return array();
+
+    default:
+      return variable_get('site_' . $name, '');
+  }
+}
+
+/**
+ * Callback for getting properties for the current page request.
+ * @see entity_metadata_system_entity_info_alter()
+ */
+function entity_metadata_system_get_page_properties($data = array(), array $options, $name) {
+  switch ($name) {
+    case 'url':
+      return $GLOBALS['base_root'] . request_uri();
+  }
+}
+
+/**
+ * Callback for getting file properties.
+ * @see entity_metadata_system_entity_info_alter()
+ */
+function entity_metadata_system_get_file_properties($file, array $options, $name) {
+  switch ($name) {
+    case 'name':
+      return $file->filename;
+
+    case 'mime':
+      return $file->filemime;
+
+    case 'size':
+      return $file->filesize;
+
+    case 'url':
+      return url(file_create_url($file->uri), $options);
+
+    case 'owner':
+      return $file->uid;
+  }
+}
+
+/**
+ * Callback for getting term properties.
+ *
+ * @see entity_metadata_taxonomy_entity_info_alter()
+ */
+function entity_metadata_taxonomy_term_get_properties($term, array $options, $name) {
+  switch ($name) {
+    case 'node_count':
+      return count(taxonomy_select_nodes($term->tid));
+
+    case 'description':
+      return check_markup($term->description, isset($term->format) ? $term->format : NULL, '', TRUE);
+
+    case 'parent':
+      if (isset($term->parent[0]) && !is_array(isset($term->parent[0]))) {
+        return $term->parent;
+      }
+      return array_keys(taxonomy_get_parents($term->tid));
+
+    case 'parents_all':
+      // We have to return an array of ids.
+      $tids = array();
+      foreach (taxonomy_get_parents_all($term->tid) as $parent) {
+        $tids[] = $parent->tid;
+      }
+      return $tids;
+  }
+}
+
+/**
+ * Callback for setting term properties.
+ *
+ * @see entity_metadata_taxonomy_entity_info_alter()
+ */
+function entity_metadata_taxonomy_term_setter($term, $name, $value) {
+  switch ($name) {
+    case 'vocabulary':
+      // Make sure to also update the taxonomy bundle key.
+      $vocabulary = taxonomy_vocabulary_load($value);
+      $term->vocabulary_machine_name = $vocabulary->machine_name;
+      return $term->vid = $value;
+    case 'parent':
+      return $term->parent = $value;
+  }
+}
+
+/**
+ * Callback for getting vocabulary properties.
+ * @see entity_metadata_taxonomy_entity_info_alter()
+ */
+function entity_metadata_taxonomy_vocabulary_get_properties($vocabulary, array $options, $name) {
+  switch ($name) {
+    case 'term_count':
+      $sql = "SELECT COUNT (1) FROM {taxonomy_term_data} td WHERE td.vid = :vid";
+      return db_query($sql, array(':vid' => $vocabulary->vid))->fetchField();
+  }
+}
+
+/**
+ * Callback for getting user properties.
+ * @see entity_metadata_user_entity_info_alter()
+ */
+function entity_metadata_user_get_properties($account, array $options, $name, $entity_type) {
+  switch ($name) {
+    case 'last_access':
+      // In case there was no access the value is 0, but we have to return NULL.
+      return empty($account->access) ? NULL : $account->access;
+
+    case 'last_login':
+      return empty($account->login) ? NULL : $account->login;
+
+    case 'name':
+      return empty($account->uid) ? variable_get('anonymous', t('Anonymous')) : $account->name;
+
+    case 'url':
+      if (empty($account->uid)) {
+        return NULL;
+      }
+      $return = entity_uri('user', $account);
+      return $return ? url($return['path'], $return['options'] + $options) : '';
+
+    case 'edit_url':
+      return empty($account->uid) ? NULL : url("user/$account->uid/edit", $options);
+
+    case 'roles':
+      return isset($account->roles) ? array_keys($account->roles) : array();
+
+    case 'theme':
+      return empty($account->theme) ? variable_get('theme_default', 'bartik') : $account->theme;
+  }
+}
+
+/**
+ * Callback for setting user properties.
+ * @see entity_metadata_user_entity_info_alter()
+ */
+function entity_metadata_user_set_properties($account, $name, $value) {
+  switch ($name) {
+    case 'roles':
+      $account->roles = array_intersect_key(user_roles(), array_flip($value));
+      break;
+  }
+}
+
+/**
+ * Options list callback returning all user roles.
+ */
+function entity_metadata_user_roles($property_name = 'roles', $info = array(), $op = 'edit') {
+  $roles = user_roles();
+  if ($op == 'edit') {
+    unset($roles[DRUPAL_AUTHENTICATED_RID], $roles[DRUPAL_ANONYMOUS_RID]);
+  }
+  return $roles;
+}
+
+/**
+ * Return the options lists for user status property.
+ */
+function entity_metadata_user_status_options_list() {
+  return array(
+    0 => t('Blocked'),
+    1 => t('Active'),
+  );
+}
+
+/**
+ * Callback defining an options list for language properties.
+ */
+function entity_metadata_language_list() {
+  $list = array();
+  $list[LANGUAGE_NONE] = t('Language neutral');
+  foreach (language_list() as $language) {
+    $list[$language->language] = $language->name;
+  }
+  return $list;
+}
+
+/**
+ * Callback for getting field property values.
+ */
+function entity_metadata_field_property_get($entity, array $options, $name, $entity_type, $info) {
+  $field = field_info_field($name);
+  $columns = array_keys($field['columns']);
+  $langcode = isset($options['language']) ? $options['language']->language : LANGUAGE_NONE;
+  $langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode, TRUE);
+  $values = array();
+  if (isset($entity->{$name}[$langcode])) {
+    foreach ($entity->{$name}[$langcode] as $delta => $data) {
+      $values[$delta] = $data[$columns[0]];
+      if ($info['type'] == 'boolean' || $info['type'] == 'list<boolean>') {
+        // Ensure that we have a clean boolean data type.
+        $values[$delta] = (boolean) $values[$delta];
+      }
+    }
+  }
+  // For an empty single-valued field, we have to return NULL.
+  return $field['cardinality'] == 1 ? ($values ? reset($values) : NULL) : $values;
+}
+
+/**
+ * Callback for setting field property values.
+ */
+function entity_metadata_field_property_set($entity, $name, $value, $langcode, $entity_type) {
+  $field = field_info_field($name);
+  $columns = array_keys($field['columns']);
+  $langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode);
+  $values = $field['cardinality'] == 1 ? array($value) : (array) $value;
+
+  $items = array();
+  foreach ($values as $delta => $value) {
+    if (isset($value)) {
+      $items[$delta][$columns[0]] = $value;
+    }
+  }
+  $entity->{$name}[$langcode] = $items;
+  // Empty the static field language cache, so the field system picks up any
+  // possible new languages.
+  drupal_static_reset('field_language');
+}
+
+/**
+ * Callback returning the options list of a field.
+ */
+function entity_metadata_field_options_list($name, $info) {
+  $field_property_info = $info;
+  if (is_numeric($name) && isset($info['parent'])) {
+    // The options list is to be returned for a single item of a multiple field.
+    $field_property_info = $info['parent']->info();
+    $name = $field_property_info['name'];
+  }
+  if (($field = field_info_field($name)) && isset($field_property_info['parent'])) {
+    // Retrieve the wrapped entity holding the field.
+    $wrapper = $field_property_info['parent'];
+    try {
+      $entity = $wrapper->value();
+    }
+    catch (EntityMetadataWrapperException $e) {
+      // No data available.
+      $entity = NULL;
+    }
+    $instance = $wrapper->getBundle() ? field_info_instance($wrapper->type(), $name, $wrapper->getBundle()) : NULL;
+    return (array) module_invoke($field['module'], 'options_list', $field, $instance, $wrapper->type(), $entity);
+  }
+}
+
+/**
+ * Callback to verbatim get the data structure of a field. Useful for fields
+ * that add metadata for their own data structure.
+ */
+function entity_metadata_field_verbatim_get($entity, array $options, $name, $entity_type, &$context) {
+  // Set contextual info useful for getters of any child properties.
+  $context['instance'] = field_info_instance($context['parent']->type(), $name, $context['parent']->getBundle());
+  $context['field'] = field_info_field($name);
+  $langcode = isset($options['language']) ? $options['language']->language : LANGUAGE_NONE;
+  $langcode = entity_metadata_field_get_language($entity_type, $entity, $context['field'], $langcode, TRUE);
+
+  if ($context['field']['cardinality'] == 1) {
+    return isset($entity->{$name}[$langcode][0]) ? $entity->{$name}[$langcode][0] : NULL;
+  }
+  return isset($entity->{$name}[$langcode]) ? $entity->{$name}[$langcode] : array();
+}
+
+/**
+ * Writes the passed field items in the object. Useful as field level setter
+ * to set the whole data structure at once.
+ */
+function entity_metadata_field_verbatim_set($entity, $name, $items, $langcode, $entity_type) {
+  $field = field_info_field($name);
+  $langcode = entity_metadata_field_get_language($entity_type, $entity, $entity_type, $langcode);
+  $value = $field['cardinality'] == 1 ? array($items) : (array) $items;
+  // Filter out any items set to NULL.
+  $entity->{$name}[$langcode] = array_filter($value);
+
+  // Empty the static field language cache, so the field system picks up any
+  // possible new languages.
+  drupal_static_reset('field_language');
+}
+
+/**
+ * Helper for determining the field language to be used.
+ *
+ * Note that we cannot use field_language() as we are not about to display
+ * values, but generally read/write values.
+ *
+ * @param $fallback
+ *   (optional) Whether to fall back to the entity default language, if no
+ *   value is available for the given language code yet.
+ *
+ * @return
+ *   The language code to use.
+ */
+function entity_metadata_field_get_language($entity_type, $entity, $field, $langcode = LANGUAGE_NONE, $fallback = FALSE) {
+  // Try to figure out the default language used by the entity.
+  // @todo: Update once http://drupal.org/node/1260640 has been fixed.
+  $default_langcode = isset($entity->language) ? $entity->language : LANGUAGE_NONE;
+
+  // Determine the right language to use.
+  if ($default_langcode != LANGUAGE_NONE && field_is_translatable($entity_type, $field)) {
+    $langcode = ($langcode != LANGUAGE_NONE) ? field_valid_language($langcode, $default_langcode) : $default_langcode;
+    if (!isset($entity->{$field['field_name']}[$langcode]) && $fallback) {
+      $langcode = $default_langcode;
+    }
+    return $langcode;
+  }
+  else {
+    return LANGUAGE_NONE;
+  }
+}
+
+/**
+ * Callback for getting the sanitized text of 'text_formatted' properties.
+ * This callback is used for both the 'value' and the 'summary'.
+ */
+function entity_metadata_field_text_get($item, array $options, $name, $type, $context) {
+  // $name is either 'value' or 'summary'.
+  if (!isset($item['safe_' . $name])) {
+    // Apply input formats.
+    $langcode = isset($options['language']) ? $options['language']->language : '';
+    $format = isset($item['format']) ? $item['format'] : filter_default_format();
+    $item['safe_' . $name] = check_markup($item[$name], $format, $langcode);
+    // To speed up subsequent calls, update $item with the 'safe_value'.
+    $context['parent']->set($item);
+  }
+  return $item['safe_' . $name];
+}
+
+/**
+ * Defines the list of all available text formats.
+ */
+function entity_metadata_field_text_formats() {
+  foreach (filter_formats() as $key => $format) {
+    $formats[$key] = $format->name;
+  }
+  return $formats;
+}
+
+/**
+ * Callback for getting the file entity of file fields.
+ */
+function entity_metadata_field_file_get($item) {
+  return $item['fid'];
+}
+
+/**
+ * Callback for setting the file entity of file fields.
+ */
+function entity_metadata_field_file_set(&$item, $property_name, $value) {
+  $item['fid'] = $value;
+}
+
+/**
+ * Callback for auto-creating file field $items.
+ */
+function entity_metadata_field_file_create_item($property_name, $context) {
+  // 'fid' is required, so 'file' has to be set as initial property.
+  return array('display' => $context['field']['settings']['display_default']);
+}
+
+/**
+ * Callback for validating file field $items.
+ */
+function entity_metadata_field_file_validate_item($items, $context) {
+  // Allow NULL values.
+  if (!isset($items)) {
+    return TRUE;
+  }
+
+  // Stream-line $items for multiple vs non-multiple fields.
+  $items = !entity_property_list_extract_type($context['type']) ? array($items) : (array) $items;
+
+  foreach ($items as $item) {
+    // File-field items require a valid file.
+    if (!isset($item['fid']) || !file_load($item['fid'])) {
+      return FALSE;
+    }
+    if (isset($context['property info']['display']) && !isset($item['display'])) {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * Access callback for the node entity.
+ *
+ * This function does not implement hook_node_access(), thus it may not be
+ * called entity_metadata_node_access().
+ */
+function entity_metadata_no_hook_node_access($op, $node = NULL, $account = NULL) {
+  if (isset($node)) {
+    return node_access($op, $node, $account);
+  }
+  // Is access to all nodes allowed?
+  if (!user_access('access content', $account)) {
+    return FALSE;
+  }
+  if (user_access('bypass node access', $account) || (!isset($account) && $op == 'view' && node_access_view_all_nodes())) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for the user entity.
+ */
+function entity_metadata_user_access($op, $entity = NULL, $account = NULL, $entity_type) {
+  $account = isset($account) ? $account : $GLOBALS['user'];
+  // Grant access to the users own user account and to the anonymous one.
+  if (isset($entity) && $op != 'delete' && (($entity->uid == $account->uid && $entity->uid) || (!$entity->uid && $op == 'view'))) {
+    return TRUE;
+  }
+  if (user_access('administer users', $account) || user_access('access user profiles', $account) && $op == 'view' && $entity->status) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for restricted user properties.
+ */
+function entity_metadata_user_properties_access($op, $property, $entity = NULL, $account = NULL) {
+  if (user_access('administer users', $account)) {
+    return TRUE;
+  }
+  $account = isset($account) ? $account : $GLOBALS['user'];
+  // Flag to indicate if this user entity is the own user account.
+  $is_own_account = isset($entity) && $account->uid == $entity->uid;
+  switch ($property) {
+    case 'name':
+      // Allow view access to anyone with access to the entity.
+      if ($op == 'view') {
+        return TRUE;
+      }
+      // Allow edit access for own user name if the permission is satisfied.
+      return $is_own_account && user_access('change own username', $account);
+    case 'mail':
+      // Allow access to own mail address.
+      return $is_own_account;
+    case 'roles':
+      // Allow view access for own roles.
+      return ($op == 'view' && $is_own_account);
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for the comment entity.
+ */
+function entity_metadata_comment_access($op, $entity = NULL, $account = NULL) {
+  if (isset($entity) && !isset($account) && comment_access($op, $entity)) {
+    return TRUE;
+  }
+  if (user_access('administer comments', $account) || user_access('access comments', $account) && $op == 'view') {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for the taxonomy entities.
+ */
+function entity_metadata_taxonomy_access($op, $entity = NULL, $account = NULL, $entity_type) {
+  if ($entity_type == 'taxonomy_vocabulary') {
+    return user_access('administer taxonomy', $account);
+  }
+  if (isset($entity) && $op == 'update' && !isset($account) && taxonomy_term_edit_access($entity)) {
+    return TRUE;
+  }
+  if (user_access('administer taxonomy', $account) || user_access('access content', $account) && $op == 'view') {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Callback to determine access for properties which are fields.
+ */
+function entity_metadata_field_access_callback($op, $name, $entity = NULL, $account = NULL, $entity_type) {
+  $field = field_info_field($name);
+  return field_access($op, $field, $entity_type, $entity, $account);
+}
+
+/**
+ * Callback to create entity objects.
+ */
+function entity_metadata_create_object($values = array(), $entity_type) {
+  $info = entity_get_info($entity_type);
+  // Make sure at least the bundle and label properties are set.
+  if (isset($info['entity keys']['bundle']) && $key = $info['entity keys']['bundle']) {
+    $values += array($key => NULL);
+  }
+  if (isset($info['entity keys']['label']) && $key = $info['entity keys']['label']) {
+    $values += array($key => NULL);
+  }
+  $entity = (object) $values;
+  $entity->is_new = TRUE;
+  return $entity;
+}
+
+/**
+ * Callback to create a new comment.
+ */
+function entity_metadata_create_comment($values = array()) {
+  $comment = (object) ($values + array(
+    'status' => COMMENT_PUBLISHED,
+    'pid' => 0,
+    'subject' => '',
+    'uid' => 0,
+    'language' => LANGUAGE_NONE,
+    'node_type' => NULL,
+    'is_new' => TRUE,
+  ));
+  $comment->cid = FALSE;
+  return $comment;
+}
+
+/**
+ * Callback to create a new node.
+ */
+function entity_metadata_create_node($values = array()) {
+  $node = (object) array(
+    'type' => $values['type'],
+    'language' => LANGUAGE_NONE,
+    'is_new' => TRUE,
+  );
+  // Set some defaults.
+  $node_options = variable_get('node_options_' . $node->type, array('status', 'promote'));
+  foreach (array('status', 'promote', 'sticky') as $key) {
+    $node->$key = (int) in_array($key, $node_options);
+  }
+  if (module_exists('comment') && !isset($node->comment)) {
+    $node->comment = variable_get("comment_$node->type", COMMENT_NODE_OPEN);
+  }
+  // Apply the given values.
+  foreach ($values as $key => $value) {
+    $node->$key = $value;
+  }
+  return $node;
+}
+
+/**
+ * Callback to save a user account.
+ */
+function entity_metadata_user_save($account) {
+  $edit = (array) $account;
+  // Don't save the hashed password as password.
+  unset($edit['pass']);
+  user_save($account, $edit);
+}
+
+/**
+ * Callback to delete a file.
+ * Watch out to not accidentilly implement hook_file_delete().
+ */
+function entity_metadata_delete_file($fid) {
+  file_delete(file_load($fid), TRUE);
+}
+
+/**
+ * Callback to view nodes.
+ */
+function entity_metadata_view_node($entities, $view_mode = 'full', $langcode = NULL) {
+  $result = node_view_multiple($entities, $view_mode, 0, $langcode);
+  // Make sure to key the result with 'node' instead of 'nodes'.
+  return array('node' => reset($result));
+}
+
+/**
+ * Callback to view comments.
+ */
+function entity_metadata_view_comment($entities, $view_mode = 'full', $langcode = NULL) {
+  $build = array();
+  $nodes = array();
+  // The comments, indexed by nid and then by cid.
+  $nid_comments = array();
+  foreach ($entities as $cid => $comment) {
+    $nid = $comment->nid;
+    $nodes[$nid] = $nid;
+    $nid_comments[$nid][$cid] = $comment;
+  }
+  $nodes = node_load_multiple(array_keys($nodes));
+  foreach ($nid_comments as $nid => $comments) {
+    $node = isset($nodes[$nid]) ? $nodes[$nid] : NULL;
+    $build += comment_view_multiple($comments, $node, $view_mode, 0, $langcode);
+  }
+  return array('comment' => $build);
+}
+
+/**
+ * Callback to view an entity, for which just ENTITYTYPE_view() is available.
+ */
+function entity_metadata_view_single($entities, $view_mode = 'full', $langcode = NULL, $entity_type) {
+  $function = $entity_type . '_view';
+  $build = array();
+  foreach ($entities as $key => $entity) {
+    $build[$entity_type][$key] = $function($entity, $view_mode, $langcode);
+  }
+  return $build;
+}
+
+/**
+ * Callback to get the form of a node.
+ */
+function entity_metadata_form_node($node) {
+  // Pre-populate the form-state with the right form include.
+  $form_state['build_info']['args'] = array($node);
+  form_load_include($form_state, 'inc', 'node', 'node.pages');
+  return drupal_build_form($node->type . '_node_form', $form_state);
+}
+
+/**
+ * Callback to get the form of a comment.
+ */
+function entity_metadata_form_comment($comment) {
+  if (!isset($comment->node_type)) {
+    $node = node_load($comment->nid);
+    $comment->node_type = 'comment_node_' . $node->type;
+  }
+  return drupal_get_form($comment->node_type . '_form', $comment);
+}
+
+/**
+ * Callback to get the form of a user account.
+ */
+function entity_metadata_form_user($account) {
+  // Pre-populate the form-state with the right form include.
+  $form_state['build_info']['args'] = array($account);
+  form_load_include($form_state, 'inc', 'user', 'user.pages');
+  return drupal_build_form('user_profile_form', $form_state);
+}
+
+/**
+ * Callback to get the form of a term.
+ */
+function entity_metadata_form_taxonomy_term($term) {
+  // Pre-populate the form-state with the right form include.
+  $form_state['build_info']['args'] = array($term);
+  form_load_include($form_state, 'inc', 'taxonomy', 'taxonomy.admin');
+  return drupal_build_form('taxonomy_form_term', $form_state);
+}
+
+/**
+ * Callback to get the form of a vocabulary.
+ */
+function entity_metadata_form_taxonomy_vocabulary($term) {
+  // Pre-populate the form-state with the right form include.
+  $form_state['build_info']['args'] = array($term);
+  form_load_include($form_state, 'inc', 'taxonomy', 'taxonomy.admin');
+  return drupal_build_form('taxonomy_form_term', $form_state);
+}
+
+/**
+ * Callback to get the form for entities using the entity API admin ui.
+ */
+function entity_metadata_form_entity_ui($entity, $entity_type) {
+  $info = entity_get_info($entity_type);
+  $form_state = form_state_defaults();
+  // Add in the include file as the form API does else with the include file
+  // specified for the active menu item.
+  if (!empty($info['admin ui']['file'])) {
+    $path = isset($info['admin ui']['file path']) ? $info['admin ui']['file path'] : drupal_get_path('module', $info['module']);
+    $form_state['build_info']['files']['entity_ui'] = $path . '/' . $info['admin ui']['file'];
+    // Also load the include file.
+    if (file_exists($form_state['build_info']['files']['entity_ui'])) {
+      require_once DRUPAL_ROOT . '/' . $form_state['build_info']['files']['entity_ui'];
+    }
+  }
+  return entity_ui_get_form($entity_type, $entity, $op = 'edit', $form_state);
+}
+
+/**
+ * Callback for querying entity properties having their values stored in the
+ * entities main db table.
+ */
+function entity_metadata_table_query($entity_type, $property, $value, $limit) {
+  $properties = entity_get_all_property_info($entity_type);
+  $info = $properties[$property] + array('schema field' => $property);
+
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', $entity_type, '=')
+        ->propertyCondition($info['schema field'], $value, is_array($value) ? 'IN' : '=')
+        ->range(0, $limit);
+
+  $result = $query->execute();
+  return !empty($result[$entity_type]) ? array_keys($result[$entity_type]) : array();
+}
+
+/**
+ * Callback for querying entities by field values. This function just queries
+ * for the value of the first specified column. Also it is only suitable for
+ * fields that don't process the data, so it's stored the same way as returned.
+ */
+function entity_metadata_field_query($entity_type, $property, $value, $limit) {
+  $query = new EntityFieldQuery();
+  $field = field_info_field($property);
+  $columns = array_keys($field['columns']);
+
+  $query->entityCondition('entity_type', $entity_type, '=')
+        ->fieldCondition($field, $columns[0], $value, is_array($value) ? 'IN' : '=')
+        ->range(0, $limit);
+
+  $result = $query->execute();
+  return !empty($result[$entity_type]) ? array_keys($result[$entity_type]) : array();
+}
diff --git a/sites/all/modules/entity/modules/comment.info.inc b/sites/all/modules/entity/modules/comment.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..4321b4c41434bd7bb78208fac9a80277021220e3
--- /dev/null
+++ b/sites/all/modules/entity/modules/comment.info.inc
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * @file
+ * Provides info about the comment entity.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of comment module.
+ *
+ * @see entity_entity_property_info()
+ */
+function entity_metadata_comment_entity_property_info() {
+  $info = array();
+  // Add meta-data about the basic comment properties.
+  $properties = &$info['comment']['properties'];
+
+  $properties['cid'] = array(
+    'label' => t("Comment ID"),
+    'type' => 'integer',
+    'description' => t("The unique ID of the comment."),
+    'schema field' => 'cid',
+  );
+  $properties['hostname'] = array(
+    'label' => t("IP Address"),
+    'description' => t("The IP address of the computer the comment was posted from."),
+    'schema field' => 'hostname',
+  );
+  $properties['name'] = array(
+    'label' => t("Name"),
+    'description' => t("The name left by the comment author."),
+    'getter callback' => 'entity_metadata_comment_get_properties',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'sanitize' => 'filter_xss',
+    'schema field' => 'name',
+  );
+  $properties['mail'] = array(
+    'label' => t("Email address"),
+    'description' => t("The email address left by the comment author."),
+    'getter callback' => 'entity_metadata_comment_get_properties',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'validation callback' => 'valid_email_address',
+    'schema field' => 'mail',
+  );
+  $properties['homepage'] = array(
+    'label' => t("Home page"),
+    'description' => t("The home page URL left by the comment author."),
+    'sanitize' => 'filter_xss_bad_protocol',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'schema field' => 'homepage',
+  );
+  $properties['subject'] = array(
+    'label' => t("Subject"),
+    'description' => t("The subject of the comment."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'sanitize' => 'filter_xss',
+    'required' => TRUE,
+    'schema field' => 'subject',
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The URL of the comment."),
+    'getter callback' => 'entity_metadata_entity_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['edit_url'] = array(
+    'label' => t("Edit URL"),
+    'description' => t("The URL of the comment's edit page."),
+    'getter callback' => 'entity_metadata_comment_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['created'] = array(
+    'label' => t("Date created"),
+    'description' => t("The date the comment was posted."),
+    'type' => 'date',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'schema field' => 'created',
+  );
+  $properties['parent'] = array(
+    'label' => t("Parent"),
+    'description' => t("The comment's parent, if comment threading is active."),
+    'type' => 'comment',
+    'getter callback' => 'entity_metadata_comment_get_properties',
+    'schema field' => 'pid',
+  );
+  $properties['node'] = array(
+    'label' => t("Node"),
+    'description' => t("The node the comment was posted to."),
+    'type' => 'node',
+    'setter callback' => 'entity_metadata_comment_setter',
+    'setter permission' => 'administer comments',
+    'required' => TRUE,
+    'schema field' => 'nid',
+  );
+  $properties['author'] = array(
+    'label' => t("Author"),
+    'description' => t("The author of the comment."),
+    'type' => 'user',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'required' => TRUE,
+    'schema field' => 'uid',
+  );
+  $properties['status'] = array(
+    'label' => t("Status"),
+    'description' => t("Whether the comment is published or unpublished."),
+    'setter callback' => 'entity_property_verbatim_set',
+    // Although the status is expected to be boolean, its schema suggests
+    // it is an integer, so we follow the schema definition.
+    'type' => 'integer',
+    'options list' => 'entity_metadata_status_options_list',
+    'setter permission' => 'administer comments',
+    'schema field' => 'status',
+  );
+  return $info;
+}
+
+/**
+ * Implements hook_entity_property_info_alter() on top of comment module.
+ * @see entity_entity_property_info_alter()
+ */
+function entity_metadata_comment_entity_property_info_alter(&$info) {
+  // Add info about comment module related properties to the node entity.
+  $properties = &$info['node']['properties'];
+  $properties['comment'] = array(
+    'label' => t("Comments allowed"),
+    'description' => t("Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write)."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'type' => 'integer',
+  );
+  $properties['comment_count'] = array(
+    'label' => t("Comment count"),
+    'description' => t("The number of comments posted on a node."),
+    'getter callback' => 'entity_metadata_comment_get_node_properties',
+    'type' => 'integer',
+  );
+  $properties['comment_count_new'] = array(
+    'label' => t("New comment count"),
+    'description' => t("The number of comments posted on a node since the reader last viewed it."),
+    'getter callback' => 'entity_metadata_comment_get_node_properties',
+    'type' => 'integer',
+  );
+
+  // The comment body field is usually available for all bundles, so add it
+  // directly to the comment entity.
+  $info['comment']['properties']['comment_body'] = array(
+    'type' => 'text_formatted',
+    'label' => t('The main body text'),
+    'getter callback' => 'entity_metadata_field_verbatim_get',
+    'setter callback' => 'entity_metadata_field_verbatim_set',
+    'property info' => entity_property_text_formatted_info(),
+    'field' => TRUE,
+    'required' => TRUE,
+  );
+  unset($info['comment']['properties']['comment_body']['property info']['summary']);
+}
diff --git a/sites/all/modules/entity/modules/field.info.inc b/sites/all/modules/entity/modules/field.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..9ef372b38f2cf3f19189ee1b8b5700f86753382c
--- /dev/null
+++ b/sites/all/modules/entity/modules/field.info.inc
@@ -0,0 +1,170 @@
+<?php
+
+/**
+ * @file
+ * Provides info for fields.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of field module.
+ *
+ * @see entity_field_info_alter()
+ * @see entity_entity_property_info()
+ */
+function entity_metadata_field_entity_property_info() {
+  $info = array();
+  // Loop over all field instances and add them as property.
+  foreach (field_info_fields() as $field_name => $field) {
+    $field += array('bundles' => array());
+    if ($field_type = field_info_field_types($field['type'])) {
+      // Add in our default callback as the first one.
+      $field_type += array('property_callbacks' => array());
+      array_unshift($field_type['property_callbacks'], 'entity_metadata_field_default_property_callback');
+
+      foreach ($field['bundles'] as $entity_type => $bundles) {
+        foreach ($bundles as $bundle) {
+          $instance = field_info_instance($entity_type, $field_name, $bundle);
+
+          if ($instance && empty($instance['deleted'])) {
+            foreach ($field_type['property_callbacks'] as $callback) {
+              $callback($info, $entity_type, $field, $instance, $field_type);
+            }
+          }
+        }
+      }
+    }
+  }
+  return $info;
+}
+
+/**
+ * Callback to add in property info defaults per field instance.
+ * @see entity_metadata_field_entity_property_info().
+ */
+function entity_metadata_field_default_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  if (!empty($field_type['property_type'])) {
+    if ($field['cardinality'] != 1) {
+      $field_type['property_type'] = 'list<' . $field_type['property_type'] . '>';
+    }
+    // Add in instance specific property info, if given and apply defaults.
+    $name = $field['field_name'];
+    $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
+    $instance += array('property info' => array());
+    $property = $instance['property info'] + array(
+      'label' => $instance['label'],
+      'type' => $field_type['property_type'],
+      'description' => t('Field "@name".', array('@name' => $name)),
+      'getter callback' => 'entity_metadata_field_property_get',
+      'setter callback' => 'entity_metadata_field_property_set',
+      'access callback' => 'entity_metadata_field_access_callback',
+      'query callback' => 'entity_metadata_field_query',
+      'translatable' => !empty($field['translatable']),
+      // Specify that this property stems from a field.
+      'field' => TRUE,
+      'required' => !empty($instance['required']),
+    );
+    // For field types of the list module add in the options list callback.
+    if (strpos($field['type'], 'list') === 0) {
+      $property['options list'] = 'entity_metadata_field_options_list';
+    }
+  }
+}
+
+/**
+ * Additional callback to adapt the property info for text fields. If a text
+ * field is processed we make use of a separate data structure so that format
+ * filters are available too. For the text value the sanitized, thus processed
+ * value is returned by default.
+ *
+ * @see entity_metadata_field_entity_property_info()
+ * @see entity_field_info_alter()
+ * @see entity_property_text_formatted_info()
+ */
+function entity_metadata_field_text_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  if (!empty($instance['settings']['text_processing']) || $field['type'] == 'text_with_summary') {
+    // Define a data structure for dealing with text that is formatted or has
+    // a summary.
+    $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+
+    $property['getter callback'] = 'entity_metadata_field_verbatim_get';
+    $property['setter callback'] = 'entity_metadata_field_verbatim_set';
+    unset($property['query callback']);
+
+    if (empty($instance['settings']['text_processing'])) {
+      $property['property info'] =  entity_property_field_item_textsummary_info();
+    }
+    else {
+      // For formatted text we use the type name 'text_formatted'.
+      $property['type'] = ($field['cardinality'] != 1) ? 'list<text_formatted>' : 'text_formatted';
+      $property['property info'] = entity_property_text_formatted_info();
+    }
+    // Enable auto-creation of the item, so that it is possible to just set
+    // the textual or summary value.
+    $property['auto creation'] = 'entity_property_create_array';
+
+    if ($field['type'] != 'text_with_summary') {
+      unset($property['property info']['summary']);
+    }
+  }
+}
+
+/**
+ * Additional callback to adapt the property info for term reference fields.
+ * @see entity_metadata_field_entity_property_info().
+ */
+function entity_metadata_field_term_reference_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+  if (count($field['settings']['allowed_values']) == 1) {
+    $settings = reset($field['settings']['allowed_values']);
+    $property['bundle'] = $settings['vocabulary'];
+  }
+  // Only add the options list callback for controlled vocabularies, thus
+  // vocabularies not using the autocomplete widget.
+  if ($instance['widget']['type'] != 'taxonomy_autocomplete') {
+    $property['options list'] = 'entity_metadata_field_options_list';
+  }
+}
+
+/**
+ * Additional callback to adapt the property info for file fields.
+ * @see entity_metadata_field_entity_property_info().
+ */
+function entity_metadata_field_file_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+  // Define a data structure so it's possible to deal with files and their
+  // descriptions.
+  $property['getter callback'] = 'entity_metadata_field_verbatim_get';
+  $property['setter callback'] = 'entity_metadata_field_verbatim_set';
+
+  // Auto-create the field $items as soon as a property is set.
+  $property['auto creation'] = 'entity_metadata_field_file_create_item';
+  $property['validation callback'] = 'entity_metadata_field_file_validate_item';
+
+  $property['property info'] = entity_property_field_item_file_info();
+
+  if (empty($instance['settings']['description_field'])) {
+    unset($property['property info']['description']);
+  }
+  if (empty($field['settings']['display_field'])) {
+    unset($property['property info']['display']);
+  }
+  unset($property['query callback']);
+}
+
+/**
+ * Additional callback to adapt the property info for image fields.
+ * This callback gets invoked after entity_metadata_field_file_callback().
+ * @see entity_metadata_field_entity_property_info().
+ */
+function entity_metadata_field_image_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+  // Update the property info with the info for image fields.
+  $property['property info'] = entity_property_field_item_image_info();
+
+  if (empty($instance['settings']['alt_field'])) {
+    unset($property['property info']['alt']);
+  }
+  if (empty($field['settings']['title_field'])) {
+    unset($property['property info']['title']);
+  }
+}
diff --git a/sites/all/modules/entity/modules/locale.info.inc b/sites/all/modules/entity/modules/locale.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..3c0f36a98a4a8f5567ce668928cb67a2c5e4e4f6
--- /dev/null
+++ b/sites/all/modules/entity/modules/locale.info.inc
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Provides locale-related properties.
+ */
+
+/**
+ * Implements hook_entity_property_info_alter() on top of locale module.
+ *
+ * @see entity_entity_property_info_alter()
+ */
+function entity_metadata_locale_entity_property_info_alter(&$info) {
+
+  $info['user']['properties']['language'] = array(
+    'label' => t("Language"),
+    'description' => t("This account's default language for e-mails, and preferred language for site presentation."),
+    'type' => 'token',
+    'getter callback' => 'entity_metadata_locale_get_user_language',
+    'setter callback' => 'entity_property_verbatim_set',
+    'options list' => 'entity_metadata_language_list',
+    'schema field' => 'language',
+    'setter permission' => 'administer users',
+  );
+
+  $info['site']['properties']['current_page']['property info']['language'] = array(
+    'label' => t("Interface language"),
+    'description' => t("The language code of the current user interface language."),
+    'type' => 'token',
+    'getter callback' => 'entity_metadata_locale_get_languages',
+    'options list' => 'entity_metadata_language_list',
+  );
+  $info['site']['properties']['current_page']['property info']['language_content'] = array(
+    'label' => t("Content language"),
+    'description' => t("The language code of the current content language."),
+    'type' => 'token',
+    'getter callback' => 'entity_metadata_locale_get_languages',
+    'options list' => 'entity_metadata_language_list',
+  );
+}
diff --git a/sites/all/modules/entity/modules/node.info.inc b/sites/all/modules/entity/modules/node.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..e4c15b76f0ea9f627203f9e63c408a0f5aea94c8
--- /dev/null
+++ b/sites/all/modules/entity/modules/node.info.inc
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * @file
+ * Provides info about the node entity.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of node module.
+ *
+ * @see entity_entity_property_info()
+ */
+function entity_metadata_node_entity_property_info() {
+  $info = array();
+  // Add meta-data about the basic node properties.
+  $properties = &$info['node']['properties'];
+
+  $properties['nid'] = array(
+    'label' => t("Node ID"),
+    'type' => 'integer',
+    'description' => t("The unique ID of the node."),
+    'schema field' => 'nid',
+  );
+  $properties['vid'] = array(
+    'label' => t("Revision ID"),
+    'type' => 'integer',
+    'description' => t("The unique ID of the node's revision."),
+    'schema field' => 'vid',
+  );
+  $properties['is_new'] = array(
+    'label' => t("Is new"),
+    'type' => 'boolean',
+    'description' => t("Whether the node is new and not saved to the database yet."),
+    'getter callback' => 'entity_metadata_node_get_properties',
+  );
+  $properties['type'] = array(
+    'label' => t("Content type"),
+    'type' => 'token',
+    'description' => t("The type of the node."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'options list' => 'node_type_get_names',
+    'required' => TRUE,
+    'schema field' => 'type',
+  );
+  $properties['title'] = array(
+    'label' => t("Title"),
+    'description' => t("The title of the node."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'schema field' => 'title',
+    'required' => TRUE,
+  );
+  $properties['language'] = array(
+    'label' => t("Language"),
+    'type' => 'token',
+    'description' => t("The language the node is written in."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'options list' => 'entity_metadata_language_list',
+    'schema field' => 'language',
+    'setter permission' => 'administer nodes',
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The URL of the node."),
+    'getter callback' => 'entity_metadata_entity_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['edit_url'] = array(
+    'label' => t("Edit URL"),
+    'description' => t("The URL of the node's edit page."),
+    'getter callback' => 'entity_metadata_node_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['status'] = array(
+    'label' => t("Status"),
+    'description' => t("Whether the node is published or unpublished."),
+    // Although the status is expected to be boolean, its schema suggests
+    // it is an integer, so we follow the schema definition.
+    'type' => 'integer',
+    'options list' => 'entity_metadata_status_options_list',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'schema field' => 'status',
+  );
+  $properties['promote'] = array(
+    'label' => t("Promoted to frontpage"),
+    'description' => t("Whether the node is promoted to the frontpage."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'schema field' => 'promote',
+    'type' => 'boolean',
+  );
+  $properties['sticky'] = array(
+    'label' => t("Sticky in lists"),
+    'description' => t("Whether the node is displayed at the top of lists in which it appears."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'schema field' => 'sticky',
+    'type' => 'boolean',
+  );
+  $properties['created'] = array(
+    'label' => t("Date created"),
+    'type' => 'date',
+    'description' => t("The date the node was posted."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'schema field' => 'created',
+  );
+  $properties['changed'] = array(
+    'label' => t("Date changed"),
+    'type' => 'date',
+    'schema field' => 'changed',
+    'description' => t("The date the node was most recently updated."),
+  );
+  $properties['author'] = array(
+    'label' => t("Author"),
+    'type' => 'user',
+    'description' => t("The author of the node."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'required' => TRUE,
+    'schema field' => 'uid',
+  );
+  $properties['source'] = array(
+    'label' => t("Translation source node"),
+    'type' => 'node',
+    'description' => t("The original-language version of this node, if one exists."),
+    'getter callback' => 'entity_metadata_node_get_properties',
+  );
+  $properties['log'] = array(
+    'label' => t("Revision log message"),
+    'type' => 'text',
+    'description' => t("In case a new revision is to be saved, the log entry explaining the changes for this version."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'access callback' => 'entity_metadata_node_revision_access',
+  );
+  $properties['revision'] = array(
+    'label' => t("Creates revision"),
+    'type' => 'boolean',
+    'description' => t("Whether saving this node creates a new revision."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'access callback' => 'entity_metadata_node_revision_access',
+  );
+  return $info;
+}
+
+/**
+ * Implements hook_entity_property_info_alter() on top of node module.
+ * @see entity_metadata_entity_property_info_alter()
+ */
+function entity_metadata_node_entity_property_info_alter(&$info) {
+  // Move the body property to the node by default, as its usually there this
+  // makes dealing with it more convenient.
+  $info['node']['properties']['body'] = array(
+    'type' => 'text_formatted',
+    'label' => t('The main body text'),
+    'getter callback' => 'entity_metadata_field_verbatim_get',
+    'setter callback' => 'entity_metadata_field_verbatim_set',
+    'property info' => entity_property_text_formatted_info(),
+    'auto creation' => 'entity_property_create_array',
+    'field' => TRUE,
+  );
+}
diff --git a/sites/all/modules/entity/modules/poll.info.inc b/sites/all/modules/entity/modules/poll.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..12d6b35e7c5e74b766edcc6fd2230ddb9afd76fb
--- /dev/null
+++ b/sites/all/modules/entity/modules/poll.info.inc
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * Provides info about poll nodes.
+ */
+
+/**
+ * Implements hook_entity_property_info_alter() on top of poll module.
+ *
+ * @see entity_entity_property_info_alter()
+ */
+function entity_metadata_poll_entity_property_info_alter(&$info) {
+  $properties = &$info['node']['bundles']['poll']['properties'];
+
+  $properties['poll_votes'] = array(
+    'label' => t("Poll votes"),
+    'description' => t("The number of votes that have been cast on a poll node."),
+    'type' => 'integer',
+    'getter callback' => 'entity_metadata_poll_node_get_properties',
+    'computed' => TRUE,
+  );
+  $properties['poll_winner'] = array(
+    'label' => t("Poll winner"),
+    'description' => t("The winning poll answer."),
+    'getter callback' => 'entity_metadata_poll_node_get_properties',
+    'sanitize' => 'filter_xss',
+    'computed' => TRUE,
+  );
+  $properties['poll_winner_votes'] = array(
+    'label' => t("Poll winner votes"),
+    'description' => t("The number of votes received by the winning poll answer."),
+    'type' => 'integer',
+    'getter callback' => 'entity_metadata_poll_node_get_properties',
+    'computed' => TRUE,
+  );
+  $properties['poll_winner_percent'] = array(
+    'label' => t("Poll winner percent"),
+    'description' => t("The percentage of votes received by the winning poll answer."),
+    'getter callback' => 'entity_metadata_poll_node_get_properties',
+    'type' => 'decimal',
+    'computed' => TRUE,
+  );
+  $properties['poll_duration'] = array(
+    'label' => t("Poll duration"),
+    'description' => t("The length of time the poll node is set to run."),
+    'getter callback' => 'entity_metadata_poll_node_get_properties',
+    'type' => 'duration',
+  );
+}
diff --git a/sites/all/modules/entity/modules/statistics.info.inc b/sites/all/modules/entity/modules/statistics.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..6633eaa75804ca11a3ff850bd9cad2d2ba5dd435
--- /dev/null
+++ b/sites/all/modules/entity/modules/statistics.info.inc
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Provides info about statistics.
+ */
+
+/**
+ * Implements hook_entity_property_info_alter() on top of statistics module.
+ *
+ * @see entity_entity_property_info_alter()
+ */
+function entity_metadata_statistics_entity_property_info_alter(&$info) {
+  $properties = &$info['node']['properties'];
+
+  $properties['views'] = array(
+    'label' => t("Number of views"),
+    'description' => t("The number of visitors who have read the node."),
+    'type' => 'integer',
+    'getter callback' => 'entity_metadata_statistics_node_get_properties',
+    'computed' => TRUE,
+  );
+  $properties['day_views'] = array(
+    'label' => t("Views today"),
+    'description' => t("The number of visitors who have read the node today."),
+    'type' => 'integer',
+    'getter callback' => 'entity_metadata_statistics_node_get_properties',
+    'computed' => TRUE,
+  );
+  $properties['last_view'] = array(
+    'label' => t("Last view"),
+    'description' => t("The date on which a visitor last read the node."),
+    'type' => 'date',
+    'getter callback' => 'entity_metadata_statistics_node_get_properties',
+    'computed' => TRUE,
+  );
+}
diff --git a/sites/all/modules/entity/modules/system.info.inc b/sites/all/modules/entity/modules/system.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..0c6ba6b06ed88902157d69a777c9ec6da4209098
--- /dev/null
+++ b/sites/all/modules/entity/modules/system.info.inc
@@ -0,0 +1,132 @@
+<?php
+
+/**
+ * @file
+ * Provides info about system-wide entities.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of system module.
+ *
+ * @see entity_entity_property_info()
+ * @see entity_metadata_site_wrapper()
+ */
+function entity_metadata_system_entity_property_info() {
+  $info = array();
+
+  // There is no site entity, but still add metadata for global site properties
+  // here. That way modules can alter and add further properties at this place.
+  // In order to make use of this metadata modules may use the wrapper returned
+  // by entity_metadata_site_wrapper().
+  $properties = &$info['site']['properties'];
+  $properties['name'] = array(
+    'label' => t("Name"),
+    'description' => t("The name of the site."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'sanitize' => 'check_plain',
+  );
+  $properties['slogan'] = array(
+    'label' => t("Slogan"),
+    'description' => t("The slogan of the site."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'sanitize' => 'check_plain',
+  );
+  $properties['mail'] = array(
+    'label' => t("Email"),
+    'description' => t("The administrative email address for the site."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The URL of the site's front page."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'type' => 'uri',
+  );
+  $properties['login_url'] = array(
+    'label' => t("Login page"),
+    'description' => t("The URL of the site's login page."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'type' => 'uri',
+  );
+  $properties['current_user'] = array(
+    'label' => t("Logged in user"),
+    'description' => t("The currently logged in user."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'type' => 'user',
+  );
+  $properties['current_date'] = array(
+    'label' => t("Current date"),
+    'description' => t("The current date and time."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'type' => 'date',
+  );
+  $properties['current_page'] = array(
+    'label' => t("Current page"),
+    'description' => t("Information related to the current page request."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'type' => 'struct',
+    'property info' => array(
+      'path' => array(
+        'label' => t("Path"),
+        'description' => t("The internal Drupal path of the current page request."),
+        'getter callback' => 'current_path',
+        'type' => 'text',
+      ),
+      'url' => array(
+        'label' => t("URL"),
+        'description' => t("The full URL of the current page request."),
+        'getter callback' => 'entity_metadata_system_get_page_properties',
+        'type' => 'uri',
+      ),
+    ),
+  );
+
+  // Files.
+  $properties = &$info['file']['properties'];
+  $properties['fid'] = array(
+    'label' => t("File ID"),
+    'description' => t("The unique ID of the uploaded file."),
+    'type' => 'integer',
+    'validation callback' => 'entity_metadata_validate_integer_positive',
+    'schema field' => 'fid',
+  );
+  $properties['name'] = array(
+    'label' => t("File name"),
+    'description' => t("The name of the file on disk."),
+    'getter callback' => 'entity_metadata_system_get_file_properties',
+    'schema field' => 'filename',
+  );
+  $properties['mime'] = array(
+    'label' => t("MIME type"),
+    'description' => t("The MIME type of the file."),
+    'getter callback' => 'entity_metadata_system_get_file_properties',
+    'sanitize' => 'filter_xss',
+    'schema field' => 'filemime',
+  );
+  $properties['size'] = array(
+    'label' => t("File size"),
+    'description' => t("The size of the file, in kilobytes."),
+    'getter callback' => 'entity_metadata_system_get_file_properties',
+    'type' => 'integer',
+    'schema field' => 'filesize',
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The web-accessible URL for the file."),
+    'getter callback' => 'entity_metadata_system_get_file_properties',
+  );
+  $properties['timestamp'] = array(
+    'label' => t("Timestamp"),
+    'description' => t("The date the file was most recently changed."),
+    'type' => 'date',
+    'schema field' => 'timestamp',
+  );
+  $properties['owner'] = array(
+    'label' => t("Owner"),
+    'description' => t("The user who originally uploaded the file."),
+    'type' => 'user',
+    'getter callback' => 'entity_metadata_system_get_file_properties',
+    'schema field' => 'uid',
+  );
+  return $info;
+}
diff --git a/sites/all/modules/entity/modules/taxonomy.info.inc b/sites/all/modules/entity/modules/taxonomy.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..e50c63d15c348a47d4c218f5ffa85084f7c1d1bf
--- /dev/null
+++ b/sites/all/modules/entity/modules/taxonomy.info.inc
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * @file
+ * Provides info about the taxonomy entity.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of taxonomy module.
+ *
+ * @see entity_entity_property_info()
+ */
+function entity_metadata_taxonomy_entity_property_info() {
+  $info = array();
+  // Add meta-data about the basic taxonomy properties.
+  $properties = &$info['taxonomy_term']['properties'];
+
+  $properties['tid'] = array(
+    'label' => t("Term ID"),
+    'description' => t("The unique ID of the taxonomy term."),
+    'type' => 'integer',
+    'schema field' => 'tid',
+  );
+  $properties['name'] = array(
+    'label' => t("Name"),
+    'description' => t("The name of the taxonomy term."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'required' => TRUE,
+    'schema field' => 'name',
+  );
+  $properties['description'] = array(
+    'label' => t("Description"),
+    'description' => t("The optional description of the taxonomy term."),
+    'sanitized' => TRUE,
+    'raw getter callback' => 'entity_property_verbatim_get',
+    'getter callback' => 'entity_metadata_taxonomy_term_get_properties',
+    'setter callback' => 'entity_property_verbatim_set',
+    'schema field' => 'description',
+  );
+  $properties['weight'] = array(
+    'label' => t("Weight"),
+    'type' => 'integer',
+    'description' => t('The weight of the term, which is used for ordering terms during display.'),
+    'setter callback' => 'entity_property_verbatim_set',
+    'schema field' => 'weight',
+  );
+  $properties['node_count'] = array(
+    'label' => t("Node count"),
+    'type' => 'integer',
+    'description' => t("The number of nodes tagged with the taxonomy term."),
+    'getter callback' => 'entity_metadata_taxonomy_term_get_properties',
+    'computed' => TRUE,
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The URL of the taxonomy term."),
+    'getter callback' => 'entity_metadata_entity_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['vocabulary'] = array(
+    'label' => t("Vocabulary"),
+    'description' => t("The vocabulary the taxonomy term belongs to."),
+    'setter callback' => 'entity_metadata_taxonomy_term_setter',
+    'type' => 'taxonomy_vocabulary',
+    'required' => TRUE,
+    'schema field' => 'vid',
+  );
+  $properties['parent'] = array(
+    'label' => t("Parent terms"),
+    'description' => t("The parent terms of the taxonomy term."),
+    'getter callback' => 'entity_metadata_taxonomy_term_get_properties',
+    'setter callback' => 'entity_metadata_taxonomy_term_setter',
+    'type' => 'list<taxonomy_term>',
+  );
+  $properties['parents_all'] = array(
+    'label' => t("All parent terms"),
+    'description' => t("Ancestors of the term, i.e. parent of all above hierarchy levels."),
+    'getter callback' => 'entity_metadata_taxonomy_term_get_properties',
+    'type' => 'list<taxonomy_term>',
+    'computed' => TRUE,
+  );
+
+  // Add meta-data about the basic vocabulary properties.
+  $properties = &$info['taxonomy_vocabulary']['properties'];
+
+  // Taxonomy vocabulary related variables.
+  $properties['vid'] = array(
+    'label' => t("Vocabulary ID"),
+    'description' => t("The unique ID of the taxonomy vocabulary."),
+    'type' => 'integer',
+    'schema field' => 'vid',
+  );
+  $properties['name'] = array(
+    'label' => t("Name"),
+    'description' => t("The name of the taxonomy vocabulary."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'required' => TRUE,
+    'schema field' => 'name',
+  );
+  $properties['machine_name'] = array(
+    'label' => t("Machine name"),
+    'type' => 'token',
+    'description' => t("The machine name of the taxonomy vocabulary."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'required' => TRUE,
+    'schema field' => 'machine_name',
+  );
+  $properties['description'] = array(
+    'label' => t("Description"),
+    'description' => t("The optional description of the taxonomy vocabulary."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'sanitize' => 'filter_xss',
+    'schema field' => 'description',
+  );
+  $properties['term_count'] = array(
+    'label' => t("Term count"),
+    'type' => 'integer',
+    'description' => t("The number of terms belonging to the taxonomy vocabulary."),
+    'getter callback' => 'entity_metadata_taxonomy_vocabulary_get_properties',
+    'computed' => TRUE,
+  );
+  return $info;
+}
diff --git a/sites/all/modules/entity/modules/user.info.inc b/sites/all/modules/entity/modules/user.info.inc
new file mode 100644
index 0000000000000000000000000000000000000000..6a8e4b8e4f80424c000280ea1fbe2048e017908b
--- /dev/null
+++ b/sites/all/modules/entity/modules/user.info.inc
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * @file
+ * Provides info about the user entity.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of user module.
+ *
+ * @see entity_entity_property_info()
+ */
+function entity_metadata_user_entity_property_info() {
+  $info = array();
+  // Add meta-data about the user properties.
+  $properties = &$info['user']['properties'];
+
+  $properties['uid'] = array(
+    'label' => t("User ID"),
+    'type' => 'integer',
+    'description' => t("The unique ID of the user account."),
+    'schema field' => 'uid',
+  );
+  $properties['name'] = array(
+    'label' => t("Name"),
+    'description' => t("The login name of the user account."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'setter callback' => 'entity_property_verbatim_set',
+    'sanitize' => 'filter_xss',
+    'required' => TRUE,
+    'access callback' => 'entity_metadata_user_properties_access',
+    'schema field' => 'name',
+  );
+  $properties['mail'] = array(
+    'label' => t("Email"),
+    'description' => t("The email address of the user account."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'validation callback' => 'valid_email_address',
+    'required' => TRUE,
+    'access callback' => 'entity_metadata_user_properties_access',
+    'schema field' => 'mail',
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The URL of the account profile page."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['edit_url'] = array(
+    'label' => t("Edit URL"),
+    'description' => t("The url of the account edit page."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['last_access'] = array(
+    'label' => t("Last access"),
+    'description' => t("The date the user last accessed the site."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'type' => 'date',
+    'schema field' => 'access',
+  );
+  $properties['last_login'] = array(
+    'label' => t("Last login"),
+    'description' => t("The date the user last logged in to the site."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'type' => 'date',
+    'schema field' => 'login',
+  );
+  $properties['created'] = array(
+    'label' => t("Created"),
+    'description' => t("The date the user account was created."),
+    'type' => 'date',
+    'schema field' => 'created',
+  );
+  $properties['roles'] = array(
+    'label' => t("User roles"),
+    'description' => t("The roles of the user."),
+    'type' => 'list<integer>',
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'setter callback' => 'entity_metadata_user_set_properties',
+    'setter permission' => 'administer users',
+    'options list' => 'entity_metadata_user_roles',
+    'access callback' => 'entity_metadata_user_properties_access',
+  );
+  $properties['status'] = array(
+    'label' => t("Status"),
+    'description' => t("Whether the user is active or blocked."),
+    'setter callback' => 'entity_property_verbatim_set',
+    // Although the status is expected to be boolean, its schema suggests
+    // it is an integer, so we follow the schema definition.
+    'type' => 'integer',
+    'options list' => 'entity_metadata_user_status_options_list',
+    'setter permission' => 'administer users',
+    'schema field' => 'status',
+  );
+  $properties['theme'] = array(
+    'label' => t("Default theme"),
+    'description' => t("The user's default theme."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'setter callback' => 'entity_property_verbatim_set',
+    'access callback' => 'entity_metadata_user_properties_access',
+    'schema field' => 'theme',
+  );
+  return $info;
+}
+
diff --git a/sites/all/modules/entity/tests/entity_feature.info b/sites/all/modules/entity/tests/entity_feature.info
new file mode 100644
index 0000000000000000000000000000000000000000..45e141aa154093824bfc2af7a86cbfe716cc4198
--- /dev/null
+++ b/sites/all/modules/entity/tests/entity_feature.info
@@ -0,0 +1,14 @@
+name = Entity feature module
+description = Provides some entities in code.
+version = VERSION
+core = 7.x
+files[] = entity_feature.module
+dependencies[] = entity_test
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2012-05-25
+version = "7.x-1.0-rc3"
+core = "7.x"
+project = "entity"
+datestamp = "1337981155"
+
diff --git a/sites/all/modules/entity/tests/entity_feature.module b/sites/all/modules/entity/tests/entity_feature.module
new file mode 100644
index 0000000000000000000000000000000000000000..c2c9fbf04e1379e4048f8e19cb9bc1caea0236e3
--- /dev/null
+++ b/sites/all/modules/entity/tests/entity_feature.module
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Test module providing some entities in code.
+ */
+
+/**
+ * Implements hook_default_entity_test_type().
+ */
+function entity_feature_default_entity_test_type() {
+  $types['main'] = entity_create('entity_test_type', array(
+    'name' => 'main',
+    'label' => t('Main test type'),
+    'weight' => 0,
+    'locked' => TRUE,
+  ));
+
+  // Types used during CRUD testing.
+  $types['test'] = entity_create('entity_test_type', array(
+    'name' => 'test',
+    'label' => 'label',
+    'weight' => 0,
+  ));
+  $types['test2'] = entity_create('entity_test_type', array(
+      'name' => 'test2',
+      'label' => 'label2',
+      'weight' => 2,
+  ));
+
+  return $types;
+}
diff --git a/sites/all/modules/entity/tests/entity_test.info b/sites/all/modules/entity/tests/entity_test.info
new file mode 100644
index 0000000000000000000000000000000000000000..ac18875a03a7b518cea26f7bad2a5d6ab8b014bc
--- /dev/null
+++ b/sites/all/modules/entity/tests/entity_test.info
@@ -0,0 +1,15 @@
+name = Entity CRUD test module
+description = Provides entity types based upon the CRUD API.
+version = VERSION
+core = 7.x
+files[] = entity_test.module
+files[] = entity_test.install
+dependencies[] = entity
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2012-05-25
+version = "7.x-1.0-rc3"
+core = "7.x"
+project = "entity"
+datestamp = "1337981155"
+
diff --git a/sites/all/modules/entity/tests/entity_test.install b/sites/all/modules/entity/tests/entity_test.install
new file mode 100644
index 0000000000000000000000000000000000000000..dce2161b5f4ea2f2f9da573352e489d6f206beff
--- /dev/null
+++ b/sites/all/modules/entity/tests/entity_test.install
@@ -0,0 +1,126 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the entity_test module.
+ */
+
+/**
+ * Implements hook_uninstall().
+ */
+function entity_test_uninstall() {
+  // Bypass entity_load() as we cannot use it here.
+  $types = db_select('entity_test_type', 'et')
+    ->fields('et')
+    ->execute()
+    ->fetchAllAssoc('name');
+
+  foreach ($types as $name => $type) {
+    field_attach_delete_bundle('entity_test', $name);
+  }
+}
+
+/**
+ * Implements hook_schema().
+ */
+function entity_test_schema() {
+  $schema['entity_test'] = array(
+    'description' => 'Stores entity_test items.',
+    'fields' => array(
+      'pid' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique entity_test item ID.',
+      ),
+      'name' => array(
+        'description' => 'The name of the entity_test.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'uid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => FALSE,
+        'default' => NULL,
+        'description' => "The {users}.uid of the associated user.",
+      ),
+    ),
+    'indexes' => array(
+      'uid' => array('uid'),
+    ),
+    'foreign keys' => array(
+      'uid' => array('users' => 'uid'),
+      'name' => array('entity_test_types' => 'name'),
+    ),
+    'primary key' => array('pid'),
+  );
+
+  $schema['entity_test_type'] = array(
+    'description' => 'Stores information about all defined entity_test types.',
+    'fields' => array(
+      'id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique entity_test type ID.',
+      ),
+      'name' => array(
+        'description' => 'The machine-readable name of this entity_test type.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+      ),
+      'label' => array(
+        'description' => 'The human-readable name of this entity_test type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'The weight of this entity_test type in relation to others.',
+      ),
+      'locked' => array(
+        'description' => 'A boolean indicating whether the administrator may delete this type.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'data' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'size' => 'big',
+        'serialize' => TRUE,
+        'description' => 'A serialized array of additional data related to this entity_test type.',
+        'merge' => TRUE,
+      ),
+      'status' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        // Set the default to ENTITY_CUSTOM without using the constant as it is
+        // not safe to use it at this point.
+        'default' => 0x01,
+        'size' => 'tiny',
+        'description' => 'The exportable status of the entity.',
+      ),
+      'module' => array(
+        'description' => 'The name of the providing module if the entity has been defined in code.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+      ),
+    ),
+    'primary key' => array('id'),
+    'unique keys' => array(
+      'name' => array('name'),
+    ),
+  );
+  return $schema;
+}
+
diff --git a/sites/all/modules/entity/tests/entity_test.module b/sites/all/modules/entity/tests/entity_test.module
new file mode 100644
index 0000000000000000000000000000000000000000..4076a9753cb0c9fa6adcdd2cb2c46b3a25e11eec
--- /dev/null
+++ b/sites/all/modules/entity/tests/entity_test.module
@@ -0,0 +1,246 @@
+<?php
+
+/**
+ * @file
+ * Test moduel for the entity API.
+ */
+
+/**
+ * Implements hook_entity_info().
+ */
+function entity_test_entity_info() {
+  $return = array(
+    'entity_test' => array(
+      'label' => t('Test Entity'),
+      'plural label' => t('Test Entities'),
+      'description' => t('An entity type used by the entity API tests.'),
+      'entity class' => 'EntityClass',
+      'controller class' => 'EntityAPIController',
+      'base table' => 'entity_test',
+      'fieldable' => TRUE,
+      'entity keys' => array(
+        'id' => 'pid',
+        'bundle' => 'name',
+      ),
+      // Make use the class' label() and uri() implementation by default.
+      'label callback' => 'entity_class_label',
+      'uri callback' => 'entity_class_uri',
+      'bundles' => array(),
+      'bundle keys' => array(
+        'bundle' => 'name',
+      ),
+      'module' => 'entity_test',
+    ),
+    'entity_test_type' => array(
+      'label' => t('Test entity type'),
+      'entity class' => 'Entity',
+      'controller class' => 'EntityAPIControllerExportable',
+      'base table' => 'entity_test_type',
+      'fieldable' => FALSE,
+      'bundle of' => 'entity_test',
+      'exportable' => TRUE,
+      'entity keys' => array(
+        'id' => 'id',
+        'name' => 'name',
+      ),
+      'module' => 'entity_test',
+    ),
+  );
+
+  // Add bundle info but bypass entity_load() as we cannot use it here.
+  $types = db_select('entity_test_type', 'et')
+    ->fields('et')
+    ->execute()
+    ->fetchAllAssoc('name');
+
+  foreach ($types as $name => $type) {
+    $return['entity_test']['bundles'][$name] = array(
+      'label' => $type->label,
+    );
+  }
+
+  // Support entity cache module.
+  if (module_exists('entitycache')) {
+    $return['entity_test']['field cache'] = FALSE;
+    $return['entity_test']['entity cache'] = TRUE;
+  }
+
+  return $return;
+}
+
+/**
+ * Gets an array of all test entity types, keyed by the name.
+ *
+ * @param $name
+ *   If set, the type with the given name is returned.
+ */
+function entity_test_get_types($name = NULL) {
+  $types = entity_load_multiple_by_name('entity_test_type', isset($name) ? array($name) : FALSE);
+  return isset($name) ? reset($types) : $types;
+}
+
+/**
+ * Load multiple test entities based on certain conditions.
+ *
+ * @param $pids
+ *   An array of entity IDs.
+ * @param $conditions
+ *   An array of conditions to match against the {entity} table.
+ * @param $reset
+ *   A boolean indicating that the internal cache should be reset.
+ * @return
+ *   An array of test entity objects, indexed by pid.
+ */
+function entity_test_load_multiple($pids = array(), $conditions = array(), $reset = FALSE) {
+  return entity_load('entity_test', $pids, $conditions, $reset);
+}
+
+/**
+ * Delete multiple test entities.
+ *
+ * @param $pids
+ *   An array of test entity IDs.
+ */
+function entity_test_delete_multiple(array $pids) {
+  entity_get_controller('entity_test')->delete($pids);
+}
+
+
+/**
+ * Main class for test entities.
+ */
+class EntityClass extends Entity {
+
+  public function __construct(array $values = array(), $entityType = NULL) {
+    parent::__construct($values, 'entity_test');
+  }
+
+  /**
+   * Override buildContent() to add the username to the output.
+   */
+  public function buildContent($view_mode = 'full', $langcode = NULL) {
+    $content['user'] = array(
+      '#markup' => "User: ". format_username(user_load($this->uid)),
+    );
+    return entity_get_controller($this->entityType)->buildContent($this, $view_mode, $langcode, $content);
+  }
+
+  /**
+   * Specifies the default label, which is picked up by label() by default.
+   */
+  protected function defaultLabel() {
+    $type = entity_test_get_types($this->name);
+    return $type->label;
+  }
+
+  /**
+   * Specifies the default uri, which is picked up by uri() by default.
+   */
+  protected function defaultURI() {
+    return array('path' => 'custom/' . $this->identifier());
+  }
+}
+
+
+/**
+ *
+ *
+ * Some hook implementations used by the tests.
+ *
+ *
+ */
+
+
+/**
+ * Implements hook_entity_insert().
+ */
+function entity_test_entity_insert($entity, $entity_type) {
+  $_SESSION['entity_hook_test']['entity_insert'][] = entity_id($entity_type, $entity);
+}
+
+/**
+ * Implements hook_entity_update().
+ */
+function entity_test_entity_update($entity, $entity_type) {
+  $_SESSION['entity_hook_test']['entity_update'][] = entity_id($entity_type, $entity);
+}
+
+/**
+ * Implements hook_entity_delete().
+ */
+function entity_test_entity_delete($entity, $entity_type) {
+  $_SESSION['entity_hook_test']['entity_delete'][] = entity_id($entity_type, $entity);
+}
+
+/**
+ * Implements hook_entity_test_type_insert().
+ */
+function entity_test_entity_test_type_insert($entity) {
+  $_SESSION['entity_hook_test']['entity_test_type_insert'][] = $entity->identifier();
+}
+
+/**
+ * Implements hook_entity_test_type_update().
+ */
+function entity_test_entity_test_type_update($entity) {
+  $_SESSION['entity_hook_test']['entity_test_type_update'][] = $entity->identifier();
+
+  // Determine changes on update.
+  if (!empty($entity->original) && $entity->original->label == 'test_changes') {
+    if ($entity->original->label != $entity->label) {
+      $entity->label .= '_update';
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_test_type_delete().
+ */
+function entity_test_entity_test_type_delete($entity) {
+  $_SESSION['entity_hook_test']['entity_test_type_delete'][] = $entity->identifier();
+}
+
+/**
+ * Implements hook_entity_test_type_presave().
+ */
+function entity_test_entity_test_type_presave($entity) {
+  // Determine changes.
+  if (!empty($entity->original) && $entity->original->label == 'test_changes') {
+    if ($entity->original->label != $entity->label) {
+      $entity->label .= '_presave';
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_property_info_alter() for testing an property of type
+ * 'entity'.
+ */
+function entity_test_entity_property_info_alter(&$info) {
+  $info['node']['properties']['reference'] = array(
+    'label' => t('Test reference'),
+    'description' => t('A generic entity reference.'),
+    'getter callback' => 'entity_test_entity_getter',
+    'setter callback' => 'entity_test_entity_setter',
+    'type' => 'entity',
+  );
+}
+
+/**
+ * Getter callback for the 'reference' property.
+ */
+function entity_test_entity_getter($node) {
+  if (empty($node->entity)) {
+    $node->entity = array('type' => 'user', 'id' => $node->uid);
+  }
+  // We have to return the entity wrapped.
+  return entity_metadata_wrapper($node->entity['type'], $node->entity['id']);
+}
+
+/**
+ * Setter callback for the 'reference' property.
+ */
+function entity_test_entity_setter($node, $property_name, $wrapper) {
+  // The entity has to be passed wrapped.
+  $node->entity = array('type' => $wrapper->type(), 'id' => $wrapper->getIdentifier());
+}
diff --git a/sites/all/modules/entity/tests/entity_test_i18n.info b/sites/all/modules/entity/tests/entity_test_i18n.info
new file mode 100644
index 0000000000000000000000000000000000000000..4a3c27c4b724d9ce1178dc38704fe5654bfe98c7
--- /dev/null
+++ b/sites/all/modules/entity/tests/entity_test_i18n.info
@@ -0,0 +1,13 @@
+name = Entity-test type translation
+description = Allows translating entity-test types.
+dependencies[] = entity_test
+dependencies[] = i18n_string
+package = Multilingual - Internationalization
+core = 7.x
+hidden = TRUE
+; Information added by drupal.org packaging script on 2012-05-25
+version = "7.x-1.0-rc3"
+core = "7.x"
+project = "entity"
+datestamp = "1337981155"
+
diff --git a/sites/all/modules/entity/tests/entity_test_i18n.module b/sites/all/modules/entity/tests/entity_test_i18n.module
new file mode 100644
index 0000000000000000000000000000000000000000..2aa3736889dcefc98c120d8c69f9bded6f6369a4
--- /dev/null
+++ b/sites/all/modules/entity/tests/entity_test_i18n.module
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * @file
+ * Entity-test i18n integration module via entity API i18n support.
+ *
+ * @see EntityDefaultI18nController
+ */
+
+/**
+ * Implements hook_entity_info_alter().
+ */
+function entity_test_i18n_entity_info_alter(&$info) {
+  // Enable i18n support via the entity API.
+  $info['entity_test_type']['i18n controller class'] = 'EntityDefaultI18nStringController';
+}
+
+/**
+ * Implements hook_entity_property_info_alter().
+ */
+function entity_test_i18n_entity_property_info_alter(&$info) {
+  // Mark some properties as translatable, but also denote that translation
+  // works with i18n_string.
+  foreach (array('label') as $name) {
+    $info['entity_test_type']['properties'][$name]['translatable'] = TRUE;
+    $info['entity_test_type']['properties'][$name]['i18n string'] = TRUE;
+  }
+}
+
+/**
+ * Implements hook_{entity_test_type}_insert().
+ */
+function entity_test_i18n_entity_test_type_insert($test_type) {
+  i18n_string_object_update('entity_test_type', $test_type);
+}
+
+/**
+ * Implements hook_{entity_test_type}_update().
+ */
+function entity_test_i18n_entity_test_type_update($test_type) {
+  // Account for name changes.
+  if ($test_type->original->name != $test_type->name) {
+    i18n_string_update_context("entity_test:entity_test_type:{$test_type->original->name}:*", "entity_test:entity_test_type:{$test_type->name}:*");
+  }
+  i18n_string_object_update('entity_test_type', $test_type);
+}
+
+/**
+ * Implements hook_{entity_test_type}_delete().
+ */
+function entity_test_i18n_entity_test_type_delete($test_type) {
+  i18n_string_object_remove('entity_test_type', $test_type);
+}
diff --git a/sites/all/modules/entity/views/entity.views.inc b/sites/all/modules/entity/views/entity.views.inc
new file mode 100644
index 0000000000000000000000000000000000000000..56b606b244155a46ceec0813fa63993de7d5b575
--- /dev/null
+++ b/sites/all/modules/entity/views/entity.views.inc
@@ -0,0 +1,634 @@
+<?php
+
+/**
+ * @file
+ * Provide views data for modules making use of the entity CRUD API.
+ */
+
+/**
+ * Implements hook_views_data().
+ *
+ * Provides Views integration for entities if they satisfy one of these
+ * conditions:
+ *  - hook_entity_info() specifies a 'views controller class' key.
+ *  - hook_entity_info() specifies a 'module' key, and the module does not
+ *    implement hook_views_data().
+ *
+ * @see entity_crud_hook_entity_info()
+ * @see entity_views_table_definition()
+ */
+function entity_views_data() {
+  $data = array();
+
+  foreach (entity_crud_get_info() as $type => $info) {
+    // Provide default integration with the basic controller class if we know
+    // the module providing the entity and it does not provide views integration.
+    if (!isset($info['views controller class'])) {
+      $info['views controller class'] = isset($info['module']) && !module_hook($info['module'], 'views_data') ? 'EntityDefaultViewsController' : FALSE;
+    }
+    if ($info['views controller class']) {
+      $controller = new $info['views controller class']($type);
+      // Relationship data may return views data for already existing tables,
+      // so merge results on the second level.
+      foreach ($controller->views_data() as $table => $table_data) {
+        $data += array($table => array());
+        $data[$table] = array_merge($data[$table], $table_data);
+      }
+    }
+  }
+
+  // Add tables based upon data selection "queries" for all entity types.
+  foreach (entity_get_info() as $type => $info) {
+    $table = entity_views_table_definition($type);
+    if ($table) {
+      $data['entity_' . $type] = $table;
+    }
+    // Generally expose properties marked as 'entity views field'.
+    $data['views_entity_' . $type] = array();
+    foreach (entity_get_all_property_info($type) as $key => $property) {
+      if (!empty($property['entity views field'])) {
+        entity_views_field_definition($key, $property, $data['views_entity_' . $type]);
+      }
+    }
+  }
+
+  // Expose generally usable entity-related fields.
+  foreach (entity_get_info() as $entity_type => $info) {
+    if (entity_type_supports($entity_type, 'view')) {
+      // Expose a field allowing to display the rendered entity.
+      $data['views_entity_' . $entity_type]['rendered_entity'] = array(
+        'title' => t('Rendered @entity-type', array('@entity-type' => $info['label'])),
+        'help' => t('The @entity-type of the current relationship rendered using a view mode.', array('@entity-type' => $info['label'])),
+        'field' => array(
+          'handler' => 'entity_views_handler_field_entity',
+          'type' => $entity_type,
+          // The EntityFieldHandlerHelper treats the 'entity object' data
+          // selector as special case for loading the base entity.
+          'real field' => 'entity object',
+        ),
+      );
+    }
+  }
+
+  $data['entity__global']['table']['group'] = t('Entity');
+  $data['entity__global']['table']['join'] = array(
+    // #global let's it appear all the time.
+    '#global' => array(),
+  );
+  $data['entity__global']['entity'] = array(
+    'title' => t('Rendered entity'),
+    'help' => t('Displays a single chosen entity.'),
+    'area' => array(
+      'handler' => 'entity_views_handler_area_entity',
+    ),
+  );
+
+  return $data;
+}
+
+/**
+ * Helper function for getting data selection based entity Views table definitions.
+ *
+ * This creates extra tables for each entity type that are not associated with a
+ * query plugin (and thus are not base tables) and just rely on the entities to
+ * retrieve the displayed data. To obtain the entities corresponding to a
+ * certain result set, the field handlers defined on the table use a generic
+ * interface defined for query plugins that are based on entity handling, and
+ * which is described in the entity_views_example_query class.
+ *
+ * These tables are called "data selection tables".
+ *
+ * Other modules providing Views integration with new query plugins that are
+ * based on entities can then use these tables as a base for their own tables
+ * (by directly using this method and modifying the returned table) and/or by
+ * specifying relationships to them. The tables returned here already specify
+ * relationships to each other wherever an entity contains a reference to
+ * another (e.g., the node author constructs a relationship from nodes to
+ * users).
+ *
+ * As filtering and other query manipulation is potentially more plugin-specific
+ * than the display, only field handlers and relationships are provided with
+ * these tables. By providing a add_selector_orderby() method, the query plugin
+ * can, however, support click-sorting for the field handlers in these tables.
+ *
+ * For a detailed discussion see http://drupal.org/node/1266036
+ *
+ * For example use see the Search API views module in the Search API project:
+ * http://drupal.org/project/search_api
+ *
+ * @param $type
+ *   The entity type whose table definition should be returned.
+ * @param $exclude
+ *   Whether properties already exposed as 'entity views field' should be
+ *   excluded. Defaults to TRUE, as they are available for all views tables for
+ *   the entity type anyways.
+ *
+ * @return
+ *   An array containing the data selection Views table definition for the
+ *   entity type.
+ *
+ * @see entity_views_field_definition()
+ */
+function entity_views_table_definition($type, $exclude = TRUE) {
+  // As other modules might want to copy these tables as a base for their own
+  // Views integration, we statically cache the tables to save some time.
+  $tables = &drupal_static(__FUNCTION__, array());
+
+  if (!isset($tables[$type])) {
+    // Work-a-round to fix updating, see http://drupal.org/node/1330874.
+    // Views data might be rebuilt on update.php before the registry is rebuilt,
+    // thus the class cannot be auto-loaded.
+    if (!class_exists('EntityFieldHandlerHelper')) {
+      module_load_include('inc', 'entity', 'views/handlers/entity_views_field_handler_helper');
+    }
+
+    $info = entity_get_info($type);
+    $tables[$type]['table'] = array(
+      'group' => $info['label'],
+      'entity type' => $type,
+    );
+    foreach (entity_get_all_property_info($type) as $key => $property) {
+      if (!$exclude || empty($property['entity views field'])) {
+        entity_views_field_definition($key, $property, $tables[$type]);
+      }
+    }
+  }
+
+  return $tables[$type];
+}
+
+/**
+ * Helper function for adding a Views field definition to data selection based Views tables.
+ *
+ * @param $field
+ *   The data selector of the field to add. E.g. "title" would derive the node
+ *   title property, "body:summary" the node body's summary.
+ * @param array $property_info
+ *   The property information for which to create a field definition.
+ * @param array $table
+ *   The table into which the definition should be inserted.
+ * @param $title_prefix
+ *   Internal use only.
+ *
+ * @see entity_views_table_definition()
+ */
+function entity_views_field_definition($field, array $property_info, array &$table, $title_prefix = '') {
+  $additional = array();
+  $additional_field = array();
+
+  // Create a valid Views field identifier (no colons, etc.). Keep the original
+  // data selector as real field though.
+  $key = _entity_views_field_identifier($field, $table);
+  if ($key != $field) {
+    $additional['real field'] = $field;
+  }
+  $field_name = EntityFieldHandlerHelper::get_selector_field_name($field);
+
+  $field_handlers = entity_views_get_field_handlers();
+
+  $property_info += entity_property_info_defaults();
+  $type = entity_property_extract_innermost_type($property_info['type']);
+  $title = $title_prefix . $property_info['label'];
+  if ($info = entity_get_info($type)) {
+    $additional['relationship'] = array(
+      'handler' => $field_handlers['relationship'],
+      'base' => 'entity_' . $type,
+      'base field' => $info['entity keys']['id'],
+      'relationship field' => $field,
+      'label' => $title,
+    );
+    if ($property_info['type'] != $type) {
+      // This is a list of entities, so we should mark the relationship as such.
+      $additional['relationship']['multiple'] = TRUE;
+    }
+    // Implementers of the field handlers alter hook could add handlers for
+    // specific entity types.
+    if (!isset($field_handlers[$type])) {
+      $type = 'entity';
+    }
+  }
+  elseif (!empty($property_info['field'])) {
+    $type = 'field';
+    // Views' Field API field handler needs some extra definitions to work.
+    $additional_field['field_name'] = $field_name;
+    $additional_field['entity_tables'] = array();
+    $additional_field['entity type'] = $table['table']['entity type'];
+    $additional_field['is revision'] = FALSE;
+  }
+  // Copied from EntityMetadataWrapper::optionsList()
+  elseif (isset($property_info['options list']) && is_callable($property_info['options list'])) {
+    // If this is a nested property, we need to get rid of all prefixes first.
+    $type = 'options';
+    $additional_field['options callback'] = array(
+      'function' => $property_info['options list'],
+      'info' => $property_info,
+    );
+  }
+  elseif ($type == 'decimal') {
+    $additional_field['float'] = TRUE;
+  }
+
+  if (isset($field_handlers[$type])) {
+    $table += array($key => array());
+    $table[$key] += array(
+      'title' => $title,
+      'help' => empty($property_info['description']) ? t('(No information available)') : $property_info['description'],
+      'field' => array(),
+    );
+    $table[$key]['field'] += array(
+      'handler' => $field_handlers[$type],
+      'type' => $property_info['type'],
+    );
+    $table[$key] += $additional;
+    $table[$key]['field'] += $additional_field;
+  }
+  if (!empty($property_info['property info'])) {
+    foreach ($property_info['property info'] as $nested_key => $nested_property) {
+      entity_views_field_definition($field . ':' . $nested_key, $nested_property, $table, $title . ' » ');
+    }
+  }
+}
+
+/**
+ * @return array
+ *   The handlers to use for the data selection based Views tables.
+ *
+ * @see hook_entity_views_field_handlers_alter()
+ */
+function entity_views_get_field_handlers() {
+  $field_handlers = drupal_static(__FUNCTION__);
+  if (!isset($field_handlers)) {
+    // Field handlers for the entity tables, by type.
+    $field_handlers = array(
+      'text'         => 'entity_views_handler_field_text',
+      'token'        => 'entity_views_handler_field_text',
+      'integer'      => 'entity_views_handler_field_numeric',
+      'decimal'      => 'entity_views_handler_field_numeric',
+      'date'         => 'entity_views_handler_field_date',
+      'duration'     => 'entity_views_handler_field_duration',
+      'boolean'      => 'entity_views_handler_field_boolean',
+      'uri'          => 'entity_views_handler_field_uri',
+      'options'      => 'entity_views_handler_field_options',
+      'field'        => 'entity_views_handler_field_field',
+      'entity'       => 'entity_views_handler_field_entity',
+      'relationship' => 'entity_views_handler_relationship',
+    );
+    drupal_alter('entity_views_field_handlers', $field_handlers);
+  }
+  return $field_handlers;
+}
+
+/**
+ * Helper function for creating valid Views field identifiers out of data selectors.
+ *
+ * Uses $table to test whether the identifier is already used, and also
+ * recognizes if a definition for the same field is already present and returns
+ * that definition's identifier.
+ *
+ * @return string
+ *   A valid Views field identifier that is not yet used as a key in $table.
+ */
+function _entity_views_field_identifier($field, array $table) {
+  $key = $base = preg_replace('/[^a-zA-Z0-9]+/S', '_', $field);
+  $i = 0;
+  // The condition checks whether this sanitized field identifier is already
+  // used for another field in this table (and whether the identifier is
+  // "table", which can never be used).
+  // If $table[$key] is set, the identifier is already used, but this might be
+  // already for the same field. To test that, we need the original field name,
+  // which is either $table[$key]['real field'], if set, or $key. If this
+  // original field name is equal to $field, we can use that key. Otherwise, we
+  // append numeric suffixes until we reach an unused key.
+  while ($key == 'table' || (isset($table[$key]) && (isset($table[$key]['real field']) ? $table[$key]['real field'] : $key) != $field)) {
+    $key = $base . '_' . ++$i;
+  }
+  return $key;
+}
+
+/**
+ * Implements hook_views_plugins().
+ */
+function entity_views_plugins() {
+  // Have views cache the table list for us so it gets
+  // cleared at the appropriate times.
+  $data = views_cache_get('entity_base_tables', TRUE);
+  if (!empty($data->data)) {
+    $base_tables = $data->data;
+  }
+  else {
+    foreach (views_fetch_data() as $table => $data) {
+      if (!empty($data['table']['entity type']) && !empty($data['table']['base'])) {
+        $base_tables[] = $table;
+      }
+    }
+    views_cache_set('entity_base_tables', $base_tables, TRUE);
+  }
+  if (!empty($base_tables)) {
+    return array(
+      'module' => 'entity',
+      'row' => array(
+        'entity' => array(
+          'title' => t('Rendered entity'),
+          'help' => t('Renders a single entity in a specific view mode (e.g. teaser).'),
+          'handler' => 'entity_views_plugin_row_entity_view',
+          'uses fields' => FALSE,
+          'uses options' => TRUE,
+          'type' => 'normal',
+          'base' => $base_tables,
+        ),
+      ),
+    );
+  }
+}
+
+/**
+ * Default controller for generating basic views integration.
+ *
+ * The controller tries to generate suiting views integration for the entity
+ * based upon the schema information of its base table and the provided entity
+ * property information.
+ * For that it is possible to map a property name to its schema/views field
+ * name by adding a 'schema field' key with the name of the field as value to
+ * the property info.
+ */
+class EntityDefaultViewsController {
+
+  protected $type, $info, $relationships;
+
+  public function __construct($type) {
+    $this->type = $type;
+    $this->info = entity_get_info($type);
+  }
+
+  /**
+   * Defines the result for hook_views_data().
+   */
+  public function views_data() {
+    $data = array();
+    $this->relationships = array();
+
+    if (!empty($this->info['base table'])) {
+      $table = $this->info['base table'];
+      // Define the base group of this table. Fields that don't
+      // have a group defined will go into this field by default.
+      $data[$table]['table']['group']  = drupal_ucfirst($this->info['label']);
+      $data[$table]['table']['entity type'] = $this->type;
+
+      // If the plural label isn't available, use the regular label.
+      $label = isset($this->info['plural label']) ? $this->info['plural label'] : $this->info['label'];
+      $data[$table]['table']['base'] = array(
+        'field' => $this->info['entity keys']['id'],
+        'title' => drupal_ucfirst($label),
+        'help' => isset($this->info['description']) ? $this->info['description'] : '',
+      );
+      $data[$table]['table']['entity type'] = $this->type;
+      $data[$table] += $this->schema_fields();
+
+      // Add in any reverse-relationships which have been determined.
+      $data += $this->relationships;
+    }
+    return $data;
+  }
+
+  /**
+   * Try to come up with some views fields with the help of the schema and
+   * the entity property information.
+   */
+  protected function schema_fields() {
+    $schema = drupal_get_schema($this->info['base table']);
+    $properties = entity_get_property_info($this->type) + array('properties' => array());
+    $data = array();
+
+    foreach ($properties['properties'] as $name => $property_info) {
+      if (isset($property_info['schema field']) && isset($schema['fields'][$property_info['schema field']])) {
+        if ($views_info = $this->map_from_schema_info($name, $schema['fields'][$property_info['schema field']], $property_info)) {
+          $data[$name] = $views_info;
+        }
+      }
+    }
+    return $data;
+  }
+
+  /**
+   * Comes up with views information based on the given schema and property
+   * info.
+   */
+  protected function map_from_schema_info($property_name, $schema_field_info, $property_info) {
+    $type = isset($property_info['type']) ? $property_info['type'] : 'text';
+    $views_field_name = $property_info['schema field'];
+
+    $return = array();
+
+    if (!empty($schema_field_info['serialize'])) {
+      return FALSE;
+    }
+
+    $description = array(
+      'title' => $property_info['label'],
+      'help' => isset($property_info['description']) ? $property_info['description'] : NULL,
+    );
+
+      // Add in relationships to related entities.
+    if (($info = entity_get_info($type)) && !empty($info['base table'])) {
+
+      // Prepare reversed relationship data.
+      $label_lowercase = drupal_strtolower($this->info['label'][0]) . drupal_substr($this->info['label'], 1);
+      $property_label_lowercase = drupal_strtolower($property_info['label'][0]) . drupal_substr($property_info['label'], 1);
+
+      // We name the field of the first reverse-relationship just with the
+      // base table to be backward compatible, for subsequents relationships we
+      // append the views field name in order to get a unique name.
+      $name = !isset($this->relationships[$info['base table']][$this->info['base table']]) ? $this->info['base table'] : $this->info['base table'] . '_' . $views_field_name;
+      $this->relationships[$info['base table']][$name] = array(
+        'title' => $this->info['label'],
+        'help' => t("Associated @label via the @label's @property.", array('@label' => $label_lowercase, '@property' => $property_label_lowercase)),
+        'relationship' => array(
+          'label' => $this->info['label'],
+          'handler' => $this->getRelationshipHandlerClass($this->type, $type),
+          'base' => $this->info['base table'],
+          'base field' => $views_field_name,
+          'relationship field' => isset($info['entity keys']['name']) ? $info['entity keys']['name'] : $info['entity keys']['id'],
+        ),
+      );
+
+      $return['relationship'] = array(
+        'label' => drupal_ucfirst($info['label']),
+        'handler' => $this->getRelationshipHandlerClass($type, $this->type),
+        'base' => $info['base table'],
+        'base field' => isset($info['entity keys']['name']) ? $info['entity keys']['name'] : $info['entity keys']['id'],
+        'relationship field' => $views_field_name,
+      );
+
+      // Add in direct field/filters/sorts for the id itself too.
+      $type = isset($info['entity keys']['name']) ? 'token' : 'integer';
+      // Append the views-field-name to the title if it is different to the
+      // property name.
+      if ($property_name != $views_field_name) {
+        $description['title'] .= ' ' . $views_field_name;
+      }
+    }
+
+    switch ($type) {
+      case 'token':
+      case 'text':
+        $return += $description + array(
+          'field' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_field',
+            'click sortable' => TRUE,
+           ),
+          'sort' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_sort',
+          ),
+          'filter' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_filter_string',
+          ),
+          'argument' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_argument_string',
+          ),
+        );
+      break;
+
+      case 'decimal':
+      case 'integer':
+        $return += $description + array(
+          'field' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_field_numeric',
+            'click sortable' => TRUE,
+            'float' => ($type == 'decimal'),
+           ),
+          'sort' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_sort',
+          ),
+          'filter' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_filter_numeric',
+          ),
+          'argument' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_argument_numeric',
+          ),
+        );
+      break;
+
+      case 'date':
+        $return += $description + array(
+          'field' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_field_date',
+            'click sortable' => TRUE,
+           ),
+          'sort' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_sort_date',
+          ),
+          'filter' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_filter_date',
+          ),
+          'argument' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_argument_date',
+          ),
+        );
+      break;
+
+      case 'uri':
+        $return += $description + array(
+          'field' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_field_url',
+            'click sortable' => TRUE,
+           ),
+          'sort' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_sort',
+          ),
+          'filter' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_filter_string',
+          ),
+          'argument' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_argument_string',
+          ),
+        );
+      break;
+
+      case 'boolean':
+        $return += $description + array(
+          'field' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_field_boolean',
+            'click sortable' => TRUE,
+           ),
+          'sort' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_sort',
+          ),
+          'filter' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_filter_boolean_operator',
+          ),
+          'argument' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_argument_string',
+          ),
+        );
+      break;
+    }
+
+    // If there is an options list callback, add to the filter and field.
+    if (isset($return['filter']) && !empty($property_info['options list'])) {
+      $return['filter']['handler'] = 'views_handler_filter_in_operator';
+      $return['filter']['options callback'] = array('EntityDefaultViewsController', 'optionsListCallback');
+      $return['filter']['options arguments'] = array($this->type, $property_name, 'view');
+    }
+    // @todo: This class_exists is needed until views 3.2.
+    if (isset($return['field']) && !empty($property_info['options list']) && class_exists('views_handler_field_machine_name')) {
+      $return['field']['handler'] = 'views_handler_field_machine_name';
+      $return['field']['options callback'] = array('EntityDefaultViewsController', 'optionsListCallback');
+      $return['field']['options arguments'] = array($this->type, $property_name, 'view');
+    }
+    return $return;
+  }
+
+  /**
+   * Determines the handler to use for a relationship to an entity type.
+   *
+   * @param $entity_type
+   *   The entity type to join to.
+   * @param $left_type
+   *   The data type from which to join.
+   */
+  function getRelationshipHandlerClass($entity_type, $left_type) {
+    // Look for an entity type which is used as bundle for the given entity
+    // type. If there is one, allow filtering the relation by bundle by using
+    // our own handler.
+    foreach (entity_get_info() as $type => $info) {
+      // In case we already join from the bundle entity we do not need to filter
+      // by bundle entity any more, so we stay with the general handler.
+      if (!empty($info['bundle of']) && $info['bundle of'] == $entity_type && $type != $left_type) {
+        return 'entity_views_handler_relationship_by_bundle';
+      }
+    }
+    return 'views_handler_relationship';
+  }
+
+  /**
+   * A callback returning property options, suitable to be used as views options callback.
+   */
+  public static function optionsListCallback($type, $selector, $op = 'view') {
+    $wrapper = entity_metadata_wrapper($type, NULL);
+    $parts = explode(':', $selector);
+    foreach ($parts as $part) {
+      $wrapper = $wrapper->get($part);
+    }
+    return $wrapper->optionsList($op);
+  }
+}
diff --git a/sites/all/modules/entity/views/entity_views_example_query.php b/sites/all/modules/entity/views/entity_views_example_query.php
new file mode 100644
index 0000000000000000000000000000000000000000..7e98e2c267ed25f8fc25090bc3b5d335faa6cd7c
--- /dev/null
+++ b/sites/all/modules/entity/views/entity_views_example_query.php
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * @file
+ * Contains an example for a Views query plugin that could use the data selection tables.
+ */
+
+/**
+ * Describes the additional methods looked for on a query plugin if data selection based tables or fields are used.
+ *
+ * Only get_result_entities() needs to be present, so results can be retrieved.
+ * The other methods are optional.
+ *
+ * If the table does not contain entities, however, the get_result_wrappers()
+ * method is necessary, too. If this is the case and there are no relations to
+ * entity tables, the get_result_entities() method is not needed.
+ *
+ * @see entity_views_table_definition()
+ */
+abstract class entity_views_example_query extends views_plugin_query {
+
+  /**
+   * Add a sort to the query.
+   *
+   * This is used to add a sort based on an Entity API data selector instead
+   * of a field alias.
+   *
+   * This method has to be present if click-sorting on fields should be allowed
+   * for some fields using the default Entity API field handlers.
+   *
+   * @param $selector
+   *   The field to sort on, as an Entity API data selector.
+   * @param $order
+   *   The order to sort items in - either 'ASC' or 'DESC'. Defaults to 'ASC'.
+   */
+  public abstract function add_selector_orderby($selector, $order = 'ASC');
+
+  /**
+   * Returns the according entity objects for the given query results.
+   *
+   * This is compatible to the get_result_entities() method used by Views.
+   *
+   * The method is responsible for resolving the relationship and returning the
+   * entity objects for that relationship. The helper methods
+   * EntityFieldHandlerHelper::construct_property_selector() and
+   * EntityFieldHandlerHelper::extract_property_multiple() can be used to do
+   * this.
+   *
+   * @param $results
+   *   The results of the query, as returned by this query plugin.
+   * @param $relationship
+   *   (optional) A relationship for which the entities should be returned.
+   * @param $field
+   *   (optional) The field for which the entity should be returned. This is
+   *   only needed in case a field is derived via a referenced entity without
+   *   using a relationship. For example, if the node's field "author:name" is
+   *   used, the user entity would be returned instead of the node entity.
+   *
+   * @return
+   *   A numerically indexed array containing two items: the entity type of
+   *   entities returned by this method; and the array of entities, keyed by the
+   *   same indexes as the results.
+   *
+   * @see EntityFieldHandlerHelper::extract_property_multiple()
+   */
+  public abstract function get_result_entities($results, $relationship = NULL, $field = NULL);
+
+  /**
+   * Returns the according metadata wrappers for the given query results.
+   *
+   * This can be used if no entities for the results can be given, but entity
+   * metadata wrappers can be constructed for them.
+   *
+   * @param $results
+   *   The results of the query, as returned by this query plugin.
+   * @param $relationship
+   *   (optional) A relationship for which the wrappers should be returned.
+   * @param $field
+   *   (optional) The field of which a wrapper should be returned.
+   *
+   * @return
+   *   A numerically indexed array containing two items: the data type of
+   *   the wrappers returned by this method; and the array of retrieved
+   *   EntityMetadataWrapper objects, keyed by the same indexes as the results.
+   */
+  public abstract function get_result_wrappers($results, $relationship = NULL, $field = NULL);
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_field_handler_helper.inc b/sites/all/modules/entity/views/handlers/entity_views_field_handler_helper.inc
new file mode 100644
index 0000000000000000000000000000000000000000..55201abaf9b687559109cef0673e428b0793f677
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_field_handler_helper.inc
@@ -0,0 +1,521 @@
+<?php
+
+/**
+ * @file
+ * Contains the EntityFieldHandlerHelper class.
+ */
+
+/**
+ * Helper class containing static implementations of common field handler methods.
+ *
+ * Used by the data selection entity field handlers to avoid code duplication.
+ *
+ * @see entity_views_table_definition()
+ */
+class EntityFieldHandlerHelper {
+
+  /**
+   * Provide appropriate default options for a handler.
+   */
+  public static function option_definition($handler) {
+    if (entity_property_list_extract_type($handler->definition['type'])) {
+      $options['list']['contains']['mode'] = array('default' => 'collapse');
+      $options['list']['contains']['separator'] = array('default' => ', ');
+      $options['list']['contains']['type'] = array('default' => 'ul');
+    }
+    $options['link_to_entity'] = array('default' => FALSE);
+
+    return $options;
+  }
+
+  /**
+   * Provide an appropriate default option form for a handler.
+   */
+  public static function options_form($handler, &$form, &$form_state) {
+    if (entity_property_list_extract_type($handler->definition['type'])) {
+      $form['list']['mode'] = array(
+        '#type' => 'select',
+        '#title' => t('List handling'),
+        '#options' => array(
+          'collapse' => t('Concatenate values using a seperator'),
+          'list' => t('Output values as list'),
+          'first' => t('Show first (if present)'),
+          'count' => t('Show item count'),
+        ),
+        '#default_value' => $handler->options['list']['mode'],
+      );
+      $form['list']['separator'] = array(
+        '#type' => 'textfield',
+        '#title' => t('List seperator'),
+        '#default_value' => $handler->options['list']['separator'],
+        '#dependency' => array('edit-options-list-mode' => array('collapse')),
+      );
+      $form['list']['type'] = array(
+        '#type' => 'select',
+        '#title' => t('List type'),
+        '#options' => array(
+          'ul' => t('Unordered'),
+          'ol' => t('Ordered'),
+        ),
+        '#default_value' => $handler->options['list']['type'],
+        '#dependency' => array('edit-options-list-mode' => array('list')),
+      );
+    }
+    $form['link_to_entity'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Link this field to its entity'),
+      '#description' => t("When using this, you should not set any other link on the field."),
+      '#default_value' => $handler->options['link_to_entity'],
+    );
+  }
+
+  /**
+   * Add the field for the entity ID (if necessary).
+   */
+  public static function query($handler) {
+    // Copied over from views_handler_field_entity::query().
+    // Sets table_alias (entity table), base_field (entity id field) and
+    // field_alias (the field's alias).
+    $handler->table_alias = $base_table = $handler->view->base_table;
+    $handler->base_field = $handler->view->base_field;
+
+    if (!empty($handler->relationship)) {
+      foreach ($handler->view->relationship as $relationship) {
+        if ($relationship->alias == $handler->relationship) {
+          $base_table = $relationship->definition['base'];
+          $handler->table_alias = $relationship->alias;
+
+          $table_data = views_fetch_data($base_table);
+          $handler->base_field = empty($relationship->definition['base field']) ? $table_data['table']['base']['field'] : $relationship->definition['base field'];
+        }
+      }
+    }
+
+    // Add the field if the query back-end implements an add_field() method,
+    // just like the default back-end.
+    if (method_exists($handler->query, 'add_field')) {
+      $handler->field_alias = $handler->query->add_field($handler->table_alias, $handler->base_field, '');
+    }
+    else {
+      // To ensure there is an alias just set the field alias to the real field.
+      $handler->field_alias = $handler->real_field;
+    }
+  }
+
+  /**
+   * Extracts the innermost field name from a data selector.
+   *
+   * @param $selector
+   *   The data selector.
+   *
+   * @return
+   *   The last component of the data selector.
+   */
+  public static function get_selector_field_name($selector) {
+    return ltrim(substr($selector, strrpos($selector, ':')), ':');
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   *
+   * @param $order
+   *   Either 'ASC' or 'DESC'.
+   */
+  public static function click_sort($handler, $order) {
+    // The normal orderby() method for this usually won't work here. So we need
+    // query plugins to provide their own method for this.
+    if (method_exists($handler->query, 'add_selector_orderby')) {
+      $selector = self::construct_property_selector($handler, TRUE);
+      $handler->query->add_selector_orderby($selector, $order);
+    }
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   *
+   * Automatically takes care of relationships, including data selection
+   * relationships. Results are written into @code $handler->wrappers @endcode
+   * and @code $handler->entity_type @endcode is set.
+   */
+  public static function pre_render($handler, &$values, $load_always = FALSE) {
+    if (empty($values)) {
+      return;
+    }
+    if (!$load_always && empty($handler->options['link_to_entity'])) {
+      // Check whether we even need to load the entities.
+      $selector = self::construct_property_selector($handler, TRUE);
+      $load = FALSE;
+      foreach ($values as $row) {
+        if (empty($row->_entity_properties) || !array_key_exists($selector, $row->_entity_properties)) {
+          $load = TRUE;
+          break;
+        }
+      }
+      if (!$load) {
+        return;
+      }
+    }
+
+    if (method_exists($handler->query, 'get_result_wrappers')) {
+      list($handler->entity_type, $handler->wrappers) = $handler->query->get_result_wrappers($values, $handler->relationship, $handler->real_field);
+    }
+    else {
+      list($handler->entity_type, $entities) = $handler->query->get_result_entities($values, $handler->relationship, $handler->real_field);
+      $handler->wrappers = array();
+      foreach ($entities as $id => $entity) {
+        $handler->wrappers[$id] = entity_metadata_wrapper($handler->entity_type, $entity);
+      }
+    }
+  }
+
+  /**
+   * Return an Entity API data selector for the given handler's relationship.
+   *
+   * A data selector is a concatenation of properties which should be followed
+   * to arrive at a desired property that may be nested in related entities or
+   * structures. The separate properties are herein concatenated with colons.
+   *
+   * For instance, a data selector of "author:roles" would mean to first
+   * access the "author" property of the given wrapper, and then for this new
+   * wrapper to access and return the "roles" property.
+   *
+   * Lists of entities are handled automatically by always returning only the
+   * first entity.
+   *
+   * @param $handler
+   *   The handler for which to construct the selector.
+   * @param $complete
+   *   If TRUE, the complete selector for the field is returned, not just the
+   *   one for its parent. Defaults to FALSE.
+   *
+   * @return
+   *   An Entity API data selector for the given handler's relationship.
+   */
+  public static function construct_property_selector($handler, $complete = FALSE) {
+    $return = '';
+    if ($handler->relationship) {
+      $current_handler = $handler;
+      $view = $current_handler->view;
+      while (!empty($current_handler->relationship) && !empty($view->relationship[$current_handler->relationship])) {
+        $current_handler = $view->relationship[$current_handler->relationship];
+        $return = $current_handler->real_field . ($return ? ":$return" : '');
+      }
+    }
+
+    if ($complete) {
+      $return .= ($return ? ':' : '') . $handler->real_field;
+    }
+    elseif ($pos = strrpos($handler->real_field, ':')) {
+      // If we have a selector as the real_field, append this to the returned
+      // relationship selector.
+      $return .= ($return ? ':' : '') . substr($handler->real_field, 0, $pos);
+    }
+
+    return $return;
+  }
+
+  /**
+   * Extracts data from several metadata wrappers based on a data selector.
+   *
+   * All metadata wrappers passed to this function have to be based on the exact
+   * same property information. The data will be returned wrapped by one or more
+   * metadata wrappers.
+   *
+   * Can be used in query plugins for the get_result_entities() and
+   * get_result_wrappers() methods.
+   *
+   * @param array $wrappers
+   *   The EntityMetadataWrapper objects from which to extract data.
+   * @param $selector
+   *   The selector specifying the data to extract.
+   *
+   * @return array
+   *   An array with numeric indices, containing the type of the extracted
+   *   wrappers in the first element. The second element of the array contains
+   *   the extracted property value(s) for each wrapper, keyed to the same key
+   *   that was used for the respecive wrapper in $wrappers. All extracted
+   *   properties are returned as metadata wrappers.
+   */
+  public static function extract_property_multiple(array $wrappers, $selector) {
+    $parts = explode(':', $selector, 2);
+    $name = $parts[0];
+
+    $results = array();
+    $entities = array();
+    $type = '';
+    foreach ($wrappers as $i => $wrapper) {
+      try {
+        $property = $wrapper->$name;
+        $type = $property->type();
+        if ($property instanceof EntityDrupalWrapper) {
+          // Remember the entity IDs to later load all at once (so as to
+          // properly utilize multiple load functionality).
+          $id = $property->getIdentifier();
+          // Only accept valid ids. $id can be FALSE for entity values that are
+          // NULL.
+          if ($id) {
+            $entities[$type][$i] = $id;
+          }
+        }
+        elseif ($property instanceof EntityStructureWrapper) {
+          $results[$i] = $property;
+        }
+        elseif ($property instanceof EntityListWrapper) {
+          foreach ($property as $item) {
+            $results[$i] = $item;
+            $type = $item->type();
+            break;
+          }
+        }
+        // Do nothing in case it cannot be applied.
+      }
+      catch (EntityMetadataWrapperException $e) {
+        // Skip single empty properties.
+      }
+    }
+
+    if ($entities) {
+      // Map back the loaded entities back to the results array.
+      foreach ($entities as $type => $id_map) {
+        $loaded = entity_load($type, $id_map);
+        foreach ($id_map as $i => $id) {
+          if (isset($loaded[$id])) {
+            $results[$i] = entity_metadata_wrapper($type, $loaded[$id]);
+          }
+        }
+      }
+    }
+
+    // If there are no further parts in the selector, we are done now.
+    if (empty($parts[1])) {
+      return array($type, $results);
+    }
+    return self::extract_property_multiple($results, $parts[1]);
+  }
+
+  /**
+   * Get the value of a certain data selector.
+   *
+   * Uses $values->_entity_properties to look for already extracted properties.
+   *
+   * @param $handler
+   *   The field handler for which to return a value.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   * @param $field
+   *   The field to extract. If no value is given, the field of the given
+   *   handler is used instead. The special "entity object" value can be used to
+   *   get the base entity instead of a special field.
+   * @param $default
+   *   The value to return if the entity or field are not present.
+   */
+  public static function get_value($handler, $values, $field = NULL, $default = NULL) {
+    // There is a value cache on each handler so parent handlers rendering a
+    // single field value from a list will get the single value, not the whole
+    // list.
+    if (!isset($field) && isset($handler->current_value)) {
+      return $handler->current_value;
+    }
+    $field = isset($field) ? $field : self::get_selector_field_name($handler->real_field);
+    $selector = self::construct_property_selector($handler);
+    $selector = $selector ? "$selector:$field" : $field;
+    if (!isset($values->_entity_properties)) {
+      $values->_entity_properties = array();
+    }
+    if (!array_key_exists($selector, $values->_entity_properties)) {
+      if (!isset($handler->wrappers[$handler->view->row_index])) {
+        $values->_entity_properties[$selector] = $default;
+      }
+      elseif (is_array($handler->wrappers[$handler->view->row_index])) {
+        $values->_entity_properties[$selector] = self::extract_list_wrapper_values($handler->wrappers[$handler->view->row_index], $field);
+      }
+      else {
+        $wrapper = $handler->wrappers[$handler->view->row_index];
+        try {
+          if ($field === 'entity object') {
+            $values->_entity_properties[$selector] = $wrapper->value();
+          }
+          else {
+            $values->_entity_properties[$selector] = isset($wrapper->$field) ? $wrapper->$field->value(array('identifier' => TRUE)) : $default;
+          }
+        }
+        catch (EntityMetadataWrapperException $e) {
+          $values->_entity_properties[$selector] = $default;
+        }
+      }
+    }
+    return $values->_entity_properties[$selector];
+  }
+
+  /**
+   * Helper method for extracting the values from an array of wrappers.
+   *
+   * Nested arrays of wrappers are also handled, the values are returned in a
+   * flat (not nested) array.
+   */
+  public static function extract_list_wrapper_values(array $wrappers, $field) {
+    $return = array();
+    foreach ($wrappers as $wrapper) {
+      if (is_array($wrapper)) {
+        $values = self::extract_list_wrapper_values($wrapper, $field);
+        if ($values) {
+          $return = array_merge($return, $values);
+        }
+      }
+      else {
+        try {
+          if ($field == 'entity object') {
+            $return[] = $wrapper->value();
+          }
+          elseif (isset($wrapper->$field)) {
+            $return[] = $wrapper->$field->value(array('identifier' => TRUE));
+          }
+        }
+        catch (EntityMetadataWrapperException $e) {
+          // An exception probably signifies a non-present property, so we just
+          // ignore it.
+        }
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * Render the field.
+   *
+   * Implements the entity link functionality and list handling. Basic handling
+   * of the single values is delegated back to the field handler.
+   *
+   * @param $handler
+   *   The field handler whose field should be rendered.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   *
+   * @return
+   *   The rendered value for the field.
+   */
+  public static function render($handler, $values) {
+    $value = $handler->get_value($values);
+    if (is_array($value)) {
+      return self::render_list($handler, $value, $values);
+    }
+    return self::render_entity_link($handler, $value, $values);
+  }
+
+  /**
+   * Render a list of values.
+   *
+   * @param $handler
+   *   The field handler whose field is rendered.
+   * @param $list
+   *   The list of values to render.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   *
+   * @return
+   *   The rendered value for the given list.
+   */
+  public static function render_list($handler, $list, $values) {
+    // Allow easy overriding of this behaviour in the specific field handler.
+    if (method_exists($handler, 'render_list')) {
+      return $handler->render_list($list, $values);
+    }
+    $mode = isset($handler->options['list']['mode']) ? $handler->options['list']['mode'] : NULL;
+    switch ($mode) {
+      case 'first':
+        $list = count($list) ? array_shift($list) : NULL;
+        if (is_array($list)) {
+          return self::render_list($handler, $list, $values);
+        }
+        elseif (isset($list)) {
+          return self::render_entity_link($handler, $list, $values);
+        }
+        return NULL;
+
+      case 'count':
+        return count($list);
+
+      // Handles both collapse and list output. Fallback is to collapse.
+      default:
+        $inner_values = array();
+        foreach ($list as $value) {
+          $value = is_array($value) ? self::render_list($handler, $value, $values) : self::render_entity_link($handler, $value, $values);
+          if ($value) {
+            $inner_values[] = $value;
+          }
+        }
+
+        // Format output as list.
+        if ($mode == 'list') {
+          $type = isset($handler->options['list']['type']) ? $handler->options['list']['type'] : 'ul';
+          return theme('item_list', array(
+            'items' => $inner_values,
+            'type' => $type,
+          ));
+        }
+
+        $separator = isset($handler->options['list']['separator']) ? $handler->options['list']['separator'] : ', ';
+        return implode($separator, $inner_values);
+    }
+  }
+
+  /**
+   * Render a single value as a link to the entity if applicable.
+   *
+   * @param $handler
+   *   The field handler whose field is rendered.
+   * @param $value
+   *   The single value to render.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   *
+   * @return
+   *   The rendered value.
+   */
+  public static function render_entity_link($handler, $value, $values) {
+    // Allow easy overriding of this behaviour in the specific field handler.
+    if (method_exists($handler, 'render_entity_link')) {
+      return $handler->render_entity_link($value, $values);
+    }
+    $render = self::render_single_value($handler, $value, $values);
+    if (!$handler->options['link_to_entity']) {
+      return $render;
+    }
+    $entity = $handler->get_value($values, 'entity object');
+    if (is_object($entity) && ($url = entity_uri($handler->entity_type, $entity))) {
+      return l($render, $url['path'], array('html' => TRUE) + $url['options']);
+    }
+    return $render;
+  }
+
+  /**
+   * Render a single value.
+   *
+   * @param $handler
+   *   The field handler whose field is rendered.
+   * @param $value
+   *   The single value to render.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   *
+   * @return
+   *   The rendered value.
+   */
+  public static function render_single_value($handler, $value, $values) {
+    // Try to use the method in the specific field handler.
+    if (method_exists($handler, 'render_single_value')) {
+      $handler->current_value = $value;
+      $return = $handler->render_single_value($value, $values);
+      unset($handler->current_value);
+      return $return;
+    }
+    // Default fallback in case the field handler doesn't provide the method.
+    return is_scalar($value) ? check_plain($value) : nl2br(check_plain(print_r($value, TRUE)));
+  }
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_area_entity.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_area_entity.inc
new file mode 100644
index 0000000000000000000000000000000000000000..de5863b5ecb518a2300bd0948812a4ec9264544a
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_area_entity.inc
@@ -0,0 +1,111 @@
+<?php
+/**
+ * @file
+ * Renders a full entity in a views area.
+ */
+
+class entity_views_handler_area_entity extends views_handler_area {
+  public function option_definition() {
+    $options = parent::option_definition();
+    $options['entity_type'] = array('default' => 'node');
+    $options['entity_id'] = array('default' => '');
+    $options['view_mode'] = array('default' => 'full');
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $entity_type_options = array();
+    foreach (entity_get_info() as $entity_type => $entity_info) {
+      $entity_type_options[$entity_type] = $entity_info['label'];
+    }
+
+    $entity_type = $this->options['entity_type'];
+
+    $form['entity_type'] = array(
+      '#type' => 'select',
+      '#title' => t('Entity type'),
+      '#options' => $entity_type_options,
+      '#description' => t('Choose the entity type you want to display in the area.'),
+      '#default_value' => $entity_type,
+      '#ajax' => array(
+        'path' => views_ui_build_form_url($form_state),
+      ),
+      '#submit' => array('views_ui_config_item_form_submit_temporary'),
+      '#executes_submit_callback' => TRUE,
+    );
+
+    $form['entity_id'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Entity id'),
+      '#description' => t('Choose the entity you want to display in the area.'),
+      '#default_value' => $this->options['entity_id'],
+    );
+
+    if ($entity_type) {
+      $entity_info = entity_get_info($entity_type);
+      $options = array();
+      if (!empty($entity_info['view modes'])) {
+        foreach ($entity_info['view modes'] as $mode => $settings) {
+          $options[$mode] = $settings['label'];
+        }
+      }
+
+      if (count($options) > 1) {
+        $form['view_mode'] = array(
+          '#type' => 'select',
+          '#options' => $options,
+          '#title' => t('View mode'),
+          '#default_value' => $this->options['view_mode'],
+        );
+      }
+      else {
+        $form['view_mode_info'] = array(
+          '#type' => 'item',
+          '#title' => t('View mode'),
+          '#description' => t('Only one view mode is available for this entity type.'),
+          '#markup' => $options ? current($options) : t('Default'),
+        );
+        $form['view_mode'] = array(
+          '#type' => 'value',
+          '#value' => $options ? key($options) : 'default',
+        );
+      }
+    }
+    return $form;
+  }
+
+  public function admin_summary() {
+    $label = parent::admin_summary();
+    if (!empty($this->options['entity_id'])) {
+      return t('@label @entity_type:@entity_id', array(
+        '@label' => $label,
+        '@entity_type' => $this->options['entity_type'],
+        '@entity_id' => $this->options['entity_id'],
+      ));
+    }
+  }
+
+  public function render($empty = FALSE) {
+    if (!$empty || !empty($this->options['empty'])) {
+      return $this->render_entity($this->options['entity_type'], $this->options['entity_id'], $this->options['view_mode']);
+    }
+    return '';
+  }
+
+  /**
+   * Render an entity using the view mode.
+   */
+  public function render_entity($entity_type, $entity_id, $view_mode) {
+    if (!empty($entity_type) && !empty($entity_id) && !empty($view_mode)) {
+      $entities = entity_load($entity_type, array($entity_id));
+      $render = entity_view($entity_type, $entities, $view_mode);
+      $render_entity = reset($render);
+      return drupal_render($render_entity);
+    }
+    else {
+      return '';
+    }
+  }
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_field_boolean.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_field_boolean.inc
new file mode 100644
index 0000000000000000000000000000000000000000..42943d9ad31d93422b280fdce18bb2377277a3a3
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_boolean.inc
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_boolean class.
+ */
+
+/**
+ * A handler to provide proper displays for booleans.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_boolean extends views_handler_field_boolean {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Provide options for this handler.
+   */
+  public function option_definition() {
+    return parent::option_definition() + EntityFieldHandlerHelper::option_definition($this);
+  }
+
+  /**
+   * Provide a options form for this handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    return parent::render($values);
+  }
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_field_date.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_field_date.inc
new file mode 100644
index 0000000000000000000000000000000000000000..89401cd094043b4eae3e5a8c2dbaecbca7dce6ff
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_date.inc
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_date class.
+ */
+
+/**
+ * A handler to provide proper displays for dates.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_date extends views_handler_field_date {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Provide options for this handler.
+   */
+  public function option_definition() {
+    return parent::option_definition() + EntityFieldHandlerHelper::option_definition($this);
+  }
+
+  /**
+   * Provide a options form for this handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    return parent::render($values);
+  }
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_field_duration.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_field_duration.inc
new file mode 100644
index 0000000000000000000000000000000000000000..53454b2da5606afc76b64304157e2ec9fba77a10
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_duration.inc
@@ -0,0 +1,130 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_duration class.
+ */
+
+/**
+ * A handler to provide proper displays for duration properties retrieved via data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_duration extends views_handler_field {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  public function option_definition() {
+    $options = parent::option_definition();
+    $options += EntityFieldHandlerHelper::option_definition($this);
+
+    $options['format_interval'] = array('default' => TRUE);
+    $options['granularity'] = array('default' => 2);
+    $options['prefix'] = array('default' => '', 'translatable' => TRUE);
+    $options['suffix'] = array('default' => '', 'translatable' => TRUE);
+
+    return $options;
+  }
+
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+
+    $form['format_interval'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Format interval'),
+      '#description' => t('If checked, the value will be formatted as a time interval. Otherwise, just the number of seconds will be displayed.'),
+      '#default_value' => $this->options['format_interval'],
+    );
+    $form['granularity'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Granularity'),
+      '#default_value' => $this->options['granularity'],
+      '#description' => t('Specify how many different units to display.'),
+      '#dependency' => array('edit-options-format-interval' => array(TRUE)),
+      '#size' => 2,
+    );
+    $form['prefix'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Prefix'),
+      '#default_value' => $this->options['prefix'],
+      '#description' => t('Text to put before the duration text.'),
+    );
+    $form['suffix'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Suffix'),
+      '#default_value' => $this->options['suffix'],
+      '#description' => t('Text to put after the duration text.'),
+    );
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    if ($this->options['format_interval']) {
+      $value = format_interval($value, (int) $this->options['granularity']);
+    }
+    return $this->sanitize_value($this->options['prefix'], 'xss') .
+        $this->sanitize_value($value) .
+        $this->sanitize_value($this->options['suffix'], 'xss');
+  }
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_field_entity.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_field_entity.inc
new file mode 100644
index 0000000000000000000000000000000000000000..0a646f767085d4cf70041bf2704381389b8924e7
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_entity.inc
@@ -0,0 +1,199 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_entity class.
+ */
+
+/**
+ * A handler to provide proper displays for entities retrieved via data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_entity extends views_handler_field {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * The entity type of the entity displayed by this field.
+   */
+  public $field_entity_type;
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Initialize the entity type with the field's entity type.
+   */
+  public function init(&$view, &$options) {
+    parent::init($view, $options);
+    $this->field_entity_type = entity_property_extract_innermost_type($this->definition['type']);
+  }
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  public function option_definition() {
+    $options = parent::option_definition();
+    $options += EntityFieldHandlerHelper::option_definition($this);
+
+    $options['display'] = array('default' => 'label');
+    $options['link_to_entity']['default'] = TRUE;
+    $options['view_mode'] = array('default' => 'default');
+
+    return $options;
+  }
+
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+    // We want a different form field at a different place.
+    unset($form['link_to_entity']);
+
+    $options = array(
+      'label' => t('Show entity label'),
+      'id' => t('Show entity ID'),
+      'view' => t('Show complete entity'),
+    );
+    $form['display'] = array(
+      '#type' => 'select',
+      '#title' => t('Display'),
+      '#description' => t('Decide how this field will be displayed.'),
+      '#options' => $options,
+      '#default_value' => $this->options['display'],
+    );
+    $form['link_to_entity'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Link to entity'),
+      '#description' => t('Link this field to the entity.'),
+      '#default_value' => $this->options['link_to_entity'],
+      '#dependency' => array('edit-options-display' => array('label', 'id')),
+    );
+
+    // Stolen from entity_views_plugin_row_entity_view.
+    $entity_info = entity_get_info($this->field_entity_type);
+    $options = array();
+    if (!empty($entity_info['view modes'])) {
+      foreach ($entity_info['view modes'] as $mode => $settings) {
+        $options[$mode] = $settings['label'];
+      }
+    }
+
+    if (count($options) > 1) {
+      $form['view_mode'] = array(
+        '#type' => 'select',
+        '#options' => $options,
+        '#title' => t('View mode'),
+        '#default_value' => $this->options['view_mode'],
+        '#dependency' => array('edit-options-display' => array('view')),
+      );
+    }
+    else {
+      $form['view_mode'] = array(
+        '#type' => 'value',
+        '#value' => $options ? key($options) : 'default',
+      );
+    }
+  }
+
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a value as a link to the entity if applicable.
+   *
+   * @param $value
+   *   The value to render.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   */
+  public function render_entity_link($entity, $values) {
+    $type = $this->field_entity_type;
+    if (!is_object($entity) && isset($entity) && $entity !== FALSE) {
+      $entity = entity_load_single($type, $entity);
+    }
+    if (!$entity) {
+      return '';
+    }
+    $render = $this->render_single_value($entity, $values);
+    if (!$this->options['link_to_entity']) {
+      return $render;
+    }
+    if (is_object($entity) && ($url = entity_uri($type, $entity))) {
+      return l($render, $url['path'], array('html' => TRUE) + $url['options']);
+    }
+    return $render;
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($entity, $values) {
+    $type = $this->field_entity_type;
+    if (!is_object($entity) && isset($entity) && $entity !== FALSE) {
+      $entity = entity_load_single($type, $entity);
+    }
+    if (!$entity) {
+      return '';
+    }
+
+    if ($this->options['display'] === 'view') {
+      $entity_view = entity_view($type, array($entity), $this->options['view_mode']);
+      return render($entity_view);
+    }
+
+    if ($this->options['display'] == 'label') {
+      $value = entity_label($type, $entity);
+    }
+    // Either $options[display] == 'id', or we have no label.
+    if (empty($value)) {
+      $value = entity_id($type, $entity);
+    }
+    $value = $this->sanitize_value($value);
+
+    return $value;
+  }
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_field_field.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_field_field.inc
new file mode 100644
index 0000000000000000000000000000000000000000..f3cd7da268165e109f9d541b4354b684b42e7724
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_field.inc
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_field class.
+ */
+
+/**
+ * A handler to provide proper displays for Field API fields.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_field extends views_handler_field_field {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * The entity for which this field is currently rendered.
+   */
+  public $entity;
+
+  /**
+   * Return TRUE if the user has access to view this field.
+   */
+  public function access() {
+    return field_access('view', $this->field_info, $this->definition['entity type']);
+  }
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query($use_groupby = FALSE) {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Override so it doesn't do any harm (or, anything at all).
+   */
+  public function post_execute(&$values) { }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values, TRUE);
+  }
+
+  /**
+   * Overridden to get the items our way.
+   */
+  public function get_items($values) {
+    $items = array();
+    // Set the entity type for the parent handler.
+    $values->_field_data[$this->field_alias]['entity_type'] = $this->entity_type;
+    // We need special handling for lists of entities as the base.
+    $entities = EntityFieldHandlerHelper::get_value($this, $values, 'entity object');
+    if (!is_array($entities)) {
+      $entities = $entities ? array($entities) : array();
+    }
+    foreach ($entities as $entity) {
+      // Only try to render the field if it is even present on this bundle.
+      // Otherwise, field_view_field() will trigger a fatal.
+      list (, , $bundle) = entity_extract_ids($this->entity_type, $entity);
+      if (field_info_instance($this->entity_type, $this->definition['field_name'], $bundle)) {
+        // Set the currently rendered entity.
+        $values->_field_data[$this->field_alias]['entity'] = $entity;
+        $items = array_merge($items, $this->set_items($values, $this->view->row_index));
+      }
+    }
+    return $items;
+  }
+
+  /**
+   * Overridden to force displaying multiple values in a single row.
+   */
+  function multiple_options_form(&$form, &$form_state) {
+    parent::multiple_options_form($form, $form_state);
+    $form['group_rows']['#default_value'] = TRUE;
+    $form['group_rows']['#disabled'] = TRUE;
+  }
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_field_numeric.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_field_numeric.inc
new file mode 100644
index 0000000000000000000000000000000000000000..bf9814910337949bd167f3b3be2c24d049a70e78
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_numeric.inc
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_numeric class.
+ */
+
+/**
+ * Render a field as a numeric value.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_numeric extends views_handler_field_numeric {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Provide options for this handler.
+   */
+  public function option_definition() {
+    return parent::option_definition() + EntityFieldHandlerHelper::option_definition($this);
+  }
+
+  /**
+   * Provide a options form for this handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    return parent::render($values);
+  }
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_field_options.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_field_options.inc
new file mode 100644
index 0000000000000000000000000000000000000000..a947d36c29a29413273e022e2191c18bef69f55c
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_options.inc
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_options class.
+ */
+
+/**
+ * A handler to provide proper displays for values chosen from a set of options.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_options extends views_handler_field {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * The key / name mapping for the options.
+   */
+  public $option_list;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Specifies the options this handler uses.
+   */
+  public function option_definition() {
+    $options = parent::option_definition();
+    $options += EntityFieldHandlerHelper::option_definition($this);
+    $options['format_name'] = array('default' => TRUE);
+    return $options;
+  }
+
+  /**
+   * Returns an option form for setting this handler's options.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+
+    $form['format_name'] = array(
+      '#title' => t('Use human-readable name'),
+      '#type' => 'checkbox',
+      '#description' => t("If this is checked, the values' names will be displayed instead of their internal identifiers."),
+      '#default_value' => $this->options['format_name'],
+      '#weight' => -5,
+    );
+  }
+
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    if (!isset($this->option_list)) {
+      $this->option_list = array();
+      $callback = $this->definition['options callback'];
+      if (is_callable($callback['function'])) {
+        // If a selector is used, get the name of the selected field.
+        $field_name = EntityFieldHandlerHelper::get_selector_field_name($this->real_field);
+        $this->option_list = call_user_func($callback['function'], $field_name, $callback['info'], 'view');
+      }
+    }
+    if ($this->options['format_name'] && isset($this->option_list[$value])) {
+      $value = $this->option_list[$value];
+    }
+
+    return $this->sanitize_value($value);
+  }
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_field_text.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_field_text.inc
new file mode 100644
index 0000000000000000000000000000000000000000..a7921dac529de43d86b17777b1f17739dac7413a
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_text.inc
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_text class.
+ */
+
+/**
+ * A handler to display text data.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_text extends views_handler_field {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Provide options for this handler.
+   */
+  public function option_definition() {
+    return parent::option_definition() + EntityFieldHandlerHelper::option_definition($this);
+  }
+
+  /**
+   * Provide a options form for this handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    return $this->sanitize_value($value, 'xss');
+  }
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_field_uri.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_field_uri.inc
new file mode 100644
index 0000000000000000000000000000000000000000..c01882af4f8217ef1a6e4fca2359aa781f9cd428
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_uri.inc
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_uri class.
+ */
+
+/**
+ * Field handler to provide simple renderer that turns a URL into a clickable link.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_uri extends views_handler_field_url {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Provide options for this handler.
+   */
+  public function option_definition() {
+    return parent::option_definition() + EntityFieldHandlerHelper::option_definition($this);
+  }
+
+  /**
+   * Provide a options form for this handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    return parent::render($values);
+  }
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_relationship.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_relationship.inc
new file mode 100644
index 0000000000000000000000000000000000000000..a15c056600cadf0a1588097e3cb6ce1e1522413f
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_relationship.inc
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_relationship class.
+ */
+
+/**
+ * Relationship handler for data selection tables.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_relationship extends views_handler_relationship {
+
+  /**
+   * Slightly modify the options form provided by the parent handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    // This won't work with data selector-based relationships, as we only
+    // inspect those *after* the results are known.
+    $form['required']['#access'] = FALSE;
+    // Notify the user of our restrictions regarding lists of entities, if
+    // appropriate.
+    if (!empty($this->definition['multiple'])) {
+      $form['multiple_note'] = array(
+        '#markup' => t('<strong>Note:</strong> This is a multi-valued relationship, which is currently not supported. ' .
+            'Only the first related entity will be shown.'),
+        '#weight' => -5,
+      );
+    }
+  }
+
+  /**
+   * Called to implement a relationship in a query.
+   *
+   * As we don't add any data to the query itself, we don't have to do anything
+   * here. Views just don't thinks we have been called unless we set our
+   * $alias property. Otherwise, this override is just here to keep PHP from
+   * blowing up by calling inexistent methods on the query plugin.
+   */
+  public function query() {
+    $this->alias = $this->options['id'];
+  }
+
+}
diff --git a/sites/all/modules/entity/views/handlers/entity_views_handler_relationship_by_bundle.inc b/sites/all/modules/entity/views/handlers/entity_views_handler_relationship_by_bundle.inc
new file mode 100644
index 0000000000000000000000000000000000000000..55b0fc2fadede1f44f8b488e721fd44ca14e16a9
--- /dev/null
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_relationship_by_bundle.inc
@@ -0,0 +1,117 @@
+<?php
+/**
+ * @file
+ * Contains the entity_views_handler_relationship_by_bundle class.
+ */
+
+/**
+ * Relationship handler for entity relationships that may limit the join to one or more bundles.
+ *
+ * This handler is only applicable for entities that are using bundle entities,
+ * i.e. entities having the 'bundle of' entity info key set.
+ *
+ * For example, this allows a relationship from users to profiles of a certain
+ * profile type.
+ *
+ * @see entity_crud_hook_entity_info()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_relationship_by_bundle extends views_handler_relationship {
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['bundle_types'] = array('default' => array());
+
+    return $options;
+  }
+
+  /**
+   * Add an entity type option.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Get the entity type and info from the table data for the base on the
+    // right hand side of the relationship join.
+    $table_data = views_fetch_data($this->definition['base']);
+    $entity_type = $table_data['table']['entity type'];
+    $entity_info = entity_get_info($entity_type);
+
+    // Get the info of the bundle entity.
+    foreach (entity_get_info() as $type => $info) {
+      if (isset($info['bundle of']) && $info['bundle of'] == $entity_type) {
+        $entity_bundle_info = $info;
+        break;
+      }
+    }
+
+    $plural_label = isset($entity_bundle_info['plural label']) ? $entity_bundle_info['plural label'] : $entity_bundle_info['label'] . 's';
+    $bundle_options = array();
+    foreach ($entity_info['bundles'] as $name => $info) {
+      $bundle_options[$name] = $info['label'];
+    }
+
+    $form['bundle_types'] = array(
+      '#title' => $plural_label,
+      '#type' => 'checkboxes',
+      '#description' => t('Restrict this relationship to one or more @bundles.', array('@bundles' => strtolower($entity_bundle_info['plural label']))),
+      '#options' => $bundle_options,
+      '#default_value' => $this->options['bundle_types'],
+    );
+  }
+
+  /**
+   * Make sure only checked bundle types are left.
+   */
+  function options_submit(&$form, &$form_state) {
+    $form_state['values']['options']['bundle_types'] = array_filter($form_state['values']['options']['bundle_types']);
+    parent::options_submit($form, $form_state);
+  }
+
+  /**
+   * Called to implement a relationship in a query.
+   *
+   * Mostly the same as the parent method, except we add an extra clause to
+   * the join.
+   */
+  function query() {
+    $table_data = views_fetch_data($this->definition['base']);
+    $base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field'];
+    $this->ensure_my_table();
+
+    $def = $this->definition;
+    $def['table'] = $this->definition['base'];
+    $def['field'] = $base_field;
+    $def['left_table'] = $this->table_alias;
+    $def['left_field'] = $this->field;
+    if (!empty($this->options['required'])) {
+      $def['type'] = 'INNER';
+    }
+
+    // Add an extra clause to the join if there are bundle types selected.
+    if ($this->options['bundle_types']) {
+      $entity_info = entity_get_info($table_data['table']['entity type']);
+      $def['extra'] = array(
+        array(
+          // The table and the IN operator are implicit.
+          'field' => $entity_info['bundle keys']['bundle'],
+          'value' => $this->options['bundle_types'],
+        ),
+      );
+    }
+
+    if (!empty($def['join_handler']) && class_exists($def['join_handler'])) {
+      $join = new $def['join_handler'];
+    }
+    else {
+      $join = new views_join();
+    }
+
+    $join->definition = $def;
+    $join->construct();
+    $join->adjusted = TRUE;
+
+    // Use a short alias for this.
+    $alias = $def['table'] . '_' . $this->table;
+    $this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
+  }
+}
diff --git a/sites/all/modules/entity/views/plugins/entity_views_plugin_row_entity_view.inc b/sites/all/modules/entity/views/plugins/entity_views_plugin_row_entity_view.inc
new file mode 100644
index 0000000000000000000000000000000000000000..db72b5f50dd7b77936ac943ae249ae95e75cab89
--- /dev/null
+++ b/sites/all/modules/entity/views/plugins/entity_views_plugin_row_entity_view.inc
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Row style plugin for displaying the results as entities.
+ */
+
+/**
+ * Plugin class for displaying Views results with entity_view.
+ */
+class entity_views_plugin_row_entity_view extends views_plugin_row {
+
+  protected $entity_type, $entities;
+
+  public function init(&$view, &$display, $options = NULL) {
+    parent::init($view, $display, $options);
+
+    // Initialize the entity-type used.
+    $table_data = views_fetch_data($this->view->base_table);
+    $this->entity_type = $table_data['table']['entity type'];
+    // Set base table and field information as used by views_plugin_row to
+    // select the entity id if used with default query class.
+    $info = entity_get_info($this->entity_type);
+    if (!empty($info['base table']) && $info['base table'] == $this->view->base_table) {
+      $this->base_table = $info['base table'];
+      $this->base_field = $info['entity keys']['id'];
+    }
+  }
+
+  public function option_definition() {
+    $options = parent::option_definition();
+    $options['view_mode'] = array('default' => 'full');
+    return $options;
+  }
+
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $entity_info = entity_get_info($this->entity_type);
+    $options = array();
+    if (!empty($entity_info['view modes'])) {
+      foreach ($entity_info['view modes'] as $mode => $settings) {
+        $options[$mode] = $settings['label'];
+      }
+    }
+
+    if (count($options) > 1) {
+      $form['view_mode'] = array(
+        '#type' => 'select',
+        '#options' => $options,
+        '#title' => t('View mode'),
+        '#default_value' => $this->options['view_mode'],
+      );
+    }
+    else {
+      $form['view_mode_info'] = array(
+        '#type' => 'item',
+        '#title' => t('View mode'),
+        '#description' => t('Only one view mode is available for this entity type.'),
+        '#markup' => $options ? current($options) : t('Default'),
+      );
+      $form['view_mode'] = array(
+        '#type' => 'value',
+        '#value' => $options ? key($options) : 'default',
+      );
+    }
+    return $form;
+  }
+
+  public function pre_render($values) {
+    if (!empty($values)) {
+      list($this->entity_type, $this->entities) = $this->view->query->get_result_entities($values, !empty($this->relationship) ? $this->relationship : NULL, isset($this->field_alias) ? $this->field_alias : NULL);
+    }
+    // Render the entities.
+    if ($this->entities) {
+      $render = entity_view($this->entity_type, $this->entities, $this->options['view_mode']);
+      // Remove the first level of the render array.
+      $this->rendered_content = reset($render);
+    }
+  }
+
+  /**
+   * Overridden to return the entity object.
+   */
+  function get_value($values, $field = NULL) {
+    return isset($this->entities[$this->view->row_index]) ? $this->entities[$this->view->row_index] : FALSE;
+  }
+
+  public function render($values) {
+    if ($entity = $this->get_value($values)) {
+      $render = $this->rendered_content[entity_id($this->entity_type, $entity)];
+      return drupal_render($render);
+    }
+  }
+}
diff --git a/sites/all/modules/entityreference/LICENSE.txt b/sites/all/modules/entityreference/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1
--- /dev/null
+++ b/sites/all/modules/entityreference/LICENSE.txt
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/sites/all/modules/entityreference/README.txt b/sites/all/modules/entityreference/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..78706c0194699be69ae72718105e50c8a5d75e53
--- /dev/null
+++ b/sites/all/modules/entityreference/README.txt
@@ -0,0 +1,16 @@
+DESCRIPTION
+===========
+Provides a field type that can reference arbitrary entities.
+
+SITE BUILDERS
+=============
+Note that when using a select widget, Entity reference loads all the
+entities in that list in order to get the entity's label. If there are
+too many loaded entities that site might reach its memory limit and crash
+(also known as WSOD). In such a case you are advised to change the widget
+to "autocomplete". If you get a WSOD when trying to edit the field
+settings, you can reach the widget settings directly by navigation to
+
+  admin/structure/types/manage/[ENTITY-TYPE]/fields/[FIELD-NAME]/widget-type
+
+Replace ENTITY-TYPE and FIELD_NAME with the correct values.
diff --git a/sites/all/modules/entityreference/entityreference.devel_generate.inc b/sites/all/modules/entityreference/entityreference.devel_generate.inc
new file mode 100644
index 0000000000000000000000000000000000000000..eee767ceffaaca7b4e79321dd4884ebf1bab2b8d
--- /dev/null
+++ b/sites/all/modules/entityreference/entityreference.devel_generate.inc
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Support for processing entity reference fields in devel generate.
+ */
+
+function entityreference_devel_generate($object, $field, $instance, $bundle) {
+  if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_CUSTOM) {
+    return devel_generate_multiple('_entityreference_devel_generate', $object, $field, $instance, $bundle);
+  }
+  else {
+    return _entityreference_devel_generate($object, $field, $instance, $bundle);
+  }
+}
+
+function _entityreference_devel_generate($object, $field, $instance, $bundle) {
+  $object_field = array();
+  // Get all the entity that are referencable here.
+  $referencable_entity = entityreference_get_selection_handler($field, $instance)->getReferencableEntities();
+  if (is_array($referencable_entity) && !empty($referencable_entity)) {
+    // Get a random key.
+    $object_field['target_id'] = array_rand($referencable_entity);
+  }
+  return $object_field;
+}
diff --git a/sites/all/modules/entityreference/entityreference.feeds.inc b/sites/all/modules/entityreference/entityreference.feeds.inc
new file mode 100644
index 0000000000000000000000000000000000000000..093fa5f88035e2d1e1382c733e92dd2a8d6a5918
--- /dev/null
+++ b/sites/all/modules/entityreference/entityreference.feeds.inc
@@ -0,0 +1,121 @@
+<?php
+
+/**
+ * @file
+ * Feeds mapping implementation for the Entity reference module
+ */
+
+/**
+ * Implements hook_feeds_processor_targets_alter().
+ *
+ * @see FeedsNodeProcessor::getMappingTargets().
+ */
+function entityreference_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+
+  foreach (field_info_instances($entity_type, $bundle_name) as
+           $name => $instance) {
+    $info = field_info_field($name);
+    if ($info['type'] == 'entityreference') {
+      $targets[$name] = array(
+        'name'        => check_plain($instance['label']),
+        'callback'    => 'entityreference_feeds_set_target',
+        'description' => t('The field instance @label of @id', array(
+          '@label' => $instance['label'],
+          '@id'    => $name,
+        )),
+      );
+    }
+  }
+}
+
+/**
+ * Entity reference callback for mapping.
+ *
+ * When the callback is invoked, $target contains the name of the field the
+ * user has decided to map to and $value contains the value of the feed item
+ * element the user has picked as a source.
+ *
+ * @param $source
+ *   A FeedsSource object.
+ * @param $entity
+ *   The entity to map to.
+ * @param $target
+ *   The target key on $entity to map to.
+ * @param $value
+ *   The value to map. MUST be an array.
+ * @param $mapping
+ *   Array of mapping settings for current value.
+ * @param $input_format
+ *   TRUE if an input format should be applied.
+ */
+function entityreference_feeds_set_target($source, $entity, $target, $value, $mapping, $input_format = FALSE) {
+
+  // Don't do anything if we weren't given any data.
+  if (empty($value)) {
+    return;
+  }
+
+  // Assume that the passed in value could really be any number of values.
+  if (is_array($value)) {
+    $values = $value;
+  } else {
+    $values = array($value);
+  }
+
+  // Get some useful field information.
+  $info = field_info_field($target);
+
+  // Set the language of the field depending on the mapping.
+  $language = isset($mapping['language']) ? $mapping['language'] : LANGUAGE_NONE;
+
+  // Iterate over all values.
+  $iterator = 0;
+  $field = isset($entity->$target) ? $entity->$target : array();
+  foreach ($values as $value) {
+
+    // Only process if this value was set for this instance.
+    if ($value) {
+
+      // Fetch the entity ID resulting from the mapping table look-up.
+      $entity_id = db_query(
+        'SELECT entity_id FROM {feeds_item} WHERE guid = :guid',
+        array(':guid' => $value)
+      )->fetchField();
+
+      /*
+       * Only add a reference to an existing entity ID if there exists a
+       * mapping between it and the provided GUID.  In cases where no such
+       * mapping exists (yet), don't do anything here.  There may be a mapping
+       * defined later in the CSV file.  If so, and the user re-runs the import
+       * (as a second pass), we can add this reference then.  (The "Update
+       * existing nodes" option must be selected during the second pass.)
+       */
+      if ($entity_id) {
+
+        // Assign the target ID.
+        $field[$language][$iterator]['target_id']   = $entity_id;
+      }
+      else /* there is no $entity_id, no mapping */ {
+
+        /*
+         * Feeds stores a hash of every line imported from CSVs in order to
+         * make the import process more efficient by ignoring lines it's
+         * already seen.  We need to short-circuit this process in this case
+         * because users may want to re-import the same line as an update later
+         * when (and if) a map to a reference exists.  So in order to provide
+         * this opportunity later, we need to destroy the hash.
+         */
+        unset($entity->feeds_item->hash);
+      }
+    }
+
+    // Break out of the loop if this field is single-valued.
+    if ($info['cardinality'] == 1) {
+      break;
+    }
+    $iterator++;
+  }
+
+  // Add the field to the entity definition.
+  $entity->{$target} = $field;
+}
diff --git a/sites/all/modules/entityreference/entityreference.info b/sites/all/modules/entityreference/entityreference.info
new file mode 100644
index 0000000000000000000000000000000000000000..8c6d530632d69f7d0e0f598242bdcd5667c19114
--- /dev/null
+++ b/sites/all/modules/entityreference/entityreference.info
@@ -0,0 +1,28 @@
+name = Entity Reference
+description = Provides a field that can reference other entities.
+core = 7.x
+package = Fields
+dependencies[] = entity
+dependencies[] = ctools
+
+; Migrate handler.
+files[] = entityreference.migrate.inc
+
+; Our plugins interfaces and abstract implementations.
+files[] = plugins/selection/abstract.inc
+files[] = plugins/selection/views.inc
+files[] = plugins/behavior/abstract.inc
+
+files[] = views/entityreference_plugin_display.inc
+files[] = views/entityreference_plugin_style.inc
+files[] = views/entityreference_plugin_row_fields.inc
+
+; Tests.
+files[] = tests/entityreference.handlers.test
+
+; Information added by drupal.org packaging script on 2012-05-30
+version = "7.x-1.0-rc3"
+core = "7.x"
+project = "entityreference"
+datestamp = "1338411955"
+
diff --git a/sites/all/modules/entityreference/entityreference.install b/sites/all/modules/entityreference/entityreference.install
new file mode 100644
index 0000000000000000000000000000000000000000..4e248efd3774cdff5d5c10dba87b8e1ec00210ce
--- /dev/null
+++ b/sites/all/modules/entityreference/entityreference.install
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * Implements hook_uninstall().
+ */
+function entityreference_uninstall() {
+  variable_del('entityreference:base-tables');
+}
+
+/**
+ * Implements hook_field_schema().
+ */
+function entityreference_field_schema($field) {
+  if ($field['type'] == 'entityreference') {
+    // Load the base table configuration from the cache.
+    $base_tables = variable_get('entityreference:base-tables', array());
+
+    $schema = array(
+      'columns' => array(
+        'target_id' => array(
+          'description' => 'The id of the target entity.',
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+        ),
+      ),
+      'indexes' => array(
+        'target_id' => array('target_id'),
+      ),
+      'foreign keys' => array(),
+    );
+
+    // Create a foreign key to the target entity type base type, if available.
+    $entity_type = $field['settings']['target_type'];
+    if (isset($base_tables[$entity_type])) {
+      list($base_table, $id_column) = $base_tables[$entity_type];
+      $schema['foreign keys'][$base_table] = array(
+        'table' => $base_table,
+        'columns' => array('target_id' => $id_column),
+      );
+    }
+
+    // Invoke the behaviors to allow them to change the schema.
+    foreach (entityreference_get_behavior_handlers($field) as $handler) {
+      $handler->schema_alter($schema, $field);
+    }
+
+    return $schema;
+  }
+}
+
+/**
+ * Update the field configuration to the new plugin structure.
+ */
+function entityreference_update_7000() {
+  // Enable ctools.
+  if (!module_enable(array('ctools'))) {
+    throw new DrupalUpdateException('This version of Entity Reference requires ctools, but it could not be enabled.');
+  }
+
+  // Get the list of fields of type 'entityreference'.
+  $fields = array();
+  foreach (field_info_fields() as $field_name => $field) {
+    // Update the field configuration.
+    if ($field['type'] == 'entityreference') {
+      $settings = &$field['settings'];
+      if (!isset($settings['handler'])) {
+        $settings['handler'] = 'base';
+        $settings['handler_settings']['target_bundles'] = $settings['target_bundles'];
+        unset($settings['target_bundles']);
+        field_update_field($field);
+      }
+    }
+
+    // Update the instance configurations.
+    foreach ($field['bundles'] as $entity_type => $bundles) {
+      foreach ($bundles as $bundle) {
+        $instance = field_info_instance($entity_type, $field_name, $bundle);
+        $save = FALSE;
+        if ($instance['widget']['type'] == 'entityreference_autocomplete') {
+          $instance['widget']['type'] = 'entityreference_autocomplete_tags';
+          $save = TRUE;
+        }
+        // When the autocomplete path is the default value, remove it from
+        // the configuration.
+        if (isset($instance['widget']['settings']['path']) && $instance['widget']['settings']['path'] == 'entityreference/autocomplete') {
+          unset($instance['widget']['settings']['path']);
+          $save = TRUE;
+        }
+        if ($save) {
+          field_update_instance($instance);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Drop "target_type" from the field schema.
+ */
+function entityreference_update_7001() {
+  if (!module_exists('field_sql_storage')) {
+    return;
+  }
+  foreach (field_info_fields() as $field_name => $field) {
+    if ($field['type'] != 'entityreference') {
+      // Not an entity reference field.
+      continue;
+    }
+
+    // Update the field settings.
+    $field = field_info_field($field_name);
+    unset($field['indexes']['target_entity']);
+    $field['indexes']['target_id'] = array('target_id');
+    field_update_field($field);
+
+    if ($field['storage']['type'] !== 'field_sql_storage') {
+      // Field doesn't use SQL storage, we cannot modify the schema.
+      continue;
+    }
+    $table_name = _field_sql_storage_tablename($field);
+    $revision_name = _field_sql_storage_revision_tablename($field);
+
+    db_drop_index($table_name, $field_name . '_target_entity');
+    db_drop_index($table_name, $field_name . '_target_id');
+    db_drop_field($table_name, $field_name . '_target_type');
+    db_add_index($table_name, $field_name . '_target_id', array($field_name . '_target_id'));
+
+    db_drop_index($revision_name, $field_name . '_target_entity');
+    db_drop_index($revision_name, $field_name . '_target_id');
+    db_drop_field($revision_name, $field_name . '_target_type');
+    db_add_index($revision_name, $field_name . '_target_id', array($field_name . '_target_id'));
+  }
+}
+
+/**
+ * Make the target_id column NOT NULL.
+ */
+function entityreference_update_7002() {
+  if (!module_exists('field_sql_storage')) {
+    return;
+  }
+  foreach (field_info_fields() as $field_name => $field) {
+    if ($field['type'] != 'entityreference') {
+      // Not an entity reference field.
+      continue;
+    }
+
+    if ($field['storage']['type'] !== 'field_sql_storage') {
+      // Field doesn't use SQL storage, we cannot modify the schema.
+      continue;
+    }
+
+    $table_name = _field_sql_storage_tablename($field);
+    $revision_name = _field_sql_storage_revision_tablename($field);
+
+    db_change_field($table_name, $field_name . '_target_id', $field_name . '_target_id', array(
+      'description' => 'The id of the target entity.',
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+    ));
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/entityreference/entityreference.migrate.inc b/sites/all/modules/entityreference/entityreference.migrate.inc
new file mode 100644
index 0000000000000000000000000000000000000000..280160f761f1f5d49ce4749e847ad9cbb0d53c6c
--- /dev/null
+++ b/sites/all/modules/entityreference/entityreference.migrate.inc
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Support for processing entity reference fields in Migrate.
+ */
+
+/**
+ * Implement hook_migrate_api().
+ */
+function entityreference_migrate_api() {
+  return array('api' => 2);
+}
+
+class MigrateEntityReferenceFieldHandler extends MigrateSimpleFieldHandler {
+  public function __construct() {
+    parent::__construct(array(
+      'value_key' => 'target_id',
+      'skip_empty' => TRUE,
+    ));
+
+    $this->registerTypes(array('entityreference'));
+  }
+}
diff --git a/sites/all/modules/entityreference/entityreference.module b/sites/all/modules/entityreference/entityreference.module
new file mode 100644
index 0000000000000000000000000000000000000000..170ac8c6e4120bf8e9008ae7e8916f9c29a802a5
--- /dev/null
+++ b/sites/all/modules/entityreference/entityreference.module
@@ -0,0 +1,1036 @@
+<?php
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function entityreference_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'entityreference') {
+    return 'plugins/' . $plugin;
+  }
+}
+
+/**
+ * Implements hook_init().
+ */
+function entityreference_init() {
+  // Include feeds.module integration.
+  if (module_exists('feeds')) {
+    module_load_include('inc','entityreference','entityreference.feeds');
+  }
+}
+
+/**
+ * Implements hook_ctools_plugin_type().
+ */
+function entityreference_ctools_plugin_type() {
+  $plugins['selection'] = array(
+    'classes' => array('class'),
+  );
+  $plugins['behavior'] = array(
+    'classes' => array('class'),
+    'process' => 'entityreference_behavior_plugin_process',
+  );
+  return $plugins;
+}
+
+/**
+ * CTools callback; Process the behavoir plugins.
+ */
+function entityreference_behavior_plugin_process(&$plugin, $info) {
+  $plugin += array(
+    'description' => '',
+    'behavior type' => 'field',
+    'access callback' => FALSE,
+    'force enabled' => FALSE,
+  );
+}
+
+/**
+ * Implementation of hook_field_info().
+ */
+function entityreference_field_info() {
+  $field_info['entityreference'] = array(
+    'label' => t('Entity Reference'),
+    'description' => t('This field reference another entity.'),
+    'settings' => array(
+      // Default to the core target entity type node.
+      'target_type' => 'node',
+      // The handler for this field.
+      'handler' => 'base',
+      // The handler settings.
+      'handler_settings' => array(),
+    ),
+    'instance_settings' => array(),
+    'default_widget' => 'entityreference_autocomplete',
+    'default_formatter' => 'entityreference_label',
+    'property_callbacks' => array('entityreference_field_property_callback'),
+  );
+  return $field_info;
+}
+
+/**
+ * Implements hook_flush_caches().
+ */
+function entityreference_flush_caches() {
+  // Because of the intricacies of the info hooks, we are forced to keep a
+  // separate list of the base tables of each entities, so that we can use
+  // it in entityreference_field_schema() without calling entity_get_info().
+  // See http://drupal.org/node/1416558 for details.
+  $base_tables = array();
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    if (!empty($entity_info['base table']) && !empty($entity_info['entity keys']['id'])) {
+      $base_tables[$entity_type] = array($entity_info['base table'], $entity_info['entity keys']['id']);
+    }
+  }
+  // We are using a variable because cache is going to be cleared right after
+  // hook_flush_caches() is finished.
+  variable_set('entityreference:base-tables', $base_tables);
+}
+
+/**
+ * Implements hook_menu().
+ */
+function entityreference_menu() {
+  $items = array();
+
+  $items['entityreference/autocomplete/single/%/%/%'] = array(
+    'title' => 'Entity Reference Autocomplete',
+    'page callback' => 'entityreference_autocomplete_callback',
+    'page arguments' => array(2, 3, 4, 5),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+  $items['entityreference/autocomplete/tags/%/%/%'] = array(
+    'title' => 'Entity Reference Autocomplete',
+    'page callback' => 'entityreference_autocomplete_callback',
+    'page arguments' => array(2, 3, 4, 5),
+    'access callback' => TRUE,
+    'type' => MENU_CALLBACK,
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function entityreference_field_is_empty($item, $field) {
+  $empty = !isset($item['target_id']) || !is_numeric($item['target_id']);
+
+  // Invoke the behaviors to allow them to override the empty status.
+  foreach (entityreference_get_behavior_handlers($field) as $handler) {
+    $handler->is_empty_alter($empty, $item, $field);
+  }
+  return $empty;
+}
+
+/**
+ * Get the behavior handlers for a given entityreference field.
+ */
+function entityreference_get_behavior_handlers($field, $instance = NULL) {
+  $object_cache = drupal_static(__FUNCTION__);
+  $identifier = $field['field_name'];
+  if (!empty($instance)) {
+    $identifier .= ':' . $instance['entity_type'] . ':' . $instance['bundle'];
+  }
+
+  if (!isset($object_cache[$identifier])) {
+    $object_cache[$identifier] = array();
+
+    // Merge in defaults.
+    $field['settings'] += array('behaviors' => array());
+
+    $object_cache[$field['field_name']] = array();
+    $behaviors = !empty($field['settings']['handler_settings']['behaviors']) ? $field['settings']['handler_settings']['behaviors'] : array();
+    if (!empty($instance['settings']['behaviors'])) {
+      $behaviors = array_merge($behaviors, $instance['settings']['behaviors']);
+    }
+    foreach ($behaviors as $behavior => $settings) {
+      if (empty($settings['status'])) {
+        // Behavior is not enabled.
+        continue;
+      }
+
+      $object_cache[$identifier][] = _entityreference_get_behavior_handler($behavior);
+    }
+  }
+
+  return $object_cache[$identifier];
+}
+
+/**
+ * Get the behavior handler for a given entityreference field and instance.
+ *
+ * @param $handler
+ *   The behavior handler name.
+ */
+function _entityreference_get_behavior_handler($behavior) {
+  $object_cache = drupal_static(__FUNCTION__);
+
+  if (!isset($object_cache[$behavior])) {
+    ctools_include('plugins');
+    $class = ctools_plugin_load_class('entityreference', 'behavior', $behavior, 'class');
+
+    $class = class_exists($class) ? $class : 'EntityReference_BehaviorHandler_Broken';
+    $object_cache[$behavior] = new $class($behavior);
+  }
+
+  return $object_cache[$behavior];
+}
+
+/**
+ * Get the selection handler for a given entityreference field.
+ */
+function entityreference_get_selection_handler($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+  ctools_include('plugins');
+  $handler = $field['settings']['handler'];
+  $class = ctools_plugin_load_class('entityreference', 'selection', $handler, 'class');
+
+  if (class_exists($class)) {
+    return call_user_func(array($class, 'getInstance'), $field, $instance, $entity_type, $entity);
+  }
+  else {
+    return EntityReference_SelectionHandler_Broken::getInstance($field, $instance, $entity_type, $entity);
+  }
+}
+
+/**
+ * Implements hook_field_load().
+ */
+function entityreference_field_load($entity_type, $entities, $field, $instances, $langcode, &$items) {
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field) as $handler) {
+    $handler->load($entity_type, $entities, $field, $instances, $langcode, $items);
+  }
+}
+
+/**
+ * Implements hook_field_validate().
+ */
+function entityreference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
+  $ids = array();
+  foreach ($items as $delta => $item) {
+    if (!entityreference_field_is_empty($item, $field) && $item['target_id'] !== NULL) {
+      $ids[$item['target_id']] = $delta;
+    }
+  }
+
+  if (!$ids) {
+    return;
+  }
+
+  $valid_ids = entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->validateReferencableEntities(array_keys($ids));
+
+  $invalid_entities = array_diff_key($ids, array_flip($valid_ids));
+  if ($invalid_entities) {
+    foreach ($invalid_entities as $id => $delta) {
+      $errors[$field['field_name']][$langcode][$delta][] = array(
+        'error' => 'entityreference_invalid_entity',
+        'message' => t('The referenced entity (@type: @id) is invalid.', array('@type' => $field['settings']['target_type'], '@id' => $id)),
+      );
+    }
+  }
+
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->validate($entity_type, $entity, $field, $instance, $langcode, $items, $errors);
+  }
+}
+
+/**
+ * Implements hook_field_presave().
+ *
+ * Adds the target type to the field data structure when saving.
+ */
+function entityreference_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->presave($entity_type, $entity, $field, $instance, $langcode, $items);
+  }
+}
+
+/**
+ * Implements hook_field_insert().
+ */
+function entityreference_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->insert($entity_type, $entity, $field, $instance, $langcode, $items);
+  }
+}
+
+/**
+ * Implements hook_field_attach_insert().
+ *
+ * Emulates a post-insert hook.
+ */
+function entityreference_field_attach_insert($entity_type, $entity) {
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
+    $field = field_info_field($field_name);
+    if ($field['type'] == 'entityreference') {
+      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+        $handler->postInsert($entity_type, $entity, $field, $instance);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_update().
+ */
+function entityreference_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->update($entity_type, $entity, $field, $instance, $langcode, $items);
+  }
+}
+
+/**
+ * Implements hook_field_attach_update().
+ *
+ * Emulates a post-update hook.
+ */
+function entityreference_field_attach_update($entity_type, $entity) {
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
+    $field = field_info_field($field_name);
+    if ($field['type'] == 'entityreference') {
+      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+        $handler->postUpdate($entity_type, $entity, $field, $instance);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_delete().
+ */
+function entityreference_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->delete($entity_type, $entity, $field, $instance, $langcode, $items);
+  }
+}
+
+/**
+ * Implements hook_field_attach_delete().
+ *
+ * Emulates a post-delete hook.
+ */
+function entityreference_field_attach_delete($entity_type, $entity) {
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
+    $field = field_info_field($field_name);
+    if ($field['type'] == 'entityreference') {
+      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+        $handler->postDelete($entity_type, $entity, $field, $instance);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function entityreference_field_settings_form($field, $instance, $has_data) {
+  // The field settings infrastructure is not AJAX enabled by default,
+  // because it doesn't pass over the $form_state.
+  // Build the whole form into a #process in which we actually have access
+  // to the form state.
+  $form = array(
+    '#type' => 'container',
+    '#process' => array('_entityreference_field_settings_process'),
+    '#element_validate' => array('_entityreference_field_settings_validate'),
+    '#field' => $field,
+    '#instance' => $instance,
+    '#has_data' => $has_data,
+  );
+  return $form;
+}
+
+function _entityreference_field_settings_process($form, $form_state) {
+  $field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
+  $instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
+  $has_data = $form['#has_data'];
+
+  $settings = $field['settings'];
+  $settings += array('handler' => 'base');
+
+  // Select the target entity type.
+  $entity_type_options = array();
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    $entity_type_options[$entity_type] = $entity_info['label'];
+  }
+
+  $form['target_type'] = array(
+    '#type' => 'select',
+    '#title' => t('Target type'),
+    '#options' => $entity_type_options,
+    '#default_value' => $field['settings']['target_type'],
+    '#required' => TRUE,
+    '#description' => t('The entity type that can be referenced through this field.'),
+    '#disabled' => $has_data,
+    '#size' => 1,
+    '#ajax' => array(
+      'callback' => 'entityreference_settings_ajax',
+      'wrapper' => $form['#id'],
+      'element' => $form['#array_parents'],
+    ),
+    '#limit_validation_errors' => array(),
+  );
+
+  ctools_include('plugins');
+  $handlers = ctools_get_plugins('entityreference', 'selection');
+  uasort($handlers, 'ctools_plugin_sort');
+  $handlers_options = array();
+  foreach ($handlers as $handler => $handler_info) {
+    $handlers_options[$handler] = check_plain($handler_info['title']);
+  }
+
+  $form['handler'] = array(
+    '#type' => 'radios',
+    '#title' => t('Entity selection mode'),
+    '#options' => $handlers_options,
+    '#default_value' => $settings['handler'],
+    '#required' => TRUE,
+    '#ajax' => array(
+      'callback' => 'entityreference_settings_ajax',
+      'wrapper' => $form['#id'],
+      'element' => $form['#array_parents'],
+    ),
+    '#limit_validation_errors' => array(),
+  );
+  $form['handler_submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Change handler'),
+    '#limit_validation_errors' => array(),
+    '#attributes' => array(
+      'class' => array('js-hide'),
+    ),
+    '#submit' => array('entityreference_settings_ajax_submit'),
+  );
+
+  $form['handler_settings'] = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+  );
+
+  $handler = entityreference_get_selection_handler($field, $instance);
+  $form['handler_settings'] += $handler->settingsForm($field, $instance);
+
+  _entityreference_get_behavior_elements($form['handler_settings'], $field, $instance, 'field');
+
+  return $form;
+}
+
+function _entityreference_field_settings_validate($form, &$form_state) {
+  // Store the new values in the form state.
+  $field = $form['#field'];
+
+  if (isset($form_state['values']['field'])) {
+    $field = drupal_array_merge_deep($field, $form_state['values']['field']);
+  }
+  $form_state['entityreference']['field'] = $field;
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function entityreference_field_instance_settings_form($field, $instance) {
+  _entityreference_get_behavior_elements($form, $field, $instance, 'instance');
+
+  return $form;
+}
+
+/**
+ * Get the field or instance elements for the field configuration.
+ */
+function _entityreference_get_behavior_elements(&$element, $field, $instance, $level) {
+  // Add the accessible behavior handlers.
+  $behavior_plugins = entityreference_get_accessible_behavior_plugins($field, $instance);
+
+  if ($behavior_plugins[$level]) {
+    $element['behaviors'] = array();
+
+    foreach ($behavior_plugins[$level] as $name => $plugin) {
+      if ($level == 'field') {
+        $settings = !empty($field['settings']['handler_settings']['behaviors'][$name]) ? $field['settings']['handler_settings']['behaviors'][$name] : array();
+      }
+      else {
+        $settings = !empty($instance['settings']['behaviors'][$name]) ? $instance['settings']['behaviors'][$name] : array();
+      }
+      $settings += array('status' => $plugin['force enabled']);
+      $element['behaviors'][$name] = array(
+        '#type' => 'fieldset',
+        '#title' => $plugin['title'],
+        '#default_value' => $settings['status'],
+      );
+      $element['behaviors'][$name]['status'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Enable %title', array('%title' => $plugin['title'])),
+        '#description' => $plugin['description'],
+        '#default_value' => $settings['status'],
+        '#disabled' => $plugin['force enabled'],
+      );
+
+      $handler = _entityreference_get_behavior_handler($name);
+      if ($behavior_elements = $handler->settingsForm($field, $instance)) {
+        $enable_element = $level == 'field' ? 'field[settings][handler_settings][behaviors]' : 'instance[settings][behaviors]';
+        foreach ($behavior_elements as $key => &$behavior_element) {
+          $behavior_element += array(
+            '#default_value' => !empty($settings[$key]) ? $settings[$key] : NULL,
+            '#states' => array(
+              'visible' => array(
+                ':input[name="' . $enable_element . '[' . $name . '][status]"]' => array('checked' => TRUE),
+              ),
+            ),
+          );
+        }
+
+        // Get the behavior settings.
+        $element['behaviors'][$name] += $behavior_elements;
+      }
+    }
+  }
+}
+
+/**
+ * Get all accessible behavior plugins.
+ */
+function entityreference_get_accessible_behavior_plugins($field, $instance) {
+  ctools_include('plugins');
+  $plugins = array('field' => array(), 'instance' => array());
+  foreach (ctools_get_plugins('entityreference', 'behavior') as $name => $plugin) {
+    $handler = _entityreference_get_behavior_handler($name);
+    $level = $plugin['behavior type'];
+    if ($handler->access($field, $instance)) {
+      $plugins[$level][$name] = $plugin;
+    }
+  }
+  return $plugins;
+}
+
+/**
+ * Ajax callback for the handler settings form.
+ *
+ * @see entityreference_field_settings_form()
+ */
+function entityreference_settings_ajax($form, $form_state) {
+  $trigger = $form_state['triggering_element'];
+  return drupal_array_get_nested_value($form, $trigger['#ajax']['element']);
+}
+
+/**
+ * Submit handler for the non-JS case.
+ *
+ * @see entityreference_field_settings_form()
+ */
+function entityreference_settings_ajax_submit($form, &$form_state) {
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Property callback for the Entity Metadata framework.
+ */
+function entityreference_field_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  // Set the property type based on the targe type.
+  $field_type['property_type'] = $field['settings']['target_type'];
+
+  // Then apply the default.
+  entity_metadata_field_default_property_callback($info, $entity_type, $field, $instance, $field_type);
+
+  // Invoke the behaviors to allow them to change the properties.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->property_info_alter($info, $entity_type, $field, $instance, $field_type);
+  }
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function entityreference_field_widget_info() {
+  $widgets['entityreference_autocomplete'] = array(
+    'label' => t('Autocomplete'),
+    'description' => t('An autocomplete text field.'),
+    'field types' => array('entityreference'),
+    'settings' => array(
+      'match_operator' => 'CONTAINS',
+      'size' => 60,
+      // We don't have a default here, because it's not the same between
+      // the two widgets, and the Field API doesn't update default
+      // settings when the widget changes.
+      'path' => '',
+    ),
+  );
+
+  $widgets['entityreference_autocomplete_tags'] = array(
+    'label' => t('Autocomplete (Tags style)'),
+    'description' => t('An autocomplete text field.'),
+    'field types' => array('entityreference'),
+    'settings' => array(
+      'match_operator' => 'CONTAINS',
+      'size' => 60,
+      // We don't have a default here, because it's not the same between
+      // the two widgets, and the Field API doesn't update default
+      // settings when the widget changes.
+      'path' => '',
+    ),
+    'behaviors' => array(
+      'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+    ),
+  );
+
+  return $widgets;
+}
+
+/**
+ * Implements hook_field_widget_info_alter().
+ */
+function entityreference_field_widget_info_alter(&$info) {
+  if (module_exists('options')) {
+    $info['options_select']['field types'][] = 'entityreference';
+    $info['options_buttons']['field types'][] = 'entityreference';
+  }
+}
+
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function entityreference_field_widget_settings_form($field, $instance) {
+  $widget = $instance['widget'];
+  $settings = $widget['settings'] + field_info_widget_settings($widget['type']);
+
+  $form = array();
+
+  if ($widget['type'] == 'entityreference_autocomplete' || $widget['type'] == 'entityreference_autocomplete_tags') {
+    $form['match_operator'] = array(
+      '#type' => 'select',
+      '#title' => t('Autocomplete matching'),
+      '#default_value' => $settings['match_operator'],
+      '#options' => array(
+        'STARTS_WITH' => t('Starts with'),
+        'CONTAINS' => t('Contains'),
+      ),
+      '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of nodes.'),
+    );
+    $form['size'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Size of textfield'),
+      '#default_value' => $settings['size'],
+      '#element_validate' => array('_element_validate_integer_positive'),
+      '#required' => TRUE,
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Implements hook_options_list().
+ */
+function entityreference_options_list($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+  return entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->getReferencableEntities();
+}
+
+/**
+ * Implements hook_query_TAG_alter().
+ */
+function entityreference_query_entityreference_alter(QueryAlterableInterface $query) {
+  $handler = $query->getMetadata('entityreference_selection_handler');
+  $handler->entityFieldQueryAlter($query);
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function entityreference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  $entity_type = $instance['entity_type'];
+  $entity = isset($element['#entity']) ? $element['#entity'] : NULL;
+  $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
+
+  if ($instance['widget']['type'] == 'entityreference_autocomplete' || $instance['widget']['type'] == 'entityreference_autocomplete_tags') {
+
+    if ($instance['widget']['type'] == 'entityreference_autocomplete') {
+      // We let the Field API handles multiple values for us, only take
+      // care of the one matching our delta.
+      if (isset($items[$delta])) {
+        $items = array($items[$delta]);
+      }
+      else {
+        $items = array();
+      }
+    }
+
+    $entity_ids = array();
+    $entity_labels = array();
+
+    // Build an array of entities ID.
+    foreach ($items as $item) {
+      $entity_ids[] = $item['target_id'];
+    }
+
+    // Load those entities and loop through them to extract their labels.
+    $entities = entity_load($field['settings']['target_type'], $entity_ids);
+
+    foreach ($entities as $entity_id => $entity_item) {
+      $label = $handler->getLabel($entity_item);
+      $key = "$label ($entity_id)";
+      // Labels containing commas or quotes must be wrapped in quotes.
+      if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
+        $key = '"' . str_replace('"', '""', $key) . '"';
+      }
+      $entity_labels[] = $key;
+    }
+
+    // Prepare the autocomplete path.
+    if (!empty($instance['widget']['settings']['path'])) {
+      $autocomplete_path = $instance['widget']['settings']['path'];
+    }
+    else {
+      $autocomplete_path = $instance['widget']['type'] == 'entityreference_autocomplete' ? 'entityreference/autocomplete/single' : 'entityreference/autocomplete/tags';
+    }
+
+    $autocomplete_path .= '/' . $field['field_name'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/';
+    if ($entity) {
+      list($id) = entity_extract_ids($entity_type, $entity);
+      $autocomplete_path .= $id;
+    }
+
+    if ($instance['widget']['type'] == 'entityreference_autocomplete') {
+      $element += array(
+        '#type' => 'textfield',
+        '#maxlength' => 1024,
+        '#default_value' => implode(', ', $entity_labels),
+        '#autocomplete_path' => $autocomplete_path,
+        '#size' => $instance['widget']['settings']['size'],
+        '#element_validate' => array('_entityreference_autocomplete_validate'),
+      );
+      return array('target_id' => $element);
+    }
+    else {
+      $element += array(
+        '#type' => 'textfield',
+        '#maxlength' => 1024,
+        '#default_value' => implode(', ', $entity_labels),
+        '#autocomplete_path' => $autocomplete_path,
+        '#size' => $instance['widget']['settings']['size'],
+        '#element_validate' => array('_entityreference_autocomplete_tags_validate'),
+      );
+      return $element;
+    }
+  }
+}
+
+function _entityreference_autocomplete_validate($element, &$form_state, $form) {
+  // If a value was entered into the autocomplete...
+  $value = '';
+  if (!empty($element['#value'])) {
+    // Take "label (entity id)', match the id from parenthesis.
+    if (preg_match("/.+\((\d+)\)/", $element['#value'], $matches)) {
+      $value = $matches[1];
+    } else {
+      // Try to get a match from the input string when the user didn't use the
+      // autocomplete but filled in a value manually.
+      $field = field_info_field($element['#field_name']);
+      $handler = entityreference_get_selection_handler($field);
+      $value = $handler->validateAutocompleteInput($element['#value'], $element, $form_state, $form);
+    }
+  }
+  // Update the value of this element so the field can validate the product IDs.
+  form_set_value($element, $value, $form_state);
+}
+
+function _entityreference_autocomplete_tags_validate($element, &$form_state, $form) {
+  $value = array();
+  // If a value was entered into the autocomplete...
+  if (!empty($element['#value'])) {
+    $entities = drupal_explode_tags($element['#value']);
+    $value = array();
+    foreach ($entities as $entity) {
+      // Take "label (entity id)', match the id from parenthesis.
+      if (preg_match("/.+\((\d+)\)/", $entity, $matches)) {
+        $value[] = array(
+          'target_id' => $matches[1],
+        );
+      } else {
+        // Try to get a match from the input string when the user didn't use the
+        // autocomplete but filled in a value manually.
+        $field = field_info_field($element['#field_name']);
+        $handler = entityreference_get_selection_handler($field);
+        $value[] = array(
+          'target_id' => $handler->validateAutocompleteInput($entity, $element, $form_state, $form),
+        );
+      }
+    }
+  }
+  // Update the value of this element so the field can validate the product IDs.
+  form_set_value($element, $value, $form_state);
+}
+
+/**
+ * Implements hook_field_widget_error().
+ */
+function entityreference_field_widget_error($element, $error) {
+  form_error($element, $error['message']);
+}
+
+/**
+ * Menu callback: autocomplete the label of an entity.
+ *
+ * @param $type
+ *   The widget type (i.e. 'single' or 'tags').
+ * @param $field_name
+ *   The name of the entity-reference field.
+ * @param $entity_type
+ *   The entity type.
+ * @param $bundle_name
+ *   The bundle name.
+ * @param $entity_id
+ *   Optional; The entity ID the entity-reference field is attached to.
+ *   Defaults to ''.
+ * @param $string
+ *   The label of the entity to query by.
+ */
+function entityreference_autocomplete_callback($type, $field_name, $entity_type, $bundle_name, $entity_id = '', $string = '') {
+  $field = field_info_field($field_name);
+  $instance = field_info_instance($entity_type, $field_name, $bundle_name);
+  $matches = array();
+
+  if (!$field || !$instance || $field['type'] != 'entityreference' || !field_access('edit', $field, $entity_type)) {
+    return MENU_ACCESS_DENIED;
+  }
+
+  $entity = $entity_id !== '' ? entity_load_single($entity_type, $entity_id) : NULL;
+  $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
+
+  if ($type == 'tags') {
+    // The user enters a comma-separated list of tags. We only autocomplete the last tag.
+    $tags_typed = drupal_explode_tags($string);
+    $tag_last = drupal_strtolower(array_pop($tags_typed));
+    if (!empty($tag_last)) {
+      $prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : '';
+    }
+  }
+  else {
+    // The user enters a single tag.
+    $prefix = '';
+    $tag_last = $string;
+  }
+
+  if (!empty($tag_last)) {
+    // Get an array of matching entities.
+    $entity_labels = $handler->getReferencableEntities($tag_last, $instance['widget']['settings']['match_operator'], 10);
+
+    // Loop through the products and convert them into autocomplete output.
+    foreach ($entity_labels as $entity_id => $label) {
+      $key = "$label ($entity_id)";
+      // Strip things like starting/trailing white spaces, line breaks and tags.
+      $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(decode_entities(strip_tags($key)))));
+      // Names containing commas or quotes must be wrapped in quotes.
+      if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
+        $key = '"' . str_replace('"', '""', $key) . '"';
+      }
+      $matches[$prefix . $key] = '<div class="reference-autocomplete">' . $label . '</div>';
+    }
+  }
+
+  drupal_json_output($matches);
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function entityreference_field_formatter_info() {
+  return array(
+    'entityreference_label' => array(
+      'label' => t('Label'),
+      'description' => t('Display the label of the referenced entities.'),
+      'field types' => array('entityreference'),
+      'settings' => array(
+        'link' => FALSE,
+      ),
+    ),
+    'entityreference_entity_id' => array(
+      'label' => t('Entity id'),
+      'description' => t('Display the id of the referenced entities.'),
+      'field types' => array('entityreference'),
+    ),
+    'entityreference_entity_view' => array(
+      'label' => t('Rendered entity'),
+      'description' => t('Display the referenced entities rendered by entity_view().'),
+      'field types' => array('entityreference'),
+      'settings' => array(
+        'view_mode' => '',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function entityreference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  if ($display['type'] == 'entityreference_label') {
+    $element['link'] = array(
+      '#title' => t('Link label to the referenced entity'),
+      '#type' => 'checkbox',
+      '#default_value' => $settings['link'],
+    );
+  }
+
+  if ($display['type'] == 'entityreference_entity_view') {
+    $entity_info = entity_get_info($field['settings']['target_type']);
+    $options = array();
+    if (!empty($entity_info['view modes'])) {
+      foreach ($entity_info['view modes'] as $view_mode => $view_mode_settings) {
+        $options[$view_mode] = $view_mode_settings['label'];
+      }
+    }
+
+    if (count($options) > 1) {
+      $element['view_mode'] = array(
+        '#type' => 'select',
+        '#options' => $options,
+        '#title' => t('View mode'),
+        '#default_value' => $settings['view_mode'],
+      );
+    }
+  }
+
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function entityreference_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $summary = array();
+
+  if ($display['type'] == 'entityreference_label') {
+    $summary[] = $settings['link'] ? t('Link to the referenced entity') : t('No link');
+  }
+
+  if ($display['type'] == 'entityreference_entity_view') {
+    $entity_info = entity_get_info($field['settings']['target_type']);
+    $summary[] = t('Rendered as @mode', array('@mode' => isset($entity_info['view modes'][$settings['view_mode']]['label']) ? $entity_info['view modes'][$settings['view_mode']]['label'] : $settings['view_mode']));
+  }
+
+  return implode('<br />', $summary);
+}
+
+/**
+ * Implements hook_field_formatter_prepare_view().
+ */
+function entityreference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
+  $target_ids = array();
+
+  // Collect every possible entity attached to any of the entities.
+  foreach ($entities as $id => $entity) {
+    foreach ($items[$id] as $delta => $item) {
+      if (isset($item['target_id'])) {
+        $target_ids[] = $item['target_id'];
+      }
+    }
+  }
+
+  if ($target_ids) {
+    $target_entities = entity_load($field['settings']['target_type'], $target_ids);
+  }
+  else {
+    $target_entities = array();
+  }
+
+  // Iterate through the fieldable entities again to attach the loaded data.
+  foreach ($entities as $id => $entity) {
+    $rekey = FALSE;
+
+    foreach ($items[$id] as $delta => $item) {
+      // Check whether the referenced entity could be loaded and that the user has access to it.
+      if (isset($target_entities[$item['target_id']]) && entity_access('view', $field['settings']['target_type'], $target_entities[$item['target_id']])) {
+        // Replace the instance value with the term data.
+        $items[$id][$delta]['entity'] = $target_entities[$item['target_id']];
+      }
+      // Otherwise, unset the instance value, since the entity does not exists or should not be accessible.
+      else {
+        unset($items[$id][$delta]);
+        $rekey = TRUE;
+      }
+    }
+
+    if ($rekey) {
+      // Rekey the items array.
+      $items[$id] = array_values($items[$id]);
+    }
+  }
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function entityreference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $result = array();
+
+  switch ($display['type']) {
+    case 'entityreference_label':
+      $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
+
+      foreach ($items as $delta => $item) {
+        $label = $handler->getLabel($item['entity']);
+        // If the link is to be displayed and the entity has a uri, display a link.
+        // Note the assignment ($url = ) here is intended to be an assignment.
+        if ($display['settings']['link'] && ($uri = entity_uri($field['settings']['target_type'], $item['entity']))) {
+          $result[$delta] = array('#markup' => l($label, $uri['path'], $uri['options']));
+        }
+        else {
+          $result[$delta] = array('#markup' => check_plain($label));
+        }
+      }
+      break;
+
+    case 'entityreference_entity_id':
+      foreach ($items as $delta => $item) {
+        $result[$delta] = array('#markup' => check_plain($item['target_id']));
+      }
+      break;
+
+    case 'entityreference_entity_view':
+      foreach ($items as $delta => $item) {
+        // Protect ourselves from recursive rendering.
+        static $depth = 0;
+        $depth++;
+        if ($depth > 20) {
+          throw new EntityReferenceRecursiveRenderingException(t('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $entity_type, '@entity_id' => $item['target_id'])));
+        }
+
+        $entity = clone $item['entity'];
+        unset($entity->content);
+        $result[$delta] = entity_view($field['settings']['target_type'], array($item['target_id'] => $entity), $display['settings']['view_mode'], $langcode, FALSE);
+        $depth = 0;
+      }
+      break;
+  }
+
+  return $result;
+}
+
+/**
+ * Exception thrown when the entity view renderer goes into a potentially infinite loop.
+ */
+class EntityReferenceRecursiveRenderingException extends Exception {}
+
+/**
+ * Implements hook_views_api().
+ */
+function entityreference_views_api() {
+  return array(
+    'api' => 3,
+    'path' => drupal_get_path('module', 'entityreference') . '/views',
+  );
+}
diff --git a/sites/all/modules/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info b/sites/all/modules/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info
new file mode 100644
index 0000000000000000000000000000000000000000..516c54255d4f879ffbb7b5f5e117518aadb37ddf
--- /dev/null
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info
@@ -0,0 +1,12 @@
+name = Entity Reference Behavior Example
+description = Provides some example code for implementing Entity Reference behaviors.
+core = 7.x
+package = Fields
+dependencies[] = entityreference
+
+; Information added by drupal.org packaging script on 2012-05-30
+version = "7.x-1.0-rc3"
+core = "7.x"
+project = "entityreference"
+datestamp = "1338411955"
+
diff --git a/sites/all/modules/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.module b/sites/all/modules/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.module
new file mode 100644
index 0000000000000000000000000000000000000000..9d6c6f8fb93f11c90f2fdc2cacea86feddae9f3c
--- /dev/null
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.module
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Example module to demonstrate Entity reference behavior handlers.
+ */
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function entityreference_behavior_example_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'entityreference') {
+    return 'plugins/' . $plugin;
+  }
+}
diff --git a/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/EntityReferenceFieldBehaviorExample.class.php b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/EntityReferenceFieldBehaviorExample.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..416104302a1832f54a7d9ad3ca668b2fa670ce43
--- /dev/null
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/EntityReferenceFieldBehaviorExample.class.php
@@ -0,0 +1,31 @@
+<?php
+
+class EntityReferenceFieldBehaviorExample extends EntityReference_BehaviorHandler_Abstract {
+
+  public function load($entity_type, $entities, $field, $instances, $langcode, &$items) {
+    drupal_set_message('Do something on load!');
+  }
+
+  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message('Do something on insert!');
+  }
+
+  public function update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message('Do something on update!');
+  }
+
+  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message('Do something on delete!');
+  }
+
+  /**
+   * Generate a settings form for this handler.
+   */
+  public function settingsForm($field, $instance) {
+    $form['test_field'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Field behavior setting'),
+    );
+    return $form;
+  }
+}
diff --git a/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/EntityReferenceInstanceBehaviorExample.class.php b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/EntityReferenceInstanceBehaviorExample.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..6e6f3291820b74d623c43d4feed970a3bff8281e
--- /dev/null
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/EntityReferenceInstanceBehaviorExample.class.php
@@ -0,0 +1,31 @@
+<?php
+
+class EntityReferenceInstanceBehaviorExample extends EntityReference_BehaviorHandler_Abstract {
+
+  public function load($entity_type, $entities, $field, $instances, $langcode, &$items) {
+    drupal_set_message('Do something on load, on the instance level!');
+  }
+
+  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message('Do something on insert, on the instance level!');
+  }
+
+  public function update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message('Do something on update, on the instance level!');
+  }
+
+  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message('Do something on delete, on the instance level!');
+  }
+
+  /**
+   * Generate a settings form for this handler.
+   */
+  public function settingsForm($field, $instance) {
+    $form['test_instance'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Instance behavior setting'),
+    );
+    return $form;
+  }
+}
\ No newline at end of file
diff --git a/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/test_field_behavior.inc b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/test_field_behavior.inc
new file mode 100644
index 0000000000000000000000000000000000000000..590087bcbe3d9be41ec5afd57f70fb2272b4a653
--- /dev/null
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/test_field_behavior.inc
@@ -0,0 +1,8 @@
+<?php
+
+$plugin = array(
+  'title' => t('Test behavior'),
+  'class' => 'EntityReferenceFieldBehaviorExample',
+  'weight' => 10,
+  'behavior type' => 'field',
+);
diff --git a/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/test_instance_behavior.inc b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/test_instance_behavior.inc
new file mode 100644
index 0000000000000000000000000000000000000000..41173fea308c9ac3fb20d2be123ba408b68259ec
--- /dev/null
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/test_instance_behavior.inc
@@ -0,0 +1,8 @@
+<?php
+
+$plugin = array(
+  'title' => t('Test instance behavior'),
+  'class' => 'EntityReferenceInstanceBehaviorExample',
+  'weight' => 10,
+  'behavior type' => 'instance',
+);
diff --git a/sites/all/modules/entityreference/plugins/behavior/EntityReferenceBehavior_ViewsFilterSelect.class.php b/sites/all/modules/entityreference/plugins/behavior/EntityReferenceBehavior_ViewsFilterSelect.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..de3187cb0fbfd552478cf43f4a09dcc9db3b6e23
--- /dev/null
+++ b/sites/all/modules/entityreference/plugins/behavior/EntityReferenceBehavior_ViewsFilterSelect.class.php
@@ -0,0 +1,18 @@
+<?php
+
+class EntityReferenceBehavior_ViewsFilterSelect extends EntityReference_BehaviorHandler_Abstract {
+
+  public function views_data_alter(&$data, $field) {
+    $entity_info = entity_get_info($field['settings']['target_type']);
+    $field_name = $field['field_name'] . '_target_id';
+    foreach ($data as $table_name => &$table_data) {
+      if (isset($table_data[$field_name])) {
+        // Set the entity id filter to use the in_operator handler with our
+        // own callback to return the values.
+        $table_data[$field_name]['filter']['handler'] = 'views_handler_filter_in_operator';
+        $table_data[$field_name]['filter']['options callback'] = 'entityreference_views_handler_options_list';
+        $table_data[$field_name]['filter']['options arguments'] = array($field['field_name']);
+      }
+    }
+  }
+}
diff --git a/sites/all/modules/entityreference/plugins/behavior/abstract.inc b/sites/all/modules/entityreference/plugins/behavior/abstract.inc
new file mode 100644
index 0000000000000000000000000000000000000000..43b2b362722a0691f5278419e68019b67943e778
--- /dev/null
+++ b/sites/all/modules/entityreference/plugins/behavior/abstract.inc
@@ -0,0 +1,187 @@
+<?php
+
+/**
+ * Additional behaviors for a Entity Reference field.
+ *
+ * Implementations that wish to provide an implementation of this should
+ * register it using CTools' plugin system.
+ */
+interface EntityReference_BehaviorHandler {
+
+  /**
+   * Constructor for the behavior.
+   *
+   * @param $behavior
+   *   The name of the behavior plugin.
+   */
+  public function __construct($behavior);
+
+  /**
+   * Alter the field schema.
+   *
+   * @see hook_field_schema()
+   */
+  public function schema_alter(&$schema, $field);
+
+  /**
+   * Alter the properties information of a field instance.
+   *
+   * @see entity_hook_field_info()
+   */
+  public function property_info_alter(&$info, $entity_type, $field, $instance, $field_type);
+
+  /**
+   * Alter the views data of a field.
+   *
+   * @see entityreference_field_views_data()
+   */
+  public function views_data_alter(&$data, $field);
+
+  /**
+   * Act on loading entity reference fields of entities.
+   *
+   * @see hook_field_load()
+   */
+  public function load($entity_type, $entities, $field, $instances, $langcode, &$items);
+
+  /**
+   * Alter the empty status of a field item.
+   *
+   * @see hook_field_is_empty()
+   */
+  public function is_empty_alter(&$empty, $item, $field);
+
+  /**
+   * Act on validating an entity reference field.
+   *
+   * @see hook_field_validate()
+   */
+  public function validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors);
+
+  /**
+   * Act on presaving an entity reference field.
+   *
+   * @see hook_field_presave()
+   */
+  public function presave($entity_type, $entity, $field, $instance, $langcode, &$items);
+
+  /**
+   * Act before inserting an entity reference field.
+   *
+   * @see hook_field_insert()
+   */
+  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items);
+
+  /**
+   * Act after inserting an entity reference field.
+   *
+   * @see hook_field_attach_insert()
+   */
+  public function postInsert($entity_type, $entity, $field, $instance);
+
+  /**
+   * Act before updating an entity reference field.
+   *
+   * @see hook_field_update()
+   */
+  public function update($entity_type, $entity, $field, $instance, $langcode, &$items);
+
+  /**
+   * Act after updating an entity reference field.
+   *
+   * @see hook_field_attach_update()
+   */
+  public function postUpdate($entity_type, $entity, $field, $instance);
+
+  /**
+   * Act before deleting an entity with an entity reference field.
+   *
+   * @see hook_field_delete()
+   */
+  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items);
+
+  /**
+   * Act after deleting an entity with an entity reference field.
+   *
+   * @see hook_field_attach_delete()
+   */
+  public function postDelete($entity_type, $entity, $field, $instance);
+
+  /**
+   * Generate a settings form for this handler.
+   */
+  public function settingsForm($field, $instance);
+
+  /**
+   * Determine if handler should appear.
+   */
+  public function access($field, $instance);
+}
+
+/**
+ * An abstract implementation of EntityReference_BehaviorHandler.
+ */
+abstract class EntityReference_BehaviorHandler_Abstract implements EntityReference_BehaviorHandler {
+
+  /**
+   * The name of the behavior plugin.
+   */
+  protected $behavior;
+
+  /**
+   * The plugin definition.
+   */
+  protected $plugin;
+
+  public function __construct($behavior) {
+    $this->behavior = $behavior;
+
+    ctools_include('plugins');
+    $plugin = ctools_get_plugins('entityreference', 'behavior', $behavior);
+    $this->plugin = $plugin;
+  }
+
+  public function schema_alter(&$schema, $field) {}
+
+  public function property_info_alter(&$info, $entity_type, $field, $instance, $field_type) {}
+
+  public function views_data_alter(&$data, $field) {}
+
+  public function load($entity_type, $entities, $field, $instances, $langcode, &$items) {}
+
+  public function is_empty_alter(&$empty, $item, $field) {}
+
+  public function validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {}
+
+  public function presave($entity_type, $entity, $field, $instance, $langcode, &$items) {}
+
+  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items) {}
+
+  public function postInsert($entity_type, $entity, $field, $instance) {}
+
+  public function update($entity_type, $entity, $field, $instance, $langcode, &$items) {}
+
+  public function postUpdate($entity_type, $entity, $field, $instance) {}
+
+  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items) {}
+
+  public function postDelete($entity_type, $entity, $field, $instance) {}
+
+  public function settingsForm($field, $instance) {}
+
+  public function access($field, $instance) {
+    return TRUE;
+  }
+}
+
+/**
+ * A broken implementation of EntityReference_BehaviorHandler.
+ */
+class EntityReference_BehaviorHandler_Broken extends EntityReference_BehaviorHandler_Abstract {
+  public function settingsForm($field, $instance) {
+    $form['behavior_handler'] = array(
+      '#markup' => t('The selected behavior handler is broken.'),
+    );
+    return $form;
+  }
+}
diff --git a/sites/all/modules/entityreference/plugins/behavior/views-select-list.inc b/sites/all/modules/entityreference/plugins/behavior/views-select-list.inc
new file mode 100644
index 0000000000000000000000000000000000000000..f1ffd35983391070c6a03eccaef628003cb7254a
--- /dev/null
+++ b/sites/all/modules/entityreference/plugins/behavior/views-select-list.inc
@@ -0,0 +1,10 @@
+<?php
+
+if (module_exists('views')) {
+  $plugin = array(
+    'title' => t('Render Views filters as select list'),
+    'description' => t('Provides a select list for Views filters on this field. This should not be used when there are over 100 entities, as it might cause an out of memory error.'),
+    'class' => 'EntityReferenceBehavior_ViewsFilterSelect',
+    'behavior type' => 'field',
+  );
+}
diff --git a/sites/all/modules/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php b/sites/all/modules/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..7db4045402abcbb2c9f842869f3084fac02f505e
--- /dev/null
+++ b/sites/all/modules/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php
@@ -0,0 +1,464 @@
+<?php
+
+/**
+ * A generic Entity handler.
+ *
+ * The generic base implementation has a variety of overrides to workaround
+ * core's largely deficient entity handling.
+ */
+class EntityReference_SelectionHandler_Generic implements EntityReference_SelectionHandler {
+
+  /**
+   * Implements EntityReferenceHandler::getInstance().
+   */
+  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+    $target_entity_type = $field['settings']['target_type'];
+
+    // Check if the entity type does exist and has a base table.
+    $entity_info = entity_get_info($target_entity_type);
+    if (empty($entity_info['base table'])) {
+      return EntityReference_SelectionHandler_Broken::getInstance($field, $instance);
+    }
+
+    if (class_exists($class_name = 'EntityReference_SelectionHandler_Generic_' . $target_entity_type)) {
+      return new $class_name($field, $instance, $entity_type, $entity);
+    }
+    else {
+      return new EntityReference_SelectionHandler_Generic($field, $instance, $entity_type, $entity);
+    }
+  }
+
+  protected function __construct($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+    $this->field = $field;
+    $this->instance = $instance;
+    $this->entity_type = $entity_type;
+    $this->entity = $entity;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::settingsForm().
+   */
+  public static function settingsForm($field, $instance) {
+    $entity_info = entity_get_info($field['settings']['target_type']);
+
+    if (!empty($entity_info['entity keys']['bundle'])) {
+      $bundles = array();
+      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+        $bundles[$bundle_name] = $bundle_info['label'];
+      }
+
+      $form['target_bundles'] = array(
+        '#type' => 'select',
+        '#title' => t('Target bundles'),
+        '#options' => $bundles,
+        '#default_value' => isset($field['settings']['handler_settings']['target_bundles']) ? $field['settings']['handler_settings']['target_bundles'] : array(),
+        '#size' => 6,
+        '#multiple' => TRUE,
+        '#description' => t('The bundles of the entity type that can be referenced. Optional, leave empty for all bundles.')
+      );
+    }
+    else {
+      $form['target_bundles'] = array(
+        '#type' => 'value',
+        '#value' => array(),
+      );
+    }
+
+    $form['sort']['type'] = array(
+      '#type' => 'radios',
+      '#title' => t('Sort by'),
+      '#options' => array(
+        'none' => t("Don't sort"),
+        'property' => t('A property of the base table of the entity'),
+        'field' => t('A field attached to this entity'),
+      ),
+      '#default_value' => isset($field['settings']['handler_settings']['sort']['type']) ? $field['settings']['handler_settings']['sort']['type'] : 'none',
+    );
+
+    $form['sort']['property'] = array(
+      '#type' => 'select',
+      '#title' => t('Sort property'),
+      '#options' => drupal_map_assoc($entity_info['schema_fields_sql']['base table']),
+      '#default_value' => isset($field['settings']['handler_settings']['sort']['property']) ? $field['settings']['handler_settings']['sort']['property'] : '',
+      '#states' => array(
+        'visible' => array(
+          ':input[name="field[settings][handler_settings][sort][type]"]' => array('value' => 'property'),
+        ),
+      ),
+    );
+
+    $fields = array();
+    foreach (field_info_instances($field['settings']['target_type']) as $bundle_name => $bundle_instances) {
+      foreach ($bundle_instances as $instance_name => $instance_info) {
+        $field_info = field_info_field($instance_name);
+        foreach ($field_info['columns'] as $column_name => $column_info) {
+          $fields[$instance_name . ':' . $column_name] = t('@label (column @column)', array('@label' => $instance_info['label'], '@column' => $column_name));
+        }
+      }
+    }
+
+    $form['sort']['field'] = array(
+      '#type' => 'select',
+      '#title' => t('Sort field'),
+      '#options' => $fields,
+      '#default_value' => isset($field['settings']['handler_settings']['sort']['type']) ? $field['settings']['handler_settings']['sort']['type'] : '',
+      '#states' => array(
+        'visible' => array(
+          ':input[name="field[settings][handler_settings][sort][type]"]' => array('value' => 'field'),
+        ),
+      ),
+    );
+
+    $form['sort']['direction'] = array(
+      '#type' => 'select',
+      '#title' => t('Sort direction'),
+      '#options' => array(
+        'ASC' => t('Ascending'),
+        'DESC' => t('Descending'),
+      ),
+      '#default_value' => isset($field['settings']['handler_settings']['sort']['direction']) ? $field['settings']['handler_settings']['sort']['direction'] : 'ASC',
+      '#states' => array(
+        'invisible' => array(
+          ':input[name="field[settings][handler_settings][sort][type]"]' => array('value' => 'none'),
+        ),
+      ),
+    );
+
+    return $form;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::getReferencableEntities().
+   */
+  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
+    $options = array();
+    $entity_type = $this->field['settings']['target_type'];
+
+    $query = $this->buildEntityFieldQuery($match, $match_operator);
+    if ($limit > 0) {
+      $query->range(0, $limit);
+    }
+
+    $results = $query->execute();
+
+    if (!empty($results[$entity_type])) {
+      $entities = entity_load($entity_type, array_keys($results[$entity_type]));
+      foreach ($entities as $entity_id => $entity) {
+        $options[$entity_id] = check_plain($this->getLabel($entity));
+      }
+    }
+
+    return $options;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::countReferencableEntities().
+   */
+  public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') {
+    $query = $this->buildEntityFieldQuery($match, $match_operator);
+    return $query
+      ->count()
+      ->execute();
+  }
+
+  /**
+   * Implements EntityReferenceHandler::validateReferencableEntities().
+   */
+  public function validateReferencableEntities(array $ids) {
+    if ($ids) {
+      $entity_type = $this->field['settings']['target_type'];
+      $query = $this->buildEntityFieldQuery();
+      $query->entityCondition('entity_id', $ids, 'IN');
+      $result = $query->execute();
+      if (!empty($result[$entity_type])) {
+        return array_keys($result[$entity_type]);
+      }
+    }
+
+    return array();
+  }
+
+  /**
+   * Implements EntityReferenceHandler::validateAutocompleteInput().
+   */
+  public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
+      $entities = $this->getReferencableEntities($input, '=', 6);
+      if (empty($entities)) {
+        // Error if there are no entities available for a required field.
+        form_error($element, t('There are no entities matching "%value"', array('%value' => $input)));
+      }
+      elseif (count($entities) > 5) {
+        // Error if there are more than 5 matching entities.
+        form_error($element, t('Many entities are called %value. Specify the one you want by appending the id in parentheses, like "@value (@id)"', array(
+          '%value' => $input,
+          '@value' => $input,
+          '@id' => key($entities),
+        )));
+      }
+      elseif (count($entities) > 1) {
+        // More helpful error if there are only a few matching entities.
+        $multiples = array();
+        foreach ($entities as $id => $name) {
+          $multiples[] = $name . ' (' . $id . ')';
+        }
+        form_error($element, t('Multiple entities match this reference; "%multiple"', array('%multiple' => implode('", "', $multiples))));
+      }
+      else {
+        // Take the one and only matching entity.
+        return key($entities);
+      }
+  }
+
+  /**
+   * Build an EntityFieldQuery to get referencable entities.
+   */
+  protected function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $this->field['settings']['target_type']);
+    if (!empty($this->field['settings']['handler_settings']['target_bundles'])) {
+      $query->entityCondition('bundle', $this->field['settings']['handler_settings']['target_bundles'], 'IN');
+    }
+    if (isset($match)) {
+      $entity_info = entity_get_info($this->field['settings']['target_type']);
+      if (isset($entity_info['entity keys']['label'])) {
+        $query->propertyCondition($entity_info['entity keys']['label'], $match, $match_operator);
+      }
+    }
+
+    // Add a generic entity access tag to the query.
+    $query->addTag($this->field['settings']['target_type'] . '_access');
+    $query->addTag('entityreference');
+    $query->addMetaData('field', $this->field);
+    $query->addMetaData('entityreference_selection_handler', $this);
+
+    // Add the sort option.
+    if (!empty($this->field['settings']['handler_settings']['sort'])) {
+      $sort_settings = $this->field['settings']['handler_settings']['sort'];
+      if ($sort_settings['type'] == 'property') {
+        $query->propertyOrderBy($sort_settings['property'], $sort_settings['direction']);
+      }
+      elseif ($sort_settings['type'] == 'field') {
+        list($field, $column) = explode(':', $sort_settings['field'], 2);
+        $query->fieldOrderBy($field, $column, $sort_settings['direction']);
+      }
+    }
+
+    return $query;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::entityFieldQueryAlter().
+   */
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+
+  }
+
+  /**
+   * Helper method: pass a query to the alteration system again.
+   *
+   * This allow Entity Reference to add a tag to an existing query, to ask
+   * access control mechanisms to alter it again.
+   */
+  protected function reAlterQuery(SelectQueryInterface $query, $tag, $base_table) {
+    // Save the old tags and metadata.
+    // For some reason, those are public.
+    $old_tags = $query->alterTags;
+    $old_metadata = $query->alterMetaData;
+
+    $query->alterTags = array($tag => TRUE);
+    $query->alterMetaData['base_table'] = $base_table;
+    drupal_alter(array('query', 'query_' . $tag), $query);
+
+    // Restore the tags and metadata.
+    $query->alterTags = $old_tags;
+    $query->alterMetaData = $old_metadata;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::getLabel().
+   */
+  public function getLabel($entity) {
+    return entity_label($this->field['settings']['target_type'], $entity);
+  }
+}
+
+/**
+ * Override for the Node type.
+ *
+ * This only exists to workaround core bugs.
+ */
+class EntityReference_SelectionHandler_Generic_node extends EntityReference_SelectionHandler_Generic {
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    // Adding the 'node_access' tag is sadly insufficient for nodes: core
+    // requires us to also know about the concept of 'published' and
+    // 'unpublished'. We need to do that as long as there are no access control
+    // modules in use on the site. As long as one access control module is there,
+    // it is supposed to handle this check.
+    if (!user_access('bypass node access') && !count(module_implements('node_grants'))) {
+      $tables = $query->getTables();
+      $query->condition(key($tables) . '.status', NODE_PUBLISHED);
+    }
+  }
+}
+
+/**
+ * Override for the User type.
+ *
+ * This only exists to workaround core bugs.
+ */
+class EntityReference_SelectionHandler_Generic_user extends EntityReference_SelectionHandler_Generic {
+  public function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
+    $query = parent::buildEntityFieldQuery($match, $match_operator);
+
+    // The user entity doesn't have a label column.
+    if (isset($match)) {
+      $query->propertyCondition('name', $match, $match_operator);
+    }
+
+    // Adding the 'user_access' tag is sadly insufficient for users: core
+    // requires us to also know about the concept of 'blocked' and
+    // 'active'.
+    if (!user_access('administer users')) {
+      $query->propertyCondition('status', 1);
+    }
+    return $query;
+  }
+
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    if (user_access('administer users')) {
+      // In addition, if the user is administrator, we need to make sure to
+      // match the anonymous user, that doesn't actually have a name in the
+      // database.
+      $conditions = &$query->conditions();
+      foreach ($conditions as $key => $condition) {
+        if ($condition['field'] == 'users.name') {
+          // Remove the condition.
+          unset($conditions[$key]);
+
+          // Re-add the condition and a condition on uid = 0 so that we end up
+          // with a query in the form:
+          //    WHERE (name LIKE :name) OR (:anonymous_name LIKE :name AND uid = 0)
+          $or = db_or();
+          $or->condition($condition['field'], $condition['value'], $condition['operator']);
+          // Sadly, the Database layer doesn't allow us to build a condition
+          // in the form ':placeholder = :placeholder2', because the 'field'
+          // part of a condition is always escaped.
+          // As a (cheap) workaround, we separately build a condition with no
+          // field, and concatenate the field and the condition separately.
+          $value_part = db_and();
+          $value_part->condition('anonymous_name', $condition['value'], $condition['operator']);
+          $value_part->compile(Database::getConnection(), $query);
+          $or->condition(db_and()
+            ->where(str_replace('anonymous_name', ':anonymous_name', (string) $value_part), $value_part->arguments() + array(':anonymous_name' => format_username(user_load(0))))
+            ->condition('users.uid', 0)
+          );
+          $query->condition($or);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Override for the Comment type.
+ *
+ * This only exists to workaround core bugs.
+ */
+class EntityReference_SelectionHandler_Generic_comment extends EntityReference_SelectionHandler_Generic {
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    // Adding the 'comment_access' tag is sadly insufficient for comments: core
+    // requires us to also know about the concept of 'published' and
+    // 'unpublished'.
+    if (!user_access('administer comments')) {
+      $tables = $query->getTables();
+      $query->condition(key($tables) . '.status', COMMENT_PUBLISHED);
+    }
+
+    // The Comment module doesn't implement any proper comment access,
+    // and as a consequence doesn't make sure that comments cannot be viewed
+    // when the user doesn't have access to the node.
+    $tables = $query->getTables();
+    $base_table = key($tables);
+    $node_alias = $query->innerJoin('node', 'n', '%alias.nid = ' . $base_table . '.nid');
+    // Pass the query to the node access control.
+    $this->reAlterQuery($query, 'node_access', $node_alias);
+
+    // Alas, the comment entity exposes a bundle, but doesn't have a bundle column
+    // in the database. We have to alter the query ourself to go fetch the
+    // bundle.
+    $conditions = &$query->conditions();
+    foreach ($conditions as $id => &$condition) {
+      if (is_array($condition) && $condition['field'] == 'node_type') {
+        $condition['field'] = $node_alias . '.type';
+        foreach ($condition['value'] as &$value) {
+          if (substr($value, 0, 13) == 'comment_node_') {
+            $value = substr($value, 13);
+          }
+        }
+        break;
+      }
+    }
+
+    // Passing the query to node_query_node_access_alter() is sadly
+    // insufficient for nodes.
+    // @see EntityReferenceHandler_node::entityFieldQueryAlter()
+    if (!user_access('bypass node access') && !count(module_implements('node_grants'))) {
+      $query->condition($node_alias . '.status', 1);
+    }
+  }
+}
+
+/**
+ * Override for the File type.
+ *
+ * This only exists to workaround core bugs.
+ */
+class EntityReference_SelectionHandler_Generic_file extends EntityReference_SelectionHandler_Generic {
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    // Core forces us to know about 'permanent' vs. 'temporary' files.
+    $tables = $query->getTables();
+    $base_table = key($tables);
+    $query->condition('status', FILE_STATUS_PERMANENT);
+
+    // Access control to files is a very difficult business. For now, we are not
+    // going to give it a shot.
+    // @todo: fix this when core access control is less insane.
+    return $query;
+  }
+
+  public function getLabel($entity) {
+    // The file entity doesn't have a label. More over, the filename is
+    // sometimes empty, so use the basename in that case.
+    return $entity->filename !== '' ? $entity->filename : basename($entity->uri);
+  }
+}
+
+/**
+ * Override for the Taxonomy term type.
+ *
+ * This only exists to workaround core bugs.
+ */
+class EntityReference_SelectionHandler_Generic_taxonomy_term extends EntityReference_SelectionHandler_Generic {
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    // The Taxonomy module doesn't implement any proper taxonomy term access,
+    // and as a consequence doesn't make sure that taxonomy terms cannot be viewed
+    // when the user doesn't have access to the vocabulary.
+    $tables = $query->getTables();
+    $base_table = key($tables);
+    $vocabulary_alias = $query->innerJoin('taxonomy_vocabulary', 'n', '%alias.vid = ' . $base_table . '.vid');
+    $query->addMetadata('base_table', $vocabulary_alias);
+    // Pass the query to the taxonomy access control.
+    $this->reAlterQuery($query, 'taxonomy_vocabulary_access', $vocabulary_alias);
+
+    // Also, the taxonomy term entity exposes a bundle, but doesn't have a bundle
+    // column in the database. We have to alter the query ourself to go fetch
+    // the bundle.
+    $conditions = &$query->conditions();
+    foreach ($conditions as $id => &$condition) {
+      if (is_array($condition) && $condition['field'] == 'vocabulary_machine_name') {
+        $condition['field'] = $vocabulary_alias . '.machine_name';
+        break;
+      }
+    }
+  }
+}
diff --git a/sites/all/modules/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php b/sites/all/modules/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..e3f87f099b2cff851891374196b8549b41e2c77c
--- /dev/null
+++ b/sites/all/modules/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php
@@ -0,0 +1,176 @@
+<?php
+
+/**
+ * Entity handler for Views.
+ */
+class EntityReference_SelectionHandler_Views implements EntityReference_SelectionHandler {
+
+  /**
+   * Implements EntityReferenceHandler::getInstance().
+   */
+  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+    return new EntityReference_SelectionHandler_Views($field, $instance);
+  }
+
+  protected function __construct($field, $instance) {
+    $this->field = $field;
+    $this->instance = $instance;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::settingsForm().
+   */
+  public static function settingsForm($field, $instance) {
+    $view_settings = empty($field['settings']['handler_settings']['view']) ? '' : $field['settings']['handler_settings']['view'];
+    $displays = views_get_applicable_views('entityreference display');
+    // Filter views that list the entity type we want, and group the separate
+    // displays by view.
+    $entity_info = entity_get_info($field['settings']['target_type']);
+    $options = array();
+    foreach ($displays as $data) {
+      list($view, $display_id) = $data;
+      if ($view->base_table == $entity_info['base table']) {
+        $options[$view->name . ':' . $display_id] = $view->name .' - ' . $view->display[$display_id]->display_title;
+      }
+    }
+
+    if ($options) {
+      // The value of the 'view_and_display' select below will need to be split
+      // into 'view_name' and 'view_display' in the final submitted values, so
+      // we massage the data at validate time on the wrapping element (not
+      // ideal).
+      $form['view']['#element_validate'] = array('entityreference_view_settings_validate');
+
+      $options = array('' => '<' . t('none') . '>') + $options;
+      $default = !empty($view_settings['view_name']) ? $view_settings['view_name'] . ':' .$view_settings['display_name'] : '';
+      $form['view']['view_and_display'] = array(
+        '#type' => 'select',
+        '#title' => t('View used to select the entities'),
+        '#options' => $options,
+        '#default_value' => $default,
+        '#description' => '<p>' . t('Choose the view and display that select the entities that can be referenced.<br />Only views with a display of type "Entity Reference" are eligible.') . '</p>',
+      );
+
+      $default = !empty($view_settings['args']) ? implode(', ', $view_settings['args']) : '';
+      $form['view']['args'] = array(
+        '#type' => 'textfield',
+        '#title' => t('View arguments'),
+        '#default_value' => $default,
+        '#required' => FALSE,
+        '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
+      );
+    }
+    else {
+      $form['view']['no_view_help'] = array(
+        '#markup' => '<p>' . t('No eligible views were found. <a href="@create">Create a view</a> with an <em>Entity Reference</em> display, or add such a display to an <a href="@existing">existing view</a>.', array(
+          '@create' => url('admin/structure/views/add'),
+          '@existing' => url('admin/structure/views'),
+        )) . '</p>',
+      );
+    }
+    return $form;
+  }
+
+  protected function initializeView($match = NULL, $match_operator = 'CONTAINS', $limit = 0, $ids = NULL) {
+    $view_name = $this->field['settings']['handler_settings']['view']['view_name'];
+    $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
+    $args = $this->field['settings']['handler_settings']['view']['args'];
+    $entity_type = $this->field['settings']['target_type'];
+
+    // Check that the view is valid and the display still exists.
+    $this->view = views_get_view($view_name);
+    if (!$this->view || !isset($this->view->display[$display_name]) || !$this->view->access($display_name)) {
+      watchdog('entityreference', 'The view %view_name is no longer eligible for the %field_name field.', array('%view_name' => $view_name, '%field_name' => $this->instance['label']), WATCHDOG_WARNING);
+      return FALSE;
+    }
+    $this->view->set_display($display_name);
+
+    // Make sure the query is not cached.
+    $this->view->is_cacheable = FALSE;
+
+    // Pass options to the display handler to make them available later.
+    $entityreference_options = array(
+      'match' => $match,
+      'match_operator' => $match_operator,
+      'limit' => $limit,
+      'ids' => $ids,
+    );
+    $this->view->display_handler->set_option('entityreference_options', $entityreference_options);
+    return TRUE;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::getReferencableEntities().
+   */
+  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
+    $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
+    $args = $this->field['settings']['handler_settings']['view']['args'];
+    $result = array();
+    if ($this->initializeView($match, $match_operator, $limit)) {
+      // Get the results.
+      $result = $this->view->execute_display($display_name, $args);
+    }
+    return $result;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::countReferencableEntities().
+   */
+  function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') {
+    $this->getReferencableEntities($match, $match_operator);
+    return $this->view->total_items;
+  }
+
+  function validateReferencableEntities(array $ids) {
+    $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
+    $args = $this->field['settings']['handler_settings']['view']['args'];
+    $result = array();
+    if ($this->initializeView(NULL, 'CONTAINS', 0, $ids)) {
+      // Get the results.
+      $entities = $this->view->execute_display($display_name, $args);
+      $result = array_keys($entities);
+    }
+    return $result;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::getLabel().
+   */
+  public function getLabel($entity) {
+    return entity_label($this->field['settings']['target_type'], $entity);
+  }
+
+  /**
+   * Implements EntityReferenceHandler::entityFieldQueryAlter().
+   */
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+
+  }
+
+}
+
+function entityreference_view_settings_validate($element, &$form_state, $form) {
+  // Split view name and display name from the 'view_and_display' value.
+  if (!empty($element['view_and_display']['#value'])) {
+    list($view, $display) = explode(':', $element['view_and_display']['#value']);
+  }
+  else {
+    $view = '';
+    $display = '';
+  }
+
+  // Explode the 'args' string into an actual array. Beware, explode() turns an
+  // empty string into an array with one empty string. We'll need an empty array
+  // instead.
+  $args_string = trim($element['args']['#value']);
+  if ($args_string === '') {
+    $args = array();
+  }
+  else {
+    // array_map is called to trim whitespaces from the arguments.
+    $args = array_map('trim', explode(',', $args_string));
+  }
+
+  $value = array('view_name' => $view, 'display_name' => $display, 'args' => $args);
+  form_set_value($element, $value, $form_state);
+}
diff --git a/sites/all/modules/entityreference/plugins/selection/abstract.inc b/sites/all/modules/entityreference/plugins/selection/abstract.inc
new file mode 100644
index 0000000000000000000000000000000000000000..fc5117c590681f627882e6f0203d1677a1305a0f
--- /dev/null
+++ b/sites/all/modules/entityreference/plugins/selection/abstract.inc
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * Abstraction of the selection logic of an entity reference field.
+ *
+ * Implementations that wish to provide an implementation of this should
+ * register it using CTools' plugin system.
+ */
+interface EntityReference_SelectionHandler {
+  /**
+   * Factory function: create a new instance of this handler for a given field.
+   *
+   * @param $field
+   *   A field datastructure.
+   * @return EntityReferenceHandler
+   */
+  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL);
+
+  /**
+   * Return a list of referencable entities.
+   *
+   * @return
+   *   An array of referencable entities, which keys are entity ids and
+   *   values (safe HTML) labels to be displayed to the user.
+   */
+  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0);
+
+  /**
+   * Count entities that are referencable by a given field.
+   */
+  public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS');
+
+  /**
+   * Validate that entities can be referenced by this field.
+   *
+   * @return
+   *   An array of entity ids that are valid.
+   */
+  public function validateReferencableEntities(array $ids);
+
+  /**
+   * Validate Input from autocomplete widget that has no Id.
+   *
+   * @see _entityreference_autocomplete_validate()
+   *
+   * @param $input
+   * 	 Single string from autocomplete widget.
+   * @param $element
+   *   The form element to set a form error.
+   * @return
+   *   Value of a matching entity id, or NULL if none.
+   */
+  public function validateAutocompleteInput($input, &$element, &$form_state, $form);
+
+  /**
+   * Give the handler a chance to alter the SelectQuery generated by EntityFieldQuery.
+   */
+  public function entityFieldQueryAlter(SelectQueryInterface $query);
+
+  /**
+   * Return the label of a given entity.
+   */
+  public function getLabel($entity);
+
+  /**
+   * Generate a settings form for this handler.
+   */
+  public static function settingsForm($field, $instance);
+}
+
+/**
+ * A null implementation of EntityReference_SelectionHandler.
+ */
+class EntityReference_SelectionHandler_Broken implements EntityReference_SelectionHandler {
+  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+    return new EntityReference_SelectionHandler_Broken($field, $instance, $entity_type, $entity);
+  }
+
+  protected function __construct($field, $instance) {
+    $this->field = $field;
+    $this->instance = $instance;
+  }
+
+  public static function settingsForm($field, $instance) {
+    $form['selection_handler'] = array(
+      '#markup' => t('The selected selection handler is broken.'),
+    );
+    return $form;
+  }
+
+  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
+    return array();
+  }
+
+  public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') {
+    return 0;
+  }
+
+  public function validateReferencableEntities(array $ids) {
+    return array();
+  }
+
+  public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
+    return NULL;
+  }
+
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {}
+
+  public function getLabel($entity) {
+    return '';
+  }
+}
diff --git a/sites/all/modules/entityreference/plugins/selection/base.inc b/sites/all/modules/entityreference/plugins/selection/base.inc
new file mode 100644
index 0000000000000000000000000000000000000000..32471c9236c44e53862c99b58e222adfd7ae141c
--- /dev/null
+++ b/sites/all/modules/entityreference/plugins/selection/base.inc
@@ -0,0 +1,7 @@
+<?php
+
+$plugin = array(
+  'title' => t('Simple (with optional filter by bundle)'),
+  'class' => 'EntityReference_SelectionHandler_Generic',
+  'weight' => -100,
+);
diff --git a/sites/all/modules/entityreference/plugins/selection/views.inc b/sites/all/modules/entityreference/plugins/selection/views.inc
new file mode 100644
index 0000000000000000000000000000000000000000..5694bf36cecaf665f92eea445cf7653c5c144c7d
--- /dev/null
+++ b/sites/all/modules/entityreference/plugins/selection/views.inc
@@ -0,0 +1,9 @@
+<?php
+
+if (module_exists('views')) {
+  $plugin = array(
+    'title' => t('Views: Filter by an entity reference view'),
+    'class' => 'EntityReference_SelectionHandler_Views',
+    'weight' => 0,
+  );
+}
diff --git a/sites/all/modules/entityreference/tests/entityreference.handlers.test b/sites/all/modules/entityreference/tests/entityreference.handlers.test
new file mode 100644
index 0000000000000000000000000000000000000000..598cb8fb7535e4e61251bdcda31a7820b3a8c575
--- /dev/null
+++ b/sites/all/modules/entityreference/tests/entityreference.handlers.test
@@ -0,0 +1,421 @@
+<?php
+
+/**
+ * Test for Entity Reference handlers.
+ */
+class EntityReferenceHandlersTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity Reference Handlers',
+      'description' => 'Tests for the base handlers provided by Entity Reference.',
+      'group' => 'Entity Reference',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp('entityreference');
+  }
+
+  protected function assertReferencable($field, $tests, $handler_name) {
+    $handler = entityreference_get_selection_handler($field);
+
+    foreach ($tests as $test) {
+      foreach ($test['arguments'] as $arguments) {
+        $result = call_user_func_array(array($handler, 'getReferencableEntities'), $arguments);
+        $this->assertEqual($result, $test['result'], t('Valid result set returned by @handler.', array('@handler' => $handler_name)));
+
+        $result = call_user_func_array(array($handler, 'countReferencableEntities'), $arguments);
+        $this->assertEqual($result, count($test['result']), t('Valid count returned by @handler.', array('@handler' => $handler_name)));
+      }
+    }
+  }
+
+  /**
+   * Test the node-specific overrides of the entity handler.
+   */
+  public function testNodeHandler() {
+    // Build a fake field instance.
+    $field = array(
+      'translatable' => FALSE,
+      'entity_types' => array(),
+      'settings' => array(
+        'handler' => 'base',
+        'target_type' => 'node',
+        'handler_settings' => array(
+          'target_bundles' => array(),
+        ),
+      ),
+      'field_name' => 'test_field',
+      'type' => 'entityreference',
+      'cardinality' => '1',
+    );
+
+    // Build a set of test data.
+    // Titles contain HTML-special characters to test escaping.
+    $nodes = array(
+      'published1' => (object) array(
+        'type' => 'article',
+        'status' => 1,
+        'title' => 'Node published1 (<&>)',
+        'uid' => 1,
+      ),
+      'published2' => (object) array(
+        'type' => 'article',
+        'status' => 1,
+        'title' => 'Node published2 (<&>)',
+        'uid' => 1,
+      ),
+      'unpublished' => (object) array(
+        'type' => 'article',
+        'status' => 0,
+        'title' => 'Node unpublished (<&>)',
+        'uid' => 1,
+      ),
+    );
+
+    $node_labels = array();
+    foreach ($nodes as $key => $node) {
+      node_save($node);
+      $node_labels[$key] = check_plain($node->title);
+    }
+
+    // Test as a non-admin.
+    $normal_user = $this->drupalCreateUser(array('access content'));
+    $GLOBALS['user'] = $normal_user;
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          $nodes['published1']->nid => $node_labels['published1'],
+          $nodes['published2']->nid => $node_labels['published2'],
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('published1', 'CONTAINS'),
+          array('Published1', 'CONTAINS'),
+        ),
+        'result' => array(
+          $nodes['published1']->nid => $node_labels['published1'],
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('published2', 'CONTAINS'),
+          array('Published2', 'CONTAINS'),
+        ),
+        'result' => array(
+          $nodes['published2']->nid => $node_labels['published2'],
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('invalid node', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+      array(
+        'arguments' => array(
+          array('Node unpublished', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'Node handler');
+
+    // Test as an admin.
+    $admin_user = $this->drupalCreateUser(array('access content', 'bypass node access'));
+    $GLOBALS['user'] = $admin_user;
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          $nodes['published1']->nid => $node_labels['published1'],
+          $nodes['published2']->nid => $node_labels['published2'],
+          $nodes['unpublished']->nid => $node_labels['unpublished'],
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('Node unpublished', 'CONTAINS'),
+        ),
+        'result' => array(
+          $nodes['unpublished']->nid => $node_labels['unpublished'],
+        ),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'Node handler (admin)');
+  }
+
+  /**
+   * Test the user-specific overrides of the entity handler.
+   */
+  public function testUserHandler() {
+    // Build a fake field instance.
+    $field = array(
+      'translatable' => FALSE,
+      'entity_types' => array(),
+      'settings' => array(
+        'handler' => 'base',
+        'target_type' => 'user',
+        'handler_settings' => array(
+          'target_bundles' => array(),
+        ),
+      ),
+      'field_name' => 'test_field',
+      'type' => 'entityreference',
+      'cardinality' => '1',
+    );
+
+    // Build a set of test data.
+    $users = array(
+      'anonymous' => user_load(0),
+      'admin' => user_load(1),
+      'non_admin' => (object) array(
+        'name' => 'non_admin <&>',
+        'mail' => 'non_admin@example.com',
+        'roles' => array(),
+        'pass' => user_password(),
+        'status' => 1,
+      ),
+      'blocked' => (object) array(
+        'name' => 'blocked <&>',
+        'mail' => 'blocked@example.com',
+        'roles' => array(),
+        'pass' => user_password(),
+        'status' => 0,
+      ),
+    );
+
+    // The label of the anonymous user is variable_get('anonymous').
+    $users['anonymous']->name = variable_get('anonymous', t('Anonymous'));
+
+    $user_labels = array();
+    foreach ($users as $key => $user) {
+      if (!isset($user->uid)) {
+        $users[$key] = $user = user_save(drupal_anonymous_user(), (array) $user);
+      }
+      $user_labels[$key] = check_plain($user->name);
+    }
+
+    // Test as a non-admin.
+    $GLOBALS['user'] = $users['non_admin'];
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          $users['admin']->uid => $user_labels['admin'],
+          $users['non_admin']->uid => $user_labels['non_admin'],
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('non_admin', 'CONTAINS'),
+          array('NON_ADMIN', 'CONTAINS'),
+        ),
+        'result' => array(
+          $users['non_admin']->uid => $user_labels['non_admin'],
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('invalid user', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+      array(
+        'arguments' => array(
+          array('blocked', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'User handler');
+
+    $GLOBALS['user'] = $users['admin'];
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          $users['anonymous']->uid => $user_labels['anonymous'],
+          $users['admin']->uid => $user_labels['admin'],
+          $users['non_admin']->uid => $user_labels['non_admin'],
+          $users['blocked']->uid => $user_labels['blocked'],
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('blocked', 'CONTAINS'),
+        ),
+        'result' => array(
+          $users['blocked']->uid => $user_labels['blocked'],
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('Anonymous', 'CONTAINS'),
+          array('anonymous', 'CONTAINS'),
+        ),
+        'result' => array(
+          $users['anonymous']->uid => $user_labels['anonymous'],
+        ),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'User handler (admin)');
+  }
+
+  /**
+   * Test the comment-specific overrides of the entity handler.
+   */
+  public function testCommentHandler() {
+    // Build a fake field instance.
+    $field = array(
+      'translatable' => FALSE,
+      'entity_types' => array(),
+      'settings' => array(
+        'handler' => 'base',
+        'target_type' => 'comment',
+        'handler_settings' => array(
+          'target_bundles' => array(),
+        ),
+      ),
+      'field_name' => 'test_field',
+      'type' => 'entityreference',
+      'cardinality' => '1',
+    );
+
+    // Build a set of test data.
+    $nodes = array(
+      'published' => (object) array(
+        'type' => 'article',
+        'status' => 1,
+        'title' => 'Node published',
+        'uid' => 1,
+      ),
+      'unpublished' => (object) array(
+        'type' => 'article',
+        'status' => 0,
+        'title' => 'Node unpublished',
+        'uid' => 1,
+      ),
+    );
+    foreach ($nodes as $node) {
+      node_save($node);
+    }
+
+    $comments = array(
+      'published_published' => (object) array(
+        'nid' => $nodes['published']->nid,
+        'uid' => 1,
+        'cid' => NULL,
+        'pid' => 0,
+        'status' => COMMENT_PUBLISHED,
+        'subject' => 'Comment Published <&>',
+        'hostname' => ip_address(),
+        'language' => LANGUAGE_NONE,
+      ),
+      'published_unpublished' => (object) array(
+        'nid' => $nodes['published']->nid,
+        'uid' => 1,
+        'cid' => NULL,
+        'pid' => 0,
+        'status' => COMMENT_NOT_PUBLISHED,
+        'subject' => 'Comment Unpublished <&>',
+        'hostname' => ip_address(),
+        'language' => LANGUAGE_NONE,
+      ),
+      'unpublished_published' => (object) array(
+        'nid' => $nodes['unpublished']->nid,
+        'uid' => 1,
+        'cid' => NULL,
+        'pid' => 0,
+        'status' => COMMENT_NOT_PUBLISHED,
+        'subject' => 'Comment Published on Unpublished node <&>',
+        'hostname' => ip_address(),
+        'language' => LANGUAGE_NONE,
+      ),
+    );
+
+    $comment_labels = array();
+    foreach ($comments as $key => $comment) {
+      comment_save($comment);
+      $comment_labels[$key] = check_plain($comment->subject);
+    }
+
+    // Test as a non-admin.
+    $normal_user = $this->drupalCreateUser(array('access content', 'access comments'));
+    $GLOBALS['user'] = $normal_user;
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          $comments['published_published']->cid => $comment_labels['published_published'],
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('Published', 'CONTAINS'),
+        ),
+        'result' => array(
+          $comments['published_published']->cid => $comment_labels['published_published'],
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('invalid comment', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+      array(
+        'arguments' => array(
+          array('Comment Unpublished', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'Comment handler');
+
+    // Test as a comment admin.
+    $admin_user = $this->drupalCreateUser(array('access content', 'access comments', 'administer comments'));
+    $GLOBALS['user'] = $admin_user;
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          $comments['published_published']->cid => $comment_labels['published_published'],
+          $comments['published_unpublished']->cid => $comment_labels['published_unpublished'],
+        ),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'Comment handler (comment admin)');
+
+    // Test as a node and comment admin.
+    $admin_user = $this->drupalCreateUser(array('access content', 'access comments', 'administer comments', 'bypass node access'));
+    $GLOBALS['user'] = $admin_user;
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          $comments['published_published']->cid => $comment_labels['published_published'],
+          $comments['published_unpublished']->cid => $comment_labels['published_unpublished'],
+          $comments['unpublished_published']->cid => $comment_labels['unpublished_published'],
+        ),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'Comment handler (comment + node admin)');
+  }
+}
diff --git a/sites/all/modules/entityreference/views/entityreference.views.inc b/sites/all/modules/entityreference/views/entityreference.views.inc
new file mode 100644
index 0000000000000000000000000000000000000000..df38395b3ebbff15a0f8fdc0b449b9c4ba92cdfc
--- /dev/null
+++ b/sites/all/modules/entityreference/views/entityreference.views.inc
@@ -0,0 +1,136 @@
+<?php
+
+/**
+ * @file
+ * Views integration for Entity Reference.
+ */
+
+/**
+ * Implements hook_field_views_data().
+ */
+function entityreference_field_views_data($field) {
+  $data = field_views_field_default_views_data($field);
+  $entity_info = entity_get_info($field['settings']['target_type']);
+  foreach ($data as $table_name => $table_data) {
+    if (isset($entity_info['base table'])) {
+      $entity = $entity_info['label'];
+      if ($entity == t('Node')) {
+        $entity = t('Content');
+      }
+
+      $field_name = $field['field_name'] . '_target_id';
+      $parameters = array('@entity' => $entity, '!field_name' => $field['field_name']);
+      $data[$table_name][$field_name]['relationship'] = array(
+        'handler' => 'views_handler_relationship',
+        'base' => $entity_info['base table'],
+        'base field' => $entity_info['entity keys']['id'],
+        'label' => t('@entity entity referenced from !field_name', $parameters),
+        'group' => t('Entity Reference'),
+        'title' => t('Referenced Entity'),
+        'help' => t('A bridge to the @entity entity that is referenced via !field_name', $parameters),
+      );
+    }
+  }
+
+  // Invoke the behaviors to allow them to change the properties.
+  foreach (entityreference_get_behavior_handlers($field) as $handler) {
+    $handler->views_data_alter($data, $field);
+  }
+
+  return $data;
+}
+
+/**
+ * Options callback for Views handler views_handler_filter_in_operator.
+ */
+function entityreference_views_handler_options_list($field_name) {
+  $field = field_info_field($field_name);
+  return entityreference_options_list($field);
+}
+
+/**
+ * Implements hook_field_views_data_views_data_alter().
+ *
+ * Views integration to provide reverse relationships on entityreference fields.
+ */
+function entityreference_field_views_data_views_data_alter(&$data, $field) {
+  foreach ($field['bundles'] as $entity_type => $bundles) {
+    $target_entity_info = entity_get_info($field['settings']['target_type']);
+    if (isset($target_entity_info['base table'])) {
+      $entity_info = entity_get_info($entity_type);
+      $entity = $entity_info['label'];
+      if ($entity == t('Node')) {
+        $entity = t('Content');
+      }
+      $target_entity = $target_entity_info['label'];
+      if ($target_entity == t('Node')) {
+        $target_entity = t('Content');
+      }
+
+      $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
+      $replacements = array('@entity' => $entity, '@target_entity' => $target_entity, '!field_name' => $field['field_name']);
+      $data[$target_entity_info['base table']][$pseudo_field_name]['relationship'] = array(
+        'handler' => 'views_handler_relationship_entity_reverse',
+        'field_name' => $field['field_name'],
+        'field table' => _field_sql_storage_tablename($field),
+        'field field' => $field['field_name'] . '_target_id',
+        'base' => $entity_info['base table'],
+        'base field' => $entity_info['entity keys']['id'],
+        'label' => t('@entity referencing @target_entity from !field_name', $replacements),
+        'group' => t('Entity Reference'),
+        'title' => t('Referencing entity'),
+        'help' => t('A bridge to the @entity entity that is referencing @target_entity via !field_name', $replacements),
+      );
+    }
+  }
+}
+
+/**
+ * Implements hook_views_plugins().
+ */
+function entityreference_views_plugins() {
+  $plugins = array(
+    'display' => array(
+      'entityreference' => array(
+        'title' => t('Entity Reference'),
+        'admin' => t('Entity Reference Source'),
+        'help' => 'Selects referenceable entities for an entity reference field',
+        'handler' => 'entityreference_plugin_display',
+        'uses hook menu' => FALSE,
+        'use ajax' => FALSE,
+        'use pager' => FALSE,
+        'accept attachments' => FALSE,
+        // Custom property, used with views_get_applicable_views() to retrieve
+        // all views with a 'Entity Reference' display.
+        'entityreference display' => TRUE,
+      ),
+    ),
+    'style' => array(
+      'entityreference_style' => array(
+        'title' => t('Entity Reference list'),
+        'help' => 'Returns results as a PHP array of labels and rendered rows.',
+        'handler' => 'entityreference_plugin_style',
+        'theme' => 'views_view_unformatted',
+        'uses row plugin' => TRUE,
+        'uses fields' => TRUE,
+        'uses options' => TRUE,
+        'type' => 'entityreference',
+        'even empty' => TRUE,
+      ),
+    ),
+    'row' => array(
+      'entityreference_fields' => array(
+        'title' => t('Inline fields'),
+        'help' => t('Displays the fields with an optional template.'),
+        'handler' => 'entityreference_plugin_row_fields',
+        'theme' => 'views_view_fields',
+        'theme path' => drupal_get_path('module', 'views') . '/theme',
+        'theme file' => 'theme.inc',
+        'uses fields' => TRUE,
+        'uses options' => TRUE,
+        'type' => 'entityreference',
+      ),
+    ),
+  );
+  return $plugins;
+}
diff --git a/sites/all/modules/entityreference/views/entityreference_plugin_display.inc b/sites/all/modules/entityreference/views/entityreference_plugin_display.inc
new file mode 100644
index 0000000000000000000000000000000000000000..1fc645018ac65ba1cdc98f17748d6c35c89557dd
--- /dev/null
+++ b/sites/all/modules/entityreference/views/entityreference_plugin_display.inc
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * @file
+ * Handler for entityreference_plugin_display.
+ */
+class entityreference_plugin_display extends views_plugin_display {
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    // Force the style plugin to 'entityreference_style' and the row plugin to
+    // 'fields'.
+    $options['style_plugin']['default'] = 'entityreference_style';
+    $options['defaults']['default']['style_plugin'] = FALSE;
+    $options['defaults']['default']['style_options'] = FALSE;
+    $options['row_plugin']['default'] = 'entityreference_fields';
+    $options['defaults']['default']['row_plugin'] = FALSE;
+    $options['defaults']['default']['row_options'] = FALSE;
+
+    // Set the display title to an empty string (not used in this display type).
+    $options['title']['default'] = '';
+    $options['defaults']['default']['title'] = FALSE;
+
+    return $options;
+  }
+
+  function get_style_type() {
+    return 'entityreference';
+  }
+
+  function execute() {
+    return $this->view->render($this->display->id);
+  }
+
+  function render() {
+    if (!empty($this->view->result) || !empty($this->view->style_plugin->definition['even empty'])) {
+      return $this->view->style_plugin->render($this->view->result);
+    }
+    return '';
+  }
+
+  function uses_exposed() {
+    return FALSE;
+  }
+
+  function query() {
+    $options = $this->get_option('entityreference_options');
+
+    // Play nice with Views UI 'preview' : if the view is not executed through
+    // EntityReference_SelectionHandler_Views::getReferencableEntities(),
+    // don't alter the query.
+    if (empty($options)) {
+      return;
+    }
+
+    // Make sure the id field is included in the results, and save its alias
+    // so that references_plugin_style can retrieve it.
+    $this->id_field_alias = $id_field = $this->view->query->add_field($this->view->base_table, $this->view->base_field);
+    if (strpos($id_field, '.') === false) {
+      $id_field = $this->view->base_table .'.'.$this->id_field_alias;
+    }
+
+    // Restrict the autocomplete options based on what's been typed already.
+    if (isset($options['match'])) {
+      $style_options = $this->get_option('style_options');
+      $value = db_like($options['match']) . '%';
+      if ($options['match_operator'] != 'STARTS_WITH') {
+        $value = '%' . $value;
+      }
+
+      // Multiple search fields are OR'd together
+      $conditions = db_or();
+
+      // Build the condition using the selected search fields
+      foreach ($style_options['search_fields'] as $field_alias) {
+        if (!empty($field_alias)) {
+          // Get the table and field names for the checked field
+          $field = $this->view->query->fields[$this->view->field[$field_alias]->field_alias];
+          // Add an OR condition for the field
+          $conditions->condition($field['table'] . '.' . $field['field'], $value, 'LIKE');
+        }
+      }
+
+      $this->view->query->add_where(NULL, $conditions);
+    }
+
+    // Add an IN condition for validation.
+    if (!empty($options['ids'])) {
+      $this->view->query->add_where(NULL, $id_field, $options['ids']);
+    }
+
+    $this->view->set_items_per_page($options['limit']);
+  }
+
+  /**
+   * Extend the default validation. 
+   */
+  function validate() {
+    $errors = parent::validate();
+    // Verify that search fields are set up.
+    $style_options = $this->get_option('style_options');
+    if (!isset($style_options['search_fields'])) {
+      $errors[] = t('Display "@display" needs a selected search fields to work properly. See the settings for the Entity Reference list format.', array('@display' => $this->display->display_title));
+    }
+    else {
+      // Verify that the search fields used actually exist.
+      //$fields = array_keys($this->view->get_items('field'));
+      $fields = array_keys($this->handlers['field']);
+      foreach ($style_options['search_fields'] as $field_alias => $enabled) {
+        if ($enabled && !in_array($field_alias, $fields)) {
+          $errors[] = t('Display "@display" uses field %field as search field, but the field is no longer present. See the settings for the Entity Reference list format.', array('@display' => $this->display->display_title, '%field' => $field_alias));
+        }
+      }
+    }
+    return $errors;
+  }
+}
diff --git a/sites/all/modules/entityreference/views/entityreference_plugin_row_fields.inc b/sites/all/modules/entityreference/views/entityreference_plugin_row_fields.inc
new file mode 100644
index 0000000000000000000000000000000000000000..400603f3f29036e176f7f9275181415d1692ef57
--- /dev/null
+++ b/sites/all/modules/entityreference/views/entityreference_plugin_row_fields.inc
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Handler for entityreference_plugin_row_fields.
+ */
+class entityreference_plugin_row_fields extends views_plugin_row_fields {
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['separator'] = array('default' => '-');
+
+    return $options;
+  }
+
+  /**
+   * Provide a form for setting options.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Expand the description of the 'Inline field' checkboxes.
+    $form['inline']['#description'] .= '<br>' . t("<strong>Note:</strong> In 'Entity Reference' displays, all fields will be displayed inline unless an explicit selection of inline fields is made here." );
+  }
+
+  function pre_render($row) {
+    // Force all fields to be inline by default.
+    if (empty($this->options['inline'])) {
+      $fields = $this->view->get_items('field', $this->display->id);
+      $this->options['inline'] = drupal_map_assoc(array_keys($fields));
+    }
+
+    return parent::pre_render($row);
+  }
+}
diff --git a/sites/all/modules/entityreference/views/entityreference_plugin_style.inc b/sites/all/modules/entityreference/views/entityreference_plugin_style.inc
new file mode 100644
index 0000000000000000000000000000000000000000..76c2e8132657786f3a0ba8d4a4d4adc98917d412
--- /dev/null
+++ b/sites/all/modules/entityreference/views/entityreference_plugin_style.inc
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Handler for entityreference_plugin_style.
+ */
+class entityreference_plugin_style extends views_plugin_style {
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['search_fields'] = array('default' => NULL);
+
+    return $options;
+  }
+
+  // Create the options form.
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $options = array();
+
+    if (isset($form['grouping'])) {
+      $options = $form['grouping'][0]['field']['#options'];
+      unset($options['']);
+      $form['search_fields'] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Search fields'),
+        '#options' => $options,
+        '#required' => TRUE,
+        '#default_value' => $this->options['search_fields'],
+        '#description' => t('Select the field(s) that will be searched when using the autocomplete widget.'),
+        '#weight' => -3,
+      );
+    }
+  }
+
+  function render() {
+    $options = $this->display->handler->get_option('entityreference_options');
+
+    // Play nice with Views UI 'preview' : if the view is not executed through
+    // EntityReference_SelectionHandler_Views::getReferencableEntities(), just
+    // display the HTML.
+    if (empty($options)) {
+      return parent::render();
+    }
+
+    // Group the rows according to the grouping field, if specified.
+    $sets = $this->render_grouping($this->view->result, $this->options['grouping']);
+
+    // Grab the alias of the 'id' field added by entityreference_plugin_display.
+    $id_field_alias = $this->display->handler->id_field_alias;
+
+    // @todo We don't display grouping info for now. Could be useful for select
+    // widget, though.
+    $results = array();
+    $this->view->row_index = 0;
+    foreach ($sets as $records) {
+      foreach ($records as $values) {
+        // Sanitize html, remove line breaks and extra whitespace.
+        $results[$values->{$id_field_alias}] = filter_xss_admin(preg_replace('/\s\s+/', ' ', str_replace("\n", '', $this->row_plugin->render($values))));
+        $this->view->row_index++;
+      }
+    }
+    unset($this->view->row_index);
+    return $results;
+  }
+}
diff --git a/sites/all/modules/form_builder/LICENSE.txt b/sites/all/modules/form_builder/LICENSE.txt
index 2c095c8d3f42488e8168f9710a4ffbfc4125a159..d159169d1050894d3ea3b98e1c965c4058208fe1 100644
--- a/sites/all/modules/form_builder/LICENSE.txt
+++ b/sites/all/modules/form_builder/LICENSE.txt
@@ -1,274 +1,339 @@
-GNU GENERAL PUBLIC LICENSE
-
-              Version 2, June 1991
-
-Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
-Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
-verbatim copies of this license document, but changing it is not allowed.
-
-                  Preamble
-
-The licenses for most software are designed to take away your freedom to
-share and change it. By contrast, the GNU General Public License is
-intended to guarantee your freedom to share and change free software--to
-make sure the software is free for all its users. This General Public License
-applies to most of the Free Software Foundation's software and to any other
-program whose authors commit to using it. (Some other Free Software
-Foundation software is covered by the GNU Library General Public License
-instead.) You can apply it to your programs, too.
-
-When we speak of free software, we are referring to freedom, not price. Our
-General Public Licenses are designed to make sure that you have the
-freedom to distribute copies of free software (and charge for this service if
-you wish), that you receive source code or can get it if you want it, that you
-can change the software or use pieces of it in new free programs; and that
-you know you can do these things.
-
-To protect your rights, we need to make restrictions that forbid anyone to
-deny you these rights or to ask you to surrender the rights. These restrictions
-translate to certain responsibilities for you if you distribute copies of the
-software, or if you modify it.
-
-For example, if you distribute copies of such a program, whether gratis or for
-a fee, you must give the recipients all the rights that you have. You must make
-sure that they, too, receive or can get the source code. And you must show
-them these terms so they know their rights.
-
-We protect your rights with two steps: (1) copyright the software, and (2)
-offer you this license which gives you legal permission to copy, distribute
-and/or modify the software.
-
-Also, for each author's protection and ours, we want to make certain that
-everyone understands that there is no warranty for this free software. If the
-software is modified by someone else and passed on, we want its recipients
-to know that what they have is not the original, so that any problems
-introduced by others will not reflect on the original authors' reputations.
-
-Finally, any free program is threatened constantly by software patents. We
-wish to avoid the danger that redistributors of a free program will individually
-obtain patent licenses, in effect making the program proprietary. To prevent
-this, we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
-The precise terms and conditions for copying, distribution and modification
-follow.
-
-           GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
-               MODIFICATION
-
-0. This License applies to any program or other work which contains a notice
-placed by the copyright holder saying it may be distributed under the terms
-of this General Public License. The "Program", below, refers to any such
-program or work, and a "work based on the Program" means either the
-Program or any derivative work under copyright law: that is to say, a work
-containing the Program or a portion of it, either verbatim or with
-modifications and/or translated into another language. (Hereinafter, translation
-is included without limitation in the term "modification".) Each licensee is
-addressed as "you".
-
-Activities other than copying, distribution and modification are not covered
-by this License; they are outside its scope. The act of running the Program is
-not restricted, and the output from the Program is covered only if its contents
-constitute a work based on the Program (independent of having been made
-by running the Program). Whether that is true depends on what the Program
-does.
-
-1. You may copy and distribute verbatim copies of the Program's source
-code as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice and
-disclaimer of warranty; keep intact all the notices that refer to this License
-and to the absence of any warranty; and give any other recipients of the
-Program a copy of this License along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and you
-may at your option offer warranty protection in exchange for a fee.
-
-2. You may modify your copy or copies of the Program or any portion of it,
-thus forming a work based on the Program, and copy and distribute such
-modifications or work under the terms of Section 1 above, provided that you
-also meet all of these conditions:
-
-a) You must cause the modified files to carry prominent notices stating that
-you changed the files and the date of any change.
-
-b) You must cause any work that you distribute or publish, that in whole or in
-part contains or is derived from the Program or any part thereof, to be
-licensed as a whole at no charge to all third parties under the terms of this
-License.
-
-c) If the modified program normally reads commands interactively when run,
-you must cause it, when started running for such interactive use in the most
-ordinary way, to print or display an announcement including an appropriate
-copyright notice and a notice that there is no warranty (or else, saying that
-you provide a warranty) and that users may redistribute the program under
-these conditions, and telling the user how to view a copy of this License.
-(Exception: if the Program itself is interactive but does not normally print such
-an announcement, your work based on the Program is not required to print
-an announcement.)
-
-These requirements apply to the modified work as a whole. If identifiable
-sections of that work are not derived from the Program, and can be
-reasonably considered independent and separate works in themselves, then
-this License, and its terms, do not apply to those sections when you distribute
-them as separate works. But when you distribute the same sections as part
-of a whole which is a work based on the Program, the distribution of the
-whole must be on the terms of this License, whose permissions for other
-licensees extend to the entire whole, and thus to each and every part
-regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest your rights to
-work written entirely by you; rather, the intent is to exercise the right to
-control the distribution of derivative or collective works based on the
-Program.
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
 
 In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of a
-storage or distribution medium does not bring the other work under the scope
-of this License.
-
-3. You may copy and distribute the Program (or a work based on it, under
-Section 2) in object code or executable form under the terms of Sections 1
-and 2 above provided that you also do one of the following:
-
-a) Accompany it with the complete corresponding machine-readable source
-code, which must be distributed under the terms of Sections 1 and 2 above
-on a medium customarily used for software interchange; or,
-
-b) Accompany it with a written offer, valid for at least three years, to give
-any third party, for a charge no more than your cost of physically performing
-source distribution, a complete machine-readable copy of the corresponding
-source code, to be distributed under the terms of Sections 1 and 2 above on
-a medium customarily used for software interchange; or,
-
-c) Accompany it with the information you received as to the offer to distribute
-corresponding source code. (This alternative is allowed only for
-noncommercial distribution and only if you received the program in object
-code or executable form with such an offer, in accord with Subsection b
-above.)
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
 
 The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source code
-means all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation and
-installation of the executable. However, as a special exception, the source
-code distributed need not include anything that is normally distributed (in
-either source or binary form) with the major components (compiler, kernel,
-and so on) of the operating system on which the executable runs, unless that
-component itself accompanies the executable.
-
-If distribution of executable or object code is made by offering access to
-copy from a designated place, then offering equivalent access to copy the
-source code from the same place counts as distribution of the source code,
-even though third parties are not compelled to copy the source along with the
-object code.
-
-4. You may not copy, modify, sublicense, or distribute the Program except as
-expressly provided under this License. Any attempt otherwise to copy,
-modify, sublicense or distribute the Program is void, and will automatically
-terminate your rights under this License. However, parties who have received
-copies, or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-5. You are not required to accept this License, since you have not signed it.
-However, nothing else grants you permission to modify or distribute the
-Program or its derivative works. These actions are prohibited by law if you
-do not accept this License. Therefore, by modifying or distributing the
-Program (or any work based on the Program), you indicate your acceptance
-of this License to do so, and all its terms and conditions for copying,
-distributing or modifying the Program or works based on it.
-
-6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the original
-licensor to copy, distribute or modify the Program subject to these terms and
-conditions. You may not impose any further restrictions on the recipients'
-exercise of the rights granted herein. You are not responsible for enforcing
-compliance by third parties to this License.
-
-7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues), conditions
-are imposed on you (whether by court order, agreement or otherwise) that
-contradict the conditions of this License, they do not excuse you from the
-conditions of this License. If you cannot distribute so as to satisfy
-simultaneously your obligations under this License and any other pertinent
-obligations, then as a consequence you may not distribute the Program at all.
-For example, if a patent license would not permit royalty-free redistribution
-of the Program by all those who receive copies directly or indirectly through
-you, then the only way you could satisfy both it and this License would be to
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
 refrain entirely from distribution of the Program.
 
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply and
-the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any patents or
-other property right claims or to contest validity of any such claims; this
-section has the sole purpose of protecting the integrity of the free software
-distribution system, which is implemented by public license practices. Many
-people have made generous contributions to the wide range of software
-distributed through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing to
-distribute software through any other system and a licensee cannot impose
-that choice.
-
-This section is intended to make thoroughly clear what is believed to be a
-consequence of the rest of this License.
-
-8. If the distribution and/or use of the Program is restricted in certain
-countries either by patents or by copyrighted interfaces, the original copyright
-holder who places the Program under this License may add an explicit
-geographical distribution limitation excluding those countries, so that
-distribution is permitted only in or among countries not thus excluded. In such
-case, this License incorporates the limitation as if written in the body of this
-License.
-
-9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will be
-similar in spirit to the present version, but may differ in detail to address new
-problems or concerns.
-
-Each version is given a distinguishing version number. If the Program specifies
-a version number of this License which applies to it and "any later version",
-you have the option of following the terms and conditions either of that
-version or of any later version published by the Free Software Foundation. If
-the Program does not specify a version number of this License, you may
-choose any version ever published by the Free Software Foundation.
-
-10. If you wish to incorporate parts of the Program into other free programs
-whose distribution conditions are different, write to the author to ask for
-permission. For software which is copyrighted by the Free Software
-Foundation, write to the Free Software Foundation; we sometimes make
-exceptions for this. Our decision will be guided by the two goals of
-preserving the free status of all derivatives of our free software and of
-promoting the sharing and reuse of software generally.
-
-               NO WARRANTY
-
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
-PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
-STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
-PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
-NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
-AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
-ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
-SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OR INABILITY TO USE THE
-PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
-OR DATA BEING RENDERED INACCURATE OR LOSSES
-SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
-PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
-IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGES.
-
-          END OF TERMS AND CONDITIONS
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/sites/all/modules/form_builder/examples/form_builder_examples.info b/sites/all/modules/form_builder/examples/form_builder_examples.info
index 18828f40a8a6af3416d2d68739ba579b5d05b73c..373b881017af301f7b7a6eefe90db30ca7dd0f92 100644
--- a/sites/all/modules/form_builder/examples/form_builder_examples.info
+++ b/sites/all/modules/form_builder/examples/form_builder_examples.info
@@ -3,9 +3,9 @@ description = Form builder support for CCK, Webform, and Profile modules.
 core = 7.x
 dependencies[] = form_builder
 
-; Information added by drupal.org packaging script on 2011-06-06
-version = "7.x-1.x-dev"
+; Information added by drupal.org packaging script on 2012-03-08
+version = "7.x-1.0"
 core = "7.x"
 project = "form_builder"
-datestamp = "1307319364"
+datestamp = "1331181344"
 
diff --git a/sites/all/modules/form_builder/form_builder_hooks.php b/sites/all/modules/form_builder/form_builder.api.php
similarity index 95%
rename from sites/all/modules/form_builder/form_builder_hooks.php
rename to sites/all/modules/form_builder/form_builder.api.php
index 38a996e62d8f525a16b4ef5897885525fad647cc..ad741acd472032d43af31d8cb02787c7db5cc674 100644
--- a/sites/all/modules/form_builder/form_builder_hooks.php
+++ b/sites/all/modules/form_builder/form_builder.api.php
@@ -66,6 +66,18 @@ function hook_form_builder_types() {
   );
 }
 
+/**
+ * Modify fields and properties that are declared by other modules.
+ *
+ * @see hook_form_builder_types()
+ */
+function hook_form_builder_types_alter(&$types) {
+  if (!empty($types['webform']['textfield']['properties'])) {
+    // Add our new placeholder properties for the webform textfield component.
+    $types['webform']['textfield']['properties'][] = 'placeholder';
+  }
+}
+
 /**
  * Defined globally available Form API properties.
  *
diff --git a/sites/all/modules/form_builder/form_builder.css b/sites/all/modules/form_builder/form_builder.css
index 8de5c3ae6aa92faae068f310c63eee2a294f0e30..d71b22be1f3628d5ae8c420287a91513b7258fbd 100644
--- a/sites/all/modules/form_builder/form_builder.css
+++ b/sites/all/modules/form_builder/form_builder.css
@@ -1,9 +1,17 @@
+/**
+ * @file
+ * Styles required for the basic functionality of the Form Builder interface.
+ */
 
 #form-builder-wrapper {
   overflow: hidden;
   padding: 10px 0;
 }
 
+#form-builder-wrapper h3.form-builder-title {
+  margin: 0;
+}
+
 #form-builder-wrapper.with-palette #form-builder-fields {
   float: right;
   padding-left: 10px;
@@ -197,6 +205,8 @@ span.form-builder-links a.progress:hover {
 #form-builder ul.form-builder-tabs {
   margin: 0;
   padding: 0;
+  float: left; /* RTL */
+  position: relative;
 }
 
 #form-builder ul.form-builder-tabs li {
@@ -219,8 +229,26 @@ span.form-builder-links a.progress:hover {
   margin-left: -1px;
   border-left: 1px solid #999;
   border-top: 1px dashed #999;
-  border-bottom: 1px solid #ebf4fa;
-  background: #ebf4fa;
+  border-bottom: 1px solid #ffffff;
+  background: #ffffff;
+}
+
+#form-builder fieldset.form-builder-group {
+  float: left; /* RTL */
+  width: 100%;
+  padding: 0;
+  margin: 0;
+  border: none;
+  border-top: 1px solid #CCC;
+}
+
+#form-builder fieldset.form-builder-group .fieldset-wrapper {
+  padding: 10px 10px 0;
+}
+
+#form-builder fieldset.form-builder-group .form-item {
+  padding: 0;
+  margin: 0 0 10px;
 }
 
 #form-builder-field-configure .form-submit {
@@ -235,12 +263,6 @@ span.form-builder-links a.progress:hover {
   padding: 6px 10px;
 }
 
-#form-builder fieldset.form-builder-group {
-  margin: 0;
-  border: none;
-  border-top: 1px solid #CCC;
-}
-
 /* Weight and parents form */
 form#form-builder-positions {
   display: none;
@@ -291,9 +313,6 @@ div.form-builder-new-field span.progress {
   color: black;
 }
 
-#form-builder-field-palette ul li.field-body_field {
-  background-image: url(images/fields/body.png);
-}
 #form-builder-field-palette ul li.field-checkboxes {
   background-image: url(images/fields/checkboxes.png);
 }
@@ -306,8 +325,7 @@ div.form-builder-new-field span.progress {
 #form-builder-field-palette ul li.field-fieldset {
   background-image: url(images/fields/fieldset.png);
 }
-#form-builder-field-palette ul li.field-file,
-#form-builder-field-palette ul li.field-upload_settings {
+#form-builder-field-palette ul li.field-file {
   background-image: url(images/fields/file.png);
 }
 #form-builder-field-palette ul li.field-grid {
@@ -322,40 +340,24 @@ div.form-builder-new-field span.progress {
 #form-builder-field-palette ul li.field-markup {
   background-image: url(images/fields/markup.png);
 }
-#form-builder-field-palette ul li.field-menu_settings {
-  background-image: url(images/fields/menu.png);
-}
 #form-builder-field-palette ul li.field-number {
   background-image: url(images/fields/number.png);
 }
 #form-builder-field-palette ul li.field-pagebreak {
   background-image: url(images/fields/pagebreak.png);
 }
-#form-builder-field-palette ul li.field-path_settings {
-  background-image: url(images/fields/path.png);
-}
 #form-builder-field-palette ul li.field-radios {
   background-image: url(images/fields/radios.png);
 }
-#form-builder-field-palette ul li.field-revision_information {
-  background-image: url(images/fields/revisions.png);
-}
 #form-builder-field-palette ul li.field-select {
   background-image: url(images/fields/select.png);
 }
 #form-builder-field-palette ul li.field-time {
   background-image: url(images/fields/time.png);
 }
-#form-builder-field-palette ul li.field-taxonomy {
-  background-image: url(images/fields/taxonomy.png);
-}
 #form-builder-field-palette ul li.field-textarea {
   background-image: url(images/fields/textarea.png);
 }
 #form-builder-field-palette ul li.field-textfield {
   background-image: url(images/fields/textfield.png);
 }
-#form-builder-field-palette ul li.field-title {
-  background-image: url(images/fields/title.png);
-}
-
diff --git a/sites/all/modules/form_builder/form_builder.garland.css b/sites/all/modules/form_builder/form_builder.garland.css
index abe75b9725f8c2dbde8333d5f87715b03298371c..a4f6d4f73a597c803e6491f1ae2fcbf3cf80f6db 100644
--- a/sites/all/modules/form_builder/form_builder.garland.css
+++ b/sites/all/modules/form_builder/form_builder.garland.css
@@ -1,8 +1,7 @@
-
 /**
  * @file
- *   Garland-specific theming for Form Builder. Expand the column to fit
- *   the add new field block (260px wide). 
+ * Garland-specific theming for Form Builder. Expand the column to fit the add
+ * new field block (260px wide).
  */
 
 body.sidebar-right #center {
@@ -19,3 +18,10 @@ body.sidebar-right #squeeze {
 body.sidebars #squeeze {
   margin: 0 280px 0 210px;
 }
+
+/* Style the tabs to work with the Garland fieldset gradient */
+#form-builder ul.form-builder-tabs li.active {
+  border-bottom: 1px solid #ebf4fa;
+  background: #ebf4fa;
+}
+
diff --git a/sites/all/modules/form_builder/form_builder.info b/sites/all/modules/form_builder/form_builder.info
index 70320e87f4dfd569f5c2c328da4cb5232ed39594..20e893b27fe3630a13c2d0c58aa738d3f0e0f475 100644
--- a/sites/all/modules/form_builder/form_builder.info
+++ b/sites/all/modules/form_builder/form_builder.info
@@ -3,9 +3,9 @@ description = Form building framework.
 dependencies[] = options_element
 core = 7.x
 
-; Information added by drupal.org packaging script on 2011-06-06
-version = "7.x-1.x-dev"
+; Information added by drupal.org packaging script on 2012-03-08
+version = "7.x-1.0"
 core = "7.x"
 project = "form_builder"
-datestamp = "1307319364"
+datestamp = "1331181344"
 
diff --git a/sites/all/modules/form_builder/form_builder.install b/sites/all/modules/form_builder/form_builder.install
index 7a3ba3e0a4206d09e36c97b8df6dfcc05d57ff45..04d5e5bfc4de132b061dffab71815526f26273cf 100644
--- a/sites/all/modules/form_builder/form_builder.install
+++ b/sites/all/modules/form_builder/form_builder.install
@@ -43,7 +43,7 @@ function form_builder_schema() {
         ),
       'form_id' => array(
         'type' => 'varchar',
-        'length' => '32',
+        'length' => '128',
         'not null' => FALSE,
       ),
       'type' => array(
@@ -84,3 +84,15 @@ function form_builder_update_7000() {
   );
   db_change_field('form_builder_cache', 'data', 'data', $spec);
 }
+
+/**
+ * Change the {form_builder_cache} table to use a longer form_id column.
+ */
+function form_builder_update_7001() {
+  $spec = array(
+    'type' => 'varchar',
+    'length' => '128',
+    'not null' => FALSE,
+  );
+  db_change_field('form_builder_cache', 'form_id', 'form_id', $spec);
+}
diff --git a/sites/all/modules/form_builder/form_builder.js b/sites/all/modules/form_builder/form_builder.js
index a8d4da24658b44c1706dd0ab294d532dbf3f5ce4..5968e7fadba4ce554fccfa6495369f21ac7d55cc 100644
--- a/sites/all/modules/form_builder/form_builder.js
+++ b/sites/all/modules/form_builder/form_builder.js
@@ -1,3 +1,4 @@
+
 (function($) {
 
 /**
@@ -7,13 +8,21 @@
 
 Drupal.behaviors.formBuilderElement = {};
 Drupal.behaviors.formBuilderElement.attach = function(context) {
-  var $wrappers = $('div.form-builder-wrapper', context);
-  var $elements = $('div.form-builder-element', context);
+  var $wrappers = $('div.form-builder-wrapper:not(.form-builder-processed)', context);
+  var $elements = $('div.form-builder-element:not(.form-builder-processed)', context);
 
   // If the context itself is a wrapper, add it to the list.
-  if ($(context).is('div.form-builder-wrapper')) {
+  if ($(context).is('div.form-builder-wrapper:not(.form-builder-processed)')) {
     $wrappers = $wrappers.add(context);
   }
+  // If the context itself is an element, add to the list.
+  else if ($(context).is('div.form-builder-element:not(.form-builder-processed)')) {
+    $elements = $elements.add(context);
+  }
+
+  // Add a guard class.
+  $wrappers.addClass('form-builder-processed');
+  $elements.addClass('form-builder-processed');
 
   // Add over effect on rollover.
   // The .hover() method is not used to avoid issues with nested hovers.
@@ -51,7 +60,7 @@ Drupal.behaviors.formBuilderElement.attach = function(context) {
 Drupal.behaviors.formBuilderFields = {};
 Drupal.behaviors.formBuilderFields.attach = function(context) {
   // Bind a function to all elements to update the preview on change.
-  var $configureForm = $('#form-builder-field-configure', context);
+  var $configureForm = $('#form-builder-field-configure');
 
   $configureForm.find('input, textarea, select')
     .not('.form-builder-field-change')
@@ -69,30 +78,32 @@ Drupal.behaviors.formBuilderFields.attach = function(context) {
  */
 Drupal.behaviors.formBuilder = {};
 Drupal.behaviors.formBuilder.attach = function(context) {
-  var formbuilder = $('#form-builder', context);
-
-  $('.form-builder-wrapper:not(.ui-draggable)', formbuilder).draggable({
-    opacity: 0.8,
+  var $formbuilder = $('#form-builder');
+  var $elements = $('.form-builder-wrapper').not('.form-builder-empty-placeholder').not('.ui-draggable');
+  $elements.draggable({
+    distance: 4, // Pixels before dragging starts.
+    handle: 'div.form-builder-title-bar, div.form-builder-element',
     helper: 'clone',
+    appendTo: $formbuilder,
+    opacity: 0.8,
+    scope: 'form-builder',
     scroll: true,
     scrollSensitivity: 50,
-    containment: 'body',
+    zIndex: 100,
     start: Drupal.formBuilder.startDrag,
-    stop: Drupal.formBuilder.stopDrag,
-    change: Drupal.formBuilder.checkFieldsets,
-    distance: 4,
-    scope: 'fields',
-    addClasses: false,
-    appendTo: '#form-builder-wrapper'
+    stop: Drupal.formBuilder.stopDrag
   });
 
-  // This sets the height of the drag target to be at least as hight as the field
+  // This sets the height of the drag target to be at least as high as the field
   // palette so that field can be more easily dropped into an empty form.  IE6
   // does not respect min-height but does treat height in the same manner that
   // min-height would be expected.  So a check for browser and version is needed
   // here.
   var property = $.browser.msie && $.browser.version < 7 ? 'height' : 'min-height';
-  formbuilder.css(property, $('#form-builder-fields').height());
+  $formbuilder.css(property, $('#form-builder-fields').height());
+
+  // Add the placeholder for an empty form.
+  Drupal.formBuilder.checkForm();
 };
 
 /**
@@ -117,6 +128,12 @@ Drupal.behaviors.formBuilderTabs.attach = function(context) {
   $tabs = $(tabs);
   $fieldsets.filter(':first').before($close).before($tabs);
 
+  // Remove 'fieldset-legend' class from tabs.
+  $tabs.find('.fieldset-legend').removeClass('fieldset-legend');
+
+  // Set clearfix on the parent div.
+  $tabs.parent().addClass('clearfix');
+
   // Hide all the fieldsets except the first.
   $fieldsets.not(':first').css('display', 'none');
   $tabs.find('li:first').addClass('active').click(Drupal.formBuilder.clickCancel);
@@ -144,28 +161,14 @@ Drupal.behaviors.formBuilderTabs.attach = function(context) {
 Drupal.behaviors.formBuilderDeleteConfirmation = {};
 Drupal.behaviors.formBuilderDeleteConfirmation.attach = function(context) {
   var $confirmForm = $('form.confirmation', context);
+
+  // If the confirmation form is the context.
+  if ($(context).is('form.confirmation')) {
+    $confirmForm = $(context);
+  }
+
   if ($confirmForm.length) {
-    $confirmForm.find('input[type=submit]').bind('click', function(event) {
-      event.preventDefault();
-      // Store the form and the options
-      var form = $confirmForm;
-      Drupal.formBuilder.ajaxOptions = {
-        url: form.attr('action'),
-        success: Drupal.formBuilder.deleteField,
-        error: Drupal.formBuilder.ajaxError,
-        type: 'post',
-        dataType: 'json',
-        action: 'deleteConfirmation',
-        data: form.serialize(),
-        tryCount: 0,
-        maxTry: 3
-      };
-      // Submit the form via ajax
-      $.ajax(Drupal.formBuilder.ajaxOptions);
-      // Bind this action to disable any submit buttons on the page.  It will be
-      // removed on success or after the retries have been exhausted.
-      $('form').submit(Drupal.formBuilder.preventSubmit);
-    });
+    $confirmForm.submit(Drupal.formBuilder.deleteField);
     $confirmForm.find('a').click(Drupal.formBuilder.clickCancel);
   }
 };
@@ -188,7 +191,7 @@ Drupal.behaviors.formBuilderBlockScroll = {};
 Drupal.behaviors.formBuilderBlockScroll.attach = function(context) {
   var $list = $('ul.form-builder-fields', context);
 
-  if ($list.length && $list.hasClass('block-scroll')) {
+  if ($list.length) {
     var $block = $list.parents('div.block:first').css('position', 'relative');
     var blockScrollStart = $block.offset().top;
 
@@ -198,7 +201,8 @@ Drupal.behaviors.formBuilderBlockScroll.attach = function(context) {
         return;
       }
 
-      var windowOffset = $(window).scrollTop();
+      var toolbarHeight = parseInt($('body.toolbar').css('padding-top'));
+      var windowOffset = $(window).scrollTop() + (toolbarHeight ? toolbarHeight : 0);
       var blockHeight = $block.height();
       var formBuilderHeight = $('#form-builder').height();
       if (windowOffset - blockScrollStart > 0) {
@@ -236,32 +240,13 @@ Drupal.behaviors.formBuilderNewField.attach = function(context) {
     $list.children('li:not(.ui-draggable)').draggable({
       opacity: 0.8,
       helper: 'clone',
+      scope: 'form-builder',
       scroll: true,
       scrollSensitivity: 50,
-      containment: 'body',
+      tolerance: 'pointer',
+      zIndex: 100,
       start: Drupal.formBuilder.startDrag,
-      stop: Drupal.formBuilder.stopDrag,
-      distance: 4,
-      scope: 'fields',
-      appendTo: '#form-builder-wrapper'
-    })
-    .bind('click', function(event) {
-      event.preventDefault();
-      event.stopPropagation();
-      var item = $(this).clone();
-      // Add a drop target at the bottom of the form to automatically drop the
-      // element onto.
-      var placeholder = $('<div class="form-builder-placeholder"></div>');
-      placeholder
-        .appendTo('#form-builder')
-        .droppable({
-          scope: 'fields',
-          drop: Drupal.formBuilder.drop
-        });
-      Drupal.formBuilder.drop({data: placeholder}, {draggable: item});
-      // Pass the element to the stopDrag method so that unique elements are
-      // properly hidden in the palette.
-      Drupal.formBuilder.stopDrag.apply(this);
+      stop: Drupal.formBuilder.stopDrag
     });
   }
 };
@@ -276,13 +261,17 @@ Drupal.formBuilder = {
   activeElement: false,
   // Variable holding the active drag object (if any).
   activeDragUi: false,
+  // Variables to keep trak of the current and previous drop target. Used to
+  // prevent overlapping targets from being shown as active at the same time.
+  activeDropzone: false,
+  previousDropzones: [],
   // Variable of the time of the last update, used to prevent old data from
   // replacing newer updates.
   lastUpdateTime: 0,
   // Status of mouse click.
   mousePressed: 0,
-  // Field configure form target
-  fieldConfigureHolder: false
+  // Selector for a custom field configuration form.
+  fieldConfigureForm: false
 };
 
 /**
@@ -319,11 +308,10 @@ Drupal.formBuilder.clickField = function(e) {
     return;
   }
 
-  var wrapper = $(this).parents('.form-builder-wrapper:first');
-  // This will get the first configure link that does not belong to a nested form element
-  // inside this form element.
-  var link = wrapper.find('a.configure').not(wrapper.find('.form-builder-element .form-builder-element a')).get(0);
-  
+  // Find the first configure link for this field, ensuring we don't get a link
+  // belonging to a nested form element within this element.
+  var $wrapper = $(this).parents('.form-builder-wrapper:first');
+  var link = $wrapper.find('a.configure').not($wrapper.find('.form-builder-element .form-builder-element a')).get(0);
   Drupal.formBuilder.editField.apply(link);
 
   return false;
@@ -339,59 +327,44 @@ Drupal.formBuilder.disableField = function(e) {
 /**
  * Load the edit form from the server.
  */
-Drupal.formBuilder.editField = function(event) {
-  if (event && $(event.target).is('a')) {
-    event.stopPropagation();
-  }
-  var element = $(this).parents('div.form-builder-wrapper').get(0);
-  var link = $(this);
+Drupal.formBuilder.editField = function() {
+  var $element = $(this).parents('div.form-builder-wrapper');
+  var $link = $(this);
 
   // Prevent duplicate clicks from taking effect if already handling a click.
   if (Drupal.formBuilder.updatingElement) {
     return false;
   }
 
-  link.addClass('progress');
+  // Show loading indicators.
+  $link.addClass('progress');
 
   // If clicking on the link a second time, close the form instead of open.
-  if (element == Drupal.formBuilder.activeElement && link.get(0) == Drupal.formBuilder.activeLink) {
+  if ($element.get(0) == Drupal.formBuilder.activeElement && $link.get(0) == Drupal.formBuilder.activeLink) {
     Drupal.formBuilder.closeActive(function() {
-      link.removeClass('progress');
-      if (Drupal.formBuilder.fieldConfigureForm) {
-        Drupal.formBuilder.fieldConfigureForm.html($('<div class="field-settings-message">' + Drupal.t('No field selected') + '</div>'));
-      }
+      $link.removeClass('progress');
     });
     Drupal.formBuilder.unsetActive();
     return false;
   }
 
-  if (!Drupal.formBuilder.fieldConfigureForm) {
-    $('<div id="#form-builder-field-configure" class="form-builder-field-configure"><div class="field-settings-message">' + Drupal.t('Loading...') + '</div></div>').appendTo(element);
-  } else {
-    $('.field-settings-message').remove();
-    Drupal.formBuilder.fieldConfigureForm.append($('<div class="field-settings-message">' + Drupal.t('Loading...') + '</div>'));
-  }
-  
-
   var getForm = function() {
-    Drupal.formBuilder.ajaxOptions = {
-      url: link.attr('href'),
+    if (Drupal.formBuilder.fieldConfigureForm) {
+      $(Drupal.formBuilder.fieldConfigureForm).html(Drupal.settings.formBuilder.fieldLoading);
+    }
+
+    $.ajax({
+      url: $link.attr('href'),
       type: 'GET',
       dataType: 'json',
       data: 'js=1',
-      success: Drupal.formBuilder.displayForm,
-      error: Drupal.formBuilder.ajaxError,
-      errorMessage: Drupal.t('Form could not be loaded at this time. Please try again later.'),
-      tryCount: 0,
-      maxTry: 3
-    }
-    
-    $.ajax(Drupal.formBuilder.ajaxOptions);
+      success: Drupal.formBuilder.displayForm
+    });
   };
 
   Drupal.formBuilder.updatingElement = true;
   Drupal.formBuilder.closeActive(getForm);
-  Drupal.formBuilder.setActive(element, link.get(0));
+  Drupal.formBuilder.setActive($element.get(0), $link.get(0));
 
   return false;
 };
@@ -399,24 +372,17 @@ Drupal.formBuilder.editField = function(event) {
 /**
  * Click handler for deleting a field.
  */
-Drupal.formBuilder.deleteField = function(callback) {
-  var active = $(Drupal.formBuilder.activeElement);
-  // Renable form submission.
-  $('form').unbind('submit', Drupal.formBuilder.preventSubmit);
-  active.fadeOut(function() {
+Drupal.formBuilder.deleteField = function() {
+  $(this).parents('div.form-builder-wrapper:first').animate({ height: 'hide', opacity: 'hide' }, 'normal', function() {
     // If this is a unique field, show the field in the palette again.
-    var elementId = active.find('.form-builder-element').attr('id');
+    var elementId = $(this).find('div.form-builder-element').attr('id');
     $('ul.form-builder-fields').find('li.' + elementId).show('slow');
     // Remove the field from the form.
-    active.remove();
-    // Close the form and unset the active element
-    Drupal.formBuilder.clickCancel();
-    // Check for empty fieldsets.
-    Drupal.formBuilder.checkFieldsets(null, null, true);
-
-    if (callback && $.isFunction(callback)) {
-      callback();
-    }
+    $(this).remove();
+
+    // Check for an entirely empty form and for empty fieldsets.
+    Drupal.formBuilder.checkForm();
+    Drupal.formBuilder.checkFieldsets([], true);
   });
 };
 
@@ -430,20 +396,23 @@ Drupal.formBuilder.clickCancel = function() {
  * Display the edit form from the server.
  */
 Drupal.formBuilder.displayForm = function(response) {
+  // Update Drupal settings.
   if (response.settings) {
     $.extend(true, Drupal.settings, response.settings);
   }
+
   var $preview = $('#form-builder-element-' + response.elementId);
-  var $form = $(response.html)
-  if (!Drupal.formBuilder.fieldConfigureForm) {
-    $('.form-builder-field-configure').html($form);
+  var $form = $(response.html);
+
+  if (Drupal.formBuilder.fieldConfigureForm) {
+    $(Drupal.formBuilder.fieldConfigureForm).html($form);
     $form.css('display', 'none');
-  } else {
-    Drupal.formBuilder.fieldConfigureForm.html($form);
-    $form.css('visibility: hidden');
   }
-  $('.field-settings-message').remove();
-  Drupal.attachBehaviors($form.parent().get(0));
+  else {
+    $form.insertAfter($preview).css('display', 'none');
+  }
+
+  Drupal.attachBehaviors($form.get(0));
 
   $form
     // Add the ajaxForm behavior to the new form.
@@ -452,16 +421,13 @@ Drupal.formBuilder.displayForm = function(response) {
     // Manually add a hidden element to pass additional data on submit.
     .prepend('<input type="hidden" name="return" value="field" />')
     // Add in any messages from the server.
-    .find('fieldset:visible:first').prepend(response.messages);
+    .find('fieldset:first').find('.fieldset-wrapper:first').prepend(response.messages);
 
-  $form.css({visibility: 'visible', display: 'none'});
   $form.slideDown(function() {
-    $preview.parents('.form-builder-wrapper:first').find('a.progress').removeClass('progress');
+    $preview.parents('div.form-builder-wrapper:first').find('a.progress').removeClass('progress');
+    $form.find('input:visible:first').focus();
   });
 
-  // Give focus to the form
-  $form.find('input:visible:first').focus();
-
   Drupal.formBuilder.updatingElement = false;
 };
 
@@ -470,25 +436,10 @@ Drupal.formBuilder.displayForm = function(response) {
  */
 Drupal.formBuilder.elementChange = function() {
   if (!Drupal.formBuilder.updatingElement) {
-    // Store the form and the options
-    var form = $(this).parents('form:first');
-    Drupal.formBuilder.ajaxOptions = {
-      url: form.attr('action'),
+    $(this).parents('form:first').ajaxSubmit({
       success: Drupal.formBuilder.updateElement,
-      error: Drupal.formBuilder.ajaxError,
-      type: 'post',
-      dataType: 'json',
-      errorMessage: Drupal.t('Field could not be updated at this time. Please try again later.'),
-      data: form.serialize(),
-      tryCount: 0,
-      maxTry: 3
-    };
-    // Submit the form via ajax
-    $.ajax(Drupal.formBuilder.ajaxOptions);
-
-    // Bind this action to disable any submit buttons on the page.  It will be
-    // removed on success or after the retries have been exhausted.
-    $('form').submit(Drupal.formBuilder.preventSubmit);
+      dataType: 'json'
+    });
   }
 
   // Clear any pending updates until further changes are made.
@@ -499,23 +450,6 @@ Drupal.formBuilder.elementChange = function() {
   Drupal.formBuilder.updatingElement = true;
 };
 
-Drupal.formBuilder.ajaxError = function (XMLHttpRequest, textStatus, errorThrown) {
-  var options = Drupal.formBuilder.ajaxOptions;
-  var message = this.errorMessage ? this.errorMessage : 'Unable to reach server.  Please try again later.';
-
-  options.tryCount++;
-  if (options.tryCount <= options.maxTry) {
-    $.ajax(options);
-  } else {
-    $('form').unbind('submit', Drupal.formBuilder.preventSubmit);
-    alert(message);
-  }
-};
-
-Drupal.formBuilder.preventSubmit = function (event) {
-  event.preventDefault();
-}
-
 /**
  * Update a field after a delay.
  *
@@ -547,7 +481,7 @@ Drupal.formBuilder.elementPendingChange = function(e) {
  * After submitting the change to the server, display the updated element.
  */
 Drupal.formBuilder.updateElement = function(response) {
-  var $configureForm = $('.form-builder-field-configure');
+  var $configureForm = $('#form-builder-field-configure');
 
   // Do not let older requests replace newer updates.
   if (response.time < Drupal.formBuilder.lastUpdateTime) {
@@ -574,56 +508,41 @@ Drupal.formBuilder.updateElement = function(response) {
   // Display messages, if any.
   $configureForm.find('.messages').remove();
   if (response.messages) {
-    $configureForm.find('fieldset:visible:first').prepend(response.messages);
+    $configureForm.find('fieldset:visible:first').find('.fieldset-wrapper:first').prepend(response.messages);
   }
 
   // Do not update the element if errors were received.
   if (!response.errors) {
     var $exisiting = $('#form-builder-element-' + response.elementId);
-    var $new = $(response.html).find('.form-builder-element:first');
+    var $new = $(response.html).find('div.form-builder-element:first');
     $exisiting.replaceWith($new);
 
     // Expand root level fieldsets after updating to prevent them from closing
     // after every update.
     $new.children('fieldset.collapsible').removeClass('collapsed');
-    Drupal.attachBehaviors($new.parent().get(0));
+    Drupal.attachBehaviors($new.get(0));
   }
 
   // Set the variable stating we're done updating.
   Drupal.formBuilder.updatingElement = false;
-  $('form').unbind('submit', Drupal.formBuilder.preventSubmit);
 };
 
 /**
  * When adding a new field, remove the placeholder and insert the new element.
  */
 Drupal.formBuilder.addElement = function(response) {
-  // This is very similar to the update element callback, only we replace the
-  // entire wrapper instead of just the element.
+  // Update Drupal settings.
   if (response.settings) {
     $.extend(true, Drupal.settings, response.settings);
   }
-  var $exisiting = $('.form-builder-new-field');
-  var $new = $(response.html);
+
+  // This is very similar to the update element callback, only we replace the
+  // entire wrapper instead of just the element.
+  var $exisiting = $('#form-builder-element-' + response.elementId).parent();
+  var $new = $(response.html).find('div.form-builder-element:first').parent();
   $exisiting.replaceWith($new);
   Drupal.attachBehaviors($new.get(0));
 
-  $new.draggable('destroy');
-  $new.draggable({
-    opacity: 0.8,
-    helper: 'clone',
-    scroll: true,
-    scrollSensitivity: 50,
-    containment: 'body',
-    start: Drupal.formBuilder.startDrag,
-    stop: Drupal.formBuilder.stopDrag,
-    change: Drupal.formBuilder.checkFieldsets,
-    distance: 4,
-    scope: 'fields',
-    addClasses: false,
-    appendTo: '#form-builder-wrapper'
-  });
-
   // Set the variable stating we're done updating.
   Drupal.formBuilder.updatingElement = false;
 
@@ -631,23 +550,25 @@ Drupal.formBuilder.addElement = function(response) {
   $('#form-builder-positions').replaceWith(response.positionForm);
 
   // Submit the new positions form to save the new element position.
-  Drupal.formBuilder.updateElementPosition($new);
+  Drupal.formBuilder.updateElementPosition($new.get(0));
 };
 
 /**
  * Given an element, update it's position (weight and parent) on the server.
  */
 Drupal.formBuilder.updateElementPosition = function(element) {
+  var $element = $(element);
+
   // Update weights of all children within this element's parent.
-  element.parent().children('.form-builder-wrapper').each(function(index) {
-    var child_id = $(this).children('.form-builder-element:first').attr('id');
+  $element.parent().children('div.form-builder-wrapper').each(function(index) {
+    var child_id = $(this).children('div.form-builder-element:first').attr('id');
     $('#form-builder-positions input.form-builder-weight').filter('.' + child_id).val(index);
   });
 
   // Update this element's parent.
-  var $parent = element.parents('.form-builder-element:first');
+  var $parent = $element.parents('div.form-builder-element:first');
   var parent_id = $parent.length ? $parent.attr('id').replace(/form-builder-element-(.*)/, '$1') : 0;
-  var child_id = element.children('.form-builder-element:first').attr('id');
+  var child_id = $element.children('div.form-builder-element:first').attr('id');
   $('#form-builder-positions input.form-builder-parent').filter('.' + child_id).val(parent_id);
 
   // Submit the position form via AJAX to save the new weights and parents.
@@ -655,163 +576,139 @@ Drupal.formBuilder.updateElementPosition = function(element) {
 };
 
 /**
- * Called when a field has been moved via Sortables.
+ * Called when a field is about to be moved via Sortables.
  *
  * @param e
  *   The event object containing status information about the event.
  * @param ui
  *   The jQuery Sortables object containing information about the sortable.
  */
-Drupal.formBuilder.drop = function(e, ui) {
-  var element = ui.draggable;
-  var placeholder = e.data ? $(e.data) : $(this);
-  
-  // If no drop target is hit, add the component to the end of the form.
-  if (placeholder.is('#form-builder')) {
-    placeholder = placeholder.children(':last');
-  } else if (placeholder.is('.form-builder-wrapper:not(.form-builder-empty-placeholder)')) {
-    placeholder = placeholder.next('.form-builder-placeholder');
+Drupal.formBuilder.startDrag = function(e, ui) {
+  Drupal.formBuilder.activeDragUi = ui;
+
+  var $this = $(this);
+  if ($this.hasClass('form-builder-unique') || $this.hasClass('form-builder-wrapper')) {
+    $this.hide();
+  }
+
+  // Check fieldsets and add placeholder text if needed.
+  Drupal.formBuilder.checkFieldsets([this, ui.helper]);
+
+  // Create the drop targets in between the form elements.
+  Drupal.formBuilder.createDropTargets(this, ui.helper);
+};
+
+/**
+ * Creates drop targets for the dragged element to be dropped into.
+ */
+Drupal.formBuilder.createDropTargets = function(draggable, helper) {
+  var $placeholder = $('<div class="form-builder-placeholder"></div>');
+  var $elements = $('#form-builder .form-builder-wrapper:not(.form-builder-empty-placeholder)').not(draggable).not(helper);
+
+  if ($elements.length == 0) {
+    // There are no form elements, insert a placeholder
+    var $formBuilder = $('#form-builder');
+    $placeholder.height($formBuilder.height());
+    $placeholder.appendTo($formBuilder);
   }
+  else {
+    $elements.each(function(i) {
+      $placeholder.clone().insertAfter(this);
+      // If the element is the first in its container, add a drop target above it.
+      if (this == $(this).parent().children('.form-builder-wrapper:not(.ui-draggable-dragging)').not(draggable)[0]) {
+        $placeholder.clone().insertBefore(this);
+      }
+    });
+  }
+
+  // Enable the drop targets
+  $('#form-builder').find('.form-builder-placeholder, .form-builder-empty-placeholder').droppable({
+    greedy: true,
+    scope: 'form-builder',
+    tolerance: 'pointer',
+    drop: Drupal.formBuilder.dropElement,
+    over: Drupal.formBuilder.dropHover,
+    out: Drupal.formBuilder.dropHover
+  });
+};
 
+/**
+ * Handles form elements being dropped onto the form.
+ *
+ * Existing elements will trigger a reorder, while new elements will be added in
+ * place to the form.
+ */
+Drupal.formBuilder.dropElement = function (event, ui) {
+  var $element = ui.draggable;
+  var $placeholder = $(this);
+  
   // If the element is a new field from the palette, update it with a real field.
-  if (element.is('.ui-draggable')) {
+  if ($element.is('.form-builder-palette-element')) {
     var name = 'new_' + new Date().getTime();
     // If this is a "unique" element, its element ID is hard-coded.
-    if (element.is('.form-builder-unique')) {
-      name = element.className.replace(/^.*?form-builder-element-([a-z0-9_]+).*?$/, '$1');
+    if ($element.is('.form-builder-unique')) {
+      name = $element.get(0).className.replace(/^.*?form-builder-element-([a-z0-9_]+).*?$/, '$1');
     }
 
     var $ajaxPlaceholder = $('<div class="form-builder-wrapper form-builder-new-field"><div id="form-builder-element-' + name + '" class="form-builder-element"><span class="progress">' + Drupal.t('Please wait...') + '</span></div></div>');
-    placeholder.replaceWith($ajaxPlaceholder);
 
-    Drupal.formBuilder.ajaxOptions = {
-      url: element.find('a').attr('href'),
+    $.ajax({
+      url: $element.find('a').attr('href'),
       type: 'GET',
       dataType: 'json',
       data: 'js=1&element_id=' + name,
-      success: Drupal.formBuilder.addElement,
-      error: Drupal.formBuilder.ajaxError,
-      errorMessage: Drupal.t('Element could not be added at this time. Please try again later.'),
-      tryCount: 0,
-      maxTry: 3
-    };
-    $.ajax(Drupal.formBuilder.ajaxOptions);
+      success: Drupal.formBuilder.addElement
+    });
+
+    $placeholder.replaceWith($ajaxPlaceholder);
 
     Drupal.formBuilder.updatingElement = true;
   }
   // Update the positions (weights and parents) in the form cache.
   else {
-    placeholder.replaceWith(element);
-    element.removeClass('original').show();
+    $element.removeAttr('style');
+    $placeholder.replaceWith($element);
     ui.helper.remove();
-    Drupal.formBuilder.updateElementPosition(element);
-
-    // Select the element
-    element.find('a.configure').click();
+    Drupal.formBuilder.updateElementPosition($element.get(0));
   }
 
   Drupal.formBuilder.activeDragUi = false;
-  $('#form-builder .form-builder-placeholder').remove();
-  
-  // Update empty fieldsets
-  Drupal.formBuilder.checkFieldsets();
 
   // Scroll the palette into view.
-  $(window).scroll();
+  $(window).triggerHandler('scroll');
 };
 
 /**
- * Called when a field is about to be moved from the new field palette.
- *
- * @param e
- *   The event object containing status information about the event.
- * @param ui
- *   The jQuery Sortables object containing information about the sortable.
+ * Adjusts the placeholder height for drop targets as they are hovered-over.
  */
-Drupal.formBuilder.startDrag = function(e, ui) {
-  var $this = $(this);
-  // Check to see if this has been pulled out of a fieldset.
-  Drupal.formBuilder.checkFieldsets();
-
-  ui.helper.width($(this).width());
-
-  if ($this.is('.form-builder-unique')) {
-    $this.css('visibility', 'hidden');
-  }
-  if ($this.is('.form-builder-wrapper')) {
-    $this.hide();
-  }
-  $this.addClass('original');
-
-  var isPagebreak = false;
-  if ($this.children('.form-builder-element-pagebreak').length > 0) {
-    isPagebreak = true;
-  }
-  if ($this.is('.field-pagebreak')) {
-    isPagebreak = true;
-  }
-
-  // Grab the formbuilder and fields and store the placeholder markup.
-  var formbuilder = $('#form-builder');
-  var fields = $('#form-builder').find('.form-builder-wrapper')
-    .not(this)
-    .not('.form-builder-empty-placeholder')
-    .not($('.original *'));
-  var placeholder = '<div class="form-builder-placeholder"></div>';
-
-  // Add a drop target at the bottom of the form.
-  $(placeholder).appendTo(formbuilder);
-
-  if (fields.length) {
-    // Insert a drop target after each field.
-    $(placeholder).insertBefore(fields);
-    // If we're not dragging a page break, add a drop target at the bottom of each fieldset.
-    if (!isPagebreak) {
-      $(placeholder).appendTo('.fieldset-wrapper:not(:has(.form-builder-empty-placeholder))');
+Drupal.formBuilder.dropHover = function (event, ui) {
+  if (event.type == 'dropover') {
+    // In the event that two droppables overlap, the latest one acts as the drop
+    // target. If there is previous active droppable hide it temporarily.
+    if (Drupal.formBuilder.activeDropzone) {
+      $(Drupal.formBuilder.activeDropzone).css('display', 'none');
+      Drupal.formBuilder.previousDropzones.push(Drupal.formBuilder.activeDropzone);
     }
-  } else {
-    // The form is empty, so make the placeholder at least the size of the form.
-    formbuilder.find('.form-builder-placeholder').css('min-height', formbuilder.css('height'));
-  }
-
-  var height = formbuilder.height();
-  formbuilder.children(':visible:not(.form-builder-placeholder)').each(function() {
-    height = height - $(this).outerHeight(true);
-  });
-  if (height > 0) {
-    $('.form-builder-placeholder:last').css('min-height', height);
+    $(this).css({ height: ui.helper.height() + 'px', display: ''}).addClass('form-builder-placeholder-hover');
+    Drupal.formBuilder.activeDropzone = this;
   }
+  else {
+    $(this).css({ height: '', display: '' }).removeClass('form-builder-placeholder-hover');
 
-  // Activate all the placeholders as drop targets.
-  var placeholders = $('.form-builder-placeholder, .form-builder-empty-placeholder');
-  if (isPagebreak) {
-    placeholders = placeholders.not('.fieldset-wrapper .form-builder-placeholder').not('.fieldset-wrapper .form-builder-empty-placeholder');
+    // If this was active drop target, we remove the active state.
+    if (Drupal.formBuilder.activeDropzone && Drupal.formBuilder.activeDropzone == this) {
+      Drupal.formBuilder.activeDropzone = false;
+    }
+    // If there is a previous drop target that was hidden, restore it.
+    if (Drupal.formBuilder.previousDropzones.length) {
+      $(Drupal.formBuilder.previousDropzones).css('display', '');
+      Drupal.formBuilder.activeDropzone = Drupal.formBuilder.previousDropzones.pop;
+    }
   }
-  
-  placeholders.droppable({
-    scope: 'fields',
-    tolerance: 'touch',
-    over: Drupal.formBuilder.over,
-    out: Drupal.formBuilder.out,
-    drop: Drupal.formBuilder.drop
-  });
-
-  // Add droppable to form elements without the over / out methods
-  $('.form-builder-wrapper').droppable({
-    scope: 'fields',
-    tolerance: 'touch',
-    drop: Drupal.formBuilder.drop
-  });
-
-  // Retain the dimensions of the draggable
-  ui.helper.width($this.width());
-  ui.helper.height($this.height());
-
-  Drupal.formBuilder.activeDragUi = ui;
 };
 
 /**
- * Called after a field has been moved from the new field palette.
+ * Called when a field has stopped moving via draggable.
  *
  * @param e
  *   The event object containing status information about the event.
@@ -820,75 +717,75 @@ Drupal.formBuilder.startDrag = function(e, ui) {
  */
 Drupal.formBuilder.stopDrag = function(e, ui) {
   var $this = $(this);
-  // Remove the droppable from all elements within the form
-  $('#form-builder .ui-droppable').droppable('destroy');
-
   // If the activeDragUi is still set, we did not drop onto the form.
   if (Drupal.formBuilder.activeDragUi) {
-    ui.helper.remove();
-    Drupal.formBuilder.activeDragUi = false;
-    $this.css('visibility', '').show().removeClass('original');
-    $(window).scroll();
-    // Remove the placeholders
-    $('#form-builder .form-builder-placeholder').remove();
-    
-    Drupal.formBuilder.checkFieldsets();
-  }
-  // If dropped onto the form and a unique field, remove it from the palette.
-  else if ($this.is('.form-builder-unique')) {
-    $this.animate({height: '0', width: '0'}, function() {
-      $this.css({visibility: '', height: '', width: '', display: 'none'});
-    });
+    if ($this.hasClass('form-builder-unique') || $this.hasClass('form-builder-wrapper')) {
+      $this.show();
+    }
   }
-};
 
-/**
- * These functions add and remove a class to a drop target and adjust its height
- * to the height of the item being dragged.
- */
-Drupal.formBuilder.over = function(e, ui) {
-  var $this = $(this);
-  if (!$this.is('.form-builder-empty-placeholder')) {
-    $this.height(ui.draggable.height());
-  }
-  $this.parent().find('.over').height(0);
-  $this.addClass('over');
-}
+  // Remove the placeholders and reset the hover state for all for elements
+  $('#form-builder .form-builder-placeholder').remove();
+  $('#form-builder .form-builder-hover').removeClass('form-builder-hover');
 
-Drupal.formBuilder.out = function(e, ui) {
-  var $this = $(this);
-  if (!$this.is('.form-builder-empty-placeholder')) {
-    $this.height(0);
-  }
-  $this.removeClass('over');
+  Drupal.formBuilder.checkFieldsets();
+
+  // Scroll the palette into view.
+  $(window).triggerHandler('scroll');
 };
 
 /**
  * Insert DIVs into empty fieldsets so that items can be dropped within them.
  *
  * This function is called every time an element changes positions during
- * a Sortables drag and drop operation.
+ * a drag and drop operation. Fieldsets are considered empty if they have no
+ * immediate children or they only contain exclusions.
  *
- * @param e
- *   The event object containing status information about the event.
- * @param ui
- *   The jQuery Sortables object containing information about the sortable.
- * @param
+ * @param exclusions
+ *   An array of DOM objects within a fieldset that should not be included when
+ *   checking if the fieldset is empty.
  */
-Drupal.formBuilder.checkFieldsets = function(e, ui, expand) {
-  var $fieldsets = $('#form-builder div.form-builder-element fieldset.form-builder-fieldset div.fieldset-wrapper');
-
-  // Find all empty fieldsets.
-  $fieldsets.each(function() {
-    // Remove placeholders.
-    $(this).children('.form-builder-empty-placeholder').remove();
-    // If there are no visible children after placeholders are removed, add a placeholder.
-    if ($(this).children(':not(.description):visible').length == 0) {
-      $(Drupal.settings.formBuilder.emptyFieldset).appendTo(this);
+Drupal.formBuilder.checkFieldsets = function(exclusions, animate) {
+  var $wrappers = $('#form-builder div.form-builder-element > fieldset.form-builder-fieldset > div.fieldset-wrapper');
+
+  // Make sure exclusions is an array and always skip any description.
+  exclusions = exclusions ? exclusions : [];
+  exclusions.push('.fieldset-description');
+
+  // Insert a placeholder into all empty fieldset wrappers.
+  $wrappers.each(function() {
+    var children = $(this).children(':visible, :not(.ui-draggable-dragging)');
+    for (var i in exclusions) {
+      children = children.not(exclusions[i]);
+    }
+
+    if (children.length == 0) {
+      // No children, add a placeholder.
+      if (animate) {
+        $(Drupal.settings.formBuilder.emptyFieldset).css('display', 'none').appendTo(this).slideDown();
+      }
+      else {
+        $(Drupal.settings.formBuilder.emptyFieldset).appendTo(this);
       }
+    }
+    else if (children.length > 1 && children.hasClass('form-builder-empty-placeholder')) {
+      // The fieldset has at least one element besides the placeholder, remove
+      // the placeholder.
+      $(this).find('.form-builder-empty-placeholder').remove();
+    }
   });
 };
 
+/**
+ * Check the root form tag and place explanatory text if the form is empty.
+ */
+Drupal.formBuilder.checkForm = function() {
+  var $formBuilder = $('#form-builder');
+  if ($formBuilder.children('div.form-builder-wrapper').length == 0) {
+    $formBuilder.append(Drupal.settings.formBuilder.emptyForm);
+  }
+};
+
 Drupal.formBuilder.setActive = function(element, link) {
   Drupal.formBuilder.unsetActive();
   Drupal.formBuilder.activeElement = element;
@@ -906,19 +803,23 @@ Drupal.formBuilder.unsetActive = function() {
 
 Drupal.formBuilder.closeActive = function(callback) {
   if (Drupal.formBuilder.activeElement) {
-    var $activeForm = Drupal.formBuilder.fieldConfigureForm ? Drupal.formBuilder.fieldConfigureForm.find('form') : $(Drupal.formBuilder.activeElement).find('form');
+    var $activeForm = Drupal.formBuilder.fieldConfigureForm ? $(Drupal.formBuilder.fieldConfigureForm).find('form') : $(Drupal.formBuilder.activeElement).find('form');
 
     if ($activeForm.length) {
       Drupal.freezeHeight();
       $activeForm.slideUp(function(){
         $(this).remove();
-        if (callback && $.isFunction(callback)) {
+        // Set a message in the custom configure form location if it exists.
+        if (Drupal.formBuilder.fieldConfigureForm) {
+          $(Drupal.formBuilder.fieldConfigureForm).html(Drupal.settings.formBuilder.noFieldSelected);
+        }
+        if (callback) {
           callback.call();
         }
       });
     }
   }
-  else if (callback) {
+  else if (callback && $.isFunction(callback)) {
     callback.call();
   }
 
@@ -945,4 +846,4 @@ Drupal.formBuilder.fixTableDragTabs = function(context) {
   }
 };
 
-})(jQuery);
\ No newline at end of file
+})(jQuery);
diff --git a/sites/all/modules/form_builder/form_builder.module b/sites/all/modules/form_builder/form_builder.module
index 84b8fec960249daf996846bef219bc54973a03b0..642d8e9808fd5c2b6c80d9bbad6be7f199019a2e 100644
--- a/sites/all/modules/form_builder/form_builder.module
+++ b/sites/all/modules/form_builder/form_builder.module
@@ -73,10 +73,22 @@ function form_builder_theme() {
       'render element' => 'element',
       'file' => 'includes/form_builder.admin.inc',
     ),
+    'form_builder_empty_form' => array(
+      'variables' => array(),
+      'file' => 'includes/form_builder.admin.inc',
+    ),
     'form_builder_empty_fieldset' => array(
       'variables' => array(),
       'file' => 'includes/form_builder.admin.inc',
     ),
+    'form_builder_no_field_selected' => array(
+      'variables' => array(),
+      'file' => 'includes/form_builder.admin.inc',
+    ),
+    'form_builder_field_loading' => array(
+      'variables' => array(),
+      'file' => 'includes/form_builder.admin.inc',
+    ),
     'form_builder_field_palette' => array(
       'variables' => array('fields' => NULL, 'groups' => NULL, 'form_type' => NULL, 'form_id' => NULL),
       'file' => 'includes/form_builder.admin.inc',
@@ -101,7 +113,7 @@ function form_builder_block_info() {
  */
 function form_builder_block_view($delta = '') {
   $block = array();
-  if ($delta == 'fields') {
+  if ($delta == 'fields' && form_builder_active_form()) {
     module_load_include('inc', 'form_builder', 'includes/form_builder.admin');
     $block['content'] = form_builder_field_palette();
   }
@@ -161,6 +173,9 @@ function form_builder_form_builder_properties($form_type) {
     'description' => array(
       'form' => 'form_builder_property_description_form',
     ),
+    'disabled' => array(
+      'form' => 'form_builder_property_disabled_form',
+    ),
     'weight' => array(
       'form' => 'form_builder_property_weight_form',
     ),
diff --git a/sites/all/modules/form_builder/includes/form_builder.admin.inc b/sites/all/modules/form_builder/includes/form_builder.admin.inc
index 4665348b374c6ecc91d4e3ab6b30ba762f3617a2..5f0e1a2b2cf63481eb92863d3910144f2ec70a3d 100644
--- a/sites/all/modules/form_builder/includes/form_builder.admin.inc
+++ b/sites/all/modules/form_builder/includes/form_builder.admin.inc
@@ -198,7 +198,18 @@ function form_builder_preview($f, &$form_state, $form, $form_type, $form_id) {
   $form['#attached']['library'][] = array('system', 'form');
   $form['#attached']['js'][] = 'misc/form.js';
   $form['#attached']['js'][] = 'misc/collapse.js';
-  $form['#attached']['js'][] = array('data' => array('formBuilder' => array('emptyFieldset' => theme('form_builder_empty_fieldset'))), 'type' => 'setting');
+
+  $form['#attached']['js'][] = array('data' => array('machineName' => array()), 'type' => 'setting');
+  $form['#attached']['js'][] = 'misc/machine-name.js';
+
+  $settings = array(
+    'emptyForm' => theme('form_builder_empty_form'),
+    'emptyFieldset' => theme('form_builder_empty_fieldset'),
+    'noFieldSelected' => theme('form_builder_no_field_selected'),
+    'fieldLoading' => theme('form_builder_field_loading'),
+  );
+
+  $form['#attached']['js'][] = array('data' => array('formBuilder' => $settings), 'type' => 'setting');
 
   $form['#attached']['css'][] = drupal_get_path('module', 'form_builder') .'/form_builder.css';
   $form['#attached']['css'][] = drupal_get_path('module', 'options_element') .'/options_element.css';
@@ -300,8 +311,8 @@ function theme_form_builder_wrapper($variables) {
   $element = $variables['element'];
 
   $output = '';
-  $output .= '<div id="form-builder-wrapper" class="' . ($element['#block_enabled'] ? 'no-palette' : 'with-palette') . '">';
-  if (!$element['#block_enabled']) {
+  $output .= '<div id="form-builder-wrapper" class="' . ($element['#show_palette'] ? 'with-palette' : 'no-palette') . '">';
+  if ($element['#show_palette']) {
     $output .= '<div id="form-builder-fields">';
     $output .= '<div class="block">';
     $output .= form_builder_field_palette();
@@ -311,7 +322,7 @@ function theme_form_builder_wrapper($variables) {
 
   $output .= '<div id="form-builder">';
   if (isset($element['#title'])) {
-    $output .= '<h3>' . $element['#title'] . '</h3>';
+    $output .= '<h3 class="form-builder-title">' . $element['#title'] . '</h3>';
   }
 
   // Add the contents of the form and close the wrappers.
@@ -359,13 +370,52 @@ function theme_form_builder_element_wrapper($variables) {
   return $output;
 }
 
+/**
+ * Placeholder for an entirely empty form before any fields are added.
+ */
+function theme_form_builder_empty_form($variables) {
+  $output = '';
+  $output .= '<div class="form-builder-empty-form form-builder-empty-placeholder">';
+  $output .= '<span>' . t('Drag a field from the palette to add it to this form.') . '</span>';
+  $output .= '</div>';
+  return $output;
+}
+
 /**
  * Placeholder for empty fieldsets during drag and drop.
  */
 function theme_form_builder_empty_fieldset($variables) {
   $output = '';
   $output .= '<div class="form-builder-wrapper form-builder-empty-placeholder">';
-  $output .= '<span>' . t('This fieldset is empty. Drag a form element into it.') .'</span>';
+  $output .= '<span>' . t('This fieldset is empty. Drag a form element into it.') . '</span>';
+  $output .= '</div>';
+  return $output;
+}
+
+/**
+ * Message shown in custom field configure forms when no field is selected.
+ *
+ * Note that this message is not displayed using the default field presentation.
+ * Modules or themes can set a custom field configuration form location by
+ * specifying a Drupal.settings.formBuilder.configureFormSelector value.
+ */
+function theme_form_builder_no_field_selected($variables) {
+  $output = '';
+  $output .= '<div class="field-settings-message">';
+  $output .= t('No field selected');
+  $output .= '</div>';
+  return $output;
+}
+
+/**
+ * Message shown in custom field configure forms when a field is loading.
+ *
+ * @see theme_form_builder_no_field_selected().
+ */
+function theme_form_builder_field_loading($variables) {
+  $output = '';
+  $output .= '<div class="field-settings-message">';
+  $output .= t('Loading...');
   $output .= '</div>';
   return $output;
 }
@@ -448,7 +498,7 @@ function form_builder_pre_render($element) {
  * Pre-render function to alter the form being edited by Form builder.
  *
  * This function modifies the form element itself and sets a #title to label the
- * form preview and an #block_enabled property to indicate to the theme wrapper
+ * form preview and an #show_palette property to indicate to the theme wrapper
  * whether the field palette should be added.
  */
 function form_builder_pre_render_form($form) {
@@ -467,9 +517,16 @@ function form_builder_pre_render_form($form) {
 
   // Check if the Form Builder block is enabled.
   // Otherwise make our own columns.
-  $form['#block_enabled'] = db_query("SELECT status FROM {block} WHERE module = 'form_builder' AND theme = :theme", array(':theme' => $theme))->fetchField();
+  if (!isset($form['#show_palette'])) {
+    if (module_exists('block')) {
+      $form['#show_palette'] = !db_query("SELECT status FROM {block} WHERE module = 'form_builder' AND theme = :theme", array(':theme' => $theme))->fetchField();
+    }
+    else {
+      $form['#show_palette'] = TRUE;
+    }
+  }
 
-  if ($form['#block_enabled'] && ($theme == 'garland' || $theme == 'minnelli')) {
+  if ($theme == 'garland' || $theme == 'minnelli') {
     $form['#attached']['css'][] = drupal_get_path('module', 'form_builder') . '/form_builder.garland.css';
   }
 
@@ -545,7 +602,7 @@ function form_builder_field_configure($form, $form_state, $form_type, $form_id,
       $function = $property_settings['form'];
       // Set a default value on the property to avoid notices.
       $element['#' . $property] = isset($element['#' . $property]) ? $element['#' . $property] : NULL;
-      $form = array_merge($form, $function($form_state, $form_type, $element));
+      $form = array_merge($form, $function($form_state, $form_type, $element, $property));
     }
   }
 
@@ -568,7 +625,7 @@ function form_builder_field_configure($form, $form_state, $form_type, $form_id,
  * Pre-render function for the field configuration form.
  */
 function form_builder_field_configure_pre_render($form) {
-  $groups = module_invoke_all('form_builder_property_groups', $form['#form_type']);
+  $groups = module_invoke_all('form_builder_property_groups', $form['#_edit_form_type']);
 
   foreach (element_children($form) as $key) {
     // If no group is specified, put the element into the default group.
@@ -628,7 +685,7 @@ function form_builder_field_configure_submit(&$form, &$form_state) {
   foreach ($form_state['values'] as $property => $value) {
     if (in_array($property, $saveable)) {
       // Remove empty properties entirely.
-      if ($value == '') {
+      if ($value === '' || is_null($value)) {
         unset($element['#'. $property]);
       }
       else {
diff --git a/sites/all/modules/form_builder/includes/form_builder.api.inc b/sites/all/modules/form_builder/includes/form_builder.api.inc
index c4203076330d1d011abdcf7fec0d2ecfa6fb1506..b22cb4a2240c6120d9dace19cfb4b0256c41c30c 100644
--- a/sites/all/modules/form_builder/includes/form_builder.api.inc
+++ b/sites/all/modules/form_builder/includes/form_builder.api.inc
@@ -17,7 +17,9 @@ function form_builder_get_properties($form_type, $reset = FALSE) {
 
   if (!isset($properties[$form_type])) {
     // Get the list of all properties for all elements.
-    $properties = module_invoke_all('form_builder_properties', $form_type);
+    foreach (module_implements('form_builder_properties') as $module) {
+      $properties = array_merge($properties, module_invoke($module, 'form_builder_properties', $form_type));
+    }
     drupal_alter('form_builder_properties', $properties, $form_type);
   }
 
@@ -63,8 +65,10 @@ function form_builder_get_form_type($form_type = NULL, $reset = FALSE) {
             $field['default']['#form_builder']['element_type'] = $field_key;
           }
         }
-
       }
+
+      // Sort fields by weight and title.
+      uasort($type, '_form_builder_sort');
     }
 
     drupal_alter('form_builder_types', $types);
@@ -218,9 +222,9 @@ function form_builder_set_element(&$form, $element, &$entire_form = NULL, $paren
       // Handle key changes and replace the existing element in place.
       elseif (isset($element['#key']) && $key != $element['#key']) {
         $new_key = $element['#key'];
-        $index = array_search($key, $form);
-        $before = array_slice($form, 0, $index + 1, TRUE);
-        $after = array_slice($form, $index + 2, NULL, TRUE);
+        $index = array_search($key, array_keys($form));
+        $before = array_slice($form, 0, $index, TRUE);
+        $after = array_slice($form, $index + 1, NULL, TRUE);
         $form = $before + array($new_key => $element) + $after;
         unset($form[$key]);
         $return = TRUE;
@@ -298,7 +302,6 @@ function form_builder_save_form(&$form, $form_type, $form_id) {
   form_builder_cache_delete($form_type, $form_id);
 }
 
-
 /**
  * Helper function to add default #form_builder properties to a form.
  */
@@ -352,3 +355,21 @@ function form_builder_add_default_properties($form, $form_type, $key = NULL, $pa
 
   return $form;
 }
+
+/**
+ * Helper function to sort elements by 'weight' and 'title'.
+ */
+function _form_builder_sort($a, $b) {
+  $a_weight = (is_array($a) && isset($a['weight'])) ? $a['weight'] : 0;
+  $b_weight = (is_array($b) && isset($b['weight'])) ? $b['weight'] : 0;
+  if ($a_weight == $b_weight) {
+    if (!isset($b['title'])) {
+      return -1;
+    }
+    if (!isset($a['title'])) {
+      return 1;
+    }
+    return strcasecmp($a['title'], $b['title']);
+  }
+  return ($a_weight < $b_weight) ? -1 : 1;
+}
diff --git a/sites/all/modules/form_builder/includes/form_builder.properties.inc b/sites/all/modules/form_builder/includes/form_builder.properties.inc
index 21658cf823c62ffe6303909d29e75c954b4ec215..42edc687f4f2a501db3dde14c6f313030c63432b 100644
--- a/sites/all/modules/form_builder/includes/form_builder.properties.inc
+++ b/sites/all/modules/form_builder/includes/form_builder.properties.inc
@@ -12,14 +12,19 @@
  * but instead the array key that is used to reference the element in the
  * Form API structure.
  */
-function form_builder_property_key_form(&$form_state, $form_type, $element) {
+function form_builder_property_key_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['key'] = array(
     '#title' => t('Form key'),
-    '#type' => 'textfield',
-    '#default_value' => $element['#key'],
-    '#required' => TRUE,
+    '#type' => 'machine_name',
+    '#default_value' => preg_match('/^new_[0-9]+$/', $element['#key']) ? '' : $element['#key'],
+    '#maxlength' => 128,
+    '#description' => t('The form key is used in the field "name" attribute. Must be alphanumeric and underscore characters.'),
+    '#machine_name' => array(
+      'source' => array('title'),
+      'label' => t('Form key'),
+    ),
     '#weight' => -9,
     '#element_validate' => array('form_builder_property_key_form_validate'),
   );
@@ -34,12 +39,37 @@ function form_builder_property_key_form_validate($element, $form_state) {
   if (!preg_match('/^[a-z0-9_]+$/', $element['#value'])) {
     form_error($element, t('The form key may only contain lowercase alphanumeric characters and underscores.'));
   }
+
+  // Check that the new key does not conflict with an existing key.
+  if ($element['#value'] != $element['#default_value']) {
+    $active_form = form_builder_active_form();
+    $form = form_builder_cache_load($active_form['form_type'], $active_form['form_id']);
+    $parents = $element['#parents'];
+    array_pop($parents);
+    $parents[] = $element['#value'];
+    $key_exists = FALSE;
+    foreach ($parents as $key) {
+      if (isset($form[$key])) {
+        $form = $form[$key];
+        $key_exists = TRUE;
+      }
+      else {
+        $key_exists = FALSE;
+        break;
+      }
+    }
+
+    if ($key_exists) {
+      form_error($element, t('The form key %key is already in use.', array('%key' => $element['#value'])));
+    }
+  }
+
 }
 
 /**
  * Configuration form for the "title" property.
  */
-function form_builder_property_title_form(&$form_state, $form_type, $element) {
+function form_builder_property_title_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['title'] = array(
@@ -56,7 +86,7 @@ function form_builder_property_title_form(&$form_state, $form_type, $element) {
 /**
  * Configuration form for the "title_display" property.
  */
-function form_builder_property_title_display_form(&$form_state, $form_type, $element) {
+function form_builder_property_title_display_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['title_display'] = array(
@@ -84,7 +114,7 @@ function form_builder_property_title_display_form(&$form_state, $form_type, $ele
  * This field is in the "hidden" builder group, meaning it's never shown in
  * the main editing interface. However, it's still there if editing without JS.
  */
-function form_builder_property_weight_form(&$form_state, $form_type, $element) {
+function form_builder_property_weight_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   if (!isset($_REQUEST['js'])) {
@@ -103,7 +133,7 @@ function form_builder_property_weight_form(&$form_state, $form_type, $element) {
 /**
  * Configuration form for the "description" property.
  */
-function form_builder_property_description_form(&$form_state, $form_type, $element) {
+function form_builder_property_description_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['description'] = array(
@@ -116,10 +146,27 @@ function form_builder_property_description_form(&$form_state, $form_type, $eleme
   return $form;
 }
 
+/**
+ * Configuration form for the "disabled" property.
+ */
+function form_builder_property_disabled_form(&$form_state, $form_type, $element, $property) {
+  $form = array();
+
+  $form['disabled'] = array(
+    '#form_builder' => array('property_group' => 'display'),
+    '#title' => t('Disabled (read-only)'),
+    '#type' => 'checkbox',
+    '#default_value' => $element['#disabled'],
+    '#weight' => 12,
+  );
+
+  return $form;
+}
+
 /**
  * Configuration form for the "required" property.
  */
-function form_builder_property_required_form(&$form_state, $form_type, $element) {
+function form_builder_property_required_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['required'] = array(
@@ -136,7 +183,7 @@ function form_builder_property_required_form(&$form_state, $form_type, $element)
 /**
  * Configuration form for the "options" property.
  */
-function form_builder_property_options_form(&$form_state, $form_type, $element) {
+function form_builder_property_options_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   // Checkboxes have an implied "multiple" property.
@@ -186,7 +233,7 @@ function form_builder_property_options_form_submit(&$form, &$form_state) {
 /**
  * Configuration form for the "default_value" property.
  */
-function form_builder_property_default_value_form(&$form_state, $form_type, $element) {
+function form_builder_property_default_value_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['default_value'] = array(
@@ -205,7 +252,7 @@ function form_builder_property_default_value_form(&$form_state, $form_type, $ele
 /**
  * Configuration form for the "markup" property.
  */
-function form_builder_property_markup_form(&$form_state, $form_type, $element) {
+function form_builder_property_markup_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   // TODO: This is a placeholder until "#markup" becomes available in D7.
@@ -235,7 +282,7 @@ function form_builder_property_markup_form_submit(&$form, &$form_state) {
 /**
  * Configuration form for the "size" property.
  */
-function form_builder_property_size_form(&$form_state, $form_type, $element) {
+function form_builder_property_size_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['size'] = array(
@@ -253,7 +300,7 @@ function form_builder_property_size_form(&$form_state, $form_type, $element) {
 /**
  * Configuration form for the "rows" property.
  */
-function form_builder_property_rows_form(&$form_state, $form_type, $element) {
+function form_builder_property_rows_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['rows'] = array(
@@ -271,7 +318,7 @@ function form_builder_property_rows_form(&$form_state, $form_type, $element) {
 /**
  * Configuration form for the "cols" property.
  */
-function form_builder_property_cols_form(&$form_state, $form_type, $element) {
+function form_builder_property_cols_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['cols'] = array(
@@ -291,7 +338,7 @@ function form_builder_property_cols_form(&$form_state, $form_type, $element) {
 /**
  * Configuration form for the "field_prefix" property.
  */
-function form_builder_property_field_prefix_form(&$form_state, $form_type, $element) {
+function form_builder_property_field_prefix_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['field_prefix'] = array(
@@ -308,7 +355,7 @@ function form_builder_property_field_prefix_form(&$form_state, $form_type, $elem
 /**
  * Configuration form for the "field_suffix" property.
  */
-function form_builder_property_field_suffix_form(&$form_state, $form_type, $element) {
+function form_builder_property_field_suffix_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['field_suffix'] = array(
@@ -325,7 +372,7 @@ function form_builder_property_field_suffix_form(&$form_state, $form_type, $elem
 /**
  * Configuration form for the "collapsible" property.
  */
-function form_builder_property_collapsible_form(&$form_state, $form_type, $element) {
+function form_builder_property_collapsible_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['collapsible'] = array(
@@ -342,7 +389,7 @@ function form_builder_property_collapsible_form(&$form_state, $form_type, $eleme
 /**
  * Configuration form for the "collapsed" property.
  */
-function form_builder_property_collapsed_form(&$form_state, $form_type, $element) {
+function form_builder_property_collapsed_form(&$form_state, $form_type, $element, $property) {
   $form = array();
 
   $form['collapsed'] = array(
diff --git a/sites/all/modules/form_builder/modules/menu.inc b/sites/all/modules/form_builder/modules/menu.inc
deleted file mode 100644
index 44c0990700d22c51a0221f05c1a51c28b10f2e8d..0000000000000000000000000000000000000000
--- a/sites/all/modules/form_builder/modules/menu.inc
+++ /dev/null
@@ -1,197 +0,0 @@
-<?php
-
-/**
- * @file
- *   Form builder implementation for menu.module.
- */
-
-/**
- * Implementation of hook_form_builder_types().
- */
-function menu_form_builder_types() {
-  $fields = array();
-
-  // Make a default menu item to pass into the menu form.
-  $item = array(
-    'mlid' => 0,
-    'plid' => 0,
-    'weight' => 0,
-    'link_title' => '',
-    'module' => '',
-    'hidden' => NULL,
-    'has_children' => NULL,
-    'customized' => NULL, 
-    'options' => NULL,
-    'expanded' => NULL,
-    'parent_depth_limit' => NULL,
-    'menu_name' => NULL,
-  );
-  $default_settings = module_invoke('menu', 'node_form_default_settings');
-
-  $fields['menu_settings'] = array(
-    'title' => t('Menu'),
-    'properties' => array(
-      'collapsible',
-      'collapsed',
-    ),
-    'default' => menu_fieldset($item, $default_settings['menu']),
-    'unique' => TRUE,
-    'configurable' => TRUE,
-    'removable' => TRUE,
-    'palette_group' => 'special',
-  );
-
-  return array(
-    'node' => $fields,
-    'example' => $fields,
-  );
-}
-
-/**
- * Implementation of hook_form_builder_load_alter().
- */
-function menu_form_builder_load_alter(&$form, $form_type, $form_id) {
-  if ($form_type == 'node') {
-    $menu_settings = node_get_form_settings($form_id, 'menu');
-
-    if ($menu_settings['enabled']) {
-      $form['menu'] = menu_fieldset($form['#node']->menu, $menu_settings);
-      $form['menu']['#form_builder'] = array(
-        'element_id' => 'menu_settings',
-        'element_type' => 'menu_settings',
-      );
-    }
-  }
-}
-
-/**
- * Implementation of hook_form_builder_save().
- */
-function menu_form_builder_save(&$form, $form_type, $form_id) {
-  if ($form_type == 'node') {
-    $node_type = $form_id;
-    $element = form_builder_get_element($form, 'menu_settings');
-    if ($element) {
-      $settings = array(
-        'enabled' => TRUE,
-        'collapsible' => !empty($element['#collapsible']),
-        'collapsed' => !empty($element['#collapsible']) && !empty($element['#collapsed']),
-        'weight' => $element['#weight'],
-      );
-    }
-    else {
-      $settings = array(
-        'enabled' => FALSE,
-      );
-    }
-    node_set_form_settings($node_type, 'menu', 'menu', $settings);
-  }
-}
-
-/**
- * Implementation of hook_form_alter().
- *
- * @todo Merge this into menu_form_alter().
- */
-function menu_node_form_alter(&$form, &$form_state, $form_id) {
-  // Set properties of the menu form item based on the menu node form settings.
-  if (isset($form['#node']) && $form['#node']->type .'_node_form' == $form_id) {
-    $settings = node_get_form_settings($form['#node']->type, 'menu');
-    if ($settings['enabled']) {
-      $form['menu']['#collapsible'] = $settings['collapsible'];
-      $form['menu']['#collapsed'] = $settings['collapsed'];
-      $form['menu']['#weight'] = $settings['weight'];
-    }
-    else {
-      $form['menu']['#access'] = FALSE;
-    }
-  }
-}
-
-/**
- * Implementation of hook_node_form_default_settings().
- *
- * Get the default settings for the menu modifications to the node form.
- */
-function menu_node_form_default_settings($node_type = NULL) {
-  $defaults = array();
-  $defaults['menu'] = array(
-    'enabled' => TRUE,
-    'collapsible' => TRUE,
-    'collapsed' => TRUE,
-    'weight' => -2,
-  );
-  return $defaults;
-}
-
-/**
- * A straight copy/paste of menu_form_alter(). Get the menu node form.
- *
- * @param $item
- *   The contents of $node->menu.
- * @param $menu_settings
- *   Settings for the menu form.
- *
- * @todo Put this function directly in menu.module, abstracting it from
- * menu_form_alter().
- */
-function menu_fieldset($item, $menu_settings = array()) {
-  $form = array(
-    '#type' => 'fieldset',
-    '#title' => t('Menu settings'),
-    '#access' => user_access('administer menu'),
-    '#collapsible' => $menu_settings['collapsible'],
-    '#collapsed' => $menu_settings['collapsible'],
-    '#tree' => TRUE,
-    '#attributes' => array('class' => 'menu-item-form'),
-    '#weight' => $menu_settings['weight'],
-  );
-
-  if ($item['mlid']) {
-    // There is an existing link.
-    $form['delete'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Delete this menu item.'),
-    );
-  }
-  if (!$item['link_title']) {
-    $form['#collapsed'] = TRUE;
-  }
-
-  foreach (array('mlid', 'module', 'hidden', 'has_children', 'customized', 'options', 'expanded', 'hidden', 'parent_depth_limit') as $key) {
-    $form[$key] = array('#type' => 'value', '#value' => $item[$key]);
-  }
-  $form['#item'] = $item;
-
-  $form['link_title'] = array('#type' => 'textfield',
-    '#title' => t('Menu link title'),
-    '#default_value' => $item['link_title'],
-    '#description' => t('The link text corresponding to this item that should appear in the menu. Leave blank if you do not wish to add this post to the menu.'),
-    '#required' => FALSE,
-  );
-  // Generate a list of possible parents (not including this item or descendants).
-  $options = menu_parent_options(menu_get_menus(), $item);
-  $default = $item['menu_name'] .':'. $item['plid'];
-  if (!isset($options[$default])) {
-    $default = 'primary-links:0';
-  }
-  $form['parent'] = array(
-    '#type' => 'select',
-    '#title' => t('Parent item'),
-    '#default_value' => $default,
-    '#options' => $options,
-    '#description' => t('The maximum depth for an item and all its children is fixed at !maxdepth. Some menu items may not be available as parents if selecting them would exceed this limit.', array('!maxdepth' => MENU_MAX_DEPTH)),
-    '#attributes' => array('class' => 'menu-title-select'),
-  );
-  $form['#submit'][] = 'menu_node_form_submit';
-
-  $form['weight'] = array(
-    '#type' => 'weight',
-    '#title' => t('Weight'),
-    '#delta' => 50,
-    '#default_value' => $item['weight'],
-    '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'),
-  );
-
-  return $form;
-}
diff --git a/sites/all/modules/form_builder/modules/node.inc b/sites/all/modules/form_builder/modules/node.inc
deleted file mode 100644
index 4c4d3ce66e4b5d5cb79ee4ce139269e28ecc7a6f..0000000000000000000000000000000000000000
--- a/sites/all/modules/form_builder/modules/node.inc
+++ /dev/null
@@ -1,892 +0,0 @@
-<?php
-
-/**
- * @file
- *   Form builder implementation for node.module.
- */
-
-/**
- * Main page for editing a content type form.
- *
- * @param $type
- *   The content type object being edited.
- */
-function node_form_edit($type) {
-  module_load_include('inc', 'form_builder', 'includes/form_builder.admin');
-
-  // TODO: These should be auto-loaded as necessary.
-  drupal_add_js('misc/autocomplete.js');
-  drupal_add_js('misc/collapse.js');
-  drupal_add_js('misc/tableheader.js');
-  drupal_add_js('misc/textarea.js');
-
-  drupal_set_message(t('This is a form preview. Click on a field to edit its properties.'), 'warning');
-
-  $output = array();
-  $output[] = form_builder_interface('node', $type->type);
-  $output[] = drupal_get_form('node_form_builder_save_form', $type);
-  return $output;
-}
-
-/**
- * Form for saving Form Builder changes.
- */
-function node_form_builder_save_form($form_state, $type, $review = FALSE) {
-  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
-  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
-
-  $form = array();
-
-  if ($review) {
-    // Allow modules to review dangerous changes before continuing.
-    $differences = form_builder_cache_difference('node', $type->type);
-    if ($differences !== FALSE) {
-      $form['warnings'] = array(
-        '#tree' => TRUE,
-      );
-
-      if (empty($form_state['post'])) {
-        drupal_set_message(t('Please review your changes before saving.'));
-      }
-
-      $changed_fields = array();
-      foreach ($differences as $difference) {
-        $field_name = isset($difference['original']['#title']) ? $difference['original']['#title'] : $difference['original']['#form_builder']['element_id'];
-        if (empty($difference['original'])) {
-          $field_name = isset($difference['modified']['#title']) ? $difference['modified']['#title'] : $difference['modified']['#form_builder']['element_id'];
-          $changed_fields[] = $field_name . ' - <strong>' . t('Added') . '</strong>';
-        }
-        elseif (empty($difference['modified'])) {
-          $changed_fields[] = $field_name . ' - <strong>' . t('Removed') . '</strong>';
-        }
-        else {
-          $changed_fields[] = $field_name . ' - <strong>' . t('Modified') . '</strong>';
-        }
-      }
-
-      $form['changed'] = array(
-        '#type' => 'markup',
-        '#value' => theme('item_list', $changed_fields),
-      );
-
-      foreach ($differences as $difference) {
-        $element_id = $difference['original']['#form_builder']['element_id'];
-        $correction_form = module_invoke_all('form_builder_correction_form', $form_state, 'node', $type->type, $element_id, $difference['original'], $difference['modified']);
-        if (!empty($correction_form)) {
-          $form['warnings'][$element_id] = $correction_form;
-        }
-      }
-
-      $form['offline'] = array(
-        '#title' => t('Site status'),
-        '#type' => 'radios',
-        '#options' => array(
-          '0' => t('Leave site online'),
-          '1' => t('Temporarily take site offline'),
-        ),
-        '#default_value' => '0',
-        '#description' => t('For large sets of changes, it is recommended that you temporarily disable access to your site while data is being saved. After changes are complete, the site will be turned back online. You can change the site status manually be visiting <a href="!url">Site maintenance</a>.', array('!url' => url('admin/settings/site-maintenance'))),
-        '#access' => variable_get('site_offline', '0') == '0',
-      );
-
-      $form['buttons']['cancel'] = array(
-        '#type' => 'markup',
-        '#value' => l('Cancel', 'admin/build/node-type/' . str_replace('_', '-', $type->type) . '/fields'),
-      );
-
-      $form['reviewed'] = array(
-        '#type' => 'value',
-        '#value' => TRUE,
-      );
-    }
-    else {
-      drupal_not_found();
-      exit;
-    }
-  }
-
-  $form['type'] = array(
-    '#type' => 'value',
-    '#value' => $type,
-  );
-
-  $form['buttons']['#weight'] = 100;
-
-  $form['buttons']['submit'] = array(
-    '#type' => 'submit',
-    '#value' => t('Save'),
-    '#weight' => -1,
-  );
-
-  return $form;
-}
-
-/**
- * Submit handler for saving changes to the node form.
- */
-function node_form_builder_save_form_submit(&$form, &$form_state) {
-  module_load_include('inc', 'form_builder', 'includes/form_builder.api');
-  module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
-  $type = $form_state['values']['type'];
-
-  if (!isset($form_state['values']['reviewed'])) {
-    $form_state['redirect'] = 'admin/build/node-type/' . str_replace('_', '-', $type->type) .'/fields/confirm';
-    return;
-  }
-
-  // Disable access to the site.
-  if ($form_state['values']['offline'] == '1') {
-    variable_set('site_offline', '1');
-  }
-
-  $node_form = form_builder_cache_load('node', $type->type);
-  form_builder_save_form($node_form, 'node', $type->type);
-
-  // Re-enable access to the site.
-  if ($form_state['values']['offline'] == '1') {
-    variable_set('site_offline', '0');
-  }
-
-  drupal_set_message(t('The changes to the %type content type form have been saved.', array('%type' => $type->name)));
-  $form_state['redirect'] = 'admin/build/node-type/' . str_replace('_', '-', $type->type);
-
-}
-
-/**
- * Implementation of hook_form_builder_types().
- */
-function node_form_builder_types() {
-  global $user;
-
-  module_load_include('inc', 'node', 'node.pages');
-
-  $fields = array();
-
-  $node = array(
-    'uid' => $user->uid,
-    'created' => 280321200, // 19 Nov 1978 05:00:00.
-    'date' => format_date(280321200, 'custom', 'Y-m-d H:i:s O'),
-    'body' => NULL,
-    'title' => NULL,
-    'format' => NULL,
-  );
-  $settings = module_invoke('node', 'node_form_default_settings');
-
-  $node['status'] = $settings['options']['status'];
-  $node['promote'] = $settings['options']['promote'];
-  $node['sticky'] = $settings['options']['sticky'];
-
-  $node = (object) $node;
-
-  $title_form = node_title_field($node, $settings['title']);
-  $title_form['#weight'] = $settings['title']['weight'];
-  $fields['title'] = array(
-    'title' => t('Title'),
-    'properties' => array(
-      'title',
-    ),
-    'default' => $title_form,
-    'unique' => TRUE,
-    'removable' => FALSE,
-    'palette_group' => 'special',
-  );
-
-  /*$body_form = node_body_field($node, $settings['body_field']['label'], $settings['body_field']['min_word_count']);
-  $body_form['#weight'] = $settings['body_field']['weight'];
-  $body_form['#body_settings'] = $settings['body_field'];
-  $fields['body_field'] = array(
-    'title' => t('Body'),
-    'properties' => array(
-      'body_settings',
-    ),
-    'default' => $body_form,
-    'unique' => TRUE,
-    'palette_group' => 'special',
-  );*/
-
-  $revision_fieldset = node_revision_fieldset($node, $settings['revision_information']);
-  $revision_fieldset['#weight'] = $settings['revision_information']['weight'];
-  $revision_fieldset['#revision_settings'] = $settings['revision_information'];
-  $fields['revision_information'] = array(
-    'title' => t('Revisions'),
-    'properties' => array(
-      'collapsible',
-      'collapsed',
-      'revision_settings',
-    ),
-    'default' => $revision_fieldset,
-    'unique' => TRUE,
-    'palette_group' => 'special',
-  );
-
-  $author_fieldset = node_author_fieldset($node, $settings['author']);
-  $author_fieldset['#author_settings'] = $settings['author'];
-  $author_fieldset['#weight'] = $settings['author']['weight'];
-  $author_fieldset['#form_builder']['removable'] = FALSE;
-  $fields['author'] = array(
-    'title' => t('Authoring'),
-    'properties' => array(
-      'collapsible',
-      'collapsed',
-    ),
-    'default' => $author_fieldset,
-    'unique' => TRUE,
-    'removable' => FALSE,
-    'palette_group' => 'special',
-  );
-
-  $options_fieldset = node_options_fieldset($node, $settings['options']);
-  $options_fieldset['#options_settings'] = $settings['options'];
-  $options_fieldset['#weight'] = $settings['options']['weight'];
-  $options_fieldset['#form_builder']['removable'] = FALSE;
-  $fields['options'] = array(
-    'title' => t('Options'),
-    'properties' => array(
-      'collapsible',
-      'collapsed',
-      'options_settings',
-    ),
-    'default' => $options_fieldset,
-    'unique' => TRUE,
-    'removable' => FALSE,
-    'palette_group' => 'special',
-  );
-
-  // Generic field for handling weights.
-  $fields['generic_field'] = array(
-    'title' => t('Generic field'),
-    'properties' => array(),
-    'removable' => FALSE,
-    'configurable' => FALSE,
-  );
-
-  return array(
-    'node' => $fields,
-  );
-}
-
-/**
- * Implementation of hook_form_builder_properties().
- */
-function node_form_builder_properties($form_type) {
-  if ($form_type == 'node') {
-    return array(
-      'body_settings' => array(
-        'form' => 'node_body_settings_form',
-        'submit' => array('node_body_settings_form_submit'),
-      ),
-      'revision_settings' => array(
-        'form' => 'node_revision_settings_form',
-      ),
-      'options_settings' => array(
-        'form' => 'node_options_settings_form',
-      ),
-    );
-  }
-}
-
-/**
- * Implementation of hook_form_builder_preview_alter().
- *
- * Update the custom node fields according to the changed node type settings.
- */
-function node_form_builder_preview_alter(&$element, $form_type, $form_id) {
-  if ($form_type == 'node') {
-    switch ($element['#form_builder']['element_id']) {
-      case 'title':
-        // No node title settings yet.
-        break;
-      case 'body_field':
-        $element['body']['#title'] = check_plain($element['#body_settings']['label']);
-        $element['body']['#required'] = $element['#body_settings']['min_word_count'] > 0;
-        break;
-      case 'revision_information':
-        $element['revision']['#default_value'] = $element['#revision_settings']['revision'];
-        break;
-      case 'author':
-        // No node author settings yet.
-        break;
-      case 'options':
-        $element['status']['#default_value'] = $element['#options_settings']['status'];
-        $element['promote']['#default_value'] = $element['#options_settings']['promote'];
-        $element['sticky']['#default_value'] = $element['#options_settings']['sticky'];
-        break;
-    }
-  }
-}
-
-/**
- * Configuration form for the "body_settings" property.
- */
-function node_body_settings_form(&$form_state, $form_type, $element) {
-  $form = array();
-
-  $form['label'] = array(
-    '#title' => t('Title'),
-    '#type' => 'textfield',
-    '#parents' => array('body_settings', 'label'),
-    '#default_value' => $element['#body_settings']['label'],
-    '#required' => TRUE,
-    '#weight' => -10,
-  );
-
-  $form['min_word_count'] = array(
-    '#form_builder' => array('property_group' => 'validation'),
-    // Manually set parents since we need this to be in the validation group.
-    '#parents' => array('body_settings', 'min_word_count'),
-    '#type' => 'select',
-    '#title' => t('Minimum number of words'),
-    '#default_value' => $element['#body_settings']['min_word_count'],
-    '#options' => drupal_map_assoc(array(0, 10, 25, 50, 75, 100, 125, 150, 175, 200)),
-    '#description' => t('The minimum number of words for the body field to be considered valid for this content type. This can be useful to rule out submissions that do not meet the site\'s standards, such as short test posts.')
-  );
-
-  return $form;
-}
-
-/**
- * Configuration form for the "revision_settings" property.
- */
-function node_revision_settings_form(&$form_state, $form_type, $element) {
-  $form = array();
-
-  $form['revision_settings']['revision'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Create new revision by default'),
-    '#parents' => array('revision_settings', 'revision'),
-    '#default_value' => $element['#revision_settings']['revision'],
-  );
-
-  return $form;
-}
-
-/**
- * Configuration form for the "options_settings" property.
- */
-function node_options_settings_form(&$form_state, $form_type, $element) {
-  $form = array();
-
-  $form['status'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Published by default'),
-    '#parents' => array('options_settings', 'status'),
-    '#default_value' => $element['#options_settings']['status'],
-  );
-
-  $form['promote'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Promoted by default'),
-    '#parents' => array('options_settings', 'promote'),
-    '#default_value' => $element['#options_settings']['promote'],
-  );
-
-  $form['sticky'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Sticky by default'),
-    '#parents' => array('options_settings', 'sticky'),
-    '#default_value' => $element['#options_settings']['sticky'],
-  );
-
-  return $form;
-}
-
-/**
- * Implementation of hook_form_builder_load().
- */
-function node_form_builder_load($form_type, $form_id) {
-  global $user;
-
-  module_load_include('inc', 'node', 'node.pages');
-
-  if ($form_type == 'node') {
-    $form_state = array('submitted' => FALSE);
-    $node_type = $form_id;
-
-    $node = array(
-      'uid' => $user->uid,
-      'created' => 280321200, // 19 Nov 1978 05:00:00.
-      'date' => format_date(280321200, 'custom', 'Y-m-d H:i:s O'),
-      'name' => (isset($user->name) ? $user->name : ''),
-      'type' => $node_type,
-      'language' => '',
-    );
-    $form = node_form($form_state, $node);
-
-    // Setup generic weight handling.
-    drupal_prepare_form($form_id .'_node_form', $form, $form_state);
-    $form['#node_generic_fields'] = array();
-    foreach (element_children($form) as $key) {
-      $element = $form[$key];
-      if (!isset($element['#form_builder']) && (!empty($element['#tree']) || (isset($element['#type']) && !in_array($element['#type'], array('value', 'hidden', 'markup', 'token', 'button', 'submit', 'vertical_tabs', 'horizontal_tabs'))))) {
-        $form[$key]['#form_builder'] = array(
-          'element_id' => $key,
-          'element_type' => 'generic_field',
-        );
-        $form['#node_generic_fields'][] = $key;
-      }
-    }
-
-    if (isset($form['title'])) {
-      $title_settings = node_get_form_settings($node_type, 'title');
-      $form['title']['#title_settings'] = $title_settings;
-      $form['title']['#weight'] = $title_settings['weight'];
-      $form['title']['#form_builder'] = array(
-        'element_id' => 'title',
-        'element_type' => 'title',
-      );
-    }
-
-    if (isset($form['body_field'])) {
-      $body_settings = node_get_form_settings($node_type, 'body_field');
-      $form['body_field']['#body_settings'] = $body_settings;
-      $form['body_field']['#weight'] = $body_settings['weight'];
-      $form['body_field']['#form_builder'] = array(
-        'element_id' => 'body_field',
-        'element_type' => 'body_field',
-      );
-    }
-
-    $revision_settings = node_get_form_settings($node_type, 'revision_information');
-    if ($revision_settings['enabled']) {
-      $form['revision_information'] = node_revision_fieldset($form['#node'], $revision_settings);
-      $form['revision_information']['#revision_settings'] = $revision_settings;
-      $form['revision_information']['#form_builder'] = array(
-        'element_id' => 'revision_information',
-        'element_type' => 'revision_information',
-      );
-    }
-    else {
-      unset($form['revision_information']);
-    }
-
-    $options_settings = node_get_form_settings($node_type, 'options');
-    $form['options'] = node_options_fieldset($form['#node'], $options_settings);
-    $form['options']['#options_settings'] = $options_settings;
-    $form['options']['#form_builder'] = array(
-      'element_id' => 'options',
-      'element_type' => 'options',
-    );
-
-    $author_settings = node_get_form_settings($node_type, 'author');
-    $form['author'] = node_author_fieldset($form['#node'], $author_settings);
-    $form['author']['#author_settings'] = $author_settings;
-    $form['author']['#form_builder'] = array(
-      'element_id' => 'author',
-      'element_type' => 'author',
-    );
-
-    unset($form['buttons']);
-
-    return $form;
-  }
-}
-
-/**
- * Implementation of hook_form_builder_save().
- */
-function node_form_builder_save(&$form, $form_type, $form_id) {
-  if ($form_type == 'node') {
-    $node_type = $form_id;
-
-    $node_element_ids = array(
-      'title' => 'title',
-      'body' => 'body_field',
-      'revision' => 'revision_information',
-      'options' => 'options',
-      'author' => 'author',
-    );
-    $node_elements = form_builder_get_elements($form, $node_element_ids);
-
-    foreach ($node_element_ids as $key => $element_id) {
-      $settings = node_get_form_settings($node_type, $element_id);
-      if (!isset($node_elements[$element_id])) {
-        $settings['enabled'] = FALSE;
-      }
-      else {
-        // Merge most settings from the #settings property.
-        foreach ($node_elements[$element_id]['#' . $key . '_settings'] as $setting_key => $setting) {
-          $settings[$setting_key] = $setting;
-        }
-        // If the field exists, it is enabled.
-        $settings['enabled'] = TRUE;
-        // Set the weight from the #weight property.
-        $settings['weight'] = $node_elements[$element_id]['#weight'];
-        // The title label is just the plain title attribute.
-        if ($element_id == 'title') {
-          $settings['label'] = $node_elements[$element_id]['#title'];
-        }
-        // Update settings if a fieldset.
-        if (isset($node_elements[$element_id]['#type']) && $node_elements[$element_id]['#type'] == 'fieldset') {
-          $settings['collapsible'] = !empty($node_elements[$element_id]['#collapsible']);
-          $settings['collapsed'] = !empty($node_elements[$element_id]['#collapsed']);
-        }
-      }
-
-      // Update the settings for this field.
-      node_set_form_settings($node_type, $element_id, 'node', $settings);
-    }
-
-    $generic_field_ids = $form['#node_generic_fields'];
-    $generic_fields = form_builder_get_elements($form, $generic_field_ids);
-    foreach ($generic_fields as $key => $field) {
-      if ($field['#form_builder']['element_type'] == 'generic_field') {
-        $settings = array(
-          'weight' => $field['#weight'],
-        );
-        node_set_form_settings($node_type, $key, 'node', $settings);
-      }
-    }
-  }
-}
-
-/**
- * Implementation of hook_form_alter().
- *
- * @todo Merge this into node_form().
- */
-function node_node_form_alter(&$form, &$form_state, $form_id) {
-  // Set properties of the node form based on the node form settings.
-  if (preg_match('/_node_form$/', $form_id)) {
-    $type = $form['#node']->type;
-    $settings = node_get_form_settings($type);
-
-    $fields = array(
-      'title',
-      'body_field',
-      'revision_information',
-      'author',
-      'options',
-    );
-
-    foreach ($fields as $key) {
-      if (isset($settings[$key]['enabled']) && !$settings[$key]['enabled']) {
-        $form[$key]['#access'] = FALSE;
-      }
-      else {
-        switch ($key) {
-          case 'title':
-            $form[$key] = node_title_field($form['#node'], $settings[$key]);
-            break;
-          case 'revision_information':
-            $form['revision_information'] = node_revision_fieldset($form['#node'], $settings[$key]);
-            break;
-          case 'author':
-            $form[$key] = node_author_fieldset($form['#node'], $settings[$key]);
-            break;
-          case 'options':
-            $form[$key] = node_options_fieldset($form['#node'], $settings[$key]);
-            break;
-        }
-      }
-    }
-
-    // Set generic weights for any field controlled by node module.
-    foreach ($settings as $key => $field_settings) {
-      if (isset($form[$key]) && $field_settings['module'] == 'node') {
-        $form[$key]['#weight'] = $field_settings['weight'];
-      }
-    }
-  }
-}
-
-/**
- * A copy/paste out of node_content_form(). The title field.
- */
-function node_title_field($node, $title_settings) {
-  return array(
-    '#type' => 'textfield',
-    '#title' => check_plain($title_settings['label']),
-    '#required' => TRUE,
-    '#default_value' => $node->title,
-    '#maxlength' => 255,
-    '#weight' => $title_settings['weight'],
-  );
-}
-
-/**
- * A straight copy/paste of a segment of node_form(). The node revision form.
- *
- * @param $node
- *   The node object being edited.
- * @param $revision_settings
- *   Settings specific to the revision fieldset.
- *
- * @todo Put this function directly in node.pages.inc, abstracting it from
- * node_form().
- */
-function node_revision_fieldset($node, $revision_settings) {
-  $form = array(
-    '#type' => 'fieldset',
-    '#title' => t('Revision information'),
-    '#collapsible' => TRUE,
-    // Collapsed by default when "Create new revision" is unchecked
-    '#collapsed' => $revision_settings['collapsed'],
-    '#weight' => $revision_settings['weight'],
-  );
-  $form['revision'] = array(
-    '#access' => user_access('administer nodes'),
-    '#type' => 'checkbox',
-    '#title' => t('Create new revision'),
-    '#default_value' => $revision_settings['revision'],
-  );
-  $form['log'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Log message'),
-    '#rows' => 2,
-    '#description' => t('An explanation of the additions or updates being made to help other authors understand your motivations.'),
-  );
-
-  return $form;
-}
-
-/**
- * A straight copy/paste of a segment of node_form(). The authoring information form.
- *
- * @param $node
- *   The node object being edited.
- * @param $authoring_settings
- *   Settings specific to the authoring information fieldset.
- *
- * @todo Put this function directly in node.pages.inc, abstracting it from
- * node_form().
- */
-function node_author_fieldset($node, $authoring_settings) {
-  $form = array(
-    '#type' => 'fieldset',
-    '#access' => user_access('administer nodes'),
-    '#title' => t('Authoring information'),
-    '#collapsible' => $authoring_settings['collapsible'],
-    '#collapsed' => $authoring_settings['collapsed'],
-    '#weight' => $authoring_settings['weight'],
-  );
-  $form['name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Authored by'),
-    '#maxlength' => 60,
-    '#autocomplete_path' => 'user/autocomplete',
-    '#default_value' => isset($node->name) ? $node->name : '',
-    '#weight' => -1,
-    '#description' => t('Leave blank for %anonymous.', array('%anonymous' => variable_get('anonymous', t('Anonymous')))),
-  );
-  $form['date'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Authored on'),
-    '#maxlength' => 25,
-    '#description' => t('Format: %time. Leave blank to use the time of form submission.', array('%time' => !empty($node->date) ? $node->date : format_date($node->created, 'custom', 'Y-m-d H:i:s O'))),
-  );
-
-  if (isset($node->date)) {
-    $form['date']['#default_value'] = $node->date;
-  }
-
-  return $form;
-}
-
-/**
- * A straight copy/paste of a segment of node_form(). The publishing options form.
- *
- * @param $node
- *   The node object being edited.
- * @param $publishing_settings
- *   Settings specific to the publishing options fieldset.
- *
- * @todo Put this function directly in node.pages.inc, abstracting it from
- * node_form().
- */
-function node_options_fieldset($node, $publishing_settings) {
-  $form = array(
-    '#type' => 'fieldset',
-    '#access' => user_access('administer nodes'),
-    '#title' => t('Publishing options'),
-    '#collapsible' => $publishing_settings['collapsible'],
-    '#collapsed' => $publishing_settings['collapsed'],
-    '#weight' => $publishing_settings['weight'],
-  );
-  $form['status'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Published'),
-    '#default_value' => $node->status,
-  );
-  $form['promote'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Promoted to front page'),
-    '#default_value' => $node->promote,
-  );
-  $form['sticky'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Sticky at top of lists'),
-    '#default_value' => $node->sticky,
-  );
-
-  return $form;
-}
-
-/**
- * Retrieve node form settings for a particular field.
- */
-function node_get_form_settings($node_type, $field = NULL, $reset = FALSE) {
-  static $form_settings = array();
-
-  if ($reset) {
-    $form_settings = array();
-    return;
-  }
-
-  if (!isset($form_settings[$node_type])) {
-    // Get settings from the node form settings table.
-    $form_settings[$node_type] = array();
-    $result = db_select('node_form_settings', 'nfs', array('fetch' => PDO::FETCH_ASSOC))
-      ->fields('nfs')
-      ->condition('nfs.type', $node_type)
-      ->execute();
-    foreach ($result as $settings) {
-      $form_settings[$node_type][$settings->field] = unserialize($settings->settings);
-      $form_settings[$node_type][$settings->field]['module'] = $settings->module;
-    }
-
-    // Get settings from the node type table.
-    $type = node_type_get_type($node_type);
-    $form_settings[$node_type]['title']['enabled'] = $type->has_title ? TRUE : FALSE;
-    $form_settings[$node_type]['title']['label'] = isset($type->title_label) ? $type->title_label : '';
-    $form_settings[$node_type]['body_field']['enabled'] = $type->has_body ? TRUE : FALSE;
-    $form_settings[$node_type]['body_field']['label'] = isset($type->body_label) ? $type->body_label : '';
-
-    // Merge default settings from modules.
-    foreach (module_implements('node_form_default_settings') as $module) {
-      $additional_settings = module_invoke($module, 'node_form_default_settings', $node_type);
-      if (!empty($additional_settings)) {
-        foreach ($additional_settings as $field_id => $field_settings) {
-          $form_settings[$node_type][$field_id]['module'] = $module;
-          if (isset($form_settings[$node_type][$field_id])) {
-            $form_settings[$node_type][$field_id] = array_merge($field_settings, $form_settings[$node_type][$field_id]);
-          }
-          else {
-            $form_settings[$node_type][$field_id] = $field_settings;
-          }
-        }
-      }
-    }
-  }
-
-  if (!isset($field)) {
-    return $form_settings[$node_type];
-  }
-  elseif (isset($form_settings[$node_type][$field])) {
-    return $form_settings[$node_type][$field];
-  }
-
-  return FALSE;
-}
-
-/**
- * Set the node form settings for a particular field.
- */
-function node_set_form_settings($node_type, $field, $module, $settings) {
-  $serialized_value = serialize($settings);
-  db_merge('node_form_settings')
-    ->key(array('type' => $node_type, 'field' => $field))
-    ->fields(array(
-      'settings' => $serialized_value,
-      'module' => $module
-    ))
-    ->execute();
-
-  // Special cases for node type settings.
-  if ($field == 'body_field') {
-    $type = node_type_get_type($node_type);
-    $type->has_body = $settings['enabled'];
-    $type->body_label = $settings['label'];
-    $type->min_word_count = $settings['min_word_count'];
-    node_type_save($type);
-    node_types_rebuild();
-    menu_rebuild();
-  }
-  if ($field == 'title') {
-    $type = node_type_get_type($node_type);
-    $type->has_title = $settings['enabled'];
-    $type->title_label = $settings['label'];
-    node_type_save($type);
-    node_types_rebuild();
-    menu_rebuild();
-  }
-
-  // Reset the static cache for the node form settings.
-  node_get_form_settings(NULL, NULL, TRUE);
-}
-
-/**
- * Delete the node form settings for a node type, field, or module.
- *
- * All parameters all optional, but at least one must be specified to have any
- * effect. Multiple parameters may be passed in to further narrow the settings
- * that will be deleted.
- *
- * @param $node_type
- *   Optional. String of the node type whose settings are to be deleted.
- * @param $field
- *   Optional. The key of the field whose setting will be deleted.
- * @param $module
- *   Options. Name of the module that provided the field settings to be deleted.
- */
-function node_delete_form_settings($node_type = NULL, $field = NULL, $module = NULL) {
-  $delete = db_delete('node_form_settings');
-  if (isset($node_type)) {
-    $delete->condition('type', $node_type);
-  }
-  if (isset($field)) {
-    $delete->condition('field', $field);
-  }
-  if (isset($field)) {
-    // @todo: bogus conditional?
-    $delete->condition('module', $module);
-  }
-
-  if (isset($node_type) || isset($field)) {
-    // @todo: bogus conditional?
-    $delete->execute();
-
-    // Reset the static cache for the node form settings.
-    node_get_form_settings(NULL, NULL, TRUE);
-  }
-}
-
-/**
- * Implementation of hook_node_form_default_settings().
- */
-function node_node_form_default_settings() {
-  $defaults = array();
-
-  $defaults['title'] = array(
-    'enabled' => TRUE,
-    'label' => t('Title'),
-    'weight' => -5,
-  );
-  $defaults['body_field'] = array(
-    'enabled' => TRUE,
-    'label' => t('Body'),
-    'min_word_count' => 0,
-    'weight' => 0,
-  );
-  $defaults['revision_information'] = array(
-    'enabled' => TRUE,
-    'collapsible' => TRUE,
-    'collapsed' => TRUE,
-    'weight' => 20,
-    'revision' => FALSE,
-  );
-  $defaults['author'] = array(
-    'collapsible' => TRUE,
-    'collapsed' => TRUE,
-    'weight' => 21,
-  );
-  $defaults['options'] = array(
-    'collapsible' => TRUE,
-    'collapsed' => TRUE,
-    'status' => 1,
-    'promote' => 0,
-    'sticky' => 0,
-    'weight' => 25,
-  );
-
-  return $defaults;
-}
diff --git a/sites/all/modules/form_builder/modules/node/form_builder_node.info b/sites/all/modules/form_builder/modules/node/form_builder_node.info
deleted file mode 100644
index 9812dd84016f640716bb2c26cab6d9d1638f593b..0000000000000000000000000000000000000000
--- a/sites/all/modules/form_builder/modules/node/form_builder_node.info
+++ /dev/null
@@ -1,11 +0,0 @@
-name = Form builder Node UI
-description = Form builder enhancements for node module.
-core = 6.x
-dependencies[] = form_builder
-
-; Information added by drupal.org packaging script on 2011-06-06
-version = "7.x-1.x-dev"
-core = "7.x"
-project = "form_builder"
-datestamp = "1307319364"
-
diff --git a/sites/all/modules/form_builder/modules/node/form_builder_node.install b/sites/all/modules/form_builder/modules/node/form_builder_node.install
deleted file mode 100644
index 4419a037ad48cbae2ba82d3741bbbae66945748d..0000000000000000000000000000000000000000
--- a/sites/all/modules/form_builder/modules/node/form_builder_node.install
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-
-/**
- * @file
- *   Add the node_settings_table to Drupal.
- */
-
-/**
- * Implementation of hook_schema().
- */
-function form_builder_node_schema() {
-  $schema = array();
-
-  $schema['node_form_settings'] = array(
-    'fields' => array(
-      'type' => array(
-        'type' => 'varchar',
-        'length' => '32',
-        'not null' => TRUE,
-      ),
-      'field' => array(
-        'type' => 'varchar',
-        'length' => '255',
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'module' => array(
-        'type' => 'varchar',
-        'length' => '255',
-        'not null' => TRUE,
-        'default' => '',
-      ),
-      'settings' => array(
-        'type' => 'text',
-        'not null' => TRUE,
-      ),
-    ),
-    'primary key' => array('type', 'field'),
-  );
-
-  return $schema;
-}
-
-/**
- * Implementation of hook_install().
- */
-function form_builder_node_install() {
-  db_update('system')
-    ->fields(array('weight' => 101))
-    ->condition('name', 'form_builder_node')
-    ->execute();
-}
diff --git a/sites/all/modules/form_builder/modules/node/form_builder_node.module b/sites/all/modules/form_builder/modules/node/form_builder_node.module
deleted file mode 100644
index 3be9fe6e63f3f9d74b79007a02eaa0ec0fd8086f..0000000000000000000000000000000000000000
--- a/sites/all/modules/form_builder/modules/node/form_builder_node.module
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-/**
- * @file
- *   Placeholder Form Builder implementations for core.
- */
-
-
-/**
- * Implementation of hook_menu().
- *
- * Note: This would be merged into node_menu().
- */
-function form_builder_node_menu() {
-  $items = array();
-
-  foreach (node_type_get_types('types') as $type) {
-    $type_url_str = str_replace('_', '-', $type->type);
-    $items['admin/build/node-type/'. $type_url_str .'/fields'] = array(
-      'title' => 'Fields',
-      'page callback' => 'node_form_edit',
-      'page arguments' => array($type),
-      'access arguments' => array('administer content types'),
-      'type' => MENU_LOCAL_TASK,
-    );
-    $items['admin/build/node-type/'. $type_url_str .'/fields/confirm'] = array(
-      'title' => 'Confirm field changes',
-      'page callback' => 'drupal_get_form',
-      'page arguments' => array('node_form_builder_save_form', $type, TRUE),
-      'access arguments' => array('administer content types'),
-      'type' => MENU_CALLBACK,
-    );
-  }
-
-  return $items;
-}
-
-/**
- * Implementation of hook_init().
- *
- * @todo Each one of these .inc files should be merged into their respective
- * modules.
- */
-function form_builder_node_init() {
-  // Pull in all the module include files.
-  $files = file_scan_directory(drupal_get_path('module', 'form_builder') . '/modules', '!^.*\.inc$!');
-  foreach ($files as $path => $file) {
-    include_once($path);
-  }
-}
-
-/**
- * Implementation of hook_form_alter().
- *
- * Call the node-specific hook_form_alter() in each .inc file.
- */
-function form_builder_node_form_alter(&$form, &$form_state, $form_id) {
-  foreach (module_implements('node_form_alter') as $module) {
-    // Prevent this function from calling itself recursively.
-    if ($module !== 'form_builder' && $module !== 'node') {
-      $function = $module . '_node_form_alter';
-      $function($form, $form_state, $form_id);
-    }
-  }
-
-  // Node must go last to set any necessary weights.
-  if (function_exists('node_node_form_alter')) {
-    node_node_form_alter($form, $form_state, $form_id);
-  }
-}
\ No newline at end of file
diff --git a/sites/all/modules/form_builder/modules/path.inc b/sites/all/modules/form_builder/modules/path.inc
deleted file mode 100644
index 3a3e6ffef829bb39c68d7843491c9ca35b70d08b..0000000000000000000000000000000000000000
--- a/sites/all/modules/form_builder/modules/path.inc
+++ /dev/null
@@ -1,151 +0,0 @@
-<?php
-
-/**
- * @file
- *   Form builder implementation for path.module.
- */
-
-/**
- * Implementation of hook_form_builder_types().
- */
-function path_form_builder_types() {
-  $fields = array();
-
-  // Make a default path settings to pass into the path form.
-  $settings = module_invoke('path', 'node_form_default_settings');
-
-  $fields['path_settings'] = array(
-    'title' => t('Path'),
-    'properties' => array(
-      'collapsible',
-      'collapsed',
-    ),
-    'default' => path_fieldset('', $settings['path']),
-    'unique' => TRUE,
-    'removable' => TRUE,
-    'configurable' => TRUE,
-    'palette_group' => 'special',
-  );
-
-  return array(
-    'node' => $fields,
-    'example' => $fields,
-  );
-}
-
-/**
- * Implementation of hook_form_builder_load_alter().
- */
-function path_form_builder_load_alter(&$form, $form_type, $form_id) {
-  if ($form_type == 'node') {
-    $settings = node_get_form_settings($form_id, 'path');
-    if ($settings['enabled']) {
-      $form['path'] = path_fieldset('', $settings);
-      $form['path']['#form_builder'] = array(
-        'element_id' => 'path_settings',
-        'element_type' => 'path_settings',
-      );
-    }
-  }
-}
-
-/**
- * Implementation of hook_form_builder_save().
- */
-function path_form_builder_save(&$form, $form_type, $form_id) {
-  if ($form_type == 'node') {
-    $element = form_builder_get_element($form, 'path_settings');
-    $node_type = $form_id;
-
-    if ($element) {
-      $settings = array(
-        'enabled' => TRUE,
-        'collapsible' => $element['#collapsible'],
-        'collapsed' => $element['#collapsed'],
-        'weight' => $element['#weight'],
-      );
-    }
-    else {
-      $settings = array(
-        'enabled' => FALSE,
-      );
-    }
-
-    node_set_form_settings($form_id, 'path', 'path', $settings);
-  }
-}
-
-/**
- * Implementation of hook_form_alter().
- *
- * @todo Merge this into path_form_alter().
- */
-function path_node_form_alter(&$form, &$form_state, $form_id) {
-  // Set properties of the path form item based on the path node form settings.
-  if (isset($form['#node']) && $form['#node']->type .'_node_form' == $form_id) {
-    $settings = node_get_form_settings($form['#node']->type, 'path');
-
-    if ($settings['enabled']) {
-      $path = isset($form['#node']->path) ? $form['#node']->path : '';
-      $form['path'] = path_fieldset($path, $settings);
-    }
-    else {
-      $form['path']['#access'] = FALSE;
-    }
-  }
-}
-
-/**
- * Implementation of hook_node_form_default_settings().
- *
- * Get the settings for the path fieldset on the node form.
- */
-function path_node_form_default_settings($type = NULL) {
-  $defaults = array();
-  $defaults['path'] = array(
-    'enabled' => TRUE,
-    'collapsible' => TRUE,
-    'collapsed' => TRUE,
-    'weight' => 30,
-  );
-  return $defaults;
-}
-
-
-/**
- * A straight copy/paste of path_form_alter(). Get the path node form.
- *
- * @param $path
- *   The contents of $node->path.
- * @param $path_settings
- *   An array with configuring properties of the path fieldset.
- *
- * @todo Put this function directly in path.module, abstracting it from
- * path_form_alter().
- */
-function path_fieldset($path, $path_settings) {
-  $form = array(
-    '#type' => 'fieldset',
-    '#title' => t('URL path settings'),
-    '#collapsible' => $path_settings['collapsible'],
-    '#collapsed' => $path_settings['collapsed'],
-    '#access' => user_access('create url aliases'),
-    '#weight' => $path_settings['weight'],
-  );
-  $form['path'] = array(
-    '#type' => 'textfield',
-    '#default_value' => $path,
-    '#maxlength' => 250,
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-    '#description' => t('Optionally specify an alternative URL by which this node can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'),
-  );
-  if ($path) {
-    $form['pid'] = array(
-      '#type' => 'value',
-      '#value' => db_query("SELECT pid FROM {url_alias} WHERE dst = :dst AND language = :language", array('path' => $path, 'language' => $form['#node']->language))->fetchField()
-    );
-  }
-
-  return $form;
-}
diff --git a/sites/all/modules/form_builder/modules/poll.inc b/sites/all/modules/form_builder/modules/poll.inc
deleted file mode 100644
index 4354e33188b4579ffc43d87bd62d043d9bb8b056..0000000000000000000000000000000000000000
--- a/sites/all/modules/form_builder/modules/poll.inc
+++ /dev/null
@@ -1,115 +0,0 @@
-<?php
-
-/**
- * @file
- *   Form builder implementation for poll.module.
- *
- *   Note this file doesn't actually do much of anything since node.inc
- *   now handles generic weight handling. But poll-specific functionality
- *   could be added here.
- */
-
-/**
- * Implementation of hook_form_builder_types().
- */
-function poll_form_builder_types() {
-  $fields = array();
-
-  $fields['poll_choices'] = array(
-    'title' => t('Menu'),
-    'properties' => array(),
-    'default' => array(),
-    'unique' => TRUE,
-    'configurable' => FALSE,
-    'removable' => FALSE,
-    'palette_group' => 'special',
-  );
-
-  $fields['poll_settings'] = array(
-    'title' => t('Menu'),
-    'properties' => array(),
-    'default' => array(),
-    'unique' => TRUE,
-    'configurable' => FALSE,
-    'removable' => FALSE,
-    'palette_group' => 'special',
-  );
-
-  return array(
-    'node' => $fields,
-  );
-}
-
-/**
- * Implementation of hook_form_builder_load_alter().
- */
-function poll_form_builder_load_alter(&$form, $form_type, $form_id) {
-  if ($form_type == 'node' && $form_id == 'poll') {
-
-    $choice_settings = node_get_form_settings($form_id, 'poll_choices');
-    $form['choice_wrapper']['#weight'] = $choice_settings['weight'];
-    $form['choice_wrapper']['#form_builder'] = array(
-      'element_id' => 'poll_choices',
-      'element_type' => 'poll_choices',
-    );
-
-    $poll_settings = node_get_form_settings($form_id, 'poll_settings');
-    $form['settings']['#weight'] = $poll_settings['weight'];
-    $form['settings']['#form_builder'] = array(
-      'element_id' => 'poll_settings',
-      'element_type' => 'poll_settings',
-    );
-  }
-}
-
-/**
- * Implementation of hook_form_builder_save().
- */
-function poll_form_builder_save(&$form, $form_type, $form_id) {
-  if ($form_type == 'node') {
-    $node_type = $form_id;
-
-    $element = form_builder_get_element($form, 'poll_choices');
-    $settings = array(
-      'weight' => $element['#weight'],
-    );
-    node_set_form_settings($node_type, 'poll_choices', 'poll', $settings);
-
-    $element = form_builder_get_element($form, 'poll_settings');
-    $settings = array(
-      'weight' => $element['#weight'],
-    );
-    node_set_form_settings($node_type, 'poll_settings', 'poll', $settings);
-  }
-}
-
-/**
- * Implementation of hook_form_alter().
- *
- * @todo Merge this into poll_form_alter().
- */
-function poll_node_form_alter(&$form, &$form_state, $form_id) {
-  // Set properties of the poll form item based on the poll node form settings.
-  if ($form_id == 'poll_node_form') {
-    $choice_settings = node_get_form_settings($form['#node']->type, 'poll_choices');
-    $poll_settings = node_get_form_settings($form['#node']->type, 'poll_settings');
-    $form['choice_wrapper']['#weight'] = $choice_settings['weight'];
-    $form['settings']['#weight'] = $poll_settings['weight'];
-  }
-}
-
-/**
- * Implementation of hook_node_form_default_settings().
- *
- * Get the default settings for the poll modifications to the node form.
- */
-function poll_node_form_default_settings($node_type = NULL) {
-  $defaults = array();
-  $defaults['poll_choices'] = array(
-    'weight' => -4,
-  );
-    $defaults['settings'] = array(
-    'weight' => -3,
-  );
-  return $defaults;
-}
diff --git a/sites/all/modules/form_builder/modules/taxonomy.inc b/sites/all/modules/form_builder/modules/taxonomy.inc
deleted file mode 100644
index 81dc88cfb783d35cf074eb5d89f2f14674546b1c..0000000000000000000000000000000000000000
--- a/sites/all/modules/form_builder/modules/taxonomy.inc
+++ /dev/null
@@ -1,256 +0,0 @@
-<?php
-
-/**
- * @file
- *   Form builder implementation for taxonomy.module.
- */
-
-/**
- * Implementation of hook_form_builder_types().
- */
-function taxonomy_form_builder_types() {
-  $fields = array();
-
-  $vocabularies = taxonomy_get_vocabularies();
-  $terms = array();
-
-  // If no taxonomies are specified, do not allow the field to be added.
-  if (empty($vocabularies)) {
-    return array();
-  }
-
-  $first_vocab = reset($vocabularies);
-  $vocabularies = array($first_vocab->vid => $first_vocab);
-  $settings = module_invoke('taxonomy', 'node_form_default_settings');;
-  $default_form = taxonomy_fieldset($vocabularies, $terms, $settings['taxonomy']);
-  $default_form['#taxonomy_vocabularies'] = array_keys($vocabularies);
-
-  $fields['taxonomy'] = array(
-    'title' => t('Taxonomy'),
-    'properties' => array(
-      'taxonomy_vocabularies',
-    ),
-    'default' => $default_form,
-    'unique' => TRUE,
-    'palette_group' => 'special',
-  );
-
-  return array(
-    'node' => $fields,
-    'example' => $fields,
-  );
-}
-
-/**
- * Implementation of hook_form_builder_properties().
- */
-function taxonomy_form_builder_properties($form_type) {
-  if ($form_type == 'node') {
-    return array(
-      'taxonomy_vocabularies' => array(
-        'form' => 'taxonomy_vocabularies_configuration',
-      ),
-    );
-  }
-}
-
-/**
- * Form builder property form callback.
- */
-function taxonomy_vocabularies_configuration(&$form_state, $form_type, $element) {
-  $form = array();
-
-  $vocabularies = taxonomy_get_vocabularies();
-  $options = array();
-  foreach ($vocabularies as $vid => $vocabulary) {
-    $options[$vid] = $vocabulary->name;
-  }
-
-  $form['taxonomy_vocabularies'] = array(
-    '#title' => t('Enabled vocabularies'),
-    '#type' => 'checkboxes',
-    '#default_value' => $element['#taxonomy_vocabularies'],
-    '#options' => $options,
-    '#required' => TRUE,
-    '#description' => t('Configure taxonomy element properties or add new vocabularies by visiting the <a href="!url">Taxonomy administration section</a>. If no vocabularies are desired for this form, remove the taxonomy element entirely.', array('!url' => url('admin/content/taxonomy'))),
-  );
-
-  return $form;
-}
-
-/**
- * Implementation of hook_form_builder_preview_alter().
- *
- * Update the taxonomy element with the new vocabularies.
- */
-function taxonomy_form_builder_preview_alter(&$element, $form_type, $form_id) {
-  if ($element['#form_builder']['element_id'] == 'taxonomy') {
-    // Remove current taxonomies from the element.
-    foreach (element_children($element) as $key) {
-      if (is_numeric($key)) {
-        unset($element[$key]);
-      }
-    }
-
-    $vocabularies = array_intersect_key(taxonomy_get_vocabularies(), array_flip($element['#taxonomy_vocabularies']));
-    $terms = array();
-    $settings = array(
-      'weight' => $element['#weight'],
-    );
-    $form = taxonomy_fieldset($vocabularies, $terms, $settings);
-    $element = array_merge($form, $element);
-  }
-}
-
-/**
- * Implementation of hook_form_builder_load_alter().
- */
-function taxonomy_form_builder_load_alter(&$form, $form_type, $form_id) {
-  if ($form_type == 'node') {
-    $settings = node_get_form_settings($form_id, 'taxonomy');
-    $vocabularies = taxonomy_get_vocabularies($form['#node']->type);
-    $terms = isset($form['#node']->terms) ? $form['#node']->terms : array();
-
-    if (count($vocabularies)) {
-      $form['taxonomy'] = taxonomy_fieldset($vocabularies, $terms, $settings);
-      $form['taxonomy']['#form_builder'] = array(
-        'element_id' => 'taxonomy',
-        'element_type' => 'taxonomy',
-      );
-      $form['taxonomy']['#taxonomy_vocabularies'] = array_keys($vocabularies);
-    }
-  }
-}
-
-/**
- * Implementation of hook_form_alter().
- *
- * @todo Merge this into taxonomy_form_alter().
- */
-function taxonomy_node_form_alter(&$form, &$form_state, $form_id) {
-  // Set properties of the menu form item based on the menu node form settings.
-  if (isset($form['#node']) && $form['#node']->type .'_node_form' == $form_id) {
-    if (isset($form['taxonomy'])) {
-      $settings = node_get_form_settings($form['#node']->type, 'taxonomy');
-      $form['taxonomy']['#weight'] = $settings['weight'];
-    }
-  }
-}
-/**
- * Implementation of hook_form_builder_save().
- */
-function taxonomy_form_builder_save(&$form, $form_type, $form_id) {
-  if ($form_type == 'node') {
-    $element = form_builder_get_element($form, 'taxonomy');
-    $vocabularies = taxonomy_get_vocabularies();
-    $node_type = $form_id;
-
-    if ($element) {
-      $settings = array('weight' => $element['#weight']);
-      variable_set('taxonomy_settings_' . $node_type, $settings);
-      $enabled_vocabularies = drupal_map_assoc($element['#taxonomy_vocabularies']);
-      foreach ($vocabularies as $vid => $vocabulary) {
-        $vocabulary = (array) $vocabulary;
-        if (isset($enabled_vocabularies[$vid]) && !isset($vocabular['nodes'][$node_type])) {
-          $vocabulary['nodes'][$node_type] = $node_type;
-          taxonomy_save_vocabulary($vocabulary);
-        }
-        elseif (!isset($enabled_vocabularies[$vid]) && isset($vocabulary['nodes'][$node_type])) {
-          unset($vocabulary['nodes'][$node_type]);
-          taxonomy_save_vocabulary($vocabulary);
-        }
-      }
-    }
-    else {
-      variable_del('taxonomy_settings_' . $node_type);
-      foreach ($vocabularies as $vid => $vocabulary) {
-        $vocabulary = (array) $vocabulary;
-        if (isset($vocabulary['nodes'][$node_type])) {
-          unset($vocabulary['nodes'][$node_type]);
-          taxonomy_save_vocabulary($vocabulary);
-        }
-      }
-    }
-  }
-}
-
-/**
- * Implementation of hook_node_form_default_settings().
- *
- * Get the settings for the taxonomy fieldset on the node form.
- */
-function taxonomy_node_form_default_settings($type = NULL) {
-  $defaults = array();
-  $defaults['taxonomy'] = array(
-    'weight' => -3,
-  );
-  return $defaults;
-}
-
-/**
- * A straight copy/paste of taxonomy_form_alter(). Get the taxonomy node form.
- *
- * @todo Put this function directly in taxonomy.module, abstracting it from
- * taxonomy_form_alter().
- */
-function taxonomy_fieldset($vocabularies, $terms, $settings) {
-  $form = array();
-
-  if (!variable_get('taxonomy_override_selector', FALSE)) {
-    foreach ($vocabularies as $vocabulary) {
-      if ($vocabulary->tags) {
-        if (isset($form_state['node_preview'])) {
-          // Typed string can be changed by the user before preview,
-          // so we just insert the tags directly as provided in the form.
-          $typed_string = $terms['tags'][$vocabulary->vid];
-        }
-        else {
-          $typed_string = taxonomy_implode_tags($terms, $vocabulary->vid) . (array_key_exists('tags', $terms) ? $terms['tags'][$vocabulary->vid] : NULL);
-        }
-        if ($vocabulary->help) {
-          $help = $vocabulary->help;
-        }
-        else {
-          $help = t('A comma-separated list of terms describing this content. Example: funny, bungee jumping, "Company, Inc.".');
-        }
-        $form['tags'][$vocabulary->vid] = array('#type' => 'textfield',
-          '#title' => $vocabulary->name,
-          '#description' => $help,
-          '#required' => $vocabulary->required,
-          '#default_value' => $typed_string,
-          '#autocomplete_path' => 'taxonomy/autocomplete/'. $vocabulary->vid,
-          '#weight' => $vocabulary->weight,
-          '#maxlength' => 255,
-        );
-      }
-      else {
-        // Extract terms belonging to the vocabulary in question.
-        $default_terms = array();
-        foreach ($terms as $term) {
-          // Free tagging has no default terms and also no vid after preview.
-          if (isset($term->vid) && $term->vid == $vocabulary->vid) {
-            $default_terms[$term->tid] = $term;
-          }
-        }
-        $form[$vocabulary->vid] = taxonomy_form($vocabulary->vid, array_keys($default_terms), $vocabulary->help);
-        $form[$vocabulary->vid]['#weight'] = $vocabulary->weight;
-        $form[$vocabulary->vid]['#required'] = $vocabulary->required;
-      }
-    }
-    if (!empty($form) && is_array($form)) {
-      if (count($form) > 1) {
-        // Add fieldset only if form has more than 1 element.
-        $form += array(
-          '#type' => 'fieldset',
-          '#title' => t('Vocabularies'),
-          '#collapsible' => TRUE,
-          '#collapsed' => FALSE,
-        );
-      }
-      $form['#weight'] = $settings['weight'];
-      $form['#tree'] = TRUE;
-    }
-  }
-
-  return $form;
-}
diff --git a/sites/all/modules/form_builder/modules/upload.inc b/sites/all/modules/form_builder/modules/upload.inc
deleted file mode 100644
index c22266f23c6650c648fd034bffc6c959252fb80c..0000000000000000000000000000000000000000
--- a/sites/all/modules/form_builder/modules/upload.inc
+++ /dev/null
@@ -1,169 +0,0 @@
-<?php
-
-/**
- * @file
- *   Form builder implementation for upload.module.
- */
-
-/**
- * Implementation of hook_form_builder_types().
- */
-function upload_form_builder_types() {
-  $fields = array();
-
-  // Make a pseudo node for the upload form.
-  $node = (object) array(
-    'type' => '',
-    'files' => array(),
-  );
-
-  // Make a default path settings to pass into the upload form.
-  $settings = module_invoke('upload', 'node_form_default_settings');
-
-  $fields['upload_settings'] = array(
-    'title' => t('Attachments'),
-    'properties' => array(
-      'collapsible',
-      'collapsed',
-    ),
-    'default' => upload_fieldset($node, $settings['attachments']),
-    'unique' => TRUE,
-    'removable' => TRUE,
-    'configurable' => TRUE,
-    'palette_group' => 'special',
-  );
-
-  return array(
-    'node' => $fields,
-    'example' => $fields,
-  );
-}
-
-/**
- * Implementation of hook_form_builder_load_alter().
- */
-function upload_form_builder_load_alter(&$form, $form_type, $form_id) {
-  if ($form_type == 'node' && isset($form['attachments'])) {
-    $form['attachments']['#form_builder'] = array(
-      'element_id' => 'upload_settings',
-      'element_type' => 'upload_settings',
-    );
-    // Unset the the attach button.
-    unset($form['attachments']['wrapper']['new']['attach']['#ahah']);
-    $form['attachments']['wrapper']['new']['attach']['#disabled'] = TRUE;
-  }
-}
-
-/**
- * Implementation of hook_form_builder_save().
- */
-function upload_form_builder_save(&$form, $form_type, $form_id) {
-  if ($form_type == 'node') {
-    $element = form_builder_get_element($form, 'upload_settings');
-    $node_type = $form_id;
-
-    if ($element) {
-      $settings = array(
-        'enabled' => TRUE,
-        'collapsible' => $element['#collapsible'],
-        'collapsed' => $element['#collapsed'],
-        'weight' => $element['#weight'],
-      );
-      variable_set('upload_' . $node_type, '1');
-    }
-    else {
-      $settings = array(
-        'enabled' => FALSE,
-      );
-      variable_set('upload_' . $node_type, '0');
-    }
-
-    node_set_form_settings($form_id, 'attachments', 'upload', $settings);
-  }
-}
-
-/**
- * Implementation of hook_form_alter().
- *
- * @todo Merge this into upload_form_alter().
- */
-function upload_node_form_alter(&$form, &$form_state, $form_id) {
-  // Set properties of the path form item based on the path node form settings.
-  if (isset($form['#node']) && $form['#node']->type .'_node_form' == $form_id) {
-    if (isset($form['attachments'])) {
-      $settings = node_get_form_settings($form['#node']->type, 'attachments');
-      $form['attachments']['#weight'] = $settings['weight'];
-      $form['attachments']['#collapsible'] = $settings['collapsible'];
-      $form['attachments']['#collapsed'] = $settings['collapsed'];
-    }
-  }
-}
-
-/**
- * Implementation of hook_node_form_default_settings().
- *
- * Get the settings for the path fieldset on the node form.
- */
-function upload_node_form_default_settings($type = NULL) {
-  $defaults = array();
-  $defaults['attachments'] = array(
-    'enabled' => TRUE,
-    'collapsible' => TRUE,
-    'collapsed' => TRUE,
-    'weight' => 30,
-  );
-  return $defaults;
-}
-
-
-/**
- * A straight copy/paste of path_form_alter(). Get the path node form.
- *
- * @param $path
- *   The contents of $node->path.
- * @param $path_settings
- *   An array with configuring properties of the path fieldset.
- *
- * @todo Put this function directly in path.module, abstracting it from
- * path_form_alter().
- */
-function upload_fieldset($node, $upload_settings) {
-  // Attachments fieldset
-  $form = array(
-    '#type' => 'fieldset',
-    '#access' => user_access('upload files'),
-    '#title' => t('File attachments'),
-    '#collapsible' => $upload_settings['collapsible'],
-    '#collapsed' => empty($node->files) && $upload_settings['collapsed'],
-    '#description' => t('Changes made to the attachments are not permanent until you save this post. The first "listed" file will be included in RSS feeds.'),
-    '#prefix' => '<div class="attachments">',
-    '#suffix' => '</div>',
-    '#weight' => 30,
-  );
-
-  // Wrapper for fieldset contents (used by ahah.js).
-  $form['wrapper'] = array(
-    '#prefix' => '<div id="attach-wrapper">',
-    '#suffix' => '</div>',
-  );
-
-  // Make sure necessary directories for upload.module exist and are
-  // writable before displaying the attachment form.
-  $path = file_directory_path();
-  $temp = file_directory_temp();
-  // Note: pass by reference
-  if (!file_check_directory($path, FILE_CREATE_DIRECTORY) || !file_check_directory($temp, FILE_CREATE_DIRECTORY)) {
-    $form['#description'] =  t('File attachments are disabled. The file directories have not been properly configured.');
-    if (user_access('administer site configuration')) {
-      $form['#description'] .= ' '. t('Please visit the <a href="@admin-file-system">file system configuration page</a>.', array('@admin-file-system' => url('admin/settings/file-system')));
-    }
-    else {
-      $form['#description'] .= ' '. t('Please contact the site administrator.');
-    }
-  }
-  elseif (drupal_function_exists('_upload_form')) {
-    $form['wrapper'] += _upload_form($node);
-  }
-
-  return $form;
-}
diff --git a/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc b/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc
index aa00c8df7f6b05d4d38b6bdbba5b6b1a576cb018..b487734670526e7080dc21f7d84234a303cc41cc 100644
--- a/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc
+++ b/sites/all/modules/form_builder/modules/webform/form_builder_webform.components.inc
@@ -18,20 +18,7 @@ function _form_builder_webform_form_builder_types_date() {
 
   $fields['date'] = array(
     'title' => t('Date'),
-    'properties' => array(
-      'title',
-      'description',
-      'default_value',
-      'required',
-      'key',
-      'title_display',
-      // Date-specific properties.
-      'timezone',
-      'year_start',
-      'year_end',
-      'year_textfield',
-      'datepicker',
-    ),
+    'weight' => -2,
   );
   $fields['date']['default'] = _form_builder_webform_default('date');
   $fields['date']['default']['#title'] = t('New date');
@@ -40,78 +27,36 @@ function _form_builder_webform_form_builder_types_date() {
 }
 
 /**
- * Implements _form_builder_webform_form_builder_properties_component().
+ * Implements _form_builder_webform_form_builder_map_component().
  */
-function _form_builder_webform_form_builder_properties_date() {
+function _form_builder_webform_form_builder_map_date() {
   return array(
-    'timezone' => array(
-      'form' => 'form_builder_webform_property_date_timezone_form',
-    ),
-    'year_start' => array(
-      'form' => 'form_builder_webform_property_date_year_start_form',
-    ),
-    'year_end' => array(
-      'form' => 'form_builder_webform_property_date_year_end_form',
-    ),
-    'year_textfield' => array(
-      'form' => 'form_builder_webform_property_date_year_textfield_form',
-    ),
-    'datepicker' => array(
-      'form' => 'form_builder_webform_property_date_datepicker_form',
+    'form_builder_type' => 'date',
+    'properties' => array(
+      'timezone' => array(
+        'form_parents' => array('default', 'timezone'),
+        'storage_parents' => array('extra', 'timezone'),
+      ),
+      'year_start' => array(
+        'form_parents' => array('validation', 'year_start'),
+        'storage_parents' => array('extra', 'year_start'),
+      ),
+      'year_end' => array(
+        'form_parents' => array('validation', 'year_end'),
+        'storage_parents' => array('extra', 'year_end'),
+      ),
+      'year_textfield' => array(
+        'form_parents' => array('display', 'year_textfield'),
+        'storage_parents' => array('extra', 'year_textfield'),
+      ),
+      'datepicker' => array(
+        'form_parents' => array('display', 'datepicker'),
+        'storage_parents' => array('extra', 'datepicker'),
+      ),
     ),
   );
 }
 
-/**
- * Implements _form_builder_webform_form_builder_save_component().
- */
-function _form_builder_webform_form_builder_save_date($component, $form_element) {
-  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
-  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
-  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
-  $component['extra']['timezone'] = isset($form_element['#timezone']) ? $form_element['#timezone'] : 'user';
-  $component['extra']['year_start'] = isset($form_element['#year_start']) ? $form_element['#year_start'] : '-2';
-  $component['extra']['year_end'] = isset($form_element['#year_end']) ? $form_element['#year_end'] : '+2';
-  $component['extra']['year_textfield'] = isset($form_element['#year_textfield']) ? $form_element['#year_textfield'] : FALSE;
-  $component['extra']['datepicker'] = isset($form_element['#datepicker']) ? $form_element['#datepicker'] : FALSE;
-  return $component;
-}
-
-/**
- * Configuration form for the "timezone" property.
- */
-function form_builder_webform_property_date_timezone_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('date', $element, 'timezone', NULL, array('extra', 'timezone'), array('extra', 'timezone'));
-}
-
-/**
- * Configuration form for the "year_start" property.
- */
-function form_builder_webform_property_date_year_start_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('date', $element, 'year_start', 'validation', array('validation', 'year_start'), array('extra', 'year_start'));
-}
-
-/**
- * Configuration form for the "year_end" property.
- */
-function form_builder_webform_property_date_year_end_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('date', $element, 'year_end', 'validation', array('validation', 'year_end'), array('extra', 'year_end'));
-}
-
-/**
- * Configuration form for the "year_textfield" property.
- */
-function form_builder_webform_property_date_year_textfield_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('date', $element, 'year_textfield', 'display', array('display', 'year_textfield'), array('extra', 'year_textfield'));
-}
-
-/**
- * Configuration form for the "datepicker" property.
- */
-function form_builder_webform_property_date_datepicker_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('date', $element, 'datepicker', 'display', array('display', 'datepicker'), array('extra', 'datepicker'));
-}
-
 /**
  * @} End of "defgroup form-builder-webform-date-callbacks"
  */
@@ -129,15 +74,7 @@ function _form_builder_webform_form_builder_types_email() {
 
   $fields['email'] = array(
     'title' => t('E-mail'),
-    'properties' => array(
-      'title',
-      'description',
-      'default_value',
-      'required',
-      'size',
-      'key',
-      'title_display',
-    ),
+    'weight' => -18,
   );
   $fields['email']['default'] = _form_builder_webform_default('email');
   $fields['email']['default']['#title'] = t('New e-mail');
@@ -146,14 +83,20 @@ function _form_builder_webform_form_builder_types_email() {
 }
 
 /**
- * Implements _form_builder_webform_form_builder_save_component().
+ * Implements _form_builder_webform_form_builder_map_component().
  */
-function _form_builder_webform_form_builder_save_email($component, $form_element) {
-  $component['extra']['width'] = isset($form_element['#size']) ? $form_element['#size'] : NULL;
-  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
-  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
-  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
-  return $component;
+function _form_builder_webform_form_builder_map_email() {
+  return array(
+    'form_builder_type' => 'email',
+    'properties' => array(
+      'size' => array(
+        'storage_parents' => array('extra', 'width'),
+      ),
+      'disabled' => array(
+        'storage_parents' => array('extra', 'disabled'),
+      ),
+    ),
+  );
 }
 
 /**
@@ -173,13 +116,7 @@ function _form_builder_webform_form_builder_types_fieldset() {
 
   $fields['fieldset'] = array(
     'title' => t('Fieldset'),
-    'properties' => array(
-      'title',
-      'description',
-      'collapsible',
-      'collapsed',
-      'key',
-    ),
+    'weight' => 19,
   );
   $fields['fieldset']['default'] = _form_builder_webform_default('fieldset');
   $fields['fieldset']['default']['#title'] = t('New fieldset');
@@ -188,13 +125,20 @@ function _form_builder_webform_form_builder_types_fieldset() {
 }
 
 /**
- * Implements _form_builder_webform_form_builder_save_component().
+ * Implements _form_builder_webform_form_builder_map_component().
  */
-function _form_builder_webform_form_builder_save_fieldset($component, $form_element) {
-  $component['extra']['collapsible'] = isset($form_element['#collapsible']) ? $form_element['#collapsible'] : NULL;
-  $component['extra']['collapsed'] = isset($form_element['#collapsed']) ? $form_element['#collapsed'] : NULL;
-  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : '';
-  return $component;
+function _form_builder_webform_form_builder_map_fieldset() {
+  return array(
+    'form_builder_type' => 'fieldset',
+    'properties' => array(
+      'collapsible' => array(
+        'storage_parents' => array('extra', 'collapsible'),
+      ),
+      'collapsed' => array(
+        'storage_parents' => array('extra', 'collapsed'),
+      ),
+    ),
+  );
 }
 
 /**
@@ -214,115 +158,63 @@ function _form_builder_webform_form_builder_types_file() {
 
   $fields['file'] = array(
     'title' => t('File'),
-    'properties' => array(
-      'title',
-      'description',
-      'required',
-      'key',
-      'title_display',
-      'webform_file_filtering',
-      'webform_file_savelocation',
-      'webform_file_width',
-    ),
+    'weight' => 6,
   );
-  $file_element = _form_builder_webform_default('file');
-  $fields['file']['default'] = $file_element['default'];
+
+  $fields['file']['default'] = _form_builder_webform_default('file');
   $fields['file']['default']['#title'] = t('New file');
-  $fields['file']['default']['#theme_wrappers'] = array('webform_element');
 
   return $fields;
 }
 
 /**
- * Implements _form_builder_webform_form_builder_properties_component().
+ * Implements _form_builder_webform_form_builder_map_component().
  */
-function _form_builder_webform_form_builder_properties_file() {
+function _form_builder_webform_form_builder_map_file() {
   return array(
-    'webform_file_filtering' => array(
-      'form' => 'form_builder_webform_property_webform_file_filtering_form',
-    ),
-    'webform_file_savelocation' => array(
-      'form' => 'form_builder_webform_property_webform_file_savelocation_form',
-    ),
-    'webform_file_width' => array(
-      'form' => 'form_builder_webform_property_webform_file_width_form',
+    'form_builder_type' => 'file',
+    'properties' => array(
+      // Webform 3.16 and earlier file filtering.
+      'webform_file_filtering' => array(
+        'form_parents' => array('validation', 'filtering'),
+        'storage_parents' => array('extra', 'filtering'),
+      ),
+      // Webform 3.17 and later file filtering.
+      'webform_file_extensions' => array(
+        'form_parents' => array('validation', 'extensions'),
+        'storage_parents' => array('extra', 'filtering'),
+      ),
+      'webform_file_size' => array(
+        'form_parents' => array('validation', 'size'),
+        'storage_parents' => array('extra', 'filtering', 'size'),
+      ),
+      'webform_file_directory' => array(
+        'form_parents' => array('extra', 'directory'),
+        'storage_parents' => array('extra', 'directory'),
+      ),
+      'webform_file_scheme' => array(
+        'form_parents' => array('extra', 'scheme'),
+        'storage_parents' => array('extra', 'scheme'),
+      ),
+      'webform_file_progress_indicator' => array(
+        'form_parents' => array('display', 'progress_indicator'),
+        'storage_parents' => array('extra', 'progress_indicator'),
+      ),
     ),
   );
 }
 
-/**
- * Implements _form_builder_webform_form_builder_load_component().
- */
-function _form_builder_webform_form_builder_load_file($form_element) {
-  // If we are loading a file element, _webform_render_file() adds some extra
-  // structure (including several element children) that we don't want here.
-  // Instead, we need the element itself to represent the file component
-  // directly.
-  if (isset($form_element['#webform_component']['type']) && $form_element['#webform_component']['type'] == 'file') {
-    $form_element['#type'] = 'file';
-    unset($form_element['#theme']);
-    foreach (element_children($form_element) as $key) {
-      unset($form_element[$key]);
-    }
-    // Set the custom webform file properties based on the values stored with
-    // the webform component.
-    if (isset($form_element['#webform_component']['extra']['filtering'])) {
-      $form_element['#webform_file_filtering'] = $form_element['#webform_component']['extra']['filtering'];
-    }
-    if (isset($form_element['#webform_component']['extra']['savelocation'])) {
-      $form_element['#webform_file_savelocation'] = $form_element['#webform_component']['extra']['savelocation'];
-    }
-    if (isset($form_element['#webform_component']['extra']['width'])) {
-      $form_element['#webform_file_width'] = $form_element['#webform_component']['extra']['width'];
-    }
-  }
-
-  return $form_element;
-}
-
 /**
  * Implements _form_builder_webform_form_builder_preview_alter_component().
  */
 function _form_builder_webform_form_builder_preview_alter_file($form_element) {
-  // Map our pseudo-property to the visible "size" property.
-  $form_element['#size'] = $form_element['#webform_file_width'];
-
-  return $form_element;
-}
-
-/**
- * Implements _form_builder_webform_form_builder_save_component().
- */
-function _form_builder_webform_form_builder_save_file($component, $form_element) {
-  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
-  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
-  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
-  $component['extra']['filtering'] = isset($form_element['#webform_file_filtering']) ? $form_element['#webform_file_filtering'] : array();
-  $component['extra']['savelocation'] = isset($form_element['#webform_file_savelocation']) ? $form_element['#webform_file_savelocation'] : NULL;
-  $component['extra']['width'] = isset($form_element['#webform_file_width']) ? $form_element['#webform_file_width'] : NULL;
-
-  return $component;
-}
-
-/**
- * Configuration form for the "webform_file_filtering" property.
- */
-function form_builder_webform_property_webform_file_filtering_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('file', $element, 'webform_file_filtering', 'validation', array('validation', 'filtering'), array('extra', 'filtering'));
-}
 
-/**
- * Configuration form for the "webform_file_savelocation" property.
- */
-function form_builder_webform_property_webform_file_savelocation_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('file', $element, 'webform_file_savelocation', 'default', array('extra', 'savelocation'), array('extra', 'savelocation'));
-}
+  // Remove AJAX wrappers.
+  $form_element['#prefix'] = '';
+  $form_element['#suffix'] = '';
+  $form_element['upload_button']['#disabled'] = TRUE;
 
-/**
- * Configuration form for the "webform_file_width" property.
- */
-function form_builder_webform_property_webform_file_width_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('file', $element, 'webform_file_width', 'display', array('display', 'width'), array('extra', 'width'));
+  return $form_element;
 }
 
 /**
@@ -343,19 +235,13 @@ function _form_builder_webform_form_builder_types_grid() {
   $fields['grid'] = array(
     'title' => t('Grid'),
     'properties' => array(
-      'title',
-      'description',
-      'required',
-      'key',
-      'title_display',
       // Grid-specific properties.
       'grid_options',
       'grid_questions',
       'custom_grid_option_keys',
       'custom_grid_question_keys',
-      'optrand',
-      'qrand',
     ),
+    'weight' => -4,
   );
   $fields['grid']['default'] = _form_builder_webform_default('grid');
   $fields['grid']['default']['#title'] = t('New grid');
@@ -365,6 +251,25 @@ function _form_builder_webform_form_builder_types_grid() {
   return $fields;
 }
 
+/**
+ * Implements _form_builder_webform_form_builder_map_component().
+ */
+function _form_builder_webform_form_builder_map_grid() {
+  return array(
+    'form_builder_type' => 'grid',
+    'properties' => array(
+      'optrand' => array(
+        'form_parents' => array('display', 'optrand'),
+        'storage_parents' => array('extra', 'optrand'),
+      ),
+      'qrand' => array(
+        'form_parents' => array('display', 'qrand'),
+        'storage_parents' => array('extra', 'qrand'),
+      ),
+    ),
+  );
+}
+
 /**
  * Implements _form_builder_webform_form_builder_properties_component().
  */
@@ -378,12 +283,6 @@ function _form_builder_webform_form_builder_properties_grid() {
       'form' => 'form_builder_webform_property_grid_questions_form',
       'submit' => array('form_builder_webform_property_grid_form_submit'),
     ),
-    'optrand' => array(
-      'form' => 'form_builder_webform_property_grid_optrand_form'
-    ),
-    'qrand' => array(
-      'form' => 'form_builder_webform_property_grid_qrand_form'
-    ),
   );
 }
 
@@ -391,15 +290,10 @@ function _form_builder_webform_form_builder_properties_grid() {
  * Implements _form_builder_webform_form_builder_load_component().
  */
 function _form_builder_webform_form_builder_load_grid($element) {
-  if (isset($element['#type']) && $element['#type'] == 'webform_grid') {
-    // Elements of type "webform_grid" are known to Form Builder as simply a
-    // "grid" field. This makes it so that we use the generic grid icon.
-    $element['#form_builder']['element_type'] = 'grid';
-
-    // Convert properties used only in Form Builder.
-    $element['#custom_grid_option_keys'] = !empty($element['#webform_component']['extra']['custom_option_keys']);
-    $element['#custom_grid_question_keys'] = !empty($element['#webform_component']['extra']['custom_question_keys']);
-  }
+  // Convert properties used only in Form Builder.
+  $element['#custom_grid_option_keys'] = !empty($element['#webform_component']['extra']['custom_option_keys']);
+  $element['#custom_grid_question_keys'] = !empty($element['#webform_component']['extra']['custom_question_keys']);
+
   return $element;
 }
 
@@ -418,14 +312,10 @@ function _form_builder_webform_form_builder_save_grid($component, $form_element)
     $questions .= $key . '|' . $question_value . "\n";
   }
 
-  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
-  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
   $component['extra']['options'] = $options;
   $component['extra']['questions'] = $questions;
   $component['extra']['custom_option_keys'] = isset($form_element['#custom_grid_option_keys']) ? $form_element['#custom_grid_option_keys'] : FALSE;
   $component['extra']['custom_question_keys'] =  isset($form_element['#custom_grid_question_keys']) ? $form_element['#custom_grid_question_keys'] : FALSE;
-  $component['extra']['optrand'] = !empty($form_element['#optrand']);
-  $component['extra']['qrand'] = !empty($form_element['#qrand']);
 
   return $component;
 }
@@ -469,20 +359,6 @@ function form_builder_webform_property_grid_form_submit(&$form, &$form_state) {
   }
 }
 
-/**
- * Configuration form for the "optrand" property.
- */
-function form_builder_webform_property_grid_optrand_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('grid', $element, 'optrand', 'display', array('display', 'optrand'), array('extra', 'optrand'));
-}
-
-/**
- * Configuration form for the "qrand" property.
- */
-function form_builder_webform_property_grid_qrand_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('grid', $element, 'qrand', 'display', array('display', 'qrand'), array('extra', 'qrand'));
-}
-
 /**
  * @} End of "defgroup form-builder-webform-time-callbacks"
  */
@@ -500,11 +376,7 @@ function _form_builder_webform_form_builder_types_hidden() {
 
   $fields['hidden'] = array(
     'title' => t('Hidden'),
-    'properties' => array(
-      'title',
-      'default_value',
-      'key',
-    ),
+    'weight' => 8,
   );
   $fields['hidden']['default'] = _form_builder_webform_default('hidden');
   $fields['hidden']['default']['#title'] = t('New hidden');
@@ -559,11 +431,10 @@ function _form_builder_webform_form_builder_types_markup() {
   $fields['markup'] = array(
     'title' => t('Markup'),
     'properties' => array(
-      'title',
       'markup',
       'format',
-      'key',
     ),
+    'weight' => 17,
   );
   $fields['markup']['default'] = _form_builder_webform_default('markup');
   $fields['markup']['default']['#markup'] = $default;
@@ -573,13 +444,20 @@ function _form_builder_webform_form_builder_types_markup() {
 }
 
 /**
- * Implements _form_builder_webform_form_builder_save_component().
+ * Implements _form_builder_webform_form_builder_map_component().
  */
-function _form_builder_webform_form_builder_save_markup($component, $form_element) {
-  $component['value'] = $form_element['#markup'];
-  $component['extra']['format'] = isset($form_element['#format']) ? $form_element['#format'] : filter_default_format();
-  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
-  return $component;
+function _form_builder_webform_form_builder_map_markup() {
+  return array(
+    'form_builder_type' => 'markup',
+    'properties' => array(
+      'markup' => array(
+        'storage_parents' => array('value'),
+      ),
+      'format' => array(
+        'storage_parents' => array('extra', 'format'),
+      ),
+    ),
+  );
 }
 
 /**
@@ -594,6 +472,10 @@ function _form_builder_webform_form_builder_preview_alter_markup($form_element)
     $form_element['#markup'] = t('Empty markup field');
   }
 
+  // This runs after drupal_pre_render_markup so the changed markup 
+  // needs to be copied to #children.
+  $form_element['#children'] = $form_element['#markup'];
+
   // Do not show the title, since it will not display in the final webform
   // either.
   $form_element['#title_display'] = 'none';
@@ -605,6 +487,87 @@ function _form_builder_webform_form_builder_preview_alter_markup($form_element)
  * @} End of "defgroup form-builder-webform-markup-callbacks"
  */
 
+
+/**
+ * @defgroup form-builder-webform-number-callbacks Callbacks for the Number component
+ * @{
+ */
+
+/**
+ * Implements _form_builder_webform_form_builder_types_component().
+ */
+function _form_builder_webform_form_builder_types_number() {
+  $fields = array();
+
+  $fields['number'] = array(
+    'title' => t('Number'),
+    'weight' => -17,
+  );
+
+  $fields['number']['default'] = _form_builder_webform_default('number');
+  $fields['number']['default']['#title'] = t('New number');
+
+  return $fields;
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_map_component().
+ */
+function _form_builder_webform_form_builder_map_number() {
+  return array(
+    'form_builder_type' => 'number',
+    'properties' => array(
+      'field_prefix' => array(
+        'storage_parents' => array('extra', 'field_prefix'),
+      ),
+      'field_suffix' => array(
+        'storage_parents' => array('extra', 'field_suffix'),
+      ),
+      // TODO: Add this option when the live preview can support it.
+      //'number_type' => array(
+      //  'form_parents' => array('display', 'type'),
+      //  'storage_parents' => array('extra', 'type'),
+      //),
+      'min' => array(
+        'form_parents' => array('validation', 'min'),
+        'storage_parents' => array('extra', 'min'),
+      ),
+      'max' => array(
+        'form_parents' => array('validation', 'max'),
+        'storage_parents' => array('extra', 'max'),
+      ),
+      'step' => array(
+        'form_parents' => array('validation', 'step'),
+        'storage_parents' => array('extra', 'step'),
+      ),
+      'decimals' => array(
+        'form_parents' => array('display', 'decimals'),
+        'storage_parents' => array('extra', 'decimals'),
+      ),
+      'point' => array(
+        'form_parents' => array('display', 'point'),
+        'storage_parents' => array('extra', 'point'),
+      ),
+      'separator' => array(
+        'form_parents' => array('display', 'separator'),
+        'storage_parents' => array('extra', 'separator'),
+      ),
+      'integer' => array(
+        'form_parents' => array('validation', 'integer'),
+        'storage_parents' => array('extra', 'integer'),
+      ),
+      'excludezero' => array(
+        'form_parents' => array('analysis', 'excludezero'),
+        'storage_parents' => array('extra', 'excludezero'),
+      ),
+    ),
+  );
+}
+
+/**
+ * @} End of "defgroup form-builder-webform-number-callbacks"
+ */
+
 /**
  * @defgroup form-builder-webform-pagebreak-callbacks Callbacks for the Pagebreak component
  * @{
@@ -618,14 +581,11 @@ function _form_builder_webform_form_builder_types_pagebreak() {
 
   $fields['pagebreak'] = array(
     'title' => t('Page break'),
-    'properties' => array(
-      'title',
-      'key',
-    ),
     'default' => array(
       '#title' => t('Page break'),
       '#type' => 'pagebreak',
     ),
+    'weight' => 20,
   );
 
   return $fields;
@@ -688,73 +648,80 @@ function _form_builder_webform_form_builder_types_select() {
   $fields['select'] = array(
     'title' => t('Select list'),
     'properties' => array(
-      'title',
-      'description',
       'default_value',
-      'required',
       'options',
       'multiple',
-      'key',
-      'title_display',
     ),
+    'weight' => -5,
   );
   $fields['select']['default'] = _form_builder_webform_default('select', array('aslist' => TRUE, 'multiple' => FALSE));
-  $fields['select']['default']['#options'] = array(t('one'), t('two'), t('three'));
-  $fields['select']['default']['#default_value'] = 0;
+  $fields['select']['default']['#options'] = array('1' => t('one'), '2' => t('two'), '3' => t('three'));
+  $fields['select']['default']['#default_value'] = 1;
   $fields['select']['default']['#title'] = t('New select');
-  $fields['select']['default']['#webform'] = array('type' => 'select');
 
   $fields['checkboxes'] = array(
     'title' => t('Checkboxes'),
     'properties' => array(
-      'title',
-      'description',
       'default_value',
-      'required',
       'options',
       'multiple',
-      'key',
-      'title_display',
     ),
+    'weight' => -6,
   );
   $fields['checkboxes']['default'] = _form_builder_webform_default('select', array('aslist' => FALSE, 'multiple' => TRUE));
-  $fields['checkboxes']['default']['#options'] = array(t('one'), t('two'), t('three'));
-  $fields['checkboxes']['default']['#default_value'] = array(0, 1);
+  $fields['checkboxes']['default']['#options'] = array('1' => t('one'), '2' => t('two'), '3' => t('three'));
+  $fields['checkboxes']['default']['#default_value'] = array(1, 2);
   $fields['checkboxes']['default']['#title'] = t('New checkboxes');
-  $fields['checkboxes']['default']['#webform'] = array('type' => 'select');
 
   $fields['radios'] = array(
     'title' => t('Radios'),
     'properties' => array(
-      'title',
-      'description',
       'default_value',
-      'required',
       'options',
-      'key',
-      'title_display',
     ),
+    'weight' => -7,
   );
   $fields['radios']['default'] = _form_builder_webform_default('select', array('aslist' => FALSE, 'multiple' => FALSE));
-  $fields['radios']['default']['#options'] = array(t('one'), t('two'), t('three'));
-  $fields['radios']['default']['#default_value'] = 0;
+  $fields['radios']['default']['#options'] = array('1' => t('one'), '2' => t('two'), '3' => t('three'));
+  $fields['radios']['default']['#default_value'] = 1;
   $fields['radios']['default']['#title'] = t('New radios');
-  $fields['radios']['default']['#webform'] = array('type' => 'select');
 
   return $fields;
 }
 
+/**
+ * Implements _form_builder_webform_form_builder_map_component().
+ */
+function _form_builder_webform_form_builder_map_select() {
+  return array(
+    'properties' => array(
+      'key_type_toggled' => array(
+        'storage_parents' => array('extra', 'custom_keys'),
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements _form_builder_webform_form_builder_properties_component().
+ */
+function _form_builder_webform_form_builder_properties_select() {
+  return array(
+    'options' => array(
+      'form' => 'form_builder_webform_property_select_options_form',
+      'submit' => array('form_builder_property_options_form_submit'),
+    ),
+  );
+}
+
 /**
  * Implements _form_builder_webform_form_builder_load_component().
  */
 function _form_builder_webform_form_builder_load_select($form_element) {
-  if (in_array($form_element['#type'], array('radios', 'checkboxes', 'select'))) {
-    $form_element['#webform']['type'] = 'select';
-    if ($form_element['#type'] == 'checkboxes') {
-      $form_element['#multiple'] = TRUE;
-    }
-    return $form_element;
-  }
+  // Properties that are only used by Form Builder and not in the normal form.
+  $form_element['#key_type_toggled'] = !empty($form_element['#webform_component']['extra']['custom_keys']);
+
+  return $form_element;
 }
 
 /**
@@ -770,11 +737,20 @@ function _form_builder_webform_form_builder_save_select($component, $form_elemen
   $component['extra']['items'] = $options;
   $component['extra']['multiple'] = $form_element['#form_builder']['element_type'] == 'checkboxes';
   $component['extra']['aslist'] = $form_element['#form_builder']['element_type'] == 'select';
-  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : '';
-  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
+
   return $component;
 }
 
+/**
+ * Configuration form for the "options" property.
+ */
+function form_builder_webform_property_select_options_form(&$form_state, $form_type, $element) {
+  // Use the default options form, but enhance to allow Webform tokens.
+  $form = form_builder_property_options_form($form_state, $form_type, $element);
+  $form['options']['#default_value_pattern'] = '^%.+\[.+\]$';
+  return $form;
+}
+
 /**
  * @} End of "defgroup form-builder-webform-select-callbacks"
  */
@@ -792,16 +768,7 @@ function _form_builder_webform_form_builder_types_textarea() {
 
   $fields['textarea'] = array(
     'title' => t('Textarea'),
-    'properties' => array(
-      'title',
-      'description',
-      'default_value',
-      'required',
-      'rows',
-      'cols',
-      'key',
-      'title_display',
-    ),
+    'weight' => -19,
   );
   $fields['textarea']['default'] = _form_builder_webform_default('textarea');
   $fields['textarea']['default']['#title'] = t('New textarea');
@@ -810,15 +777,23 @@ function _form_builder_webform_form_builder_types_textarea() {
 }
 
 /**
- * Implements _form_builder_webform_form_builder_save_component().
+ * Implements _form_builder_webform_form_builder_map_component().
  */
-function _form_builder_webform_form_builder_save_textarea($component, $form_element) {
-  $component['extra']['description'] = $form_element['#description'];
-  $component['extra']['cols'] = $form_element['#cols'];
-  $component['extra']['rows'] = $form_element['#rows'];
-  $component['extra']['disabled'] = empty($form_element['#disabled']) ? NULL : TRUE;
-  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
-  return $component;
+function _form_builder_webform_form_builder_map_textarea() {
+  return array(
+    'form_builder_type' => 'textarea',
+    'properties' => array(
+      'cols' => array(
+        'storage_parents' => array('extra', 'cols'),
+      ),
+      'rows' => array(
+        'storage_parents' => array('extra', 'rows'),
+      ),
+      'disabled' => array(
+        'storage_parents' => array('extra', 'disabled'),
+      ),
+    ),
+  );
 }
 
 /**
@@ -838,17 +813,7 @@ function _form_builder_webform_form_builder_types_textfield() {
 
   $fields['textfield'] = array(
     'title' => t('Textfield'),
-    'properties' => array(
-      'title',
-      'description',
-      'field_prefix',
-      'field_suffix',
-      'default_value',
-      'required',
-      'size',
-      'key',
-      'title_display',
-    ),
+    'weight' => -20,
   );
   $fields['textfield']['default'] = _form_builder_webform_default('textfield');
   $fields['textfield']['default']['#title'] = t('New textfield');
@@ -857,17 +822,29 @@ function _form_builder_webform_form_builder_types_textfield() {
 }
 
 /**
- * Implements _form_builder_webform_form_builder_save_component().
+ * Implements _form_builder_webform_form_builder_map_component().
  */
-function _form_builder_webform_form_builder_save_textfield($component, $form_element) {
-  $component['extra']['width'] = isset($form_element['#size']) ? $form_element['#size'] : NULL;
-  $component['extra']['maxlength'] = isset($form_element['#maxlength']) ? $form_element['#maxlength'] : NULL;
-  $component['extra']['field_prefix'] = isset($form_element['#field_prefix']) ? $form_element['#field_prefix'] : NULL;
-  $component['extra']['field_suffix'] = isset($form_element['#field_suffix']) ? $form_element['#field_suffix'] : NULL;
-  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
-  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
-  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
-  return $component;
+function _form_builder_webform_form_builder_map_textfield() {
+  return array(
+    'form_builder_type' => 'textfield',
+    'properties' => array(
+      'size' => array(
+        'storage_parents' => array('extra', 'width'),
+      ),
+      'maxlength' => array(
+        'storage_parents' => array('extra', 'maxlength'),
+      ),
+      'field_prefix' => array(
+        'storage_parents' => array('extra', 'field_prefix'),
+      ),
+      'field_suffix' => array(
+        'storage_parents' => array('extra', 'field_suffix'),
+      ),
+      'disabled' => array(
+        'storage_parents' => array('extra', 'disabled'),
+      ),
+    ),
+  );
 }
 
 /**
@@ -887,17 +864,7 @@ function _form_builder_webform_form_builder_types_time() {
 
   $fields['time'] = array(
     'title' => t('Time'),
-    'properties' => array(
-      'title',
-      'description',
-      'default_value',
-      'required',
-      'key',
-      'title_display',
-      // Date-specific properties.
-      'timezone',
-      'hourformat',
-    ),
+    'weight' => -1,
   );
   $fields['time']['default'] = _form_builder_webform_default('time');
   $fields['time']['default']['#title'] = t('New time');
@@ -905,61 +872,85 @@ function _form_builder_webform_form_builder_types_time() {
   return $fields;
 }
 
+
 /**
- * Implements _form_builder_webform_form_builder_properties_component().
+ * Implements _form_builder_webform_form_builder_map_component().
  */
-function _form_builder_webform_form_builder_properties_time() {
+function _form_builder_webform_form_builder_map_time() {
   return array(
-    'timezone' => array(
-      'form' => 'form_builder_webform_property_time_timezone_form',
-    ),
-    'hourformat' => array(
-      'form' => 'form_builder_webform_property_time_hourformat_form',
+    'form_builder_type' => 'time',
+    'properties' => array(
+      'timezone' => array(
+        'form_parents' => array('extra', 'timezone'),
+        'storage_parents' => array('extra', 'timezone'),
+      ),
+      'hourformat' => array(
+        'storage_parents' => array('display', 'hourformat'),
+        'storage_parents' => array('extra', 'hourformat'),
+      ),
     ),
   );
 }
 
 /**
- * Implements _form_builder_webform_form_builder_load_component().
+ * @} End of "defgroup form-builder-webform-time-callbacks"
  */
-function _form_builder_webform_form_builder_load_time($element) {
-  if (isset($element['#type']) && $element['#type'] == 'webform_time') {
-    // Elements of type "webform_time" are known to Form Builder as simply a
-    // "time" field. This makes it so that we use the generic time icon.
-    $element['#form_builder']['element_type'] = 'time';
-  }
-  return $element;
-}
 
 /**
- * Implements _form_builder_webform_form_builder_save_component().
+ * Helper function; Generate a configuration form based on a map.
  */
-function _form_builder_webform_form_builder_save_time($component, $form_element) {
-  $component['extra']['description'] = isset($form_element['#description']) ? $form_element['#description'] : NULL;
-  $component['extra']['disabled'] = isset($form_element['#disabled']) ? $form_element['#disabled'] : FALSE;
-  $component['extra']['title_display'] = isset($form_element['#title_display']) ? $form_element['#title_display'] : 'before';
-  $component['extra']['timezone'] = isset($form_element['#timezone']) ? $form_element['#timezone'] : 'user';
-  $component['extra']['hourformat'] = isset($form_element['#hourformat']) ? $form_element['#hourformat'] : '12-hour';
-  return $component;
+function _form_builder_webform_mapped_form(&$form_state, $form_type, $element, $property) {
+  $form = array();
+  if ($component_type = $element['#webform_component']['type']) {
+    if ($map = _form_builder_webform_property_map($component_type)) {
+      $property_group = isset($map['properties'][$property]['property_group']) ? $map['properties'][$property]['property_group'] : reset($map['properties'][$property]['form_parents']);
+      $form = _form_builder_webform_build_edit_form($component_type, $element, $property, $property_group, $map['properties'][$property]['form_parents'], $map['properties'][$property]['storage_parents']);
+    }
+  }
+  return $form;
 }
 
 /**
- * Configuration form for the "timezone" property.
+ * Helper function; Save an element to a Webform component based on a map.
  */
-function form_builder_webform_property_time_timezone_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('time', $element, 'timezone', NULL, array('extra', 'timezone'), array('extra', 'timezone'));
+function _form_builder_webform_save_mapped_component($component, $element) {
+  if ($map = _form_builder_webform_property_map($component['type'])) {
+    foreach ($map['properties'] as $property => $property_map) {
+      if (isset($element['#' . $property]) && isset($property_map['storage_parents'])) {
+        _form_builder_webform_save_mapped_component_value($component, $element['#' . $property], $property_map['storage_parents']);
+      }
+    }
+  }
+  return $component;
 }
 
 /**
- * Configuration form for the "hourformat" property.
+ * Recursive function to set the value of a $component property.
  */
-function form_builder_webform_property_time_hourformat_form(&$form_state, $form_type, $element) {
-  return _form_builder_webform_build_edit_form('time', $element, 'hourformat', 'display', array('display', 'hourformat'), array('extra', 'hourformat'));
+function _form_builder_webform_save_mapped_component_value(&$component, $value, $parents) {
+  $parent = array_shift($parents);
+  if (empty($parents)) {
+    $component[$parent] = $value;
+  }
+  else {
+    _form_builder_webform_save_mapped_component_value($component[$parent], $value, $parents);
+  }
 }
 
 /**
- * @} End of "defgroup form-builder-webform-time-callbacks"
+ * Helper function; Alter a form element upon load based on a map.
  */
+function _form_builder_webform_set_mapped_type($element) {
+  if ($map = _form_builder_webform_property_map($element['#webform_component']['type'])) {
+    // Keep the internal type of this element as the component type. For example
+    // this may match an $element['#type'] of 'webform_date' and set the
+    // $element['#form_builder']['element_type'] to simply 'date'.
+    if (isset($map['form_builder_type'])) {
+      $element['#form_builder']['element_type'] = $map['form_builder_type'];
+    }
+  }
+  return $element;
+}
 
 /**
  * Helper function; Generate a default FAPI element for any component type.
@@ -968,6 +959,15 @@ function _form_builder_webform_default($component_type, $merge_extras = array())
   $default_component = webform_component_invoke($component_type, 'defaults');
   $default_component['extra'] = isset($default_component['extra']) ? array_merge($default_component['extra'], $merge_extras) : $merge_extras;
   $default_element = webform_component_invoke($component_type, 'render', $default_component, NULL, FALSE);
+
+  // Set a bare-minimum component for identification of the component type.
+  $default_element['#webform_component'] = $default_component;
+  $default_element['#webform_component']['type'] = $component_type;
+
+  // Call the loading function to make sure that the default element gets the
+  // same treatment as an existing one.
+  $default_element = _form_builder_webform_set_mapped_type($default_element);
+
   return $default_element;
 }
 
@@ -977,7 +977,7 @@ function _form_builder_webform_default($component_type, $merge_extras = array())
  * The returned form is derived from a subcomponent of the component form
  * provided by the Webform module.
  *
- * @param $type
+ * @param $component_type
  *   The webform component type to be edited.
  * @param $element
  *   A form array representing the element whose configuration form we are
@@ -1008,11 +1008,13 @@ function _form_builder_webform_default($component_type, $merge_extras = array())
  *   A form array that can be used to edit the specified part of the webform
  *   component represented by $element.
  */
-function _form_builder_webform_build_edit_form($type, $element, $property, $form_builder_property_group, $form_nested_keys, $component_nested_keys) {
+function _form_builder_webform_build_edit_form($component_type, $element, $property, $form_builder_property_group, $form_nested_keys, $component_nested_keys) {
+  module_load_include('inc', 'webform', 'includes/webform.components');
+
   // The Webform module stores existing component data as part of the passed-in
   // element. If the component doesn't exist yet, initialize a default
   // component.
-  $defaults_function = '_webform_defaults_' . $type;
+  $defaults_function = '_webform_defaults_' . $component_type;
   $component = isset($element['#webform_component']) ? $element['#webform_component'] : $defaults_function();
 
   // The most up-to-date configuration data stored by Form Builder for the
@@ -1024,8 +1026,10 @@ function _form_builder_webform_build_edit_form($type, $element, $property, $form
 
   // Build the entire _webform_edit_file() form based on the current state of
   // the component, and obtain the slice of it that we want.
-  $edit_function = '_webform_edit_' . $type;
-  $form = $edit_function($component);
+  $empty_form = array();
+  $empty_form_state = form_state_defaults();
+  $node = (object) array('nid' => NULL);
+  $form = webform_component_edit_form($empty_form, $empty_form_state, $node, $component);
   $form = drupal_array_get_nested_value($form, $form_nested_keys);
 
   // Force the form to have a consistent #tree structure so it will appear in
diff --git a/sites/all/modules/form_builder/modules/webform/form_builder_webform.info b/sites/all/modules/form_builder/modules/webform/form_builder_webform.info
index 01dba515657f48335ab0abf2aa1f0964286b07c4..3f48fec72ecdfb47099ed7c2f1686d786b46da17 100644
--- a/sites/all/modules/form_builder/modules/webform/form_builder_webform.info
+++ b/sites/all/modules/form_builder/modules/webform/form_builder_webform.info
@@ -4,9 +4,9 @@ core = 7.x
 dependencies[] = form_builder
 dependencies[] = webform
 
-; Information added by drupal.org packaging script on 2011-06-06
-version = "7.x-1.x-dev"
+; Information added by drupal.org packaging script on 2012-03-08
+version = "7.x-1.0"
 core = "7.x"
 project = "form_builder"
-datestamp = "1307319364"
+datestamp = "1331181344"
 
diff --git a/sites/all/modules/form_builder/modules/webform/form_builder_webform.module b/sites/all/modules/form_builder/modules/webform/form_builder_webform.module
index 9b2764aca1c52cec52cf3296b79cc72837fb6269..a0d356e2aa41e5af45f960136939790041e6d682 100644
--- a/sites/all/modules/form_builder/modules/webform/form_builder_webform.module
+++ b/sites/all/modules/form_builder/modules/webform/form_builder_webform.module
@@ -33,10 +33,7 @@ function form_builder_webform_components_page($node) {
   $build['#attached']['js'][] = $path . '/js/webform.js';
   $build['#attached']['js'][] = $path . '/js/webform-admin.js';
   $build['#attached']['js'][] = $path . '/js/select-admin.js';
-  // START UNL CHANGE SEE README-UNL.txt
-  global $base_path;
-  $build['#attached']['js'][] = $base_path . 'misc/ui/jquery.ui.datepicker.min.js';
-  // END UNL CHANGE
+  $build['#attached']['library'][] = array('system', 'ui.datepicker');
 
   $build[] = form_builder_interface('webform', $node->nid);
   $build[] = drupal_get_form('form_builder_webform_save_form', $node->nid);
@@ -109,8 +106,10 @@ function form_builder_webform_save_node($node) {
  * Save the contents of a form component into Webform's database tables.
  */
 function form_builder_webform_save_component($node, $element_id, $form) {
+  module_load_include('inc', 'form_builder_webform', 'form_builder_webform.components');
+
   $element = form_builder_get_element($form, $element_id);
-  $type = isset($element['#webform']['type']) ? $element['#webform']['type'] : $element['#form_builder']['element_type'];
+  $type = isset($element['#webform_component']['type']) ? $element['#webform_component']['type'] : $element['#form_builder']['element_type'];
 
   // Check for existing components.
   $cid = substr($element_id, 4);
@@ -118,7 +117,7 @@ function form_builder_webform_save_component($node, $element_id, $form) {
     $component = $node->webform['components'][$cid];
   }
   // Populate a new default component.
-  elseif (isset($element['#webform']['is_new'])) {
+  elseif (isset($element['#webform_component']['is_new'])) {
     if ($component = webform_component_invoke($type, 'defaults')) {
       $component['type'] = $type;
     }
@@ -146,7 +145,7 @@ function form_builder_webform_save_component($node, $element_id, $form) {
   $parent = form_builder_get_element($form, $element['#form_builder']['parent_id']);
   if ($parent) {
     // If the parent is new, the database must be queried for the cid of the parent.
-    if (isset($parent['#webform']['is_new']) && $parent['#webform']['is_new']) {
+    if (isset($parent['#webform_component']['is_new']) && $parent['#webform_component']['is_new']) {
       $results = db_query('SELECT cid, form_key FROM {webform_component} WHERE form_key = :key AND nid = :nid', array(':key' => $element['#form_builder']['parent_id'], ':nid' => $node->nid));
       foreach($results as $result) {
         $component['pid'] = $result->cid;
@@ -165,11 +164,14 @@ function form_builder_webform_save_component($node, $element_id, $form) {
   if (isset($element['#default_value'])) {
     $component['value'] = is_array($element['#default_value']) ? implode(',', $element['#default_value']) : $element['#default_value'];
   }
-  elseif (empty($element['#webform']['is_new'])) {
+  elseif (empty($element['#webform_component']['is_new'])) {
     $component['value'] = NULL;
   }
 
-  // Save any specific settings.
+  // Set all properties based on property maps.
+  $component = _form_builder_webform_save_mapped_component($component, $element);
+
+  // Allow each component to set any specific settings that can't be mapped.
   if ($saved_component = form_builder_webform_component_invoke($type, 'form_builder_save', $component, $element)) {
     $component = $saved_component;
   }
@@ -190,6 +192,20 @@ function form_builder_webform_cancel(&$form, &$form_state) {
   form_builder_cache_delete('webform', $form_state['values']['nid']);
 }
 
+/**
+ * Implements hook_form_builder_property_groups().
+ */
+function form_builder_webform_form_builder_property_groups($form_type) {
+  $groups = array();
+  if ($form_type == 'webform') {
+    $groups['analysis'] = array(
+      'weight' => 4,
+      'title' => t('Analysis'),
+    );
+  }
+  return $groups;
+}
+
 /**
  * Implements hook_form_builder_types().
  *
@@ -201,6 +217,13 @@ function form_builder_webform_form_builder_types() {
   $components = webform_components();
   foreach ($components as $type => $component) {
     if ($additional_fields = form_builder_webform_component_invoke($type, 'form_builder_types')) {
+      if ($map = _form_builder_webform_property_map($type)) {
+        foreach ($additional_fields as $field_name => $field_type) {
+          foreach ($map['properties'] as $property_name => $property_info) {
+            $additional_fields[$field_name]['properties'][] = $property_name;
+          }
+        }
+      }
       $fields = array_merge($fields, $additional_fields);
     }
   }
@@ -216,8 +239,20 @@ function form_builder_webform_form_builder_properties($form_type) {
 
   if ($form_type == 'webform') {
     $components = webform_components();
-    foreach ($components as $type => $component) {
-      if ($additional_properties = form_builder_webform_component_invoke($type, 'form_builder_properties')) {
+    foreach ($components as $component_type => $component) {
+      // Components providing a map to automatically list properties.
+      if ($map = _form_builder_webform_property_map($component_type)) {
+        foreach ($map['properties'] as $property_name => $property_map) {
+          if (isset($property_map['form_parents'])) {
+            $properties[$property_name] = array(
+              'form' => '_form_builder_webform_mapped_form',
+            );
+          }
+        }
+      }
+
+      // Individual components manually providing properties.
+      if ($additional_properties = form_builder_webform_component_invoke($component_type, 'form_builder_properties')) {
         $properties = array_merge($properties, $additional_properties);
       }
     }
@@ -260,6 +295,7 @@ function form_builder_webform_form_builder_load($form_builder_type, $form_builde
     // Change 'pagebreak' components back, as described above.
     foreach ($pagebreak_component_keys as $key) {
       $form['submitted'][$key]['#type'] = 'pagebreak';
+      $form['submitted'][$key]['#webform_component']['type'] = 'pagebreak';
     }
 
     // Perform final processing of the form, and return it.
@@ -273,6 +309,8 @@ function form_builder_webform_form_builder_load($form_builder_type, $form_builde
  * Recursive helper function to populate #form_builder['element_id'] values.
  */
 function form_builder_webform_load_process(&$form, $node, $pid = 0) {
+  module_load_include('inc', 'form_builder_webform', 'form_builder_webform.components');
+
   foreach (element_children($form) as $key) {
     $cid = webform_get_cid($node, $key, $pid);
     $form[$key]['#form_builder'] = array(
@@ -281,8 +319,13 @@ function form_builder_webform_load_process(&$form, $node, $pid = 0) {
 
     // Add any component-specific loading. Note that all components are
     // invoked here because the component type isn't yet known.
-    foreach (webform_components() as $type => $info) {
-      if ($element = form_builder_webform_component_invoke($type, 'form_builder_load', $form[$key])) {
+    if (isset($form[$key]['#webform_component']['type'])) {
+      $component_type = $form[$key]['#webform_component']['type'];
+
+      // Set the internal type based on any mappings.
+      $form[$key] = _form_builder_webform_set_mapped_type($form[$key]);
+
+      if ($element = form_builder_webform_component_invoke($component_type, 'form_builder_load', $form[$key])) {
         $form[$key] = $element;
       }
     }
@@ -297,7 +340,7 @@ function form_builder_webform_load_process(&$form, $node, $pid = 0) {
  */
 function form_builder_webform_form_builder_add_element_alter(&$element, $form_type, $form_id) {
   if ($form_type == 'webform') {
-    $element['#webform']['is_new'] = TRUE;
+    $element['#webform_component']['is_new'] = TRUE;
   }
 }
 
@@ -319,15 +362,16 @@ function form_builder_webform_form_builder_preview_alter(&$element, $form_type,
       $element['#value'] = _webform_filter_values($element['#default_value'], NULL, NULL, NULL, FALSE);
     }
 
-    // Add info to the #webform_component array so that theme_webform_element will
-    // work properly.
-    $element['#webform_component']['type'] = $element['#form_builder']['element_type'];
-
     // Let components do any extra filtering if needed.
-    $type = isset($element['#webform']['type']) ? $element['#webform']['type'] : $element['#form_builder']['element_type'];
+    $type = isset($element['#webform_component']['type']) ? $element['#webform_component']['type'] : $element['#form_builder']['element_type'];
     if ($new_element = form_builder_webform_component_invoke($type, 'form_builder_preview_alter', $element)) {
       $element = $new_element;
     }
+
+    // A #title_display property of 0 (as stored by Webform) means no setting.
+    if (isset($element['#title_display']) && $element['#title_display'] == 0) {
+      unset($element['#title_display']);
+    }
   }
 }
 
@@ -384,14 +428,14 @@ function _form_builder_remove_conditional_form_element_pre_render(&$form) {
  * default implementation of the callback on behalf of the component, the
  * result obtained from that is returned.
  *
- * @param $type
+ * @param $component_type
  *   The component type as a string.
  * @param $callback
  *   The callback to execute.
  * @param ...
  *   Any additional parameters required by the $callback.
  */
-function form_builder_webform_component_invoke($type, $callback) {
+function form_builder_webform_component_invoke($component_type, $callback) {
   $args = func_get_args();
 
   // First try invoking the callback in the webform component itself.
@@ -401,9 +445,9 @@ function form_builder_webform_component_invoke($type, $callback) {
   }
 
   // Otherwise look for a default implementation provided by this module.
-  $type = array_shift($args);
+  $component_type = array_shift($args);
   $callback = array_shift($args);
-  $function = '_form_builder_webform_' . $callback . '_' . $type;
+  $function = '_form_builder_webform_' . $callback . '_' . $component_type;
   module_load_include('inc', 'form_builder_webform', 'form_builder_webform.components');
   if (function_exists($function)) {
     return call_user_func_array($function, $args);
@@ -425,17 +469,53 @@ function _webform_render_pagebreak_clone($component, $value = NULL, $filter = TR
 }
 
 /**
- * Implements hook_form_FORM_ID_alter().
- *
- * Customizations to the field configuration form to better integrate with webforms.
+ * Helper function; Retrieve a component's map and merge in generic properties.
  */
-function form_builder_webform_form_form_builder_field_configure_alter(&$form, &$form_state, $form_id) {
-  // Change the list of options from the default Drupal values to the acceptable
-  // webform values.
-  $form['title_display']['#options'] = array(
-    'before' => t('Above'),
-    'inline' => t('Inline'),
-    'none' => t('Hidden'),
-  );
-  $form['title_display']['#default_value'] = isset($form['title_display']['#default_value']) ? $form['title_display']['#default_value'] : 'before';
+function _form_builder_webform_property_map($component_type) {
+  static $maps;
+
+  if (!isset($maps[$component_type])) {
+    module_load_include('inc', 'webform', 'includes/webform.components');
+    $map = form_builder_webform_component_invoke($component_type, 'form_builder_map');
+    $map = $map ? $map : array();
+
+    if (webform_component_feature($component_type, 'title')) {
+      $map['properties']['title'] = array();
+    }
+
+    if (webform_component_feature($component_type, 'title_display')) {
+      $map['properties']['title_display'] = array(
+        'form_parents' => array('display', 'title_display'),
+        'storage_parents' => array('extra', 'title_display'),
+      );
+    }
+
+    if (webform_component_feature($component_type, 'default_value')) {
+      $map['properties']['default_value'] = array();
+    }
+
+    if (webform_component_feature($component_type, 'description')) {
+      $map['properties']['description'] = array(
+        'storage_parents' => array('extra', 'description'),
+      );
+    }
+
+    if (webform_component_feature($component_type, 'private')) {
+      $map['properties']['private'] = array(
+        'form_parents' => array('display', 'private'),
+        'storage_parents' => array('extra', 'private'),
+      );
+    }
+  
+    if (webform_component_feature($component_type, 'required')) {
+      $map['properties']['required'] = array();
+    }
+
+    // All components support the key property.
+    $map['properties']['key'] = array();
+
+    $maps[$component_type] = $map;
+  }
+
+  return $maps[$component_type];
 }
diff --git a/sites/all/modules/link/LICENSE.txt b/sites/all/modules/link/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d159169d1050894d3ea3b98e1c965c4058208fe1
--- /dev/null
+++ b/sites/all/modules/link/LICENSE.txt
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/sites/all/modules/link/link.css b/sites/all/modules/link/link.css
new file mode 100644
index 0000000000000000000000000000000000000000..7bdec9e18a560a2c7384c1eb377b158c36066d71
--- /dev/null
+++ b/sites/all/modules/link/link.css
@@ -0,0 +1,8 @@
+div.link-field-column {
+  float: left;
+  width: 48%;
+}
+
+div.link-field-column .form-text {
+  width: 95%;
+}
diff --git a/sites/all/modules/link/link.info b/sites/all/modules/link/link.info
new file mode 100644
index 0000000000000000000000000000000000000000..8a5d0c18ccfbddac667cf29f77072cc5a5eb6aec
--- /dev/null
+++ b/sites/all/modules/link/link.info
@@ -0,0 +1,25 @@
+name = Link
+description = Defines simple link field types.
+core = 7.x
+package = Fields
+
+files[] = link.module
+files[] = link.install
+; Tests
+files[] = tests/link.test
+files[] = tests/link.attribute.test
+files[] = tests/link.crud.test
+files[] = tests/link.crud_browser.test
+files[] = tests/link.token.test
+files[] = tests/link.validate.test
+
+; Views Handlers
+files[] = views/link_views_handler_argument_target.inc
+files[] = views/link_views_handler_filter_protocol.inc
+
+; Information added by drupal.org packaging script on 2011-10-23
+version = "7.x-1.0"
+core = "7.x"
+project = "link"
+datestamp = "1319392535"
+
diff --git a/sites/all/modules/link/link.install b/sites/all/modules/link/link.install
new file mode 100644
index 0000000000000000000000000000000000000000..fdfc5d1e2da4ab883317d9fd25a2a1b42be2cbc9
--- /dev/null
+++ b/sites/all/modules/link/link.install
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * @file
+ * Install file for the link module.
+ */
+
+/**
+ * Upgrade notes:
+ * Things we need to make sure work when upgrading from Drupal 6 to Drupal 7:
+ */
+
+/**
+ * Implements hook_field_schema().
+ */
+function link_field_schema($field) {
+  return array(
+    'columns' => array(
+      'url' => array(
+        'type' => 'varchar',
+        'length' => 2048, // Maximum URLs length.
+        'not null' => FALSE,
+        'sortable' => TRUE
+      ),
+      'title' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+        'sortable' => TRUE
+      ),
+      'attributes' => array(
+        'type' => 'text',
+        'size' => 'medium',
+        'not null' => FALSE
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_update_last_removed().
+ */
+function link_update_last_removed() {
+  return 6001;
+}
+
+/**
+ * Handles moving settings data from field_config.data to field_config_instance.data.
+ */
+function link_update_7000() {
+  
+  // For each field that is a link field, we need to copy the settings from the general field level down to the instance.
+  //$field_data = array();
+  $result = db_query("SELECT id, field_name, data FROM {field_config} WHERE module = 'link' AND type = 'link_field'");
+  foreach ($result as $field) {
+    $field_id = $field->id;
+    $name = $field->field_name;
+    $field_data = unserialize($field->data);
+    
+    $instances = db_query("SELECT id, data FROM {field_config_instance} WHERE field_id = :field_id", array(':field_id' => $field_id));
+    foreach ($instances as $instance) {
+      // If this field has been updated already, we want to skip it.
+      $instance_data = unserialize($instance->data);
+      $update_instance = FALSE;
+      if (!isset($instance_data['settings']['title'])) {
+        foreach ($field_data['settings'] as $key => $value) {
+          if (!isset($instance_data['settings'][$key])) {
+            $instance_data['settings'][$key] = $value;
+            $update_instance = TRUE;
+          }
+        }
+        if ($update_instance) {
+          // update the database.
+          $num_updated = db_update('field_config_instance')
+            ->fields(array('data' => serialize($instance_data)))
+            ->condition('id', $instance->id)
+            ->execute();
+        }
+      }
+    }
+  }
+  
+  return t("Instance settings have been set with the data from the field settings.");
+}
+
+/**
+ * Renames all displays from foobar to link_foobar
+ */
+function link_update_7001() {
+  // for each field that is a link field, we need to update the display types:
+  
+  $result = db_query("SELECT id, field_name, data FROM {field_config} WHERE module = 'link' AND type = 'link_field'");
+  foreach ($result as $field) {
+    $field_id = $field->id;
+    $name = $field->field_name;
+    $field_data = unserialize($field->data);
+    
+    $instances = db_query("SELECT id, data FROM {field_config_instance} WHERE field_id = :field_id", array(':field_id' => $field_id));
+    foreach ($instances as $instance) {
+      // If this field has been updated already, we want to skip it.
+      $instance_data = unserialize($instance->data);
+      $update_instance = FALSE;
+      foreach ($instance_data['display'] as $display_name => $display_data) {
+        if ($display_data['type'] && (0 !== strpos($display_data['type'], 'link_'))) {
+          $instance_data['display'][$display_name]['type'] = 'link_'. $display_data['type'];
+          $update_instance = TRUE;
+        }
+      }
+      if ($update_instance) {
+        // update the database.
+        $num_updated = db_update('field_config_instance')
+          ->fields(array('data' => serialize($instance_data)))
+          ->condition('id', $instance->id)
+          ->execute();
+      }
+    }
+  }
+}
diff --git a/sites/all/modules/link/link.module b/sites/all/modules/link/link.module
new file mode 100644
index 0000000000000000000000000000000000000000..c7af1ffbfbe667e3647581ec3b299a511ace9780
--- /dev/null
+++ b/sites/all/modules/link/link.module
@@ -0,0 +1,1106 @@
+<?php
+
+/**
+ * @file
+ * Defines simple link field types.
+ */
+
+define('LINK_EXTERNAL', 'external');
+define('LINK_INTERNAL', 'internal');
+define('LINK_FRONT', 'front');
+define('LINK_EMAIL', 'email');
+define('LINK_NEWS', 'news');
+define('LINK_DOMAINS', 'aero|arpa|asia|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|local');
+
+define('LINK_TARGET_DEFAULT', 'default');
+define('LINK_TARGET_NEW_WINDOW', '_blank');
+define('LINK_TARGET_TOP', '_top');
+define('LINK_TARGET_USER', 'user');
+
+/**
+ * Maximum URLs length - needs to match value in link.install.
+ */
+define('LINK_URL_MAX_LENGTH', 2048);
+
+/**
+ * Implements hook_field_info().
+ */
+function link_field_info() {
+  return array(
+    'link_field' => array(
+      'label' => t('Link'),
+      'description' => t('Store a title, href, and attributes in the database to assemble a link.'),
+      'settings' => array(
+        'attributes' => _link_default_attributes(),
+        'url' => 0,
+        'title' => 'optional',
+        'title_value' => '',
+        'title_maxlength' => 128, //patch #1307788 from nmc
+        'enable_tokens' => 1,
+        'display' => array(
+          'url_cutoff' => 80,
+        ),
+      ),
+      'instance_settings' => array(
+        'attributes' => _link_default_attributes(),
+        'url' => 0,
+        'title' => 'optional',
+        'title_value' => '',
+        'title_maxlength' => 128, // patch #1307788 from nmc
+        'enable_tokens' => 1,
+        'display' => array(
+          'url_cutoff' => 80,
+        ),
+        'validate_url' => 1,
+      ),
+      'default_widget' => 'link_field',
+      'default_formatter' => 'link_default',
+      // Support hook_entity_property_info() from contrib "Entity API".
+      'property_type' => 'field_item_link',
+      'property_callbacks' => array('link_field_property_info_callback'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function link_field_instance_settings_form($field, $instance) {
+  $form = array(
+    '#element_validate' => array('link_field_settings_form_validate'),
+  );
+  
+  $form['validate_url'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Validate URL'),
+    '#default_value' => isset($instance['settings']['validate_url']) && ($instance['settings']['validate_url'] !== '') ? $instance['settings']['validate_url'] : TRUE,
+    '#description' => t('If checked, the URL field will be verified as a valid URL during validation.'),
+  );
+
+  $form['url'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Optional URL'),
+    '#default_value' => isset($instance['settings']['url']) ? $instance['settings']['url'] : '',
+    '#return_value' => 'optional',
+    '#description' => t('If checked, the URL field is optional and submitting a title alone will be acceptable. If the URL is omitted, the title will be displayed as plain text.'),
+  );
+
+  $title_options = array(
+    'optional' => t('Optional Title'),
+    'required' => t('Required Title'),
+    'value' => t('Static Title'),
+    'none' => t('No Title'),
+  );
+
+  $form['title'] = array(
+    '#type' => 'radios',
+    '#title' => t('Link Title'),
+    '#default_value' => isset($instance['settings']['title']) ? $instance['settings']['title'] : 'optional',
+    '#options' => $title_options,
+    '#description' => t('If the link title is optional or required, a field will be displayed to the end user. If the link title is static, the link will always use the same title. If <a href="http://drupal.org/project/token">token module</a> is installed, the static title value may use any other node field as its value. Static and token-based titles may include most inline XHTML tags such as <em>strong</em>, <em>em</em>, <em>img</em>, <em>span</em>, etc.'),
+  );
+
+  $form['title_value'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Static title'),
+    '#default_value' => isset($instance['settings']['title_value']) ? $instance['settings']['title_value'] : '',
+    '#description' => t('This title will always be used if &ldquo;Static Title&rdquo; is selected above.'),
+  );
+
+  $form['title_maxlength'] = array( // patch #1307788 from nmc
+    '#type' => 'textfield',
+    '#title' => t('Max length of title field'),
+    '#default_value' => isset($instance['settings']['title_maxlength']) ? $instance['settings']['title_maxlength'] : '128',
+    '#description' => t('Set a maximum length on the title field (applies only if Link Title is optional or required).  The maximum limit is 255 characters.'),
+    '#maxlength' => 3,
+    '#size' => 3,
+    );
+
+  if (module_exists('token')) {
+    // Add token module replacements fields
+    $form['tokens'] = array(
+      '#type' => 'fieldset',
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#title' => t('Placeholder tokens'),
+      '#description' => t("The following placeholder tokens can be used in both paths and titles. When used in a path or title, they will be replaced with the appropriate values."),
+    );
+    $token_type = array(
+      'theme' => 'token_tree',
+      'token_types' => array($instance['entity_type']),
+      'global_types' => TRUE,
+      'click_insert' => TRUE,
+      'recursion_limit' => 2,
+    );
+    $form['tokens']['help'] = array(
+      '#type' => 'markup',
+      '#markup' => theme('token_tree', $token_type),
+    );
+
+    $form['enable_tokens'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Allow user-entered tokens'),
+      '#default_value' => isset($instance['settings']['enable_tokens']) ? $instance['settings']['enable_tokens'] : 1,
+      '#description' => t('Checking will allow users to enter tokens in URLs and Titles on the node edit form. This does not affect the field settings on this page.'),
+    );
+  }
+
+  $form['display'] = array(
+    '#tree' => TRUE,
+  );
+  $form['display']['url_cutoff'] = array(
+    '#type' => 'textfield',
+    '#title' => t('URL Display Cutoff'),
+    '#default_value' => isset($instance['settings']['display']['url_cutoff']) ? $instance['settings']['display']['url_cutoff'] : '80',
+    '#description' => t('If the user does not include a title for this link, the URL will be used as the title. When should the link title be trimmed and finished with an elipsis (&hellip;)? Leave blank for no limit.'),
+    '#maxlength' => 3,
+   '#size' => 3,
+  );
+
+  $target_options = array(
+    LINK_TARGET_DEFAULT => t('Default (no target attribute)'),
+    LINK_TARGET_TOP => t('Open link in window root'),
+    LINK_TARGET_NEW_WINDOW => t('Open link in new window'),
+    LINK_TARGET_USER => t('Allow the user to choose'),
+  );
+  $form['attributes'] = array(
+    '#tree' => TRUE,
+  );
+  $form['attributes']['target'] = array(
+    '#type' => 'radios',
+    '#title' => t('Link Target'),
+    '#default_value' => empty($instance['settings']['attributes']['target']) ? LINK_TARGET_DEFAULT : $instance['settings']['attributes']['target'],
+    '#options' => $target_options,
+  );
+  $form['attributes']['rel'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Rel Attribute'),
+    '#description' => t('When output, this link will have this rel attribute. The most common usage is <a href="http://en.wikipedia.org/wiki/Nofollow">rel=&quot;nofollow&quot;</a> which prevents some search engines from spidering entered links.'),
+    '#default_value' => empty($instance['settings']['attributes']['rel']) ? '' : $instance['settings']['attributes']['rel'],
+    '#field_prefix' => 'rel = "',
+    '#field_suffix' => '"',
+    '#size' => 20,
+  );
+  $form['attributes']['class'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Additional CSS Class'),
+    '#description' => t('When output, this link will have this class attribute. Multiple classes should be separated by spaces.'),
+    '#default_value' => empty($instance['settings']['attributes']['class']) ? '' : $instance['settings']['attributes']['class'],
+  );
+  $form['attributes']['configurable_title'] = array(
+    '#title' => t("Allow the user to enter a link 'title' attribute"),
+    '#type' => 'checkbox',
+    '#default_value' => empty($instance['settings']['attributes']['configurable_title']) ? '' : $instance['settings']['attributes']['configurable_title'],
+  );
+  $form['attributes']['title'] = array(
+    '#title' => t("Default link 'title' Attribute"),
+    '#type' => 'textfield',
+    '#description' => t('When output, links will use this "title" attribute if the user does not provide one and when different from the link text. Read <a href="http://www.w3.org/TR/WCAG10-HTML-TECHS/#links">WCAG 1.0 Guidelines</a> for links comformances. Tokens values will be evaluated.'),
+    '#default_value' => empty($instance['settings']['attributes']['title']) ? '' : $instance['settings']['attributes']['title'],
+    '#field_prefix' => 'title = "',
+    '#field_suffix' => '"',
+    '#size' => 20,
+  );
+  return $form;
+}
+
+/**
+ * Validate the field settings form.
+ */
+function link_field_settings_form_validate($element, &$form_state, $complete_form) {
+  if ($form_state['values']['instance']['settings']['title'] === 'value'
+      && empty($form_state['values']['instance']['settings']['title_value'])) {
+    form_set_error('title_value', t('A default title must be provided if the title is a static value.'));
+  }
+  if (!empty($form_state['values']['instance']['settings']['display']['url_cutoff'])  // patch #1307788 from nmc
+      && !is_numeric($form_state['values']['instance']['settings']['display']['url_cutoff'])) {
+    form_set_error('display', t('URL Display Cutoff value must be numeric.'));
+  }
+  if (empty($form_state['values']['instance']['settings']['title_maxlength'])) {     // patch #1307788 from nmc
+    form_set_value($element['title_maxlength'], '128', $form_state);
+  } elseif (!is_numeric($form_state['values']['instance']['settings']['title_maxlength'])) {
+    form_set_error('title_maxlength', t('The max length of the link title must be numeric.'));
+  } elseif ($form_state['values']['instance']['settings']['title_maxlength'] > 255) {
+    form_set_error('title_maxlength', t('The max length of the link title cannot be greater than 255 characters.'));
+  }
+
+}
+
+/**
+ * Implement hook_field_is_empty().
+ */
+function link_field_is_empty($item, $field) {
+  return empty($item['title']) && empty($item['url']);
+}
+
+/**
+ * Implements hook_field_load().
+ */
+function link_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
+  foreach ($entities as $id => $entity) {
+    foreach ($items[$id] as $delta => $item) {
+      $items[$id][$delta]['attributes'] = _link_load($field, $item, $instances[$id]);
+    }
+  }
+}
+
+/**
+ * Implements hook_field_validate().
+ */
+function link_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
+  $optional_field_found = FALSE;
+  if ($instance['settings']['validate_url'] !== 0 || is_null($instance['settings']['validate_url']) || !isset($instance['settings']['validate_url'])) {
+    foreach ($items as $delta => $value) {
+      _link_validate($items[$delta], $delta, $field, $entity, $instance, $optional_field_found);
+    }
+  }
+
+  if ($instance['settings']['url'] === 'optional' && $instance['settings']['title'] === 'optional' && $instance['required'] && !$optional_field_found) {
+    form_set_error($field['field_name'] .'][0][title', t('At least one title or URL must be entered.'));
+  }
+}
+
+/**
+ * Implements hook_field_presave().
+ */
+function link_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  foreach ($items as $delta => $value) {
+    _link_process($items[$delta], $delta, $field, $entity);
+  }
+}
+
+/**
+ * Implements hook_field_prepare_view().
+ */
+function link_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
+  foreach ($items as $entity_id => $entity_items) {
+    foreach ($entity_items as $delta => $value) {
+      _link_sanitize($items[$entity_id][$delta], $delta, $field, $instances[$entity_id], $entities[$entity_id]);
+    }
+  }
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function link_field_widget_info() {
+  return array(
+    'link_field' => array(
+      'label' => 'Link',
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function link_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  $element += array(
+    '#type' => $instance['widget']['type'],
+    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
+  );
+  return $element;
+}
+
+/**
+ * Unpacks the item attributes for use.
+ */
+function _link_load($field, $item, $instance) {
+  /*return $item['attributes'] = isset($item['attributes']) ?
+                                unserialize($item['attributes']) :
+                                $instance['settings']['attributes'];*/
+  if (isset($item['attributes'])) {
+    return unserialize($item['attributes']);
+  }
+  else if (isset($instance['settings']['attributes'])) {
+    return $instance['settings']['attributes'];
+  }
+  else {
+    return $field['settings']['attributes'];
+  }
+}
+
+/**
+ * Prepares the item attributes and url for storage.
+ */
+function _link_process(&$item, $delta = 0, $field, $entity) {
+  // Trim whitespace from URL.
+  $item['url'] = trim($item['url']);
+
+  // if no attributes are set then make sure $item['attributes'] is an empty array - this lets $field['attributes'] override it.
+  if (empty($item['attributes'])) {
+    $item['attributes'] = array();
+  }
+
+  // Serialize the attributes array.
+  if (!is_string($item['attributes'])) {
+    $item['attributes'] = serialize($item['attributes']);
+  }
+
+  // Don't save an invalid default value (e.g. 'http://').
+  if ((isset($field['widget']['default_value'][$delta]['url']) && $item['url'] == $field['widget']['default_value'][$delta]['url'])
+      && is_object($node)) {
+    if (!link_validate_url($item['url'])) {
+      unset($item['url']);
+    }
+  }
+}
+
+/**
+ * Validates that the link field has been entered properly.
+ */
+function _link_validate(&$item, $delta, $field, $node, $instance, &$optional_field_found) {
+  if ($item['url']
+      && !(isset($instance['default_value'][$delta]['url'])
+      && $item['url'] === $instance['default_value'][$delta]['url']
+      && !$instance['required'])) {
+    // Validate the link.
+    if (link_validate_url(trim($item['url'])) == FALSE) {
+      form_set_error($field['field_name'] .']['. $delta .'][url', t('Not a valid URL.'));
+    }
+    // Require a title for the link if necessary.
+    if ($instance['settings']['title'] == 'required' && strlen(trim($item['title'])) == 0) {
+      form_set_error($field['field_name'] .']['. $delta .'][title', t('Titles are required for all links.'));
+    }
+  }
+  // Require a link if we have a title.
+  if ($instance['settings']['url'] !== 'optional'
+      && strlen(isset($item['title']) ? $item['title'] : NULL) > 0
+      && strlen(trim($item['url'])) == 0) {
+    form_set_error($field['field_name'] .']['. $delta .'][url', t('You cannot enter a title without a link url.'));
+  }
+  // In a totally bizzaro case, where URLs and titles are optional but the field is required, ensure there is at least one link.
+  if ($instance['settings']['url'] === 'optional'
+      && $instance['settings']['title'] === 'optional'
+      && (strlen(trim($item['url'])) !== 0 || strlen(trim($item['title'])) !== 0)) {
+    $optional_field_found = TRUE;
+  }
+  // Require entire field
+  if ($instance['settings']['url'] === 'optional'
+    && $instance['settings']['title'] === 'optional'
+    && $instance['required'] == 1
+    && !$optional_field_found
+    && isset($instance['id'])) {
+    form_set_error($instance['field_name'] .'][0][title',
+                   t('At least one title or URL must be entered.'));
+  }
+}
+
+/**
+ * Cleanup user-entered values for a link field according to field settings.
+ *
+ * @param $item
+ *   A single link item, usually containing url, title, and attributes.
+ * @param $delta
+ *   The delta value if this field is one of multiple fields.
+ * @param $field
+ *   The CCK field definition.
+ * @param $node
+ *   The node containing this link.
+ */
+function _link_sanitize(&$item, $delta, &$field, $instance, &$node) {
+  // Don't try to process empty links.
+  if (empty($item['url']) && empty($item['title'])) {
+    return;
+  }
+
+  // Replace URL tokens.
+  if (isset($instance['settings']['enable_tokens']) && $instance['settings']['enable_tokens']) {
+    global $user;
+    // Load the node if necessary for nodes in views.
+    $token_node = isset($node->nid) ? node_load($node->nid) : $node;
+    $item['url'] = token_replace($item['url'], array('node' => $token_node));
+  }
+
+  $type = link_validate_url($item['url']);
+  // If we can't determine the type of url, and we've been told not to validate it,
+  // then we assume it's a LINK_EXTERNAL type for later processing. #357604
+  if ($type == FALSE && $instance['settings']['validate_url'] === 0) {
+    $type = LINK_EXTERNAL;
+  }
+  $url = link_cleanup_url($item['url']);
+
+  // Separate out the anchor if any.
+  if (strpos($url, '#') !== FALSE) {
+    $item['fragment'] = substr($url, strpos($url, '#') + 1);
+    $url = substr($url, 0, strpos($url, '#'));
+  }
+  // Separate out the query string if any.
+  if (strpos($url, '?') !== FALSE) {
+    $query = substr($url, strpos($url, '?') + 1);
+    parse_str($query, $query_array);
+    $item['query'] = $query_array;
+    $url = substr($url, 0, strpos($url, '?'));
+  }
+
+  $item['url'] = check_plain($url);
+
+  // Create a shortened URL for display.
+  $display_url = $type == LINK_EMAIL ?
+                  str_replace('mailto:', '', $url) :
+                  url($url, array('query' => isset($item['query']) ?
+                                              $item['query'] :
+                                              NULL,
+                                  'fragment' => isset($item['fragment']) ?
+                                                $item['fragment'] :
+                                                NULL,
+                                  'absolute' => TRUE));
+  if ($instance['settings']['display']['url_cutoff'] && strlen($display_url) > $instance['settings']['display']['url_cutoff']) {
+    $display_url = substr($display_url, 0, $instance['settings']['display']['url_cutoff']) ."...";
+  }
+  $item['display_url'] = $display_url;
+
+  // Use the title defined at the instance level.
+  if ($instance['settings']['title'] == 'value' && strlen(trim($instance['settings']['title_value']))) {
+    $title = $instance['settings']['title_value'];
+  }
+  // Use the title defined by the user at the widget level.
+  else if (isset($item['title'])) {
+    $title = $item['title'];
+  }
+  else {
+    $title = '';
+  }
+
+  // Replace tokens.
+  if ($title && ($instance['settings']['title'] == 'value' || $instance['settings']['enable_tokens'])) {
+    // Load the node if necessary for nodes in views.
+    $token_node = isset($node->nid) ? node_load($node->nid) : $node;
+    $title = filter_xss(token_replace($title, array('node' => $token_node)),
+                        array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
+    $item['html'] = TRUE;
+  }
+  $item['title'] = empty($title) ? $item['display_url'] : $title;
+
+  if (!isset($item['attributes'])) {
+    $item['attributes'] = array();
+  }
+
+  // Unserialize attributtes array if it has not been unserialized yet.
+  if (!is_array($item['attributes'])) {
+    $item['attributes'] = (array)unserialize($item['attributes']);
+  }
+
+  // Add default attributes.
+  if (!is_array($instance['settings']['attributes'])){
+    $instance['settings']['attributes'] = _link_default_attributes();
+  }
+  else {
+    $instance['settings']['attributes'] += _link_default_attributes();
+  }
+
+  // Merge item attributes with attributes defined at the field level.
+  $item['attributes'] += $instance['settings']['attributes'];
+
+  // If user is not allowed to choose target attribute, use default defined at
+  // field level.
+  if ($instance['settings']['attributes']['target'] != LINK_TARGET_USER) {
+    $item['attributes']['target'] = $instance['settings']['attributes']['target'];
+  }
+
+  // Remove the target attribute if the default (no target) is selected.
+  if (empty($item['attributes']) || $item['attributes']['target'] == LINK_TARGET_DEFAULT) {
+    unset($item['attributes']['target']);
+  }
+
+  // Remove the rel=nofollow for internal links.
+  if ($type != LINK_EXTERNAL && strpos($item['attributes']['rel'], 'nofollow') !== FALSE) {
+    $item['attributes']['rel'] = str_replace('nofollow', '', $item['attributes']);
+  }
+
+  // Handle "title" link attribute.
+  if (!empty($item['attributes']['title']) && module_exists('token')) {
+    // Load the node (necessary for nodes in views).
+    $token_node = isset($node->nid) ? node_load($node->nid) : $node;
+    $item['attributes']['title'] = filter_xss(token_replace($item['attributes']['title'], array('node' => $token_node)),
+                        array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
+  }
+  // Remove title attribute if it's equal to link text.
+  if (isset($item['attributes']['title']) && $item['attributes']['title'] == $item['title']) {
+    unset($item['attributes']['title']);
+  }
+  unset($item['attributes']['configurable_title']);
+
+  // Remove empty attributes.
+  $item['attributes'] = array_filter($item['attributes']);
+
+  // Sets title to trimmed url if one exists
+  // @TODO: Do we need this?  It seems not.
+  /*if(!empty($item['display_url']) && empty($item['title'])) {
+    $item['title'] = $item['display_url'];
+  }
+  elseif(!isset($item['title'])) {
+    $item['title'] = $item['url'];
+  }*/
+
+}
+
+/**
+ * Implements hook_theme().
+ */
+function link_theme() {
+  return array(
+    /*'link_field_settings' => array(
+      'variables' => array('element' => NULL),
+    ),*/
+    'link_formatter_link_default' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_plain' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_title_plain' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_url' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_short' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_label' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_separate' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_field' => array(
+      'render element' => 'element',
+    ),
+  );
+}
+
+/**
+ * FAPI theme for an individual text elements.
+ */
+function theme_link_field($vars) {
+  drupal_add_css(drupal_get_path('module', 'link') .'/link.css');
+
+  $element = $vars['element'];
+  // Prefix single value link fields with the name of the field.
+  if (empty($element['#field']['multiple'])) {
+    if (isset($element['url']) && !isset($element['title'])) {
+      unset($element['url']['#title']);
+    }
+  }
+
+  $output = '';
+  $output .= '<div class="link-field-subrow clearfix">';
+  if (isset($element['title'])) {
+    $output .= '<div class="link-field-title link-field-column">'. drupal_render($element['title']) .'</div>';
+  }
+  $output .= '<div class="link-field-url'. (isset($element['title']) ? ' link-field-column' : '') .'">'. drupal_render($element['url']) .'</div>';
+  $output .= '</div>';
+  if (!empty($element['attributes']['target'])) {
+    $output .= '<div class="link-attributes">'. drupal_render($element['attributes']['target']) .'</div>';
+  }
+  if (!empty($element['attributes']['title'])) {
+    $output .= '<div class="link-attributes">'. drupal_render($element['attributes']['title']) .'</div>';
+  }
+  return $output;
+}
+
+/**
+ * Implements hook_element_info().
+ */
+function link_element_info() {
+  $elements = array();
+  $elements['link_field'] =  array(
+    '#input' => TRUE,
+    '#process' => array('link_field_process'),
+    '#theme' => 'link_field',
+    '#theme_wrappers' => array('form_element'),
+  );
+  return $elements;
+}
+
+function _link_default_attributes() {
+  return array(
+    'target' => LINK_TARGET_DEFAULT,
+    'class' => '',
+    'rel' => '',
+  );
+}
+
+/**
+ * Process the link type element before displaying the field.
+ *
+ * Build the form element. When creating a form using FAPI #process,
+ * note that $element['#value'] is already set.
+ *
+ * The $fields array is in $complete_form['#field_info'][$element['#field_name']].
+ */
+function link_field_process($element, $form_state, $complete_form) {
+  $instance = field_widget_instance($element, $form_state);
+  $settings = $instance['settings'];
+  $element['url'] = array(
+    '#type' => 'textfield',
+    '#maxlength' => LINK_URL_MAX_LENGTH,
+    '#title' => t('URL'),
+    '#required' => ($element['#delta'] == 0 && $settings['url'] !== 'optional') ? $element['#required'] : FALSE,
+    '#default_value' => isset($element['#value']['url']) ? $element['#value']['url'] : NULL,
+  );
+  if ($settings['title'] !== 'none' && $settings['title'] !== 'value') {
+    $element['title'] = array(
+      '#type' => 'textfield',
+      '#maxlength' => $settings['title_maxlength'],  // patch #1307788 from nmc
+      '#title' => t('Title'),
+      '#description' => t('The link title is limited to '.$settings['title_maxlength'].' characters maximum.'), // patch #1307788 from nmc
+      '#required' => ($settings['title'] == 'required' && (($element['#delta'] == 0 && $element['#required']) || !empty($element['#value']['url']))) ? TRUE : FALSE, // davereids patch from jan 2011
+      '#default_value' => isset($element['#value']['title']) ? $element['#value']['title'] : NULL,
+    );
+  }
+
+  // Initialize field attributes as an array if it is not an array yet.
+  if (!is_array($settings['attributes'])) {
+    $settings['attributes'] = array();
+  }
+  // Add default attributes.
+  $settings['attributes'] += _link_default_attributes();
+  $attributes = isset($element['#value']['attributes']) ? $element['#value']['attributes'] : $settings['attributes'];
+  if (!empty($settings['attributes']['target']) && $settings['attributes']['target'] == LINK_TARGET_USER) {
+    $element['attributes']['target'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Open URL in a New Window'),
+      '#return_value' => LINK_TARGET_NEW_WINDOW,
+      '#default_value' => isset($attributes['target']) ? $attributes['target'] : FALSE,
+    );
+  }
+  if (!empty($settings['attributes']['configurable_title']) && $settings['attributes']['configurable_title'] == 1) {
+    $element['attributes']['title'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Link "title" attribute'),
+      '#default_value' => isset($attributes['title']) ? $attributes['title'] : '',
+      '#field_prefix' => 'title = "',
+      '#field_suffix' => '"',
+    );
+  }
+
+  // To prevent an extra required indicator, disable the required flag on the
+  // base element since all the sub-fields are already required if desired.
+  $element['#required'] = FALSE; // davereids patch from jan 2011
+
+  return $element;
+}
+
+/**
+ * Implementation of hook_field_formatter_info().
+ */
+function link_field_formatter_info() {
+  return array(
+    'link_default' => array(
+      'label' => t('Title, as link (default)'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_title_plain' => array(
+      'label' => t('Title, as plain text'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_url' => array(
+      'label' => t('URL, as link'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_plain' => array(
+      'label' => t('URL, as plain text'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_short' => array(
+      'label' => t('Short, as link with title "Link"'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_label' => array(
+      'label' => t('Label, as link with label as title'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_separate' => array(
+      'label' => t('Separate title and URL'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function link_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $elements = array();
+  foreach ($items as $delta => $item) {
+    $elements[$delta] = array(
+      '#markup' => theme('link_formatter_'. $display['type'], array('element' => $item, 'field' => $instance)),
+    );
+  }
+  return $elements;
+}
+
+/**
+ * Theme function for 'default' text field formatter.
+ */
+function theme_link_formatter_link_default($vars) {
+  $link_options = $vars['element'];
+  unset($link_options['element']['title']);
+  unset($link_options['element']['url']);
+  
+  // Issue #1199806 by ss81: Fixes fatal error when the link URl is equal to page URL
+  if (isset($link_options['attributes']['class'])) {
+    $link_options['attributes']['class'] = array($link_options['attributes']['class']);
+  }
+  
+  // Display a normal link if both title and URL are available.
+  if (!empty($vars['element']['title']) && !empty($vars['element']['url'])) {
+    return l($vars['element']['title'], $vars['element']['url'], $link_options);
+  }
+  // If only a title, display the title.
+  elseif (!empty($vars['element']['title'])) {
+    return check_plain($vars['element']['title']);
+  }
+  elseif (!empty($vars['element']['url'])) {
+    return l($vars['element']['title'], $vars['element']['url'], $link_options);
+  }
+}
+
+/**
+ * Theme function for 'plain' text field formatter.
+ */
+function theme_link_formatter_link_plain($vars) {
+  $link_options = $vars['element'];
+  unset($link_options['element']['title']);
+  unset($link_options['element']['url']);
+  return empty($vars['element']['url']) ?
+    check_plain($vars['element']['title']) :
+    url($vars['element']['url'], $link_options);
+}
+
+/**
+ * Theme function for 'title_plain' text field formatter.
+ */
+function theme_link_formatter_link_title_plain($vars) {
+  return empty($vars['element']['title']) ? '' : check_plain($vars['element']['title']);
+}
+
+/**
+ * Theme function for 'url' text field formatter.
+ */
+function theme_link_formatter_link_url($vars) {
+  $link_options = $vars['element'];
+  unset($link_options['element']['title']);
+  unset($link_options['element']['url']);
+  return $vars['element']['url'] ? l($vars['element']['display_url'], $vars['element']['url'], $link_options) : '';
+}
+
+/**
+ * Theme function for 'short' text field formatter.
+ */
+function theme_link_formatter_link_short($vars) {
+  $link_options = $vars['element'];
+  unset($link_options['element']['title']);
+  unset($link_options['element']['url']);
+  return $vars['element']['url'] ? l(t('Link'), $vars['element']['url'], $link_options) : '';
+}
+
+/**
+ * Theme function for 'label' text field formatter.
+ */
+function theme_link_formatter_link_label($vars) {
+  $link_options = $vars['element'];
+  unset($link_options['element']['title']);
+  unset($link_options['element']['url']);
+  return $vars['element']['url'] ? l($vars['field']['label'], $vars['element']['url'], $link_options) : '';
+}
+
+/**
+ * Theme function for 'separate' text field formatter.
+ */
+
+function theme_link_formatter_link_separate($vars) {
+  $class = empty($vars['element']['attributes']['class']) ? '' : ' '. $vars['element']['attributes']['class'];
+  unset($vars['element']['attributes']['class']);
+  $link_options = $vars['element'];
+  unset($link_options['element']['title']);
+  unset($link_options['element']['url']);
+  $title = empty($vars['element']['title']) ? '' : check_plain($vars['element']['title']);
+  
+  /** 
+   * @TODO static html markup looks not very elegant to me (who takes it off?)
+   * needs smarter output solution and an optional title/url seperator (digidog) 
+   */
+  $output = '';
+  $output .= '<div class="link-item '. $class .'">';
+  if (!empty($title)) {
+    $output .= '<div class="link-title">'. $title .'</div>';
+  }
+  $output .= '<div class="link-url">'. l($vars['element']['url'], $vars['element']['url'], $link_options) .'</div>';
+  $output .= '</div>';
+  return $output;
+}
+
+
+function link_token_list($type = 'all') {
+  if ($type === 'field' || $type === 'all') {
+    $tokens = array();
+
+    $tokens['link']['url'] = t("Link URL");
+    $tokens['link']['title'] = t("Link title");
+    $tokens['link']['view'] = t("Formatted html link");
+
+    return $tokens;
+  }
+}
+
+function link_token_values($type, $object = NULL) {
+  if ($type === 'field') {
+    $item = $object[0];
+
+    $tokens['url'] = $item['url'];
+    $tokens['title'] = $item['title'];
+    $tokens['view'] = isset($item['view']) ? $item['view'] : '';
+
+    return $tokens;
+  }
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function link_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'link') .'/views',
+  );
+}
+
+/**
+ * Forms a valid URL if possible from an entered address.
+ * Trims whitespace and automatically adds an http:// to addresses without a protocol specified
+ *
+ * @param string $url
+ * @param string $protocol The protocol to be prepended to the url if one is not specified
+ */
+function link_cleanup_url($url, $protocol = "http") {
+  $url = trim($url);
+  $type = link_validate_url($url);
+
+  if ($type === LINK_EXTERNAL) {
+    // Check if there is no protocol specified.
+    $protocol_match = preg_match("/^([a-z0-9][a-z0-9\.\-_]*:\/\/)/i", $url);
+    if (empty($protocol_match)) {
+      // But should there be? Add an automatic http:// if it starts with a domain name.
+      $domain_match = preg_match('/^(([a-z0-9]([a-z0-9\-_]*\.)+)('. LINK_DOMAINS .'|[a-z]{2}))/i', $url);
+      if (!empty($domain_match)) {
+        $url = $protocol ."://". $url;
+      }
+    }
+  }
+
+  return $url;
+}
+
+/**
+ * A lenient verification for URLs. Accepts all URLs following RFC 1738 standard
+ * for URL formation and all email addresses following the RFC 2368 standard for
+ * mailto address formation.
+ *
+ * @param string $text
+ * @return mixed Returns boolean FALSE if the URL is not valid. On success, returns an object with
+ * the following attributes: protocol, hostname, ip, and port.
+ */
+function link_validate_url($text) {
+  $LINK_ICHARS_DOMAIN = (string) html_entity_decode(implode("", array( // @TODO completing letters ...
+    "&#x00E6;", // æ
+    "&#x00C6;", // Æ
+    "&#x00C0;", // À
+    "&#x00E0;", // à
+    "&#x00C1;", // Á
+    "&#x00E1;", // á
+    "&#x00C2;", // Â
+    "&#x00E2;", // â
+    "&#x00E5;", // å
+    "&#x00C5;", // Å
+    "&#x00E4;", // ä
+    "&#x00C4;", // Ä
+    "&#x00C7;", // Ç
+    "&#x00E7;", // ç
+    "&#x00D0;", // Ð
+    "&#x00F0;", // ð
+    "&#x00C8;", // È
+    "&#x00E8;", // è
+    "&#x00C9;", // É
+    "&#x00E9;", // é
+    "&#x00CA;", // Ê
+    "&#x00EA;", // ê
+    "&#x00CB;", // Ë
+    "&#x00EB;", // ë
+    "&#x00CE;", // Î
+    "&#x00EE;", // î
+    "&#x00CF;", // Ï
+    "&#x00EF;", // ï
+    "&#x00F8;", // ø
+    "&#x00D8;", // Ø
+    "&#x00F6;", // ö
+    "&#x00D6;", // Ö
+    "&#x00D4;", // Ô
+    "&#x00F4;", // ô
+    "&#x00D5;",	// Õ
+    "&#x00F5;",	// õ
+    "&#x0152;", // Œ
+    "&#x0153;", // œ
+    "&#x00FC;", // ü
+    "&#x00DC;", // Ü
+    "&#x00D9;", // Ù
+    "&#x00F9;", // ù
+    "&#x00DB;", // Û
+    "&#x00FB;", // û
+    "&#x0178;", // Ÿ
+    "&#x00FF;", // ÿ 
+    "&#x00D1;", // Ñ
+    "&#x00F1;", // ñ
+    "&#x00FE;", // þ
+    "&#x00DE;", // Þ
+    "&#x00FD;", // ý
+    "&#x00DD;", // Ý
+    "&#x00BF;", // ¿
+  )), ENT_QUOTES, 'UTF-8');
+
+  $LINK_ICHARS = $LINK_ICHARS_DOMAIN . (string) html_entity_decode(implode("", array(
+    "&#x00DF;", // ß
+  )), ENT_QUOTES, 'UTF-8');
+  $allowed_protocols = variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'));
+
+  // Starting a parenthesis group with (?: means that it is grouped, but is not captured
+  $protocol = '((?:'. implode("|", $allowed_protocols) .'):\/\/)';
+  $authentication = "(?:(?:(?:[\w\.\-\+!$&'\(\)*\+,;=" . $LINK_ICHARS . "]|%[0-9a-f]{2})+(?::(?:[\w". $LINK_ICHARS ."\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})*)?)?@)";
+  $domain = '(?:(?:[a-z0-9' . $LINK_ICHARS_DOMAIN . ']([a-z0-9'. $LINK_ICHARS_DOMAIN . '\-_\[\]])*)(\.(([a-z0-9' . $LINK_ICHARS_DOMAIN . '\-_\[\]])+\.)*('. LINK_DOMAINS .'|[a-z]{2}))?)';
+  $ipv4 = '(?:[0-9]{1,3}(\.[0-9]{1,3}){3})';
+  $ipv6 = '(?:[0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})';
+  $port = '(?::([0-9]{1,5}))';
+
+  // Pattern specific to external links.
+  $external_pattern = '/^'. $protocol .'?'. $authentication .'?('. $domain .'|'. $ipv4 .'|'. $ipv6 .' |localhost)'. $port .'?';
+
+  // Pattern specific to internal links.
+  $internal_pattern = "/^(?:[a-z0-9". $LINK_ICHARS ."_\-+\[\]]+)";
+  $internal_pattern_file = "/^(?:[a-z0-9". $LINK_ICHARS ."_\-+\[\]\.]+)$/i";
+
+  $directories = "(?:\/[a-z0-9". $LINK_ICHARS ."_\-\.~+%=&,$'#!():;*@\[\]]*)*";
+  // Yes, four backslashes == a single backslash.
+  $query = "(?:\/?\?([?a-z0-9". $LINK_ICHARS ."+_|\-\.~\/\\\\%=&,$'():;*@\[\]{} ]*))";
+  $anchor = "(?:#[a-z0-9". $LINK_ICHARS ."_\-\.~+%=&,$'():;*@\[\]\/\?]*)";
+
+  // The rest of the path for a standard URL.
+  $end = $directories .'?'. $query .'?'. $anchor .'?'.'$/i';
+
+  $message_id = '[^@].*@'. $domain;
+  $newsgroup_name = '(?:[0-9a-z+-]*\.)*[0-9a-z+-]*';
+  $news_pattern = '/^news:('. $newsgroup_name .'|'. $message_id .')$/i';
+
+  $user = '[a-zA-Z0-9'. $LINK_ICHARS .'_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\'\[\]]+';
+  $email_pattern = '/^mailto:'. $user .'@'.'(?:'. $domain .'|'. $ipv4 .'|'. $ipv6 .'|localhost)'. $query .'?$/';
+
+  if (strpos($text, '<front>') === 0) {
+    return LINK_FRONT;
+  }
+  if (in_array('mailto', $allowed_protocols) && preg_match($email_pattern, $text)) {
+    return LINK_EMAIL;
+  }
+  if (in_array('news', $allowed_protocols) && preg_match($news_pattern, $text)) {
+    return LINK_NEWS;
+  }
+  if (preg_match($internal_pattern . $end, $text)) {
+    return LINK_INTERNAL;
+  }
+  if (preg_match($external_pattern . $end, $text)) {
+    return LINK_EXTERNAL;
+  }
+  if (preg_match($internal_pattern_file, $text)) {
+    return LINK_INTERNAL;
+  }
+
+  return FALSE;
+}
+
+/**
+ * Implements hook_migrate_field_alter().
+ */
+function link_content_migrate_field_alter(&$field_value, $instance_value) {
+  if ($field_value['type'] == 'link') {
+    // need to change the type:
+    $field_value['type'] = 'link_field';
+  }
+}
+
+/**
+ * Implements hook_migrate_instance_alter().
+ *
+ * Widget type also changed to link_field.
+ */
+function link_content_migrate_instance_alter(&$instance_value, $field_value) {
+  if ($instance_value['widget']['module'] == 'link'
+      && $instance_value['widget']['type'] == 'link') {
+    $instance_value['widget']['type'] = 'link_field';
+  }
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function link_field_settings_form() {
+  return array();
+}
+
+/**
+ * Additional callback to adapt the property info of link fields.
+ * @see entity_metadata_field_entity_property_info().
+ */
+function link_field_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+  // Define a data structure so it's possible to deal with both the link title
+  // and URL.
+  $property['getter callback'] = 'entity_metadata_field_verbatim_get';
+  $property['setter callback'] = 'entity_metadata_field_verbatim_set';
+
+  // Auto-create the field item as soon as a property is set.
+ $property['auto creation'] = 'link_field_item_create';
+
+  $property['property info'] = link_field_item_property_info();
+  $property['property info']['url']['required'] = !$instance['settings']['url'];
+  $property['property info']['title']['required'] = ($instance['settings']['title'] == 'required');
+  if ($instance['settings']['title'] == 'none') {
+    unset($property['property info']['title']);
+  }
+
+  unset($property['query callback']);
+}
+
+/**
+ * Callback for creating a new, empty link field item.
+ *
+ * @see link_field_property_info_callback()
+ */
+function link_field_item_create() {
+  return array('title' => NULL, 'url' => NULL);
+}
+
+/**
+ * Defines info for the properties of the link-field item data structure.
+ */
+function link_field_item_property_info() {
+  $properties['title'] = array(
+    'type' => 'text',
+    'label' => t('The title of the link.'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  $properties['url'] = array(
+    'type' => 'uri',
+    'label' => t('The URL of the link.'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  return $properties;
+}
diff --git a/sites/all/modules/link/tests/link.attribute.test b/sites/all/modules/link/tests/link.attribute.test
new file mode 100644
index 0000000000000000000000000000000000000000..398713a04e640c42fe167c5881ab26ccfb31c230
--- /dev/null
+++ b/sites/all/modules/link/tests/link.attribute.test
@@ -0,0 +1,781 @@
+<?php
+
+/**
+ * @file
+ * Basic simpletests to test options on link module.
+ */
+
+class LinkAttributeCrudTest extends DrupalWebTestCase {
+
+  private $zebra;
+
+  public $permissions = array(
+    'access content',
+    'administer content types',
+    'administer nodes',
+    'administer filters',
+    'access comments',
+    'post comments',
+    'skip comment approval',
+    'access administration pages',
+  );
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link Attribute Tests',
+      'description' => 'Tests the field attributes, making sure they appear in various displayed situations.',
+      'group' => 'Link',
+    );
+  }
+
+  function setup() {
+    $this->zebra = 0;
+    parent::setup('field_ui', 'link'); // was 'views'
+    //$this->loginWithPermissions($this->permissions);
+    // Create and login user.
+    $account = $this->drupalCreateUser(array('administer content types'));
+    $this->drupalLogin($account);
+  }
+
+  function createLink($url, $title, $attributes = array()) {
+    return array(
+      'url' => $url,
+      'title' => $title,
+      'attributes' => $attributes,
+    );
+  }
+
+  private function assertLinkOnNode($field_name, $link_value, $message = '', $group = 'Other') {
+    $this->zebra++;
+    $zebra_string = ($this->zebra % 2 == 0) ? 'even' : 'odd';
+    $cssFieldLocator = 'field-'. str_replace('_', '-', $field_name);
+    $this->assertPattern('@<div class="field field-type-link '. $cssFieldLocator .'".*<div class="field-item '. $zebra_string .'">\s*'. $link_value .'\s*</div>@is',
+                         $message,
+                         $group);
+  }
+
+  /**
+   * A simple test that just creates a new node type, adds a link field to it, creates a new node of that type, and makes sure
+   * that the node is being displayed.
+   */
+  function testBasic() {
+    /*$this->acquireContentTypes(1);
+    variable_set('node_options_'. $this->content_types[0]->name, array('status', 'promote'));*/
+
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+    $title = $this->randomName(20);
+
+    $this->drupalGet('admin/structure/types');
+
+    // Create the content type.
+    $this->clickLink(t('Add content type'));
+
+    $edit = array (
+      'name' => $content_type_friendly,
+      'type' => $content_type_machine,
+    );
+    $this->drupalPost(NULL, $edit, t('Save and add fields'));
+    $this->assertText(t('The content type @name has been added.', array('@name' => $content_type_friendly)));
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    $single_field_name = 'field_'. $single_field_name_machine;
+    $edit = array (
+      'fields[_add_new_field][label]' => $single_field_name_friendly,
+      'fields[_add_new_field][field_name]' => $single_field_name_machine,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // We'll go with the default settings for this run-through.
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+
+    // Using all the default settings, so press the button.
+    $this->drupalPost(NULL, array(), t('Save settings'));
+    $this->assertText(t('Saved @name configuration.', array('@name' => $single_field_name_friendly)));
+
+    // Somehow clicking "save" isn't enough, and we have to do a
+    // node_types_rebuild().
+    node_types_rebuild();
+    menu_rebuild();
+    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => $content_type_machine))->fetchField();
+    $this->assertTrue($type_exists, 'The new content type has been created in the database.');
+
+    $permission = 'create ' . $content_type_machine . ' content';
+    $permission_edit = 'edit ' . $content_type_machine . ' content';
+    // Reset the permissions cache.
+    $this->checkPermissions(array($permission), TRUE);
+
+    // Now that we have a new content type, create a user that has privileges
+    // on the content type.
+    $permissions = array_merge($this->permissions, array($permission));
+    $account = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($account);
+
+    // Go to page.
+    $this->drupalGet('node/add/'. $content_type_machine);
+
+    // Add a node.
+    $edit = array(
+      'title' => $title,
+      'field_'. $single_field_name_machine. '[und][0][title]' => 'Link',
+      'field_'. $single_field_name_machine. '[und][0][url]' => 'http://www.drupal.org/',
+    );
+
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText(t('@content_type_friendly @title has been created', array('@content_type_friendly' => $content_type_friendly, '@title' => $title)));
+
+    /*$field_settings = array(
+      'type' => 'link',
+      'widget_type' => 'link',
+      'type_name' => $this->content_types[0]->name,
+      'attributes' => array(), // <-- This is needed or we have an error.
+    );
+
+    $field = $this->createField($field_settings, 0);
+    //$this->pass('<pre>'. print_r($field, TRUE) .'</pre>');
+    $field_db_info = content_database_info($field);*/
+
+    //$this->acquireNodes(2);
+    /*$node = $this->drupalCreateNode(array('type' => $content_type_machine,
+                                          'promote' => 1));
+    $test_nid = $node->nid;*/
+
+    //$node = node_load($this->nodes[0]->nid);
+    //$node->promote = 1; // We want this to show on front page for the teaser test.
+    /*$this->assert('debug', print_r($node, TRUE), 'Debug');
+    $node->{$single_field_name}['und'][0] = $this->createLink('http://www.example.com', 'Test Link');
+    node_save($node);
+    $this->assert('debug', print_r($node, TRUE), 'Debug');*/
+
+    //$this->drupalGet('node/'. $test_nid .'/edit');
+    $this->drupalGet('node/add/'. $content_type_machine);
+
+    // lets add a node:
+    $edit = array(
+      'title' => $title,
+      'field_' . $single_field_name_machine . '[und][0][url]' => 'http://www.example.com/',
+      'field_' . $single_field_name_machine . '[und][0][title]' => 'Display',
+    );
+
+    // Now we can fill in the second item in the multivalue field and save.
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText(t('@content_type_friendly @title has been created', array('@content_type_friendly' => $content_type_friendly, '@title' => $title)));
+
+    $this->assertText('Display');
+    //$this->assertText('http://www.example.com/');
+    $this->assertLinkByHref('http://www.example.com');
+  }
+
+  private function createNodeType($content_type_machine, $content_type_friendly) {
+    $this->drupalGet('admin/structure/types');
+
+    // Create the content type.
+    $this->clickLink(t('Add content type'));
+
+    $edit = array (
+      'name' => $content_type_friendly,
+      'type' => $content_type_machine,
+    );
+    $this->drupalPost(NULL, $edit, t('Save and add fields'));
+    $this->assertText(t('The content type @name has been added.', array('@name' => $content_type_friendly)));
+  }
+
+  private function createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine) {
+    $edit = array (
+      'fields[_add_new_field][label]' => $single_field_name_friendly,
+      'fields[_add_new_field][field_name]' => $single_field_name_machine,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // We'll go with the default settings for this run-through.
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+
+    // Using all the default settings, so press the button.
+    $this->drupalPost(NULL, array(), t('Save settings'));
+    $this->assertText(t('Saved @name configuration.', array('@name' => $single_field_name_friendly)));
+
+    // Somehow clicking "save" isn't enough, and we have to do a
+    // node_types_rebuild().
+    node_types_rebuild();
+    menu_rebuild();
+    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => $content_type_machine))->fetchField();
+    $this->assertTrue($type_exists, 'The new content type has been created in the database.');
+  }
+
+  function createNodeTypeUser($content_type_machine) {
+    $permission = 'create ' . $content_type_machine . ' content';
+    $permission_edit = 'edit ' . $content_type_machine . ' content';
+    // Reset the permissions cache.
+    $this->checkPermissions(array($permission), TRUE);
+
+    // Now that we have a new content type, create a user that has privileges
+    // on the content type.
+    $permissions = array_merge($this->permissions, array($permission));
+    $account = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($account);
+  }
+
+  function createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $title, $url, $node_title = '') {
+    // Go to page.
+    $this->drupalGet('node/add/'. $content_type_machine);
+
+    if (!$node_title) {
+      $node_title = $this->randomName(20);
+    }
+    $edit = array(
+      'title' => $node_title,
+    );
+    if ($url) {
+      $edit['field_' . $single_field_name_machine . '[und][0][url]'] = $url;
+    }
+    if ($title) {
+      $edit['field_' . $single_field_name_machine . '[und][0][title]'] = $title;
+    }
+
+    // Now we can fill in the second item in the multivalue field and save.
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText(t('@content_type_friendly @title has been created', array('@content_type_friendly' => $content_type_friendly, '@title' => $node_title)));
+
+  }
+
+  function testFormatterPlain() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_plain',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertText($link_url);
+    $this->assertNoText($link_text);
+    $this->assertNoLinkByHref($link_url);
+  }
+
+  function testFormatterPlainWithQuerystring() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_plain',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/?q=test';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertText($link_url);
+    $this->assertNoText($link_text);
+    $this->assertNoLinkByHref($link_url);
+  }
+
+  function testFormatterPlainWithFragment() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_plain',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/#test';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertText($link_url);
+    $this->assertNoText($link_text);
+    $this->assertNoLinkByHref($link_url);
+  }
+
+  function testFormatterURL() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_url',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertNoText($link_text);
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterURLWithQuerystring() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_url',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/?q=test';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertNoText($link_text);
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterURLWithAnchor() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_url',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/#test';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertNoText($link_text);
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterShort() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_short',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertText('Link');
+    $this->assertNoText($link_text);
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterShortWithQuerystring() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_short',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/?q=test';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertText('Link');
+    $this->assertNoText($link_text);
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterShortWithFragment() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_short',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/#test';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertText('Link');
+    $this->assertNoText($link_text);
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterLabel() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_label',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertNoText($link_text);
+    $this->assertText($single_field_name_friendly);
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterLabelWithQuerystring() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_label',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/?q=test';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertNoText($link_text);
+    $this->assertText($single_field_name_friendly);
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterLabelWithFragment() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_label',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/#test';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertNoText($link_text);
+    $this->assertText($single_field_name_friendly);
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterSeparate() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_separate',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = $this->randomName(20);
+    $link_url = 'http://www.example.com/';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertText($link_text);
+    $this->assertLink($link_url);
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterSeparateWithQuerystring() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_separate',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = $this->randomName(20);
+    $link_url = 'http://www.example.com/?q=test';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertText($link_text);
+    $this->assertLink('http://www.example.com/');
+    $this->assertLinkByHref($link_url);
+  }
+
+  function testFormatterSeparateWithFragment() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_separate',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_text = $this->randomName(20);
+    $link_url = 'http://www.example.com/#test';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+
+    $this->assertText($link_text);
+    $this->assertLink('http://www.example.com/');
+    $this->assertLinkByHref($link_url);
+  }
+  
+  function testFormatterPlainTitle() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+    
+    $this->createNodeType($content_type_machine, $content_type_friendly);
+    
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+    
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_title_plain',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    
+    $this->createNodeTypeUser($content_type_machine);
+    
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+    
+    $this->assertText($link_text);
+    $this->assertNoText($link_url);
+    $this->assertNoLinkByHref($link_url);
+  }
+
+  /**
+   * This test sees that we can create a link field with a defined class, and make sure
+   * that class displays properly when the link is displayed.
+   */
+  /*function testLinkWithClassOnField() {
+    $this->acquireContentTypes(1);
+    $field_settings = array(
+      'type' => 'link',
+      'widget_type' => 'link',
+      'type_name' => $this->content_types[0]->name,
+      'attributes' => array(
+        'class' => 'test-class',
+        'target' => 'default',
+        'rel' => FALSE,
+      ),
+    );
+
+    $field = $this->createField($field_settings, 0);
+    //$this->pass('<pre>'. print_r($field, TRUE) .'</pre>');
+    $field_db_info = content_database_info($field);
+
+    $this->acquireNodes(2);
+
+    $node = node_load($this->nodes[0]->nid);
+    $node->promote = 1; // We want this to show on front page for the teaser test.
+    $node->{$field['field_name']}[0] = $this->createLink('http://www.example.com', 'Test Link');
+    node_save($node);
+
+    // Does this display on the node page?
+    $this->drupalGet('node/'. $this->nodes[0]->nid);
+    //$this->outputScreenContents('Link field with class', 'link_');
+    $this->assertLinkOnNode($field['field_name'], l('Test Link', 'http://www.example.com', array('attributes' => array('class' => 'test-class'))));
+
+    // Does this display on the front page?
+    $this->drupalGet('<front>');
+    // reset the zebra!
+    $this->zebra = 0;
+    $this->assertLinkOnNode($field['field_name'], l('Test Link', 'http://www.example.com', array('attributes' => array('class' => 'test-class'))));
+  }*/
+
+}
diff --git a/sites/all/modules/link/tests/link.crud.test b/sites/all/modules/link/tests/link.crud.test
new file mode 100644
index 0000000000000000000000000000000000000000..cdd7fc5aec4fb7ab27f96a8de19d5ec104cd97cf
--- /dev/null
+++ b/sites/all/modules/link/tests/link.crud.test
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * @file
+ * Basic CRUD simpletests for the link module, based off of content.crud.test in CCK.
+ */
+
+class LinkContentCrudTest extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link CRUD - Basic API tests',
+      'description' => 'Tests the field CRUD (create, read, update, delete) API.',
+      'group' => 'Link',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('field_ui', 'link'); // was views?
+    //$this->loginWithPermissions();
+  }
+
+  /**
+   * All we're doing here is creating a content type, creating a simple link field
+   * on that content type.
+   */
+  function testLinkCreateFieldAPI() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+    $title = $this->randomName(20);
+
+    // Create and login user.
+    $account = $this->drupalCreateUser(array('administer content types'));
+    $this->drupalLogin($account);
+
+    $this->drupalGet('admin/structure/types');
+
+    // Create the content type.
+    $this->clickLink(t('Add content type'));
+
+
+    $edit = array (
+      'name' => $content_type_friendly,
+      'type' => $content_type_machine,
+    );
+    $this->drupalPost(NULL, $edit, t('Save and add fields'));
+    $this->assertText(t('The content type @name has been added.', array('@name' => $content_type_friendly)));
+
+    //$field = $this->createField(array('type' => 'link', 'widget_type' => 'link'), 0);
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    $edit = array (
+      'fields[_add_new_field][label]' => $single_field_name_friendly,
+      'fields[_add_new_field][field_name]' => $single_field_name_machine,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // We'll go with the default settings for this run-through.
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+
+    // Using all the default settings, so press the button.
+    $this->drupalPost(NULL, array(), t('Save settings'));
+    $this->assertText(t('Saved @name configuration.', array('@name' => $single_field_name_friendly)));
+
+    // Somehow clicking "save" isn't enough, and we have to do a
+    // node_types_rebuild().
+    node_types_rebuild();
+    menu_rebuild();
+    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => $content_type_machine))->fetchField();
+    $this->assertTrue($type_exists, 'The new content type has been created in the database.');
+
+    /*$table_schema = drupal_get_schema();
+    $this->assertEqual(1, 1, print_r(array_keys($table_schema), TRUE));
+    // Check the schema - the values should be in the per-type table.
+    $this->assertSchemaMatchesTables(array(
+      'per_type' => array(
+        $this->content_types[0]->type => array($field['field_name'] => array('url', 'title', 'attributes')),
+      ),
+    ));*/
+  }
+}
diff --git a/sites/all/modules/link/tests/link.crud_browser.test b/sites/all/modules/link/tests/link.crud_browser.test
new file mode 100644
index 0000000000000000000000000000000000000000..7b01da0ff75e2e2c1d8ba06a0fc5f416dbcf6491
--- /dev/null
+++ b/sites/all/modules/link/tests/link.crud_browser.test
@@ -0,0 +1,373 @@
+<?php
+
+/**
+ * @file
+ * Testing CRUD API in the browser.
+ */
+
+/**
+ * Testing that users can not input bad URLs or labels
+ */
+class LinkUITest extends DrupalWebTestcase {
+
+  /**
+   * Link supposed to be good
+   */
+  const LINK_INPUT_TYPE_GOOD = 0;
+
+  /**
+   * Link supposed to have a bad title
+   */
+  const LINK_INPUT_TYPE_BAD_TITLE = 1;
+
+  /**
+   * Link supposed to have a bad URL
+   */
+  const LINK_INPUT_TYPE_BAD_URL = 2;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link CRUD - browser test',
+      'description' => 'Tests the field CRUD (create, read, update, delete) API 2.',
+      'group' => 'Link',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('field_ui', 'link');
+  }
+
+  /**
+   * Creates a link field for the "page" type and creates a page with a link.
+   */
+  function testLinkCreate() {
+    //libxml_use_internal_errors(true);
+    $account = $this->drupalCreateUser(array('administer content types',
+                                             'administer nodes',
+                                             'administer filters',
+                                             'access content',
+                                             'create page content',
+                                             'access administration pages'));
+    $this->drupalLogin($account);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array(), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+
+    $permission = 'create page content';
+    $this->checkPermissions(array($permission), TRUE);
+
+    // create page form
+    //$this->drupalGet('node/add');
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField('edit-field-'. $name .'-und-0-title', 'Title found');
+    $this->assertField('edit-field-'. $name .'-und-0-url', 'URL found');
+
+    $input_test_cases = array(
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName(),
+        'msg' => 'Link found',
+        'type' => self::LINK_INPUT_TYPE_GOOD
+      ),
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '<script>alert("hi");</script>',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '<script src="http://devil.site.com"></script>',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '" onmouseover="alert(\'hi\')',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+       array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '\' onmouseover="alert(\'hi\')',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+     array(
+        'href' => 'javascript:alert("http://example.com/' . $this->randomName() . '")',
+        'label' => $this->randomName(),
+        'msg' => 'js url',
+        'type' => self::LINK_INPUT_TYPE_BAD_URL
+      ),
+    );
+    $test_case = array(
+      'href' => 'www.example.com/'. $this->randomName(),
+      'label' => $this->randomName(),
+      'msg' => 'Link found',
+      'type' => self::LINK_INPUT_TYPE_GOOD,
+    );
+    $test_case['expected_href'] = 'http://'. $test_case['href'];
+    $input_test_cases[] = $test_case;
+
+    foreach ($input_test_cases as $input) {
+      $this->drupalLogin($account);
+      $this->drupalGet('node/add/page');
+
+      $edit = array(
+        'title' => $input['label'],
+        $field_name . '[und][0][title]' => $input['label'],
+        $field_name . '[und][0][url]' => $input['href'],
+      );
+      $this->drupalPost(NULL, $edit, t('Save'));
+      if ($input['type'] == self::LINK_INPUT_TYPE_BAD_URL) {
+        $this->assertRaw(t('Not a valid URL.'), 'Not a valid URL: ' . $input['href']);
+        continue;
+      }
+      else {
+        $this->assertRaw(t(' has been created.',
+                           array('@type' => 'Basic Page', '%title' => $edit['title'])),
+                         'Page created: ' . $input['href']);
+      }
+      $url = $this->getUrl();
+
+      // change to anonym user
+      $this->drupalLogout();
+
+      $this->drupalGet($url);
+      //debug($this);
+      // If simpletest starts using something to override the error system, this will flag
+      // us and let us know it's broken.
+      $this->assertFalse(libxml_use_internal_errors(TRUE));
+      if (isset($input['expected_href'])) {
+        $path = '//a[@href="'. $input['expected_href'] .'" and text()="'. $input['label'] .'"]';
+      }
+      else {
+        $path = '//a[@href="'. $input['href'] .'" and text()="'. $input['label'] .'"]';
+      }
+      //$this->pass(htmlentities($path));
+      $elements = $this->xpath($path);
+      libxml_use_internal_errors(FALSE);
+      $this->assertIdentical(isset($elements[0]), $input['type'] == self::LINK_INPUT_TYPE_GOOD, $input['msg']);
+    }
+    //libxml_use_internal_errors(FALSE);
+  }
+
+  /**
+   * Creates a link field for the "page" type and creates a page with a link.
+   * Just like the above test, only here we're turning off the validation on the field.
+   */
+  /*function testLinkCreate_NoValidation() {
+    //libxml_use_internal_errors(true);
+    $account = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($account);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array('validate_url' => FALSE), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    _content_type_info(TRUE);
+    $fields = content_fields();
+    $this->assertTRUE(0 === $fields['field_'. $name]['validate_url'], 'Make sure validation is off.');
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField($field_name . '[0][title]', 'Title found');
+    $this->assertField($field_name . '[0][url]', 'URL found');
+
+    $input_test_cases = array(
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName(),
+        'msg' => 'Link found',
+        'type' => self::LINK_INPUT_TYPE_GOOD
+      ),
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '<script>alert("hi");</script>',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '<script src="http://devil.site.com"></script>',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '" onmouseover="alert(\'hi\')',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+       array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '\' onmouseover="alert(\'hi\')',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+     array(
+        'href' => 'javascript:alert("http://example.com/' . $this->randomName() . '")',
+        'label' => $this->randomName(),
+        'msg' => 'js url',
+        'type' => self::LINK_INPUT_TYPE_BAD_URL
+      ),
+    );
+    foreach ($input_test_cases as $input) {
+      $this->drupalLogin($account);
+      $this->drupalGet('node/add/page');
+
+      $edit = array(
+        'title' => $input['label'],
+        $field_name . '[0][title]' => $input['label'],
+        $field_name . '[0][url]' => $input['href'],
+      );
+      $this->drupalPost(NULL, $edit, t('Save'));
+      if ($input['type'] == self::LINK_INPUT_TYPE_BAD_URL) {
+        //$this->assertRaw(t('Not a valid URL.'), 'Not a valid URL: ' . $input['href']);
+        $this->assertNoRaw($input['href']);
+        $this->assertRaw(t('@type %title has been created.', array('@type' => 'Basic Page', '%title' => $edit['title'])), 'Page created: ' . $input['href']);
+        continue;
+      }
+      else {
+        $this->assertRaw(t('@type %title has been created.', array('@type' => 'Basic Page', '%title' => $edit['title'])), 'Page created: ' . $input['href']);
+      }
+      $url = $this->getUrl();
+
+      // change to anonym user
+      $this->drupalLogout();
+
+      $this->drupalGet($url);
+      //debug($this);
+      // If simpletest starts using something to override the error system, this will flag
+      // us and let us know it's broken.
+      $this->assertFalse(libxml_use_internal_errors(TRUE));
+      $path = '//a[@href="'. $input['href'] .'" and text()="'. $input['label'] .'"]';
+      //$this->pass(htmlentities($path));
+      $elements = $this->xpath($path);
+      libxml_use_internal_errors(FALSE);
+      $this->assertIdentical(isset($elements[0]), $input['type'] == self::LINK_INPUT_TYPE_GOOD, $input['msg']);
+    }
+    //libxml_use_internal_errors(FALSE);
+  }*/
+
+  /**
+   * Testing that if you use <strong> in a static title for your link, that the
+   * title actually displays <strong>.
+   */
+  function testStaticLinkCreate() {
+    $account = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($account);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $field_name = 'field_'. $name;
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array(
+      'instance[settings][title]' => 'value',
+      'instance[settings][title_value]' => '<strong>'. $name .'</strong>'), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $this->assertField($field_name . '[und][0][url]', 'URL found');
+
+    $input = array(
+      'href' => 'http://example.com/' . $this->randomName()
+    );
+
+    $edit = array(
+      'title' => $name,
+      $field_name . '[und][0][url]' => $input['href'],
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l('<strong>'. $name .'</strong>', $input['href'], array('html' => TRUE)));
+  }
+
+  /**
+   * If we're creating a new field and just hit 'save' on the default options, we want to make
+   * sure they are set to the expected results.
+   */
+  function testCRUDCreateFieldDefaults() {
+    $account = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($account);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array(), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+    //_content_type_info(TRUE);
+    //$fields = content_fields();
+    //$field = $fields['field_'. $name];
+    //$field = field_info_field('field_'. $name);
+    _field_info_collate_fields(TRUE);
+    $instances = field_info_instances('node', 'page');
+    //$this->debug($instances);
+    //$this->assert('debug', '<pre>'. print_r($instances, TRUE) .'</pre>', 'Debug');
+    $instance = $instances['field_'. $name];
+    //$this->assertTrue(1 === $instance['validate_url'], 'Make sure validation is on.');
+    $this->assertFalse($instance['required'], 'Make sure field is not required.');
+    $this->assertEqual($instance['settings']['title'], 'optional', 'Title should be optional by default.');
+    $this->assertTrue($instance['settings']['enable_tokens'], 'Enable Tokens should be off by default.');
+    $this->assertEqual($instance['settings']['display']['url_cutoff'], 80, 'Url cutoff should be at 80 characters.');
+    $this->assertEqual($instance['settings']['attributes']['target'], 'default', 'Target should be "default"');
+    $this->assertFalse($instance['settings']['attributes']['rel'], 'Rel should be blank by default.');
+    $this->assertFalse($instance['settings']['attributes']['class'], 'By default, no class should be set.');
+    $this->assertFalse($instance['settings']['title_value'], 'By default, no title should be set.');
+
+    //$this->fail('<pre>'. print_r($fields['field_'. $name], TRUE) .'</pre>');
+  }
+}
diff --git a/sites/all/modules/link/tests/link.test b/sites/all/modules/link/tests/link.test
new file mode 100644
index 0000000000000000000000000000000000000000..dfb4dda337f0162710949d454b3b0bd8db00bf67
--- /dev/null
+++ b/sites/all/modules/link/tests/link.test
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * @file
+ * Link base test file - contains common functions for testing links.
+ */
+
+class LinkBaseTestClass extends DrupalWebTestCase {
+  public $permissions = array(
+    'access content',
+    'administer content types',
+    'administer nodes',
+    'administer filters',
+    'access comments',
+    'post comments',
+    'access administration pages',
+    'create page content',
+  );
+
+  public $account;
+
+  function setUp($modules = array()) {
+    if ($modules) {
+      parent::setUp($modules);
+    }
+    else {
+      parent::setUp('field_ui', 'link');
+    }
+    $this->account = $this->drupalCreateUser($this->permissions);
+    $this->drupalLogin($this->account);
+  }
+
+  function createLinkField($node_type = 'page',
+                           $settings = array()) {
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $field_name = 'field_'. $name;
+    $this->drupalPost('admin/structure/types/manage/'. $node_type .'/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, $settings, t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+
+    return $field_name;
+  }
+}
diff --git a/sites/all/modules/link/tests/link.token.test b/sites/all/modules/link/tests/link.token.test
new file mode 100644
index 0000000000000000000000000000000000000000..d23f46a78e54a675b4c5943e5831a12a97912551
--- /dev/null
+++ b/sites/all/modules/link/tests/link.token.test
@@ -0,0 +1,383 @@
+<?php
+
+/**
+ * @file
+ * Contains simpletests making sure token integration works.
+ */
+
+/**
+ * Testing that tokens can be used in link titles
+ */
+class LinkTokenTest extends LinkBaseTestClass {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link tokens - browser test',
+      'description' => 'Tests including tokens in link titles, making sure they appear in node views.',
+      'group' => 'Link',
+      'dependencies' => array('token'),
+    );
+  }
+
+  function setUp($modules = array()) {
+    $modules[] = 'field_ui';
+    $modules[] = 'link';
+    $modules[] = 'token';
+    parent::setUp($modules);
+  }
+
+  /**
+   * Creates a link field with a required title enabled for user-entered tokens.
+   * Creates a node with a token in the link title and checks the value.
+   */
+  function testUserTokenLinkCreate() {
+    /*$account = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($account);*/
+
+    // create field
+    $settings = array(
+      'instance[settings][enable_tokens]' => 1,
+    );
+    $field_name = $this->createLinkField('page',
+                                        $settings);
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    //$field_name = 'field_' . $name;
+    $this->assertField($field_name . '[und][0][title]', 'Title found');
+    $this->assertField($field_name . '[und][0][url]', 'URL found');
+
+    $input = array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName(),
+    );
+
+    //$this->drupalLogin($account);
+    $this->drupalGet('node/add/page');
+
+    $edit = array(
+      'title' => $input['label'],
+      $field_name . '[und][0][title]' => $input['label'] . " [node:content-type:machine-name]",
+      $field_name . '[und][0][url]' => $input['href'],
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l($input['label'] . ' page', $input['href']));
+  }
+
+
+  /**
+   * Creates a link field with a static title and an admin-entered token.
+   * Creates a node with a link and checks the title value.
+   */
+  function testStaticTokenLinkCreate() {
+
+    // create field
+    $name = $this->randomName();
+    $settings = array(
+      'instance[settings][title]' => 'value',
+      'instance[settings][title_value]' => $name .' [node:content-type:machine-name]');
+    $field_name = $this->createLinkField('page', $settings);
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $this->assertField($field_name . '[und][0][url]', 'URL found');
+
+    $input = array(
+      'href' => 'http://example.com/' . $this->randomName()
+    );
+
+    //$this->drupalLogin($account);
+    $this->drupalGet('node/add/page');
+
+    $edit = array(
+      'title' => $name,
+      $field_name . '[und][0][url]' => $input['href'],
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l($name . ' page', $input['href']));
+  }
+
+  /**
+   * Creates a link field with a static title and an admin-entered token.
+   * Creates a node with a link and checks the title value.
+   *
+   * Basically, I want to make sure the [title-raw] token works, because it's a
+   * token that changes from node to node, where [type]'s always going to be the
+   * same.
+   */
+  function testStaticTokenLinkCreate2() {
+
+    // create field
+    $name = $this->randomName();
+    $settings = array(
+      'instance[settings][title]' => 'value',
+      'instance[settings][title_value]' => $name .' [node:title]');
+    $field_name = $this->createLinkField('page', $settings);
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $this->assertField($field_name . '[und][0][url]', 'URL found');
+
+    $input = array(
+      'href' => 'http://example.com/' . $this->randomName()
+    );
+
+    //$this->drupalLogin($account);
+    $this->drupalGet('node/add/page');
+
+    $edit = array(
+      'title' => $name,
+      $field_name . '[und][0][url]' => $input['href'],
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l($name .' '. $name, $input['href']));
+  }
+
+  // This test doesn't seem to actually work, due to lack of 'title' in url.
+  function _test_Link_With_Title_Attribute_token_url_form() {
+   /* $this->loginWithPermissions($this->permissions);
+    $this->acquireContentTypes(1);
+    $field_settings = array(
+      'type' => 'link',
+      'widget_type' => 'link',
+      'type_name' => $this->content_types[0]->name,
+      'attributes' => array(
+        'class' => '',
+        'target' => 'default',
+        'rel' => 'nofollow',
+        'title' => '',
+      ),
+    );
+
+    $field = $this->createField($field_settings, 0);
+    //$this->fail('<pre>'. print_r($field, TRUE) .'</pre>');
+    $field_name = $field['field_name'];
+    $field_db_info = content_database_info($field);
+    $url_type = str_replace('_', '-', $this->content_types[0]->type);
+
+    $edit = array('attributes[title]' => '['. $field_name .'-url]',
+                  'enable_tokens' => TRUE);
+
+    $this->drupalPost('admin/content/node-type/'. $url_type .'/fields/'. $field['field_name'],
+                      $edit, t('Save field settings'));
+    $this->assertText(t('Saved field @field_name', array('@field_name' => $field['field_name'])));*/
+    $name = $this->randomName();
+    $settings = array(
+      'instance[settings][attributes][rel]' => 'nofollow',
+    );
+
+    $field_name = $this->createLinkField('page', $settings);
+
+    // So, having saved this field_name, let's see if it works...
+    //$this->acquireNodes(1);
+
+    //$node = node_load($this->nodes[0]->nid);
+
+    //$this->drupalGet('node/'. $this->nodes[0]->nid);
+
+    $edit = array();
+    $test_link_url = 'http://www.example.com/test';
+    $edit[$field_name .'[und][0][url]'] = $test_link_url;
+    $title = 'title_'. $this->randomName(20);
+    $edit[$field_name .'[und][0][title]'] = $title;
+    $edit['title'] = $name;
+
+    $this->drupalGet('node/add/page');
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Make sure we get a new version!
+    //$node = node_load($this->nodes[0]->nid, NULL, TRUE);
+    $this->assertText(t('Basic page @title has been updated.',
+                        array('@title' => $name)));
+
+    //$this->drupalGet('node/'. $node->nid);
+    $this->assertText($title, 'Make sure the link title/text shows');
+    $this->assertRaw(' title="'. $test_link_url .'"', "Do we show the link url as the title attribute?");
+    $this->assertNoRaw(' title="['. $field_name .'-url]"');
+    $this->assertTrue(module_exists('token'), t('Assure that Token Module is enabled.'));
+    //$this->fail($this->content);
+  }
+
+  /**
+   * If the title of the link is set to the title attribute, then the title
+   * attribute isn't supposed to show.
+   */
+  function _test_Link_With_Title_Attribute_token_title_form() {
+    $this->loginWithPermissions($this->permissions);
+    $this->acquireContentTypes(1);
+    $field_settings = array(
+      'type' => 'link',
+      'widget_type' => 'link',
+      'type_name' => $this->content_types[0]->name,
+      'attributes' => array(
+        'class' => '',
+        'target' => 'default',
+        'rel' => 'nofollow',
+        'title' => '',
+      ),
+    );
+
+    $field = $this->createField($field_settings, 0);
+    $field_name = $field['field_name'];
+    $field_db_info = content_database_info($field);
+    $url_type = str_replace('_', '-', $this->content_types[0]->type);
+
+    $edit = array('attributes[title]' => '['. $field_name .'-title]',
+                  'enable_tokens' => TRUE);
+
+    $this->drupalPost('admin/content/node-type/'. $url_type .'/fields/'. $field['field_name'],
+                      $edit, t('Save field settings'));
+    $this->assertText(t('Saved field @field_name', array('@field_name' => $field['field_name'])));
+
+    // So, having saved this field_name, let's see if it works...
+    $this->acquireNodes(1);
+
+    $node = node_load($this->nodes[0]->nid);
+
+    $this->drupalGet('node/'. $this->nodes[0]->nid);
+
+    $edit = array();
+    $edit[$field['field_name'] .'[0][url]'] = 'http://www.example.com/test';
+    $title = 'title_'. $this->randomName(20);
+    $edit[$field['field_name'] .'[0][title]'] = $title;
+
+    $this->drupalPost('node/'. $this->nodes[0]->nid .'/edit', $edit, t('Save'));
+
+    // Make sure we get a new version!
+    $node = node_load($this->nodes[0]->nid, NULL, TRUE);
+    $this->assertText(t('@type @title has been updated.',
+                        array('@title' => $node->title,
+                              '@type' => $this->content_types[0]->name)));
+
+    $this->drupalGet('node/'. $node->nid);
+    $this->assertText($title, 'Make sure the link title/text shows');
+    $this->assertNoRaw(' title="'. $title .'"', "We should not show the link title as the title attribute?");
+    $this->assertNoRaw(' title="['. $field_name .'-title]"');
+    //$this->fail($this->content);
+  }
+
+  /**
+   *  Trying to set the url to contain a token.
+   */
+  function _testUserTokenLinkCreateInURL() {
+    $account = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($account);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      '_add_new_field[label]' => $name,
+      '_add_new_field[field_name]' => $name,
+      '_add_new_field[type]' => 'link',
+      '_add_new_field[widget_type]' => 'link',
+    );
+    $this->drupalPost('admin/content/node-type/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(
+      'title' => 'required',
+      'enable_tokens' => 1), t('Save field settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Added field %label.', array('%label' => $name)), 'Field added');
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField($field_name . '[0][title]', 'Title found');
+    $this->assertField($field_name . '[0][url]', 'URL found');
+
+    $input = array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName(),
+    );
+
+    $this->drupalLogin($account);
+    $this->drupalGet('node/add/page');
+
+    $edit = array(
+      'title' => $input['label'],
+      $field_name . '[0][title]' => $input['label'],
+      $field_name . '[0][url]' => $input['href'] . "/[type]",
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l($input['label'], $input['href'] .'/page'));
+    //$this->fail($this->content);
+  }
+
+  /**
+   *  Trying to set the url to contain a token.
+   */
+  function _testUserTokenLinkCreateInURL2() {
+    $account = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($account);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      '_add_new_field[label]' => $name,
+      '_add_new_field[field_name]' => $name,
+      '_add_new_field[type]' => 'link',
+      '_add_new_field[widget_type]' => 'link',
+    );
+    $this->drupalPost('admin/content/node-type/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(
+      'title' => 'required',
+      'enable_tokens' => 1), t('Save field settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Added field %label.', array('%label' => $name)), 'Field added');
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField($field_name . '[0][title]', 'Title found');
+    $this->assertField($field_name . '[0][url]', 'URL found');
+
+    $input = array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName(),
+    );
+
+    $this->drupalLogin($account);
+    $this->drupalGet('node/add/page');
+
+    $edit = array(
+      'title' => $input['label'],
+      $field_name . '[0][title]' => $input['label'],
+      $field_name . '[0][url]' => $input['href'] . "/[author-uid]",
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l($input['label'], $input['href'] .'/'. $account->uid));
+  }
+}
diff --git a/sites/all/modules/link/tests/link.validate.test b/sites/all/modules/link/tests/link.validate.test
new file mode 100644
index 0000000000000000000000000000000000000000..affa7e94517f2d584b893d6d702083f8865f561f
--- /dev/null
+++ b/sites/all/modules/link/tests/link.validate.test
@@ -0,0 +1,501 @@
+<?php
+
+/**
+ * @file
+ * Tests that exercise the validation functions in the link module.
+ */
+
+class LinkValidateTestCase extends LinkBaseTestClass {
+
+  function setUp($modules = array()) {
+    parent::setUp($modules);
+  }
+
+  function createLink($url, $title, $attributes = array()) {
+    return array(
+      'url' => $url,
+      'title' => $title,
+      'attributes' => $attributes,
+    );
+  }
+
+  /**
+   * Takes a url, and sees if it can validate that the url is valid.
+   */
+  public function link_test_validate_url($url) {
+
+    $field_name = $this->createLinkField();
+
+    $permission = 'create page content';
+    $this->checkPermissions(array($permission), TRUE);
+
+    $this->drupalGet('node/add/page');
+
+    $label = $this->randomName();
+    $edit = array(
+      'title' => $label,
+      $field_name . '[und][0][title]' => $label,
+      $field_name . '[und][0][url]' => $url,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertRaw(t(' has been created.'), 'Node created');
+
+    $nid = 1; //$matches[1];
+
+    $node = node_load($nid);
+
+    $this->assertEqual($url, $node->{$field_name}['und'][0]['url']);
+  }
+}
+
+class LinkValidateTest extends LinkValidateTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link Validation Tests',
+      'description' => 'Tests the field validation.',
+      'group' => 'Link',
+    );
+  }
+
+  function test_link_validate_basic_url() {
+    $this->link_test_validate_url('http://www.example.com');
+  }
+
+  /**
+   * Test if we're stopped from posting a bad url on default validation.
+   */
+  function test_link_validate_bad_url_validate_default() {
+    $account = $this->drupalCreateUser(array('administer content types',
+                                             'administer nodes',
+                                             'administer filters',
+                                             'access content',
+                                             'create page content',
+                                             'access administration pages'));
+    $this->drupalLogin($account);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array(), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField('edit-field-'. $name .'-und-0-title', 'Title found');
+    $this->assertField('edit-field-'. $name .'-und-0-url', 'URL found');
+
+
+    $edit = array(
+      'title' => 'Simple Title',
+      $field_name .'[und][0][url]' => 'edik:naw',
+    );
+
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText(t('Not a valid URL.'));
+  }
+
+  /**
+   * Test if we're stopped from posting a bad url with validation on.
+   */
+  function test_link_validate_bad_url_validate_on() {
+    $account = $this->drupalCreateUser(array('administer content types',
+                                             'administer nodes',
+                                             'administer filters',
+                                             'access content',
+                                             'create page content',
+                                             'access administration pages'));
+    $this->drupalLogin($account);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array('instance[settings][validate_url]' => TRUE), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField('edit-field-'. $name .'-und-0-title', 'Title found');
+    $this->assertField('edit-field-'. $name .'-und-0-url', 'URL found');
+
+
+    $edit = array(
+      'title' => 'Simple Title',
+      $field_name .'[und][0][url]' => 'edik:naw',
+    );
+
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText(t('Not a valid URL.'));
+
+  }
+
+  /**
+   * Test if we can post a bad url if the validation is expressly turned off.
+   */
+  function test_link_validate_bad_url_validate_off() {
+    $account = $this->drupalCreateUser(array('administer content types',
+                                             'administer nodes',
+                                             'administer filters',
+                                             'access content',
+                                             'create page content',
+                                             'access administration pages'));
+    $this->drupalLogin($account);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array('instance[settings][validate_url]' => FALSE), t('Save settings'));
+
+    /*$instance_details = db_query("SELECT * FROM {field_config_instance} WHERE field_name = :field_name AND bundle = 'page'", array(':field_name' => 'field_'. $name))->fetchObject();
+    $this->fail('<pre>'. print_r($instance_details, TRUE) .'</pre>');
+    $this->fail('<pre>'. print_r(unserialize($instance_details->data), TRUE) .'</pre>');*/
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField('edit-field-'. $name .'-und-0-title', 'Title found');
+    $this->assertField('edit-field-'. $name .'-und-0-url', 'URL found');
+
+
+    $edit = array(
+      'title' => 'Simple Title',
+      $field_name .'[und][0][url]' => 'edik:naw',
+    );
+
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertNoText(t('Not a valid URL.'));
+
+  }
+
+  /**
+   * Test if a bad url can sneak through un-filtered if we play with the validation...
+   */
+  function x_test_link_validate_switching_between_validation_status() {
+    $this->acquireContentTypes(1);
+    $account = $this->drupalCreateUser(array('administer content types',
+                                             'administer nodes',
+                                             'access administration pages',
+                                             'access content',
+                                             'create '. $this->content_types[0]->type .' content',
+                                             'edit any '. $this->content_types[0]->type .' content'));
+    $this->drupalLogin($account);
+    variable_set('node_options_'. $this->content_types[0]->name, array('status', 'promote'));
+    $field_settings = array(
+      'type' => 'link',
+      'widget_type' => 'link',
+      'type_name' => $this->content_types[0]->name,
+      'attributes' => array(), // <-- This is needed or we have an error
+      'validate_url' => 0,
+    );
+
+    $field = $this->createField($field_settings, 0);
+    //$this->fail('<pre>'. print_r($field, TRUE) .'</pre>');
+    $field_db_info = content_database_info($field);
+
+    $this->acquireNodes(2);
+
+    $node = node_load($this->nodes[0]->nid);
+
+    $this->drupalGet('node/'. $this->nodes[0]->nid);
+
+    $edit = array();
+    $title = $this->randomName();
+    $url = 'javascript:alert("http://example.com/' . $this->randomName() . '")';
+    $edit[$field['field_name'] .'[0][url]'] = $url;
+    $edit[$field['field_name'] .'[0][title]'] = $title;
+
+    $this->drupalPost('node/'. $this->nodes[0]->nid .'/edit', $edit, t('Save'));
+    //$this->pass($this->content);
+    $this->assertNoText(t('Not a valid URL.'));
+
+    // Make sure we get a new version!
+    $node = node_load($this->nodes[0]->nid, NULL, TRUE);
+    $this->assertEqual($url, $node->{$field['field_name']}[0]['url']);
+
+    $this->drupalGet('node/'. $node->nid);
+    $this->assertNoRaw($url, 'Make sure Javascript does not display.');
+
+    // Turn the array validation back _on_.
+    $edit = array('validate_url' => TRUE);
+    $node_type_link = str_replace('_', '-', $node->type);
+    //$this->drupalGet('admin/content/node-type/'. $node_type_link .'/fields'); ///'. $field['field_name']);
+    //$this->fail($this->content);
+    $this->drupalPost('admin/content/node-type/'. $node_type_link .'/fields/'. $field['field_name'], $edit, t('Save field settings'));
+
+    $this->drupalGet('node/'. $node->nid);
+    // This actually works because the display_url goes through the core
+    // url() function.  But we should have a test that makes sure it continues
+    // to work.
+    $this->assertNoRaw($url, 'Make sure Javascript does not display.');
+    //$this->fail($this->content);
+
+  }
+
+  // Validate that '<front>' is a valid url.
+  function test_link_front_url() {
+    $this->link_test_validate_url('<front>');
+  }
+
+  // Validate that an internal url would be accepted.
+  function test_link_internal_url() {
+    $this->link_test_validate_url('node/32');
+  }
+
+  // Validate a simple mailto.
+  function test_link_mailto() {
+    $this->link_test_validate_url('mailto:jcfiala@gmail.com');
+  }
+
+  function test_link_external_https() {
+    $this->link_test_validate_url('https://www.example.com/');
+  }
+
+  function test_link_ftp() {
+    $this->link_test_validate_url('ftp://www.example.com/');
+  }
+}
+
+class LinkValidateTestNews extends LinkValidateTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link News Validation Tests',
+      'description' => 'Tests the field validation for usenet urls.',
+      'group' => 'Link',
+    );
+  }
+
+  // Validate a news link to a message group
+  function test_link_news() {
+    $this->link_test_validate_url('news:comp.infosystems.www.misc');
+  }
+
+  // Validate a news link to a message id.  Said ID copied off of google groups.
+  function test_link_news_message() {
+    $this->link_test_validate_url('news:hj0db8$vrm$1@news.eternal-september.org');
+  }
+}
+
+class LinkValidateSpecificURL extends LinkValidateTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Link Specific URL Validation Tests',
+      'description' => 'Tests field validation with unusual urls',
+      'group' => 'Link',
+    );
+  }
+
+  // Lets throw in a lot of umlouts for testing!
+  function test_umlout_url() {
+    $this->link_test_validate_url('http://üÜü.exämple.com/nöde');
+  }
+
+  function test_umlout_mailto() {
+    $this->link_test_validate_url('mailto:Üser@exÅmple.com');
+  }
+
+  function test_german_b_url() {
+    $this->link_test_validate_url('http://www.test.com/ßstuff');
+  }
+
+  function test_special_n_url() {
+    $this->link_test_validate_url('http://www.testÑñ.com/');
+  }
+
+  function test_curly_brackets_in_query() {
+    $this->link_test_validate_url('http://www.healthyteennetwork.org/index.asp?Type=B_PR&SEC={2AE1D600-4FC6-4B4D-8822-F1D5F072ED7B}&DE={235FD1E7-208D-4363-9854-4E6775EB8A4C}');
+  }
+
+  /**
+   * Here, we're testing that a very long url is stored properly in the db.
+   *
+   * Basicly, trying to test http://drupal.org/node/376818
+   */
+  function testLinkURLFieldIsBig() {
+    $long_url = 'http://th.wikipedia.org/wiki/%E0%B9%82%E0%B8%A3%E0%B8%87%E0%B9%80%E0%B8%A3%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%80%E0%B8%9A%E0%B8%8D%E0%B8%88%E0%B8%A1%E0%B8%A3%E0%B8%B2%E0%B8%8A%E0%B8%B9%E0%B8%97%E0%B8%B4%E0%B8%A8_%E0%B8%99%E0%B8%84%E0%B8%A3%E0%B8%A8%E0%B8%A3%E0%B8%B5%E0%B8%98%E0%B8%A3%E0%B8%A3%E0%B8%A1%E0%B8%A3%E0%B8%B2%E0%B8%8A';
+    $this->link_test_validate_url($long_url);
+  }
+
+}
+
+/**
+ * A series of tests of links, only going against the link_validate_url function in link.module.
+ *
+ * Validation is guided by the rules in http://tools.ietf.org/html/rfc1738 !
+ */
+class LinkValidateUrlLight extends DrupalWebTestCase {
+
+  //function setUp() {
+    // do we need to include something here?
+    //module_load_include('inc', 'link');
+  //}
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link Light Validation Tests',
+      'description' => 'Tests the link_validate_url() function by itself, without invoking the full drupal/cck lifecycle.',
+      'group' => 'Link',
+    );
+  }
+
+  /**
+   * Translates the LINK type constants to english for display and debugging of tests
+   */
+  function name_Link_Type($type) {
+    switch ($type) {
+      case LINK_FRONT:
+        return "Front";
+      case LINK_EMAIL:
+        return "Email";
+      case LINK_NEWS:
+        return "Newsgroup";
+      case LINK_INTERNAL:
+        return "Internal Link";
+      case LINK_EXTERNAL:
+        return "External Link";
+      case FALSE:
+        return "Invalid Link";
+      default:
+        return "Bad Value:". $type;
+    }
+  }
+
+  // Make sure that a link labelled <front> works.
+  function testValidateFrontLink() {
+    $valid = link_validate_url('<front>');
+    $this->assertEqual(LINK_FRONT, $valid, 'Make sure that front link is verfied and identified');
+  }
+
+  function testValidateEmailLink() {
+    $valid = link_validate_url('mailto:bob@example.com');
+    $this->assertEqual(LINK_EMAIL, $valid, "Make sure a basic mailto is verified and identified");
+  }
+
+  function testValidateEmailLinkBad() {
+    $valid = link_validate_url(':bob@example.com');
+    $this->assertEqual(FALSE, $valid, 'Make sure just a bad address is correctly failed');
+  }
+
+  function testValidateNewsgroupLink() {
+    $valid = link_validate_url('news:comp.infosystems.www.misc');
+    $this->assertEqual(LINK_NEWS, $valid, 'Make sure link to newsgroup validates as news.');
+  }
+
+  function testValidateNewsArticleLink() {
+    $valid = link_validate_url('news:hj0db8$vrm$1@news.eternal-september.org');
+    $this->assertEqual(LINK_NEWS, $valid, 'Make sure link to specific article valiates as news.');
+  }
+
+  function testValidateBadNewsgroupLink() {
+    $valid = link_validate_url('news:comp.bad_name.misc');
+    $this->assertEqual(FALSE, $valid, 'newsgroup names can\'t contain underscores, so it should come back as invalid.');
+  }
+
+  function testValidateInternalLink() {
+    $valid = link_validate_url('node/5');
+    $this->assertEqual(LINK_INTERNAL, $valid, 'Test normal internal link.');
+  }
+
+  function testValidateInternalLinkWithDot() {
+    $valid = link_validate_url('rss.xml');
+    $this->assertEqual(LINK_INTERNAL, $valid, 'Test rss.xml internal link.');
+  }
+
+  function testValidateInternalLinkToFile() {
+    $valid = link_validate_url('files/test.jpg');
+    $this->assertEqual(LINK_INTERNAL, $valid, 'Test files/test.jpg internal link.');
+  }
+
+  function testValidateExternalLinks() {
+    $links = array(
+      'http://localhost:8080/',
+      'www.example.com',
+      'www.example.com/',
+      'http://username:p%40ssw0rd!@www.example.com/',
+      'http://@www.example.com/',
+      'http://username:@www.example.com/',
+      'http://username:password@www.example.com:8080/',
+      'http://127.0.0.1:80/',
+      'http://127.173.24.255:4723/',
+      '127.173.24.255:4723/',
+      'http://255.255.255.255:4823/',
+      'www.test-site.com',
+      'http://example.com/index.php?q=node/123',
+      'http://example.com/index.php?page=this\that',
+      'http://example.com/?first_name=Joe Bob&last_name=Smith',
+      // Anchors
+      'http://www.example.com/index.php#test',
+      'http://www.example.com/index.php#this@that.',
+      'http://www.example.com/index.php#',
+      'http://www.cnn.com/video/#/video/politics/2008/12/09/intv.madeleine.albright.cnn',
+      'http://www.archive.org/stream/aesopsfables00aesorich#page/n7/mode/2up',
+      'http://www.example.com/blah/#this@that?',
+    );
+    // Test all of the protocols.
+    $allowed_protocols = variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'));
+    foreach ($allowed_protocols as $protocol) {
+      if ($protocol !== 'news' && $protocol !== 'mailto') {
+        $links[] = $protocol .'://www.example.com';
+      }
+    }
+    foreach ($links as $link) {
+      $valid = link_validate_url($link);
+      $this->assertEqual(LINK_EXTERNAL, $valid, 'Testing that '. $link .' is a valid external link.');
+      // The following two lines are commented out and only used for comparisons.
+      //$valid2 = valid_url($link, TRUE);
+      //$this->assertEqual(TRUE, $valid2, "Using valid_url() on $link.");
+    }
+  }
+
+  function testInvalidExternalLinks() {
+    $links = array(
+      'http://www.ex ample.com/',
+      '//www.example.com/',
+      'http://25.0.0/', // bad ip!
+      'http://4827.0.0.2/',
+      'http://www.testß.com/', // ß not allowed in domain names!
+      //'http://www.-fudge.com/', // domains can't have sections starting with a dash.
+    );
+    foreach ($links as $link) {
+      $valid = link_validate_url($link);
+      $this->assertEqual(FALSE, $valid, 'Testing that '. $link .' is not a valid link.');
+    }
+  }
+
+}
diff --git a/sites/all/modules/link/views/link.views.inc b/sites/all/modules/link/views/link.views.inc
new file mode 100644
index 0000000000000000000000000000000000000000..27d5182fa85c45b00ad7d86d87238bfa32ec8534
--- /dev/null
+++ b/sites/all/modules/link/views/link.views.inc
@@ -0,0 +1,113 @@
+<?php
+/**
+ * @file
+ * Contains functions handling views integration.
+ */
+
+/**
+ * Implementation of hook_views_handlers().
+ */
+/*function link_views_handlers() {
+  return array(
+    'info' => array(
+      'path' => drupal_get_path('module', 'link') .'/views',
+    ),
+    'handlers' => array(
+      'link_views_handler_argument_target' => array(
+        'parent' => 'views_handler_argument',
+      ),
+      'link_views_handler_filter_protocol' => array(
+        'parent' => 'views_handler_filter_string',
+      ),
+    ),
+  );
+}*/
+
+/**
+ * Return CCK Views data for the link_field_settings($op == 'views data').
+ *
+ * @TODO: Is there some way to tell views I have formatters for it?
+ */
+/*function link_views_content_field_data($field) {
+  // Build the automatic views data provided for us by CCK.
+  // This creates all the information necessary for the "url" field.
+  $data = content_views_field_views_data($field);
+
+  $db_info = content_database_info($field);
+  $table_alias = content_views_tablename($field);
+  $field_types = _content_field_types();
+
+  // Tweak the automatic views data for the link "url" field.
+  // Set the filter title to "@label URL"
+  $data[$table_alias][$field['field_name'] .'_url']['filter']['title'] = t('@label URL', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']);
+  // Remove the argument handling for URLs.
+  unset($data[$table_alias][$field['field_name'] .'_url']['argument']);
+
+  // Build out additional views data for the link "title" field.
+  $data[$table_alias][$field['field_name'] .'_title'] = array(
+    'group' => t('Content'),
+    'title' => t('@label title', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
+    'help' =>  $data[$table_alias][$field['field_name'] .'_url']['help'],
+    'argument' => array(
+      'field' => $db_info['columns']['title']['column'],
+      'tablename' => $db_info['table'],
+      'handler' => 'content_handler_argument_string',
+      'click sortable' => TRUE,
+      'name field' => '', // TODO, mimic content.views.inc :)
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+    'filter' => array(
+      'field' => $db_info['columns']['title']['column'],
+      'title' => t('@label title', array('@label' => t($field_types[$field['type']]['label']))),
+      'tablename' => $db_info['table'],
+      'handler' => 'content_handler_filter_string',
+      'additional fields' => array(),
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+    'sort' => array(
+      'field' => $db_info['columns']['title']['column'],
+      'tablename' => $db_info['table'],
+      'handler' => 'content_handler_sort',
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+  );
+
+  // Build out additional Views filter for the link "protocol" pseudo field.
+  // TODO: Add a protocol argument.
+  $data[$table_alias][$field['field_name'] .'_protocol'] = array(
+    'group' => t('Content'),
+    'title' => t('@label protocol', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
+    'help' =>  $data[$table_alias][$field['field_name'] .'_url']['help'],
+    'filter' => array(
+      'field' => $db_info['columns']['url']['column'],
+      'title' => t('@label protocol', array('@label' => t($field_types[$field['type']]['label']))),
+      'tablename' => $db_info['table'],
+      'handler' => 'link_views_handler_filter_protocol',
+      'additional fields' => array(),
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+  );
+
+  // Build out additional Views argument for the link "target" pseudo field.
+  // TODO: Add a target filter.
+  $data[$table_alias][$field['field_name'] .'_target'] = array(
+    'group' => t('Content'),
+    'title' => t('@label target', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
+    'help' =>  $data[$table_alias][$field['field_name'] .'_url']['help'],
+    'argument' => array(
+      'field' => $db_info['columns']['attributes']['column'],
+      'title' => t('@label target', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
+      'tablename' => $db_info['table'],
+      'handler' => 'link_views_handler_argument_target',
+      'additional fields' => array(),
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+  );
+
+  return $data;
+}*/
diff --git a/sites/all/modules/link/views/link_views_handler_argument_target.inc b/sites/all/modules/link/views/link_views_handler_argument_target.inc
new file mode 100644
index 0000000000000000000000000000000000000000..b0a2a3ee48118e7c18e049f6f7d14beccd9782fc
--- /dev/null
+++ b/sites/all/modules/link/views/link_views_handler_argument_target.inc
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * @file
+ * Argument handler to filter results by target.
+ */
+
+/**
+ * Argument handler to filter results by target.
+ */
+class link_views_handler_argument_target extends views_handler_argument {
+
+  /**
+   * Provide defaults for the argument when a new one is created.
+   */
+  function options(&$options) {
+    parent::options($options);
+  }
+
+  /**
+   * Provide a default options form for the argument.
+   */
+  function options_form(&$form, &$form_state) {
+    $defaults = $this->default_actions();
+
+    $form['title'] = array(
+      '#prefix' => '<div class="clear-block">',
+      '#suffix' => '</div>',
+      '#type' => 'textfield',
+      '#title' => t('Title'),
+      '#default_value' => $this->options['title'],
+      '#description' => t('The title to use when this argument is present; it will override the title of the view and titles from previous arguments. You can use percent substitution here to replace with argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
+    );
+
+    $form['clear_start'] = array(
+      '#value' => '<div class="clear-block">',
+    );
+
+    $form['defaults_start'] = array(
+      '#value' => '<div class="views-left-50">',
+    );
+
+    $form['default_action'] = array(
+      '#type' => 'radios',
+      '#title' => t('Action to take if argument is not present'),
+      '#default_value' => $this->options['default_action'],
+    );
+
+    $form['defaults_stop'] = array(
+      '#value' => '</div>',
+    );
+
+    $form['wildcard'] = array(
+      '#prefix' => '<div class="views-right-50">',
+      // prefix and no suffix means these two items will be grouped together.
+      '#type' => 'textfield',
+      '#title' => t('Wildcard'),
+      '#size' => 20,
+      '#default_value' => $this->options['wildcard'],
+      '#description' => t('If this value is received as an argument, the argument will be ignored; i.e, "all values"'),
+    );
+
+    $form['wildcard_substitution'] = array(
+      '#suffix' => '</div>',
+      '#type' => 'textfield',
+      '#title' => t('Wildcard title'),
+      '#size' => 20,
+      '#default_value' => $this->options['wildcard_substitution'],
+      '#description' => t('The title to use for the wildcard in substitutions elsewhere.'),
+    );
+
+    $form['clear_stop'] = array(
+      '#value' => '</div>',
+    );
+
+    $options = array();
+    $validate_options = array();
+    foreach ($defaults as $id => $info) {
+      $options[$id] = $info['title'];
+      if (empty($info['default only'])) {
+        $validate_options[$id] = $info['title'];
+      }
+      if (!empty($info['form method'])) {
+        $this->{$info['form method']}($form, $form_state);
+      }
+    }
+
+    $form['default_action']['#options'] = $options;
+
+    $form['validate_type'] = array(
+      '#type' => 'select',
+      '#title' => t('Validator'),
+      '#default_value' => $this->options['validate_type'],
+    );
+
+    $validate_types = array('none' => t('<Basic validation>'));
+    $plugins = views_fetch_plugin_data('argument validator');
+    foreach ($plugins as $id => $info) {
+      $valid = TRUE;
+      if (!empty($info['type'])) {
+        $valid = FALSE;
+        if (empty($this->definition['validate type'])) {
+          continue;
+        }
+        foreach ((array) $info['type'] as $type) {
+          if ($type == $this->definition['validate type']) {
+            $valid = TRUE;
+            break;
+          }
+        }
+      }
+
+      // If we decide this validator is ok, add it to the list.
+      if ($valid) {
+        $plugin = views_get_plugin('argument validator', $id);
+        if ($plugin) {
+          $plugin->init($this->view, $this, $id);
+          if ($plugin->access()) {
+            $plugin->validate_form($form, $form_state, $id);
+            $validate_types[$id] = $info['title'];
+          }
+        }
+      }
+    }
+
+    asort($validate_types);
+    $form['validate_type']['#options'] = $validate_types;
+    // Show this gadget if *anything* but 'none' is selected
+
+    $form['validate_fail'] = array(
+      '#type' => 'select',
+      '#title' => t('Action to take if argument does not validate'),
+      '#default_value' => $this->options['validate_fail'],
+      '#options' => $validate_options,
+    );
+  }
+
+  /**
+   * Set up the query for this argument.
+   *
+   * The argument sent may be found at $this->argument.
+   */
+  function query() {
+    $this->ensure_my_table();
+    // Because attributes are stored serialized, our only option is to also
+    // serialize the data we're searching for and use LIKE to find similar data.
+    $this->query->add_where(0, $this->table_alias .'.'. $this->real_field ." LIKE '%%%s%'", serialize(array('target' => $this->argument)));
+  }
+}
diff --git a/sites/all/modules/link/views/link_views_handler_filter_protocol.inc b/sites/all/modules/link/views/link_views_handler_filter_protocol.inc
new file mode 100644
index 0000000000000000000000000000000000000000..f43e345c4b2e5790b33e6cfc83fb5a92ce83cc70
--- /dev/null
+++ b/sites/all/modules/link/views/link_views_handler_filter_protocol.inc
@@ -0,0 +1,106 @@
+<?php
+
+/**
+ * @file
+ * Contains filter handlers for protocol filters with views.
+ */
+
+/**
+ * Filter handler for limiting a view to URLs of a certain protocol.
+ */
+class link_views_handler_filter_protocol extends views_handler_filter_string {
+  /**
+   * Set defaults for the filter options.
+   */
+  function options(&$options) {
+    parent::options($options);
+    $options['operator'] = 'OR';
+    $options['value'] = 'http';
+    $options['case'] = 0;
+  }
+
+  /**
+   * Define the operators supported for protocols.
+   */
+  function operators() {
+    $operators = array(
+      'OR' => array(
+        'title' => t('Is one of'),
+        'short' => t('='),
+        'method' => 'op_protocol',
+        'values' => 1,
+      ),
+    );
+
+    return $operators;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['case'] = array(
+      '#type' => 'value',
+      '#value' => 0,
+    );
+  }
+
+  /**
+   * Provide a select list to choose the desired protocols.
+   */
+  function value_form(&$form, &$form_state) {
+    // We have to make some choices when creating this as an exposed
+    // filter form. For example, if the operator is locked and thus
+    // not rendered, we can't render dependencies; instead we only
+    // render the form items we need.
+    $which = 'all';
+    if (!empty($form_state['exposed']) && empty($this->options['expose']['operator'])) {
+      $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
+    }
+
+    if ($which == 'all' || $which == 'value') {
+      $form['value'] = array(
+        '#type' => 'select',
+        '#title' => t('Protocol'),
+        '#default_value' => $this->value,
+        '#options' => drupal_map_assoc(variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'))),
+        '#multiple' => 1,
+        '#size' => 4,
+        '#description' => t('The protocols displayed here are those globally available. You may add more protocols by modifying the <em>filter_allowed_protocols</em> variable in your installation.'),
+      );
+    }
+  }
+
+  /**
+   * Filter down the query to include only the selected protocols.
+   */
+  function op_protocol($field, $upper) {
+    $db_type = db_driver();
+
+    $protocols = $this->value;
+
+    $where_conditions = array();
+    foreach ($protocols as $protocol) {
+      // Simple case, the URL begins with the specified protocol.
+      $condition = $field .' LIKE \''. $protocol .'%\'';
+
+      // More complex case, no protocol specified but is automatically cleaned up
+      // by link_cleanup_url(). RegEx is required for this search operation.
+      if ($protocol == 'http') {
+        if ($db_type == 'pgsql') {
+          // PostGreSQL code has NOT been tested. Please report any problems to the link issue queue.
+          // pgSQL requires all slashes to be double escaped in regular expressions.
+          // See http://www.postgresql.org/docs/8.1/static/functions-matching.html#FUNCTIONS-POSIX-REGEXP
+          $condition .= ' OR '. $field .' ~* \''.'^(([a-z0-9]([a-z0-9\\-_]*\\.)+)('. LINK_DOMAINS .'|[a-z][a-z]))'.'\'';
+        }
+        else {
+          // mySQL requires backslashes to be double (triple?) escaped within character classes.
+          // See http://dev.mysql.com/doc/refman/5.0/en/string-comparison-functions.html#operator_regexp
+          $condition .= ' OR '. $field .' REGEXP \''.'^(([a-z0-9]([a-z0-9\\\-_]*\.)+)('. LINK_DOMAINS .'|[a-z][a-z]))'.'\'';
+        }
+      }
+
+      $where_conditions[] = $condition;
+    }
+
+    $this->query->add_where($this->options['group'], implode(' '. $this->operator .' ', $where_conditions));
+  }
+}
diff --git a/sites/all/modules/options_element/LICENSE.txt b/sites/all/modules/options_element/LICENSE.txt
index 2c095c8d3f42488e8168f9710a4ffbfc4125a159..d159169d1050894d3ea3b98e1c965c4058208fe1 100644
--- a/sites/all/modules/options_element/LICENSE.txt
+++ b/sites/all/modules/options_element/LICENSE.txt
@@ -1,274 +1,339 @@
-GNU GENERAL PUBLIC LICENSE
-
-              Version 2, June 1991
-
-Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
-Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
-verbatim copies of this license document, but changing it is not allowed.
-
-                  Preamble
-
-The licenses for most software are designed to take away your freedom to
-share and change it. By contrast, the GNU General Public License is
-intended to guarantee your freedom to share and change free software--to
-make sure the software is free for all its users. This General Public License
-applies to most of the Free Software Foundation's software and to any other
-program whose authors commit to using it. (Some other Free Software
-Foundation software is covered by the GNU Library General Public License
-instead.) You can apply it to your programs, too.
-
-When we speak of free software, we are referring to freedom, not price. Our
-General Public Licenses are designed to make sure that you have the
-freedom to distribute copies of free software (and charge for this service if
-you wish), that you receive source code or can get it if you want it, that you
-can change the software or use pieces of it in new free programs; and that
-you know you can do these things.
-
-To protect your rights, we need to make restrictions that forbid anyone to
-deny you these rights or to ask you to surrender the rights. These restrictions
-translate to certain responsibilities for you if you distribute copies of the
-software, or if you modify it.
-
-For example, if you distribute copies of such a program, whether gratis or for
-a fee, you must give the recipients all the rights that you have. You must make
-sure that they, too, receive or can get the source code. And you must show
-them these terms so they know their rights.
-
-We protect your rights with two steps: (1) copyright the software, and (2)
-offer you this license which gives you legal permission to copy, distribute
-and/or modify the software.
-
-Also, for each author's protection and ours, we want to make certain that
-everyone understands that there is no warranty for this free software. If the
-software is modified by someone else and passed on, we want its recipients
-to know that what they have is not the original, so that any problems
-introduced by others will not reflect on the original authors' reputations.
-
-Finally, any free program is threatened constantly by software patents. We
-wish to avoid the danger that redistributors of a free program will individually
-obtain patent licenses, in effect making the program proprietary. To prevent
-this, we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
-The precise terms and conditions for copying, distribution and modification
-follow.
-
-           GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
-               MODIFICATION
-
-0. This License applies to any program or other work which contains a notice
-placed by the copyright holder saying it may be distributed under the terms
-of this General Public License. The "Program", below, refers to any such
-program or work, and a "work based on the Program" means either the
-Program or any derivative work under copyright law: that is to say, a work
-containing the Program or a portion of it, either verbatim or with
-modifications and/or translated into another language. (Hereinafter, translation
-is included without limitation in the term "modification".) Each licensee is
-addressed as "you".
-
-Activities other than copying, distribution and modification are not covered
-by this License; they are outside its scope. The act of running the Program is
-not restricted, and the output from the Program is covered only if its contents
-constitute a work based on the Program (independent of having been made
-by running the Program). Whether that is true depends on what the Program
-does.
-
-1. You may copy and distribute verbatim copies of the Program's source
-code as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice and
-disclaimer of warranty; keep intact all the notices that refer to this License
-and to the absence of any warranty; and give any other recipients of the
-Program a copy of this License along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and you
-may at your option offer warranty protection in exchange for a fee.
-
-2. You may modify your copy or copies of the Program or any portion of it,
-thus forming a work based on the Program, and copy and distribute such
-modifications or work under the terms of Section 1 above, provided that you
-also meet all of these conditions:
-
-a) You must cause the modified files to carry prominent notices stating that
-you changed the files and the date of any change.
-
-b) You must cause any work that you distribute or publish, that in whole or in
-part contains or is derived from the Program or any part thereof, to be
-licensed as a whole at no charge to all third parties under the terms of this
-License.
-
-c) If the modified program normally reads commands interactively when run,
-you must cause it, when started running for such interactive use in the most
-ordinary way, to print or display an announcement including an appropriate
-copyright notice and a notice that there is no warranty (or else, saying that
-you provide a warranty) and that users may redistribute the program under
-these conditions, and telling the user how to view a copy of this License.
-(Exception: if the Program itself is interactive but does not normally print such
-an announcement, your work based on the Program is not required to print
-an announcement.)
-
-These requirements apply to the modified work as a whole. If identifiable
-sections of that work are not derived from the Program, and can be
-reasonably considered independent and separate works in themselves, then
-this License, and its terms, do not apply to those sections when you distribute
-them as separate works. But when you distribute the same sections as part
-of a whole which is a work based on the Program, the distribution of the
-whole must be on the terms of this License, whose permissions for other
-licensees extend to the entire whole, and thus to each and every part
-regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest your rights to
-work written entirely by you; rather, the intent is to exercise the right to
-control the distribution of derivative or collective works based on the
-Program.
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
 
 In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of a
-storage or distribution medium does not bring the other work under the scope
-of this License.
-
-3. You may copy and distribute the Program (or a work based on it, under
-Section 2) in object code or executable form under the terms of Sections 1
-and 2 above provided that you also do one of the following:
-
-a) Accompany it with the complete corresponding machine-readable source
-code, which must be distributed under the terms of Sections 1 and 2 above
-on a medium customarily used for software interchange; or,
-
-b) Accompany it with a written offer, valid for at least three years, to give
-any third party, for a charge no more than your cost of physically performing
-source distribution, a complete machine-readable copy of the corresponding
-source code, to be distributed under the terms of Sections 1 and 2 above on
-a medium customarily used for software interchange; or,
-
-c) Accompany it with the information you received as to the offer to distribute
-corresponding source code. (This alternative is allowed only for
-noncommercial distribution and only if you received the program in object
-code or executable form with such an offer, in accord with Subsection b
-above.)
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
 
 The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source code
-means all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation and
-installation of the executable. However, as a special exception, the source
-code distributed need not include anything that is normally distributed (in
-either source or binary form) with the major components (compiler, kernel,
-and so on) of the operating system on which the executable runs, unless that
-component itself accompanies the executable.
-
-If distribution of executable or object code is made by offering access to
-copy from a designated place, then offering equivalent access to copy the
-source code from the same place counts as distribution of the source code,
-even though third parties are not compelled to copy the source along with the
-object code.
-
-4. You may not copy, modify, sublicense, or distribute the Program except as
-expressly provided under this License. Any attempt otherwise to copy,
-modify, sublicense or distribute the Program is void, and will automatically
-terminate your rights under this License. However, parties who have received
-copies, or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-5. You are not required to accept this License, since you have not signed it.
-However, nothing else grants you permission to modify or distribute the
-Program or its derivative works. These actions are prohibited by law if you
-do not accept this License. Therefore, by modifying or distributing the
-Program (or any work based on the Program), you indicate your acceptance
-of this License to do so, and all its terms and conditions for copying,
-distributing or modifying the Program or works based on it.
-
-6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the original
-licensor to copy, distribute or modify the Program subject to these terms and
-conditions. You may not impose any further restrictions on the recipients'
-exercise of the rights granted herein. You are not responsible for enforcing
-compliance by third parties to this License.
-
-7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues), conditions
-are imposed on you (whether by court order, agreement or otherwise) that
-contradict the conditions of this License, they do not excuse you from the
-conditions of this License. If you cannot distribute so as to satisfy
-simultaneously your obligations under this License and any other pertinent
-obligations, then as a consequence you may not distribute the Program at all.
-For example, if a patent license would not permit royalty-free redistribution
-of the Program by all those who receive copies directly or indirectly through
-you, then the only way you could satisfy both it and this License would be to
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
 refrain entirely from distribution of the Program.
 
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply and
-the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any patents or
-other property right claims or to contest validity of any such claims; this
-section has the sole purpose of protecting the integrity of the free software
-distribution system, which is implemented by public license practices. Many
-people have made generous contributions to the wide range of software
-distributed through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing to
-distribute software through any other system and a licensee cannot impose
-that choice.
-
-This section is intended to make thoroughly clear what is believed to be a
-consequence of the rest of this License.
-
-8. If the distribution and/or use of the Program is restricted in certain
-countries either by patents or by copyrighted interfaces, the original copyright
-holder who places the Program under this License may add an explicit
-geographical distribution limitation excluding those countries, so that
-distribution is permitted only in or among countries not thus excluded. In such
-case, this License incorporates the limitation as if written in the body of this
-License.
-
-9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will be
-similar in spirit to the present version, but may differ in detail to address new
-problems or concerns.
-
-Each version is given a distinguishing version number. If the Program specifies
-a version number of this License which applies to it and "any later version",
-you have the option of following the terms and conditions either of that
-version or of any later version published by the Free Software Foundation. If
-the Program does not specify a version number of this License, you may
-choose any version ever published by the Free Software Foundation.
-
-10. If you wish to incorporate parts of the Program into other free programs
-whose distribution conditions are different, write to the author to ask for
-permission. For software which is copyrighted by the Free Software
-Foundation, write to the Free Software Foundation; we sometimes make
-exceptions for this. Our decision will be guided by the two goals of
-preserving the free status of all derivatives of our free software and of
-promoting the sharing and reuse of software generally.
-
-               NO WARRANTY
-
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
-PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
-STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
-PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
-NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
-AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
-ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
-SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OR INABILITY TO USE THE
-PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
-OR DATA BEING RENDERED INACCURATE OR LOSSES
-SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
-PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
-IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGES.
-
-          END OF TERMS AND CONDITIONS
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/sites/all/modules/options_element/options_element.css b/sites/all/modules/options_element/options_element.css
index d3654f97c5edce1223fe299e6439ab76e2b97b73..2ff1bac2cd6030ea6bea9721cfc599c054f2dab6 100644
--- a/sites/all/modules/options_element/options_element.css
+++ b/sites/all/modules/options_element/options_element.css
@@ -1,4 +1,3 @@
-/* $Id: options_element.css,v 1.6 2010/03/24 23:53:14 quicksketch Exp $ */
 
 div.options-widget .draggable a.tabledrag-handle {
   padding-right: .3em /* RTL */
@@ -40,6 +39,10 @@ div.options-widget a.remove {
   background-image: url(delete.png);
 }
 
+div.default-value-pattern-match {
+  float: left; /* RTL */
+}
+
 div.form-options-manual,
 div.form-option-add {
   text-align: right; /* RTL */
diff --git a/sites/all/modules/options_element/options_element.inc b/sites/all/modules/options_element/options_element.inc
index eda288ad29c989a26b077f8f095d63012a4d3f38..d6a90cc2e0c290ab96162a74c26edfacb2d03930 100644
--- a/sites/all/modules/options_element/options_element.inc
+++ b/sites/all/modules/options_element/options_element.inc
@@ -1,5 +1,4 @@
 <?php
-// $Id: options_element.inc,v 1.12 2011/01/12 07:25:13 quicksketch Exp $
 
 /**
  * @file
@@ -38,6 +37,9 @@ function theme_options($variables) {
   if (isset($element['default_value_field'])) {
     $options .= drupal_render($element['default_value_field']);
   }
+  if (isset($element['default_value_pattern'])) {
+    $options .= drupal_render($element['default_value_pattern']);
+  }
 
   $settings = '';
   if (isset($element['custom_keys'])) {
@@ -157,11 +159,12 @@ function _form_options_expand($element) {
   }
 
   // Add the field for storing default values.
-  if ($element['#default_value'] !== FALSE && !isset($element['default_value_field'])) {
+  if ($element['#default_value_allowed'] && !isset($element['default_value_field'])) {
     $element['default_value_field'] = array(
       '#title' => t('Default value'),
       '#type' => 'textfield',
       '#size' => 60,
+      '#maxlength' => 1024,
       '#value' => isset($element['#default_value']) ? ($element['#multiple'] ? implode(', ', (array) $element['#default_value']) : $element['#default_value']) : '',
       '#description' => t('Specify the keys that should be selected by default.'),
     );
@@ -170,6 +173,15 @@ function _form_options_expand($element) {
     }
   }
 
+  // Add the field for storing a default value pattern.
+  if ($element['#default_value_pattern']) {
+    $element['default_value_pattern'] = array(
+      '#type' => 'hidden',
+      '#value' => $element['#default_value_pattern'],
+      '#attributes' => array('class' => array('default-value-pattern')),
+    );
+  }
+
   // Remove properties that will confuse the FAPI.
   unset($element['#options']);
   $element['#required'] = FALSE;
@@ -264,22 +276,31 @@ function _form_type_options_value(&$element, $edit = FALSE) {
         $default_items = explode(',', $edit['default_value_field']);
         foreach ($default_items as $key) {
           $key = trim($key);
-          if ($value = _form_options_search($key, $options)) {
+          $value = _form_options_search($key, $options, $element['#default_value_pattern']);
+          if (!is_null($value)) {
             $default_value[] = $value;
           }
         }
       }
       else {
-        $default_value = _form_options_search(trim($edit['default_value_field']), $options);
+        $default_value = _form_options_search(trim($edit['default_value_field']), $options, $element['#default_value_pattern']);
       }
     }
+    else {
+      $default_value = NULL;
+    }
 
-    return array(
+    $return = array(
       'options' => $options,
       'default_value' => $default_value,
       'options_text' => $edit['options_field'],
-      'default_value_text' => $edit['default_value_field'],
     );
+
+    if (isset($edit['default_value_field'])) {
+      $return['default_value_text'] = $edit['default_value_field'];
+    }
+
+    return $return;
   }
 }
 
@@ -374,7 +395,13 @@ function _form_options_from_text($text, $key_type, $flat = FALSE, &$duplicates =
 
   // Expand the list into a nested array, assign keys and check duplicates.
   $options = array();
-  $new_key = 0;
+  $new_key = 1;
+  foreach ($items as $item) {
+    $int_key = $item['key'] * 1;
+    if (is_int($int_key)) {
+      $new_key = max($int_key, $new_key);
+    }
+  }
   foreach ($items as $item) {
     // Assign a key if needed.
     if ($key_type == 'none') {
@@ -408,15 +435,18 @@ function _form_options_from_text($text, $key_type, $flat = FALSE, &$duplicates =
 /**
  * Recursive function for finding default value keys. Matches on keys or values.
  */
-function _form_options_search($needle, $haystack) {
+function _form_options_search($needle, $haystack, $include_pattern) {
   if (isset($haystack[$needle])) {
     return $needle;
   }
+  elseif ($include_pattern && preg_match('/' . $include_pattern . '/', $needle)) {
+    return $needle;
+  }
   foreach ($haystack as $key => $value) {
-    if (is_array($value) && ($return = _form_options_search($needle, $value))) {
-      return $return;
+    if (is_array($value)) {
+      return _form_options_search($needle, $value, $include_pattern);
     }
-    if ($value == $needle) {
+    elseif ($value == $needle) {
       return $key;
     }
   }
diff --git a/sites/all/modules/options_element/options_element.info b/sites/all/modules/options_element/options_element.info
index 1b03698a5be3f3a0bfbccf391e476e28dc98f742..d370e45105f5455b32b48763475e679a138cea55 100644
--- a/sites/all/modules/options_element/options_element.info
+++ b/sites/all/modules/options_element/options_element.info
@@ -1,11 +1,10 @@
-; $Id: options_element.info,v 1.3 2011/01/05 02:25:47 quicksketch Exp $
 name = Options element
 description = A custom form element for entering the options in select lists, radios, or checkboxes.
 core = 7.x
 
-; Information added by drupal.org packaging script on 2011-01-12
-version = "7.x-1.4"
+; Information added by drupal.org packaging script on 2012-03-17
+version = "7.x-1.7"
 core = "7.x"
 project = "options_element"
-datestamp = "1294818406"
+datestamp = "1332018945"
 
diff --git a/sites/all/modules/options_element/options_element.js b/sites/all/modules/options_element/options_element.js
index db771d387ae0b8b4abc0210d318df126332d7864..0d71ae7fc76ea453e2cc77e560369cae7146195b 100644
--- a/sites/all/modules/options_element/options_element.js
+++ b/sites/all/modules/options_element/options_element.js
@@ -1,4 +1,3 @@
-// $Id: options_element.js,v 1.13 2011/01/12 07:22:01 quicksketch Exp $
 
 /**
  * @file
@@ -39,6 +38,11 @@ Drupal.optionsElement = function(element) {
   this.customKeys = Boolean(element.className.match(/options-key-custom/));
   this.identifier = this.manualOptionsElement.id + '-widget';
   this.enabled = $(this.manualOptionsElement).attr('readonly') == '';
+  this.defaultValuePattern = $(element).find('input.default-value-pattern').val();
+
+  if (this.defaultValuePattern) {
+    this.defaultValuePattern = new RegExp(this.defaultValuePattern);
+  }
 
   // Warning messages.
   this.keyChangeWarning = Drupal.t('Custom keys have been specified in this list. Removing these custom keys may change way data is stored. Are you sure you wish to remove these custom keys?');
@@ -53,7 +57,8 @@ Drupal.optionsElement = function(element) {
 
   // Enable add item link.
   $(this.optionAddElement).find('a').click(function() {
-    self.addOption($('table tr:last', self.optionsElement).get(0));
+    var newOption = self.addOption($('table tr:last', self.optionsElement).get(0));
+    $(newOption).find('input[type=text]:visible:first').focus();
     return false;
   });
 
@@ -161,7 +166,7 @@ Drupal.optionsElement.prototype.updateWidgetElements = function() {
   // Enable button for adding options.
   $('a.add', this.optionsElement).click(function() {
     var newOption = self.addOption($(this).parents('tr:first').get(0));
-    $(newOption).find('a.add').focus();
+    $(newOption).find('input[type=text]:visible:first').focus();
     return false;
   });
 
@@ -253,8 +258,14 @@ Drupal.optionsElement.prototype.updateManualElements = function() {
 
   // Update with the new text and trigger the change action on the field.
   this.optionsToText();
+
   if (this.manualDefaultValueElement) {
-    this.manualDefaultValueElement.value = multiple ? defaultValue.join(', ') : defaultValue;
+    // Don't wipe out custom pattern-matched default values.
+    defaultValue = multiple ? defaultValue.join(', ') : defaultValue;
+    if (defaultValue || !(this.defaultValuePattern && this.defaultValuePattern.test(this.manualDefaultValueElement.value))) {
+      this.manualDefaultValueElement.value = defaultValue;
+      $('.default-value-pattern-match', this.element).remove();
+    }
   }
 
   $(this.manualOptionsElement).change();
@@ -354,7 +365,7 @@ Drupal.optionsElement.prototype.addOption = function(currentOption) {
   // Enable button for adding options.
   $('a.add', newOption).click(function() {
     var newOption = self.addOption($(this).parents('tr:first').get(0));
-    $(newOption).find('a.add').focus();
+    $(newOption).find('input[type=text]:visible:first').focus();
     return false;
   });
 
@@ -702,15 +713,15 @@ Drupal.theme.prototype.optionsElement = function(optionsElement) {
     for (var n = 0; n < indent; n++) {
       output += Drupal.theme('tableDragIndentation');
     }
-    output += '<input type="hidden" class="option-parent" value="' + parent + '" />';
+    output += '<input type="hidden" class="option-parent" value="' + parent.replace(/"/g, '&quot;') + '" />';
     output += '<input type="hidden" class="option-depth" value="' + indent + '" />';
     if (hasDefault) {
-      output += '<input type="' + defaultType + '" name="' + optionsElement.identifier + '-default" class="form-radio option-default" value="' + key + '"' + (status == 'checked' ? ' checked="checked"' : '') + (status == 'disabled' ? ' disabled="disabled"' : '') + ' />';
+      output += '<input type="' + defaultType + '" name="' + optionsElement.identifier + '-default" class="form-radio option-default" value="' + key.replace(/"/g, '&quot;') + '"' + (status == 'checked' ? ' checked="checked"' : '') + (status == 'disabled' ? ' disabled="disabled"' : '') + ' />';
     }
     output += '</td><td class="' + (keyType == 'textfield' ? 'option-key-cell' : 'option-value-cell') +'">';
-    output += '<input type="' + keyType + '" class="' + (keyType == 'textfield' ? 'form-text ' : '') + 'option-key" value="' + key + '" />';
+    output += '<input type="' + keyType + '" class="' + (keyType == 'textfield' ? 'form-text ' : '') + 'option-key" value="' + key.replace(/"/g, '&quot;') + '" />';
     output += keyType == 'textfield' ? '</td><td class="option-value-cell">' : '';
-    output += '<input class="form-text option-value" type="text" value="' + value + '" />';
+    output += '<input class="form-text option-value" type="text" value="' + value.replace(/"/g, '&quot;') + '" />';
     output += '</td><td class="option-actions-cell">'
     output += '<a class="add" title="' + Drupal.t('Add new option') + '" href="#"' + (status == 'disabled' ? ' style="display: none"' : '') + '><span class="add">' + Drupal.t('Add') + '</span></a>';
     output += '<a class="remove" title="' + Drupal.t('Remove option') + '" href="#"' + (status == 'disabled' ? ' style="display: none"' : '') + '><span class="remove">' + Drupal.t('Remove') + '</span></a>';
@@ -754,11 +765,20 @@ Drupal.theme.prototype.optionsElement = function(optionsElement) {
 
   output += '</tbody>';
   output += '</table>';
-  output += '<div>';
+
+  if (optionsElement.defaultValuePattern && optionsElement.manualDefaultValueElement && optionsElement.defaultValuePattern.test(optionsElement.manualDefaultValueElement.value)) {
+    output += Drupal.theme('optionsElementPatternMatch', optionsElement.manualDefaultValueElement.value);
+  }
+
+  output += '</div>';
 
   return output;
 };
 
+Drupal.theme.prototype.optionsElementPatternMatch = function(matchedValue) {
+  return '<div class="default-value-pattern-match"><span>' + Drupal.t('Manual default value') + '</span>: ' + matchedValue + '</div>';
+};
+
 Drupal.theme.prototype.optionsElementAdd = function() {
   return '<div class="form-option-add"><a href="#">' + Drupal.t('Add item') + '</a></div>';
 };
diff --git a/sites/all/modules/options_element/options_element.module b/sites/all/modules/options_element/options_element.module
index cee8a84f1aa911128d39c0933634bcc8aac793c3..db007de545e2d5b186770925a770bb8bd0730cf7 100644
--- a/sites/all/modules/options_element/options_element.module
+++ b/sites/all/modules/options_element/options_element.module
@@ -1,5 +1,4 @@
 <?php
-// $Id: options_element.module,v 1.7 2010/09/05 02:17:22 quicksketch Exp $
 
 /**
  * @file
@@ -65,6 +64,12 @@
  *   the "none" key type.
  * - key_type_toggled: Determine if the toggle checkbox is set or not by
  *   default.
+ * - default_value_allowed: Indicates whether the end user should be able to
+ *   modify the default value when editing the options list. Defaults to TRUE.
+ * - default_value_pattern: If allowing dynamic default value keys, such as a
+ *   token, specify a regular expression pattern that will also be allowed as
+ *   a default value. Include pattern delimiters. Defaults to an empty string.
+ *
  *   @code
  *   $element['options'] = array(
  *     '#type' => 'options',
@@ -87,6 +92,8 @@ function options_element_element_info() {
     '#key_type' => 'mixed',
     '#key_type_toggle' => NULL,
     '#key_type_toggled' => FALSE,
+    '#default_value_allowed' => TRUE,
+    '#default_value_pattern' => '',
     '#element_validate' => array('form_options_validate'),
     '#disabled' => FALSE,
   );
diff --git a/sites/all/modules/options_element/translations/ru.po b/sites/all/modules/options_element/translations/ru.po
deleted file mode 100644
index c3116ea6cb8b7c9cc880c7d956fe985d1deebeb0..0000000000000000000000000000000000000000
--- a/sites/all/modules/options_element/translations/ru.po
+++ /dev/null
@@ -1,146 +0,0 @@
-# $Id$
-#
-# LANGUAGE translation of Drupal (general)
-# Copyright YEAR NAME <EMAIL@ADDRESS>
-# Generated from files:
-#  options_element.inc,v 1.6 2010/03/29 03:22:11 quicksketch
-#  options_element.info,v 1.2 2010/03/24 23:53:14 quicksketch
-#  options_element.js,v 1.8 2010/03/29 03:22:11 quicksketch
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: rus-drupal.ru\n"
-"POT-Creation-Date: 2010-03-31 03:04+0400\n"
-"PO-Revision-Date: 2010-03-31 03:32+0300\n"
-"Last-Translator: Andrey Mikheychik <andrey@armaturich.ru>\n"
-"Language-Team: Rus-Drupal <mail@rus-drupal.ru>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"X-Poedit-Language: Russian\n"
-"X-Poedit-Country: Russia\n"
-
-#: options_element.inc:56
-msgid "Options"
-msgstr "Варианты выбора"
-
-#: options_element.inc:64
-msgid "Option settings"
-msgstr "Настройки варианта выбора"
-
-#: options_element.inc:99
-msgid "Customize keys"
-msgstr "Модифицировать ключи"
-
-#: options_element.inc:103
-msgid "Customizing the keys will allow you to save one value internally while showing a different option to the user."
-msgstr "Модификация ключей позволит сохранить одно значение внутренним, показывая другое значение пользователю."
-
-#: options_element.inc:110
-msgid "Allow multiple values"
-msgstr "Позволить различные значения"
-
-#: options_element.inc:114
-msgid "Multiple values will let users select multiple items in this list."
-msgstr "Различные значения позволят пользователям выбирать несколько пунктов из списка."
-
-#: options_element.inc:126
-msgid "List options one option per line."
-msgstr "Перечислите варианты выбора по одному варианту в строке."
-
-#: options_element.inc:141
-msgid "Key-value pairs may be specified by separating each option with pipes, such as <em>key|value</em>."
-msgstr "Пары ключ-значение могут быть определены разделением каждого пункта вертикальной чертой, например, <em>key|value</em>."
-
-#: options_element.inc:144
-msgid "If the %toggle field is checked, key-value pairs may be specified by separating each option with pipes, such as <em>key|value</em>."
-msgstr "Если поле %toggle отмечено, то пары ключ-значение могут быть определены разделением каждого пункта с помощью вертикальной черты, например <em>key|value</em>."
-
-#: options_element.inc:147
-msgid "This field requires all specified keys to be integers."
-msgstr "Это поле требует, чтобы все ключи были целочисленными."
-
-#: options_element.inc:154
-msgid "Default value"
-msgstr "Значение по умолчанию"
-
-#: options_element.inc:158
-msgid "Specify the keys that should be selected by default."
-msgstr "Определяет ключ, который должен быть выбран по умолчанию."
-
-#: options_element.inc:161
-msgid "Multiple default values may be specified by separating keys with commas."
-msgstr "Различные значения могут быть определены, указав ключи через запятую."
-
-#: options_element.inc:184
-msgid "The key %key has been used multiple times. Each key must be unique to display properly."
-msgstr "Ключ %key использован несколько раз. Каждый ключ должен быть уникальным, чтобы отображаться правильно."
-
-#: options_element.inc:189
-msgid "The following keys have been used multiple times. Each key must be unique to display properly."
-msgstr "Эти ключи использованы несколько раз. Каждый ключ должен быть уникальным для корректного отображения."
-
-#: options_element.inc:199
-msgid "At least one option must be specified."
-msgstr "Как минимум один вариант выбора должен быть определён."
-
-#: options_element.inc:206
-msgid "The keys for the %title field must be integers."
-msgstr "Ключи для поля %title должны быть целочисленными."
-
-#: options_element.inc:224
-msgid "The %title field supports a maximum of @count options. Please reduce the number of options."
-msgstr "Поле %title поддерживает максимум @count вариантов выбора. Пожалуйста, уменьшите количество вариантов."
-
-#: options_element.info:0
-msgid "Options element"
-msgstr "Элемент вариантов выбора"
-
-#: options_element.info:0
-msgid "A custom form element for entering the options in select lists, radios, or checkboxes."
-msgstr "Специальный элемент формы для ввода вариантов выбор в выпадающих списках, кнопках-переключателях или флаговой кнопки."
-
-#: options_element.js:0
-msgid "Custom keys have been specified in this list. Removing these custom keys may change way data is stored. Are you sure you wish to remove these custom keys?"
-msgstr "Отдельные ключи определяются в этом списке. Удаление этих отдельных ключей может изменить то, как хранятся данные. Вы уверены, что хотите удалить эти ключи?"
-
-#: options_element.js:0
-msgid "Normal entry"
-msgstr "Обычный ввод"
-
-#: options_element.js:0;0
-msgid "Manual entry"
-msgstr "Ввод вручную"
-
-#: options_element.js:0
-msgid "Add new option"
-msgstr "Добавить новый вариант выбора"
-
-#: options_element.js:0
-msgid "Add"
-msgstr "Добавить"
-
-#: options_element.js:0
-msgid "Remove option"
-msgstr "Удалить вариант выбора"
-
-#: options_element.js:0
-msgid "Remove"
-msgstr "Удалить"
-
-#: options_element.js:0
-msgid "Default"
-msgstr "По умолчанию"
-
-#: options_element.js:0
-msgid "Key"
-msgstr "Ключ"
-
-#: options_element.js:0
-msgid "Value"
-msgstr "Значение"
-
-#: options_element.js:0
-msgid "Add item"
-msgstr "Добавить пункт"
-
diff --git a/sites/all/modules/ux_elements/LICENSE.txt b/sites/all/modules/ux_elements/LICENSE.txt
deleted file mode 100644
index 2c095c8d3f42488e8168f9710a4ffbfc4125a159..0000000000000000000000000000000000000000
--- a/sites/all/modules/ux_elements/LICENSE.txt
+++ /dev/null
@@ -1,274 +0,0 @@
-GNU GENERAL PUBLIC LICENSE
-
-              Version 2, June 1991
-
-Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
-Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
-verbatim copies of this license document, but changing it is not allowed.
-
-                  Preamble
-
-The licenses for most software are designed to take away your freedom to
-share and change it. By contrast, the GNU General Public License is
-intended to guarantee your freedom to share and change free software--to
-make sure the software is free for all its users. This General Public License
-applies to most of the Free Software Foundation's software and to any other
-program whose authors commit to using it. (Some other Free Software
-Foundation software is covered by the GNU Library General Public License
-instead.) You can apply it to your programs, too.
-
-When we speak of free software, we are referring to freedom, not price. Our
-General Public Licenses are designed to make sure that you have the
-freedom to distribute copies of free software (and charge for this service if
-you wish), that you receive source code or can get it if you want it, that you
-can change the software or use pieces of it in new free programs; and that
-you know you can do these things.
-
-To protect your rights, we need to make restrictions that forbid anyone to
-deny you these rights or to ask you to surrender the rights. These restrictions
-translate to certain responsibilities for you if you distribute copies of the
-software, or if you modify it.
-
-For example, if you distribute copies of such a program, whether gratis or for
-a fee, you must give the recipients all the rights that you have. You must make
-sure that they, too, receive or can get the source code. And you must show
-them these terms so they know their rights.
-
-We protect your rights with two steps: (1) copyright the software, and (2)
-offer you this license which gives you legal permission to copy, distribute
-and/or modify the software.
-
-Also, for each author's protection and ours, we want to make certain that
-everyone understands that there is no warranty for this free software. If the
-software is modified by someone else and passed on, we want its recipients
-to know that what they have is not the original, so that any problems
-introduced by others will not reflect on the original authors' reputations.
-
-Finally, any free program is threatened constantly by software patents. We
-wish to avoid the danger that redistributors of a free program will individually
-obtain patent licenses, in effect making the program proprietary. To prevent
-this, we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
-The precise terms and conditions for copying, distribution and modification
-follow.
-
-           GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
-               MODIFICATION
-
-0. This License applies to any program or other work which contains a notice
-placed by the copyright holder saying it may be distributed under the terms
-of this General Public License. The "Program", below, refers to any such
-program or work, and a "work based on the Program" means either the
-Program or any derivative work under copyright law: that is to say, a work
-containing the Program or a portion of it, either verbatim or with
-modifications and/or translated into another language. (Hereinafter, translation
-is included without limitation in the term "modification".) Each licensee is
-addressed as "you".
-
-Activities other than copying, distribution and modification are not covered
-by this License; they are outside its scope. The act of running the Program is
-not restricted, and the output from the Program is covered only if its contents
-constitute a work based on the Program (independent of having been made
-by running the Program). Whether that is true depends on what the Program
-does.
-
-1. You may copy and distribute verbatim copies of the Program's source
-code as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice and
-disclaimer of warranty; keep intact all the notices that refer to this License
-and to the absence of any warranty; and give any other recipients of the
-Program a copy of this License along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and you
-may at your option offer warranty protection in exchange for a fee.
-
-2. You may modify your copy or copies of the Program or any portion of it,
-thus forming a work based on the Program, and copy and distribute such
-modifications or work under the terms of Section 1 above, provided that you
-also meet all of these conditions:
-
-a) You must cause the modified files to carry prominent notices stating that
-you changed the files and the date of any change.
-
-b) You must cause any work that you distribute or publish, that in whole or in
-part contains or is derived from the Program or any part thereof, to be
-licensed as a whole at no charge to all third parties under the terms of this
-License.
-
-c) If the modified program normally reads commands interactively when run,
-you must cause it, when started running for such interactive use in the most
-ordinary way, to print or display an announcement including an appropriate
-copyright notice and a notice that there is no warranty (or else, saying that
-you provide a warranty) and that users may redistribute the program under
-these conditions, and telling the user how to view a copy of this License.
-(Exception: if the Program itself is interactive but does not normally print such
-an announcement, your work based on the Program is not required to print
-an announcement.)
-
-These requirements apply to the modified work as a whole. If identifiable
-sections of that work are not derived from the Program, and can be
-reasonably considered independent and separate works in themselves, then
-this License, and its terms, do not apply to those sections when you distribute
-them as separate works. But when you distribute the same sections as part
-of a whole which is a work based on the Program, the distribution of the
-whole must be on the terms of this License, whose permissions for other
-licensees extend to the entire whole, and thus to each and every part
-regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest your rights to
-work written entirely by you; rather, the intent is to exercise the right to
-control the distribution of derivative or collective works based on the
-Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of a
-storage or distribution medium does not bring the other work under the scope
-of this License.
-
-3. You may copy and distribute the Program (or a work based on it, under
-Section 2) in object code or executable form under the terms of Sections 1
-and 2 above provided that you also do one of the following:
-
-a) Accompany it with the complete corresponding machine-readable source
-code, which must be distributed under the terms of Sections 1 and 2 above
-on a medium customarily used for software interchange; or,
-
-b) Accompany it with a written offer, valid for at least three years, to give
-any third party, for a charge no more than your cost of physically performing
-source distribution, a complete machine-readable copy of the corresponding
-source code, to be distributed under the terms of Sections 1 and 2 above on
-a medium customarily used for software interchange; or,
-
-c) Accompany it with the information you received as to the offer to distribute
-corresponding source code. (This alternative is allowed only for
-noncommercial distribution and only if you received the program in object
-code or executable form with such an offer, in accord with Subsection b
-above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source code
-means all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation and
-installation of the executable. However, as a special exception, the source
-code distributed need not include anything that is normally distributed (in
-either source or binary form) with the major components (compiler, kernel,
-and so on) of the operating system on which the executable runs, unless that
-component itself accompanies the executable.
-
-If distribution of executable or object code is made by offering access to
-copy from a designated place, then offering equivalent access to copy the
-source code from the same place counts as distribution of the source code,
-even though third parties are not compelled to copy the source along with the
-object code.
-
-4. You may not copy, modify, sublicense, or distribute the Program except as
-expressly provided under this License. Any attempt otherwise to copy,
-modify, sublicense or distribute the Program is void, and will automatically
-terminate your rights under this License. However, parties who have received
-copies, or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-5. You are not required to accept this License, since you have not signed it.
-However, nothing else grants you permission to modify or distribute the
-Program or its derivative works. These actions are prohibited by law if you
-do not accept this License. Therefore, by modifying or distributing the
-Program (or any work based on the Program), you indicate your acceptance
-of this License to do so, and all its terms and conditions for copying,
-distributing or modifying the Program or works based on it.
-
-6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the original
-licensor to copy, distribute or modify the Program subject to these terms and
-conditions. You may not impose any further restrictions on the recipients'
-exercise of the rights granted herein. You are not responsible for enforcing
-compliance by third parties to this License.
-
-7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues), conditions
-are imposed on you (whether by court order, agreement or otherwise) that
-contradict the conditions of this License, they do not excuse you from the
-conditions of this License. If you cannot distribute so as to satisfy
-simultaneously your obligations under this License and any other pertinent
-obligations, then as a consequence you may not distribute the Program at all.
-For example, if a patent license would not permit royalty-free redistribution
-of the Program by all those who receive copies directly or indirectly through
-you, then the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply and
-the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any patents or
-other property right claims or to contest validity of any such claims; this
-section has the sole purpose of protecting the integrity of the free software
-distribution system, which is implemented by public license practices. Many
-people have made generous contributions to the wide range of software
-distributed through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing to
-distribute software through any other system and a licensee cannot impose
-that choice.
-
-This section is intended to make thoroughly clear what is believed to be a
-consequence of the rest of this License.
-
-8. If the distribution and/or use of the Program is restricted in certain
-countries either by patents or by copyrighted interfaces, the original copyright
-holder who places the Program under this License may add an explicit
-geographical distribution limitation excluding those countries, so that
-distribution is permitted only in or among countries not thus excluded. In such
-case, this License incorporates the limitation as if written in the body of this
-License.
-
-9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will be
-similar in spirit to the present version, but may differ in detail to address new
-problems or concerns.
-
-Each version is given a distinguishing version number. If the Program specifies
-a version number of this License which applies to it and "any later version",
-you have the option of following the terms and conditions either of that
-version or of any later version published by the Free Software Foundation. If
-the Program does not specify a version number of this License, you may
-choose any version ever published by the Free Software Foundation.
-
-10. If you wish to incorporate parts of the Program into other free programs
-whose distribution conditions are different, write to the author to ask for
-permission. For software which is copyrighted by the Free Software
-Foundation, write to the Free Software Foundation; we sometimes make
-exceptions for this. Our decision will be guided by the two goals of
-preserving the free status of all derivatives of our free software and of
-promoting the sharing and reuse of software generally.
-
-               NO WARRANTY
-
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
-PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
-STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
-PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
-NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
-AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
-ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
-SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OR INABILITY TO USE THE
-PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
-OR DATA BEING RENDERED INACCURATE OR LOSSES
-SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
-PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
-IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGES.
-
-          END OF TERMS AND CONDITIONS
diff --git a/sites/all/modules/ux_elements/css/horizontal_tab.css b/sites/all/modules/ux_elements/css/horizontal_tab.css
deleted file mode 100644
index 47b1bcb99334b721e7640d48dc4e44b58f76dbf4..0000000000000000000000000000000000000000
--- a/sites/all/modules/ux_elements/css/horizontal_tab.css
+++ /dev/null
@@ -1,54 +0,0 @@
-/* $Id: horizontal_tab.css,v 1.1 2010/12/21 15:19:26 jameselliott Exp $ */
-
-.horizontal-tabs-processed .horizontal-tabs-pane {
-  clear: both;
-  margin-top: 0;
-  padding: 0;
-}
-
-.horizontal-tabs-processed .horizontal-tabs-pane > legend {
-  display: none;
-}
-
-.horizontal-tabs .horizontal-tabs-list {
-  margin: 0;
-}
-
-.horizontal-tab-button {
-  list-style: none;
-}
-
-.horizontal-tab-button {
-  float: left; /* LTR */
-  margin-right: 4px; /* LTR */
-  position: relative;
-  top: 1px;
-  z-index: 0;
-}
-
-.horizontal-tab-button.last {
-  margin-right: 0;
-}
-
-.horizontal-tab-button a {
-  background: #efefef;
-  border: 1px solid #d5d5d5;
-  border-bottom-color: #ccc;
-  display: inline-block;
-  padding: 1px 5px 3px;
-  color: #000;
-}
-
-.horizontal-tab-button a:hover {
-  background: #d5d5d5;
-  text-decoration: none;
-}
-
-.horizontal-tab-button.selected a,
-.horizontal-tab-button.selected a:active {
-  background: #fff;
-  border: 1px solid #ccc;
-  border-bottom-color: #fff;
-  outline: none;
-  z-index: 1;
-}
diff --git a/sites/all/modules/ux_elements/css/vertical_accordion.css b/sites/all/modules/ux_elements/css/vertical_accordion.css
deleted file mode 100644
index 861bbea9ae664818dd6117826384a01b9e481e9a..0000000000000000000000000000000000000000
--- a/sites/all/modules/ux_elements/css/vertical_accordion.css
+++ /dev/null
@@ -1,105 +0,0 @@
-/* $Id: vertical_accordion.css,v 1.1 2010/12/21 15:19:26 jameselliott Exp $ */
-
-/* @group Pane header */
-
-.vertical-accordion .pane-header {
-  background: repeat scroll 0 0 #dfdfdf;
-  background:
-    -moz-linear-gradient(
-      -90deg,
-      #fcfcfc 0pt,
-      #e3e3e1 100%)
-      repeat scroll 0 0 #d8d8d8;
-  background:
-    -webkit-gradient(
-      linear,
-      left top,
-      left bottom,
-      color-stop(0.0, rgba(252, 252, 252, 1.0)),
-      color-stop(1.0, rgba(227, 227, 225, 1.0))
-    );
-  display: block;
-  filter: progid:DXImageTransform.Microsoft.gradient(
-    GradientType='0',
-    startColorstr=#fcfcfc, 
-    endColorstr=#e3e3e1);
-  font-size: 0.9231em;
-  line-height: 1;
-  margin-top: 0;
-  padding: 6px 3px 5px 11px;
-  text-transform: none;
-}
-
-.vertical-accordion .pane-header:hover {
-  background: repeat scroll 0 0 #d9d9d9;
-  background:
-    -moz-linear-gradient(
-      -90deg,
-      #f6f6f6 0pt,
-      #d6d6d4 100%)
-      repeat scroll 0 0 #d8d8d8;
-  background:
-    -webkit-gradient(
-      linear,
-      left top,
-      left bottom,
-      color-stop(0.0, rgba(246, 246, 246, 1.0)),
-      color-stop(1.0, rgba(214, 214, 212, 1.0))
-    );
-  filter: progid:DXImageTransform.Microsoft.gradient(
-    GradientType='0',
-    startColorstr=#f6f6f6, 
-    endColorstr=#d6d6d4);
-  text-decoration: none;
-}
-
-.vertical-accordion .pane-header ~ .pane-header {
-  border-top-width: 0;
-}
-
-.vertical-accordion .pane-header .ui-icon {
-  color: inherit;
-  display: none;
-  background: none;
-  /* CSS triangle */
-  border-bottom: none;
-  border-left: 4px solid transparent;
-  border-right: 4px solid transparent;
-  border-top: 5px solid;
-  height: 0;
-  left: 11px;
-  margin-top: 0;
-  top: 45%;
-  width: 0;
-}
-
-.vertical-accordion .pane-header.ui-state-active {
-  font-weight: normal;
-  padding-left: 24px;
-}
-
-.vertical-accordion .pane-header.ui-state-active .ui-icon {
-  display: block;
-}
-
-/* @end */
-
-/* @group Pane content */
-
-.vertical-accordion .ui-accordion-content {
-  margin: 0;
-  padding: 0 11px;
-  top: auto;
-}
-
-.vertical-accordion .ui-accordion-content > :first-child {
-  margin-top: 10px;
-  padding-top: 0;
-}
-
-.vertical-accordion .ui-accordion-content > :last-child {
-  margin-bottom: 10px;
-  padding-bottom: 0;
-}
-
-/* @end */
diff --git a/sites/all/modules/ux_elements/js/horizontal_tab.js b/sites/all/modules/ux_elements/js/horizontal_tab.js
deleted file mode 100644
index 8ea486265053bbb510ab53f1b26b8ebacb5489da..0000000000000000000000000000000000000000
--- a/sites/all/modules/ux_elements/js/horizontal_tab.js
+++ /dev/null
@@ -1,156 +0,0 @@
-// $Id: horizontal_tab.js,v 1.1 2010/12/21 15:19:26 jameselliott Exp $
-
-(function ($) {
-
-/**
- * Copy of the functionality of vertical tabs in Drupal 7 core
- */
-Drupal.behaviors.horizontalTabs = {
-  attach: function (context) {
-    $('.horizontal-tabs-panes', context).once('horizontal-tabs', function () {
-      var focusID = $(':hidden.horizontal-tabs-active-tab', this).val();
-      var tab_focus;
-
-      // Check if there are some fieldsets that can be converted to horizontal-tabs
-      var $fieldsets = $('> fieldset', this);
-      if ($fieldsets.length == 0) {
-        return;
-      }
-
-      // Create the tab column.
-      var tab_list = $('<ul class="horizontal-tabs-list"></ul>');
-      $(this).wrap('<div class="horizontal-tabs clearfix"></div>').before(tab_list);
-
-      // Transform each fieldset into a tab.
-      $fieldsets.each(function () {
-        var horizontal_tab = new Drupal.horizontalTab({
-          title: $('> legend', this).text(),
-          fieldset: $(this)
-        });
-        tab_list.append(horizontal_tab.item);
-        $(this)
-          .removeClass('collapsible collapsed')
-          .addClass('horizontal-tabs-pane')
-          .data('horizontalTab', horizontal_tab);
-        if (this.id == focusID) {
-          tab_focus = $(this);
-        }
-      });
-
-      $('> li:first', tab_list).addClass('first');
-      $('> li:last', tab_list).addClass('last');
-
-      if (!tab_focus) {
-        // If the current URL has a fragment and one of the tabs contains an
-        // element that matches the URL fragment, activate that tab.
-        if (window.location.hash && $(window.location.hash, this).length) {
-          tab_focus = $(window.location.hash, this).closest('.horizontal-tabs-\n\
-\n\
-pane');
-        }
-        else {
-          tab_focus = $('> .horizontal-tabs-pane:first', this);
-        }
-      }
-      if (tab_focus.length) {
-        tab_focus.data('horizontalTab').focus();
-      }
-      
-      // Set a min width so the tabs won't float below
-      var minWidth = 0;
-      $('> li', tab_list).each(function () {
-        var outer = $(this).outerWidth(true);
-        minWidth = minWidth + outer;
-      });
-      $(this).parent().css('min-width', minWidth);
-
-    });
-  }
-};
-
-/**
- * The horizontal tab object represents a single tab within a tab group.
- *
- * @param settings
- *   An object with the following keys:
- *   - title: The name of the tab.
- *   - fieldset: The jQuery object of the fieldset that is the tab pane.
- */
-Drupal.horizontalTab = function (settings) {
-  var self = this;
-  $.extend(this, settings, Drupal.theme('horizontalTab', settings));
-
-  this.link.click(function () {
-    self.focus();
-    return false;
-  });
-
-  // Keyboard events added:
-  // Pressing the Enter key will open the tab pane.
-  this.link.keydown(function(event) {
-    if (event.keyCode == 13) {
-      self.focus();
-      // Set focus on the first input field of the visible fieldset/tab pane.
-      $("fieldset.horizontal-tabs-pane :input:visible:enabled:first").focus();
-      return false;
-    }
-  });
-
-  // Pressing the Enter key lets you leave the tab again.
-  this.fieldset.keydown(function(event) {
-    // Enter key should not trigger inside <textarea> to allow for multi-line entries.
-    if (event.keyCode == 13 && event.target.nodeName != "TEXTAREA") {
-      // Set focus on the selected tab button again.
-      $(".horizontal-tab-button.selected a").focus();
-      return false;
-    }
-  });
-};
-
-Drupal.horizontalTab.prototype = {
-  /**
-   * Displays the tab's content pane.
-   */
-  focus: function () {
-    this.fieldset
-      .siblings('fieldset.horizontal-tabs-pane')
-        .each(function () {
-          var tab = $(this).data('horizontalTab');
-          tab.fieldset.hide();
-          tab.item.removeClass('selected');
-        })
-      .end()
-      .show()
-      .siblings(':hidden.horizontal-tabs-active-tab')
-      .val(this.fieldset.attr('id'));
-
-    this.item.addClass('selected');
-    // Mark the active tab for screen readers.
-    $('#active-horizontal-tab').remove();
-    this.link.append('<span id="active-horizontal-tab" class="element-invisible">' + Drupal.t('(active tab)') + '</span>');
-    $(this.fieldset).trigger('horizontalTabActivate', this);
-  }
-};
-
-/**
- * Theme function for a horizontal tab.
- *
- * @param settings
- *   An object with the following keys:
- *   - title: The name of the tab.
- * @return
- *   This function has to return an object with at least these keys:
- *   - item: The root tab jQuery element
- *   - link: The anchor tag that acts as the clickable area of the tab
- *       (jQuery version)
- */
-Drupal.theme.prototype.horizontalTab = function (settings) {
-  var tab = {};
-  tab.item = $('<li class="horizontal-tab-button" tabindex="-1"></li>')
-    .append(tab.link = $('<a href="#"></a>')
-    .append(tab.title = $('<span></span>').text(settings.title))
-  );
-  return tab;
-};
-
-})(jQuery);
diff --git a/sites/all/modules/ux_elements/js/vertical_accordion.js b/sites/all/modules/ux_elements/js/vertical_accordion.js
deleted file mode 100644
index ceb69cc5a14da453c426cdc0ab7704e227affecb..0000000000000000000000000000000000000000
--- a/sites/all/modules/ux_elements/js/vertical_accordion.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// $Id: vertical_accordion.js,v 1.2 2010/12/21 15:54:27 jameselliott Exp $
-
-(function ($) {
-
-/**
- * Call jQuery Accordion on vertical_accordion elements
- */
-Drupal.behaviors.verticalAccordion = {
-  attach: function (context) {
-    $('.vertical-accordion', context).once('vertical-accordion', function(){
-      $(this).accordion({
-        header: '.pane-header',
-        clearStyle: true,
-        autoHeight: false
-      });
-    });
-  }
-};
-
-})(jQuery);
diff --git a/sites/all/modules/ux_elements/ux_elements.info b/sites/all/modules/ux_elements/ux_elements.info
deleted file mode 100644
index f3da328a7cf2e833fdf707de3e5979b03bec5d3f..0000000000000000000000000000000000000000
--- a/sites/all/modules/ux_elements/ux_elements.info
+++ /dev/null
@@ -1,12 +0,0 @@
-; $Id: ux_elements.info,v 1.2 2010/12/21 15:43:30 jameselliott Exp $
-name = UX Elements
-description = Adds more element types to those provided by Drupal core
-core = 7.x
-files[] = ux_elements.module
-
-; Information added by drupal.org packaging script on January 1, 1970 - 00:00
-version = "7.x-1.0-beta1"
-core = "7.x"
-project = "ux_elements"
-datestamp = "1296665600"
-
diff --git a/sites/all/modules/ux_elements/ux_elements.module b/sites/all/modules/ux_elements/ux_elements.module
deleted file mode 100644
index b61c821a0e0adb465786716f8fc659b58ac247d9..0000000000000000000000000000000000000000
--- a/sites/all/modules/ux_elements/ux_elements.module
+++ /dev/null
@@ -1,137 +0,0 @@
-<?php
-// $Id: ux_elements.module,v 1.2 2010/12/21 15:43:30 jameselliott Exp $
-
-/**
- * @file: Module for adding horizontal_tabs and vertical_accordion element types
- */
-
-/*
- * Implements hook_element_info().
- */
-function ux_elements_element_info() {
-  $types = array();
-  $types['horizontal_tabs'] = array(
-    '#theme_wrappers' => array('horizontal_tabs'),
-    '#default_tab' => '',
-    '#pre_render' => array('form_pre_render_fieldset'),
-    '#process' => array('form_process_horizontal_tabs'),
-  );
-  $types['vertical_accordion'] = array(
-    '#theme_wrappers' => array('vertical_accordion', 'fieldset'),
-    '#pre_render' => array('form_pre_render_fieldset', 'form_pre_render_vertical_accordion'),
-    '#process' => array('form_process_fieldset'),
-  );
-
-  return $types;
-}
-
-/*
- * Implements hook_theme().
- */
-function ux_elements_theme() {
-  return array(
-    'horizontal_tabs' => array(
-      'render element' => 'element',
-    ),
-    'vertical_accordion' => array(
-      'render element' => 'element',
-    ),
-    'vertical_accordion_pane' => array(
-      'render element' => 'element',
-    ),
-  );
-}
-
-/**
- * Creates a group formatted as horizontal tabs.
- *
- * @param $element
- *   An associative array containing the properties and children of the
- *   fieldset.
- * @param $form_state
- *   The $form_state array for the form this vertical tab widget belongs to.
- * @return
- *   The processed element.
- */
-function form_process_horizontal_tabs($element, &$form_state) {
-  // Inject a new fieldset as child, so that form_process_fieldset() processes
-  // this fieldset like any other fieldset.
-  $element['group'] = array(
-    '#type' => 'fieldset',
-    '#theme_wrappers' => array(),
-    '#parents' => $element['#parents'],
-  );
-
-  // Add JS and CSS necessary for the horizontal tabs
-  $element['#attached']['js'][] = drupal_get_path('module', 'ux_elements') . '/js/horizontal_tab.js';
-  $element['#attached']['css'][] = drupal_get_path('module', 'ux_elements') . '/css/horizontal_tab.css';
-
-  return $element;
-}
-
-/**
- * Returns HTML for an element's children fieldsets as horizontal tabs.
- *
- * @param $variables
- */
-function theme_horizontal_tabs($variables) {
-  $element = $variables['element'];
-
-  $output = '<h2 class="element-invisible">' . t('Horizontal Tabs') . '</h2>';
-  $output .= '<div class="horizontal-tabs-panes">' . $element['#children'] . '</div>';
-  return $output;
-}
-
-/**
- * Alters fieldset children of this element to have a specific theme wrapper
- *
- * @param $element
- */
-function form_pre_render_vertical_accordion($element) {
-  // Add a special theme wrapper to the children of this element.
-  $children = element_children($element);
-  foreach($children as $key) {
-    if ($element[$key]['#type']) {
-      $element[$key]['#theme_wrappers'] = array('vertical_accordion_pane');
-    }
-  }
-
-  // Add JS and CSS necessary for the vertical accordion.
-  drupal_add_js(drupal_get_path('module', 'ux_elements') . '/js/vertical_accordion.js', array('group' => 'JS_DEFAULT', 'weight' => 50));
-  drupal_add_css(drupal_get_path('module', 'ux_elements') . '/css/vertical_accordion.css');
-  drupal_add_library('system', 'ui.accordion');
-
-  return $element;
-}
-
-/**
- * Returns HTML for an element's children fieldsets as a vertical accordion.
- *
- * @param $variables
- */
-function theme_vertical_accordion($variables) {
-  $element = $variables['element'];
-
-  $output = '<div class="vertical-accordion">' . $element['#children'] . '</div>';
-  return $output;
-}
-
-/**
- * Returns HTML for a vertical accordion's children fieldsets as panes.
- *
- * @param $variables
- */
-function theme_vertical_accordion_pane($variables) {
-  $element = $variables['element'];
-
-  $output = '<a href="#" class="pane-header">' . $element['#title'] . '</a>';
-  $output .= '<div class="pane form-wrapper">' . $element['#children'];
-
-  if (isset($element['#value'])) {
-    $output .= $element['#value'];
-  }
-
-  $output .= '</div>';
-
-  return $output;
-}
\ No newline at end of file
diff --git a/sites/all/modules/webform/LICENSE.txt b/sites/all/modules/webform/LICENSE.txt
index 2c095c8d3f42488e8168f9710a4ffbfc4125a159..d159169d1050894d3ea3b98e1c965c4058208fe1 100644
--- a/sites/all/modules/webform/LICENSE.txt
+++ b/sites/all/modules/webform/LICENSE.txt
@@ -1,274 +1,339 @@
-GNU GENERAL PUBLIC LICENSE
-
-              Version 2, June 1991
-
-Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
-Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
-verbatim copies of this license document, but changing it is not allowed.
-
-                  Preamble
-
-The licenses for most software are designed to take away your freedom to
-share and change it. By contrast, the GNU General Public License is
-intended to guarantee your freedom to share and change free software--to
-make sure the software is free for all its users. This General Public License
-applies to most of the Free Software Foundation's software and to any other
-program whose authors commit to using it. (Some other Free Software
-Foundation software is covered by the GNU Library General Public License
-instead.) You can apply it to your programs, too.
-
-When we speak of free software, we are referring to freedom, not price. Our
-General Public Licenses are designed to make sure that you have the
-freedom to distribute copies of free software (and charge for this service if
-you wish), that you receive source code or can get it if you want it, that you
-can change the software or use pieces of it in new free programs; and that
-you know you can do these things.
-
-To protect your rights, we need to make restrictions that forbid anyone to
-deny you these rights or to ask you to surrender the rights. These restrictions
-translate to certain responsibilities for you if you distribute copies of the
-software, or if you modify it.
-
-For example, if you distribute copies of such a program, whether gratis or for
-a fee, you must give the recipients all the rights that you have. You must make
-sure that they, too, receive or can get the source code. And you must show
-them these terms so they know their rights.
-
-We protect your rights with two steps: (1) copyright the software, and (2)
-offer you this license which gives you legal permission to copy, distribute
-and/or modify the software.
-
-Also, for each author's protection and ours, we want to make certain that
-everyone understands that there is no warranty for this free software. If the
-software is modified by someone else and passed on, we want its recipients
-to know that what they have is not the original, so that any problems
-introduced by others will not reflect on the original authors' reputations.
-
-Finally, any free program is threatened constantly by software patents. We
-wish to avoid the danger that redistributors of a free program will individually
-obtain patent licenses, in effect making the program proprietary. To prevent
-this, we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
-The precise terms and conditions for copying, distribution and modification
-follow.
-
-           GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
-               MODIFICATION
-
-0. This License applies to any program or other work which contains a notice
-placed by the copyright holder saying it may be distributed under the terms
-of this General Public License. The "Program", below, refers to any such
-program or work, and a "work based on the Program" means either the
-Program or any derivative work under copyright law: that is to say, a work
-containing the Program or a portion of it, either verbatim or with
-modifications and/or translated into another language. (Hereinafter, translation
-is included without limitation in the term "modification".) Each licensee is
-addressed as "you".
-
-Activities other than copying, distribution and modification are not covered
-by this License; they are outside its scope. The act of running the Program is
-not restricted, and the output from the Program is covered only if its contents
-constitute a work based on the Program (independent of having been made
-by running the Program). Whether that is true depends on what the Program
-does.
-
-1. You may copy and distribute verbatim copies of the Program's source
-code as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice and
-disclaimer of warranty; keep intact all the notices that refer to this License
-and to the absence of any warranty; and give any other recipients of the
-Program a copy of this License along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and you
-may at your option offer warranty protection in exchange for a fee.
-
-2. You may modify your copy or copies of the Program or any portion of it,
-thus forming a work based on the Program, and copy and distribute such
-modifications or work under the terms of Section 1 above, provided that you
-also meet all of these conditions:
-
-a) You must cause the modified files to carry prominent notices stating that
-you changed the files and the date of any change.
-
-b) You must cause any work that you distribute or publish, that in whole or in
-part contains or is derived from the Program or any part thereof, to be
-licensed as a whole at no charge to all third parties under the terms of this
-License.
-
-c) If the modified program normally reads commands interactively when run,
-you must cause it, when started running for such interactive use in the most
-ordinary way, to print or display an announcement including an appropriate
-copyright notice and a notice that there is no warranty (or else, saying that
-you provide a warranty) and that users may redistribute the program under
-these conditions, and telling the user how to view a copy of this License.
-(Exception: if the Program itself is interactive but does not normally print such
-an announcement, your work based on the Program is not required to print
-an announcement.)
-
-These requirements apply to the modified work as a whole. If identifiable
-sections of that work are not derived from the Program, and can be
-reasonably considered independent and separate works in themselves, then
-this License, and its terms, do not apply to those sections when you distribute
-them as separate works. But when you distribute the same sections as part
-of a whole which is a work based on the Program, the distribution of the
-whole must be on the terms of this License, whose permissions for other
-licensees extend to the entire whole, and thus to each and every part
-regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest your rights to
-work written entirely by you; rather, the intent is to exercise the right to
-control the distribution of derivative or collective works based on the
-Program.
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
 
 In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of a
-storage or distribution medium does not bring the other work under the scope
-of this License.
-
-3. You may copy and distribute the Program (or a work based on it, under
-Section 2) in object code or executable form under the terms of Sections 1
-and 2 above provided that you also do one of the following:
-
-a) Accompany it with the complete corresponding machine-readable source
-code, which must be distributed under the terms of Sections 1 and 2 above
-on a medium customarily used for software interchange; or,
-
-b) Accompany it with a written offer, valid for at least three years, to give
-any third party, for a charge no more than your cost of physically performing
-source distribution, a complete machine-readable copy of the corresponding
-source code, to be distributed under the terms of Sections 1 and 2 above on
-a medium customarily used for software interchange; or,
-
-c) Accompany it with the information you received as to the offer to distribute
-corresponding source code. (This alternative is allowed only for
-noncommercial distribution and only if you received the program in object
-code or executable form with such an offer, in accord with Subsection b
-above.)
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
 
 The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source code
-means all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation and
-installation of the executable. However, as a special exception, the source
-code distributed need not include anything that is normally distributed (in
-either source or binary form) with the major components (compiler, kernel,
-and so on) of the operating system on which the executable runs, unless that
-component itself accompanies the executable.
-
-If distribution of executable or object code is made by offering access to
-copy from a designated place, then offering equivalent access to copy the
-source code from the same place counts as distribution of the source code,
-even though third parties are not compelled to copy the source along with the
-object code.
-
-4. You may not copy, modify, sublicense, or distribute the Program except as
-expressly provided under this License. Any attempt otherwise to copy,
-modify, sublicense or distribute the Program is void, and will automatically
-terminate your rights under this License. However, parties who have received
-copies, or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-5. You are not required to accept this License, since you have not signed it.
-However, nothing else grants you permission to modify or distribute the
-Program or its derivative works. These actions are prohibited by law if you
-do not accept this License. Therefore, by modifying or distributing the
-Program (or any work based on the Program), you indicate your acceptance
-of this License to do so, and all its terms and conditions for copying,
-distributing or modifying the Program or works based on it.
-
-6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the original
-licensor to copy, distribute or modify the Program subject to these terms and
-conditions. You may not impose any further restrictions on the recipients'
-exercise of the rights granted herein. You are not responsible for enforcing
-compliance by third parties to this License.
-
-7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues), conditions
-are imposed on you (whether by court order, agreement or otherwise) that
-contradict the conditions of this License, they do not excuse you from the
-conditions of this License. If you cannot distribute so as to satisfy
-simultaneously your obligations under this License and any other pertinent
-obligations, then as a consequence you may not distribute the Program at all.
-For example, if a patent license would not permit royalty-free redistribution
-of the Program by all those who receive copies directly or indirectly through
-you, then the only way you could satisfy both it and this License would be to
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
 refrain entirely from distribution of the Program.
 
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply and
-the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any patents or
-other property right claims or to contest validity of any such claims; this
-section has the sole purpose of protecting the integrity of the free software
-distribution system, which is implemented by public license practices. Many
-people have made generous contributions to the wide range of software
-distributed through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing to
-distribute software through any other system and a licensee cannot impose
-that choice.
-
-This section is intended to make thoroughly clear what is believed to be a
-consequence of the rest of this License.
-
-8. If the distribution and/or use of the Program is restricted in certain
-countries either by patents or by copyrighted interfaces, the original copyright
-holder who places the Program under this License may add an explicit
-geographical distribution limitation excluding those countries, so that
-distribution is permitted only in or among countries not thus excluded. In such
-case, this License incorporates the limitation as if written in the body of this
-License.
-
-9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will be
-similar in spirit to the present version, but may differ in detail to address new
-problems or concerns.
-
-Each version is given a distinguishing version number. If the Program specifies
-a version number of this License which applies to it and "any later version",
-you have the option of following the terms and conditions either of that
-version or of any later version published by the Free Software Foundation. If
-the Program does not specify a version number of this License, you may
-choose any version ever published by the Free Software Foundation.
-
-10. If you wish to incorporate parts of the Program into other free programs
-whose distribution conditions are different, write to the author to ask for
-permission. For software which is copyrighted by the Free Software
-Foundation, write to the Free Software Foundation; we sometimes make
-exceptions for this. Our decision will be guided by the two goals of
-preserving the free status of all derivatives of our free software and of
-promoting the sharing and reuse of software generally.
-
-               NO WARRANTY
-
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
-PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
-STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
-PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
-NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
-AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
-ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
-SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OR INABILITY TO USE THE
-PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
-OR DATA BEING RENDERED INACCURATE OR LOSSES
-SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
-PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
-IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGES.
-
-          END OF TERMS AND CONDITIONS
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/sites/all/modules/webform/components/date.inc b/sites/all/modules/webform/components/date.inc
index 6121046a45fd98d4d9827a3a3d8c2c62e33c95fa..40d6dedd3bfc0b61a50cc1d7fc14aba2d146f930 100644
--- a/sites/all/modules/webform/components/date.inc
+++ b/sites/all/modules/webform/components/date.inc
@@ -117,23 +117,25 @@ function _webform_edit_date($component) {
  * Implements _webform_render_component().
  */
 function _webform_render_date($component, $value = NULL, $filter = TRUE) {
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
   $element = array(
     '#type' => 'date',
     '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
     '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
     '#weight' => $component['weight'],
-    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
     '#required' => $component['mandatory'],
     '#start_date' => trim($component['extra']['start_date']),
     '#end_date' => trim($component['extra']['end_date']),
     '#year_textfield' => $component['extra']['year_textfield'],
-    '#default_value' => $filter ? _webform_filter_values($component['value'], NULL, NULL, NULL, FALSE) : $component['value'],
+    '#default_value' => $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'],
     '#timezone' => $component['extra']['timezone'],
     '#process' => array('webform_expand_date'),
     '#theme' => 'webform_date',
     '#theme_wrappers' => array('webform_element'),
     '#element_validate' => array('webform_validate_date'),
-    '#webform_component' => $component,
+    '#translatable' => array('title', 'description'),
   );
 
   if ($component['extra']['datepicker']) {
@@ -291,15 +293,27 @@ function webform_validate_date($element, $form_state) {
     $timestamp = strtotime($element['year']['#value'] . '-' . $element['month']['#value'] . '-' . $element['day']['#value']);
     $format = webform_date_format('short');
 
+    // Flip start and end if needed.
+    $date1 = strtotime($element['#start_date']);
+    $date2 = strtotime($element['#end_date']);
+    if ($date1 !== FALSE && $date2 !== FALSE) {
+      $start_date = $date1 < $date2 ? $date1 : $date2;
+      $end_date = $date1 > $date2 ? $date1 : $date2;
+    }
+    else {
+      $start_date = $date1;
+      $end_date = $date2;
+    }
+
     // Check that the date is after the start date.
-    if ($element['#start_date'] !== '' && (($start_date = strtotime($element['#start_date'])) || $start_date !== FALSE)) {
+    if ($start_date !== FALSE) {
       if ($timestamp < $start_date) {
         form_error($element, t('The entered date must be @start_date or later.', array('@start_date' => date($format, $start_date))));
       }
     }
 
     // Check that the date is before the end date.
-    if ($element['#end_date'] !== '' && (($end_date = strtotime($element['#end_date'])) || $end_date !== FALSE)) {
+    if ($end_date !== FALSE) {
       if ($timestamp > $end_date) {
         form_error($element, t('The entered date must be @end_date or earlier.', array('@end_date' => date($format, $end_date))));
       }
@@ -328,7 +342,7 @@ function _webform_display_date($component, $value, $format = 'html') {
     '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
     '#format' => $format,
     '#value' => $value,
-    '#webform_component' => $component,
+    '#translatable' => array('title'),
   );
 }
 
diff --git a/sites/all/modules/webform/components/email.inc b/sites/all/modules/webform/components/email.inc
index a09670958a38d450d5538a6d4189bb3a109e0a72..9a65e7f74c9990275b9877251fe9e0b0e51390b9 100644
--- a/sites/all/modules/webform/components/email.inc
+++ b/sites/all/modules/webform/components/email.inc
@@ -33,6 +33,10 @@ function _webform_defaults_email() {
  */
 function _webform_theme_email() {
   return array(
+    'webform_email' => array(
+      'render element' => 'element',
+      'file' => 'components/email.inc',
+    ),
     'webform_display_email' => array(
       'render element' => 'element',
       'file' => 'components/email.inc',
@@ -108,18 +112,20 @@ function _webform_edit_email_validate($element, &$form_state) {
  */
 function _webform_render_email($component, $value = NULL, $filter = TRUE) {
   global $user;
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
   $element = array(
-    '#type' => 'textfield',
+    '#type' => 'webform_email',
     '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
     '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
-    '#default_value' => _webform_filter_values($component['value']),
+    '#default_value' => $filter ? _webform_filter_values($component['value'], $node) : $component['value'],
     '#required' => $component['mandatory'],
     '#weight' => $component['weight'],
-    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
     '#attributes' => $component['extra']['attributes'],
     '#element_validate'  => array('_webform_validate_email'),
     '#theme_wrappers' => array('webform_element'),
-    '#webform_component' => $component,
+    '#translatable' => array('title', 'description'),
   );
 
   // Add an e-mail class for identifying the difference from normal textfields.
@@ -135,7 +141,12 @@ function _webform_render_email($component, $value = NULL, $filter = TRUE) {
   }
 
   if ($component['extra']['disabled']) {
-    $element['#attributes']['readonly'] = 'readonly';
+    if ($filter) {
+      $element['#attributes']['readonly'] = 'readonly';
+    }
+    else {
+      $element['#disabled'] = TRUE;
+    }
   }
 
   // Change the 'width' option to the correct 'size' option.
@@ -146,6 +157,29 @@ function _webform_render_email($component, $value = NULL, $filter = TRUE) {
   return $element;
 }
 
+/**
+ * Theme function to render an email component.
+ */
+function theme_webform_email($variables) {
+  $element = $variables['element'];
+
+  // This IF statement is mostly in place to allow our tests to set type="text"
+  // because SimpleTest does not support type="email".
+  if (!isset($element['#attributes']['type'])) {
+    $element['#attributes']['type'] = 'email';
+  }
+
+  // Convert properties to attributes on the element if set.
+  foreach (array('id', 'name', 'value', 'size') as $property) {
+    if (isset($element['#' . $property]) && $element['#' . $property] !== '') {
+      $element['#attributes'][$property] = $element['#' . $property];
+    }
+  }
+  _form_set_class($element, array('form-text', 'form-email'));
+
+  return '<input' . drupal_attributes($element['#attributes']) . ' />';
+}
+
 /**
  * A Drupal Form API Validation function. Validates the entered values from
  * email components on the client-side form.
@@ -160,7 +194,7 @@ function _webform_render_email($component, $value = NULL, $filter = TRUE) {
 function _webform_validate_email($form_element, &$form_state) {
   $component = $form_element['#webform_component'];
   $value = trim($form_element['#value']);
-  if (!empty($value) && !valid_email_address($value)) {
+  if ($value !== '' && !valid_email_address($value)) {
     form_error($form_element, t('%value is not a valid email address.', array('%value' => $value)));
   }
   else {
@@ -179,7 +213,7 @@ function _webform_display_email($component, $value, $format = 'html') {
     '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
     '#format' => $format,
     '#value' => isset($value[0]) ? $value[0] : '',
-    '#webform_component' => $component,
+    '#translatable' => array('title'),
   );
 }
 
diff --git a/sites/all/modules/webform/components/fieldset.inc b/sites/all/modules/webform/components/fieldset.inc
index 92875b47e217c0ab715f70d6ad7ed7365a52bdf0..6233804bdec81394def1c0bb8c70ec902fd40a5d 100644
--- a/sites/all/modules/webform/components/fieldset.inc
+++ b/sites/all/modules/webform/components/fieldset.inc
@@ -52,23 +52,21 @@ function _webform_edit_fieldset($component) {
  * Implements _webform_render_component().
  */
 function _webform_render_fieldset($component, $value = NULL, $filter = TRUE) {
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
   $element = array(
     '#type' => 'fieldset',
     '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
+    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : NULL,
     '#weight' => $component['weight'],
-    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
     '#collapsible' => $component['extra']['collapsible'],
     '#collapsed' => $component['extra']['collapsed'],
     '#attributes' => array('class' => array('webform-component-fieldset'), 'id' => 'webform-component-' . $component['form_key']),
-    '#pre_render' => array('webform_fieldset_prerender'),
-    '#webform_component' => $component,
+    '#pre_render' => array('webform_fieldset_prerender', 'webform_element_title_display'),
+    '#translatable' => array('title', 'description'),
   );
 
-  // Hide the fieldset title if #title_display is 'none'.
-  if (!empty($component['extra']['title_display']) && $component['extra']['title_display'] == 'none') {
-    $element['#title'] = NULL;
-  }
-
   return $element;
 }
 
@@ -89,13 +87,13 @@ function _webform_display_fieldset($component, $value, $format = 'html') {
       '#title' => $component['name'],
       '#weight' => $component['weight'],
       '#theme_wrappers' => array('webform_element_text'),
+      '#translatable' => array('title'),
     );
   }
   else {
     $element = _webform_render_fieldset($component, $value);
   }
 
-  $element['#webform_component'] = $component;
   $element['#format'] = $format;
 
   return $element;
diff --git a/sites/all/modules/webform/components/file.inc b/sites/all/modules/webform/components/file.inc
index 7a4a9d8276325949bd7ff4c921befb092df081c4..4a5654f7afa93455791e650769409973ce3167dc 100644
--- a/sites/all/modules/webform/components/file.inc
+++ b/sites/all/modules/webform/components/file.inc
@@ -19,10 +19,11 @@ function _webform_defaults_file() {
       'filtering' => array(
         'types' => array('gif', 'jpg', 'png'),
         'addextensions' => '',
-        'size' => 800,
+        'size' => '2 MB',
       ),
-      'savelocation' => '',
-      'width' => '',
+      'scheme' => 'public',
+      'directory' => '',
+      'progress_indicator' => 'throbber',
       'title_display' => 0,
       'description' => '',
       'attributes' => array(),
@@ -36,11 +37,7 @@ function _webform_defaults_file() {
  */
 function _webform_theme_file() {
   return array(
-    'webform_edit_file' => array(
-      'render element' => 'form',
-      'file' => 'components/file.inc',
-    ),
-    'webform_render_file' => array(
+    'webform_edit_file_extensions' => array(
       'render element' => 'element',
       'file' => 'components/file.inc',
     ),
@@ -56,34 +53,54 @@ function _webform_theme_file() {
  */
 function _webform_edit_file($component) {
     $form = array();
-    $form['#theme'] = 'webform_edit_file';
+    $form['#element_validate'] = array('_webform_edit_file_check_directory');
+    $form['#after_build'] = array('_webform_edit_file_check_directory');
+
+    $form['validation']['size'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Max upload size'),
+      '#default_value' => $component['extra']['filtering']['size'],
+      '#description' => t('Enter the max file size a user may upload such as 2 MB or 800 KB. Your server has a max upload size of @size.', array('@size' => format_size(file_upload_max_size()))),
+      '#size' => 10,
+      '#parents' => array('extra', 'filtering', 'size'),
+      '#element_validate' => array('_webform_edit_file_size_validate'),
+      '#weight' => 1,
+    );
 
-    $form['validation']['filtering'] = array(
-      '#element_validate' => array('_webform_edit_file_filtering_validate'),
+    $form['validation']['extensions'] = array(
+      '#element_validate' => array('_webform_edit_file_extensions_validate'),
       '#parents' => array('extra', 'filtering'),
+      '#theme' => 'webform_edit_file_extensions',
+      '#theme_wrappers' => array('form_element'),
+      '#title' => t('Allowed file extensions'),
+      '#attached' => array(
+        'js' => array(drupal_get_path('module', 'webform') . '/js/webform-admin.js'),
+        'css' => array(drupal_get_path('module', 'webform') . '/css/webform-admin.css'),
+      ),
+      '#weight' => 2,
     );
 
     // Find the list of all currently valid extensions.
     $current_types = isset($component['extra']['filtering']['types']) ? $component['extra']['filtering']['types'] : array();
 
     $types = array('gif', 'jpg', 'png');
-    $form['validation']['filtering']['types']['webimages'] = array(
+    $form['validation']['extensions']['types']['webimages'] = array(
       '#type' => 'checkboxes',
-      '#title' => t('Web Images'),
+      '#title' => t('Web images'),
       '#options' => drupal_map_assoc($types),
       '#default_value' => array_intersect($current_types, $types),
     );
 
     $types = array('bmp', 'eps', 'tif', 'pict', 'psd');
-    $form['validation']['filtering']['types']['desktopimages'] = array(
+    $form['validation']['extensions']['types']['desktopimages'] = array(
       '#type' => 'checkboxes',
-      '#title' => t('Desktop Images'),
+      '#title' => t('Desktop images'),
       '#options' => drupal_map_assoc($types),
       '#default_value' => array_intersect($current_types, $types),
     );
 
     $types = array('txt', 'rtf', 'html', 'odf', 'pdf', 'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'xml');
-    $form['validation']['filtering']['types']['documents'] = array(
+    $form['validation']['extensions']['types']['documents'] = array(
       '#type' => 'checkboxes',
       '#title' => t('Documents'),
       '#options' => drupal_map_assoc($types),
@@ -91,7 +108,7 @@ function _webform_edit_file($component) {
     );
 
     $types = array('avi', 'mov', 'mp3', 'ogg', 'wav');
-    $form['validation']['filtering']['types']['media'] = array(
+    $form['validation']['extensions']['types']['media'] = array(
       '#type' => 'checkboxes',
       '#title' => t('Media'),
       '#options' => drupal_map_assoc($types),
@@ -99,45 +116,60 @@ function _webform_edit_file($component) {
     );
 
     $types = array('bz2', 'dmg', 'gz', 'jar', 'rar', 'sit', 'tar', 'zip');
-    $form['validation']['filtering']['types']['archives'] = array(
+    $form['validation']['extensions']['types']['archives'] = array(
       '#type' => 'checkboxes',
       '#title' => t('Archives'),
       '#options' => drupal_map_assoc($types),
       '#default_value' => array_intersect($current_types, $types),
     );
 
-    $form['validation']['filtering']['addextensions'] = array(
+    $form['validation']['extensions']['addextensions'] = array(
       '#type' => 'textfield',
-      '#title' => t('Additional Extensions'),
+      '#title' => t('Additional extensions'),
       '#default_value' => $component['extra']['filtering']['addextensions'],
       '#description' => t('Enter a list of additional file extensions for this upload field, seperated by commas.<br /> Entered extensions will be appended to checked items above.'),
-      '#size' => 60,
+      '#size' => 20,
       '#weight' => 3,
-      '#default_value' => $component['extra']['filtering']['addextensions'],
     );
 
-    $form['validation']['filtering']['size'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Max Upload Size'),
-      '#default_value' => $component['extra']['filtering']['size'],
-      '#description' => t('Enter the max file size a user may upload (in KB).'),
-      '#size' => 10,
-      '#weight' => 3,
-      '#field_suffix' => t('KB'),
-      '#default_value' => $component['extra']['filtering']['size'],
-      '#parents' => array('extra', 'filtering', 'size'),
-      '#element_validate' => array('_webform_edit_file_size_validate'),
+    $scheme_options = array();
+    foreach (file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE) as $scheme => $stream_wrapper) {
+      $scheme_options[$scheme] = $stream_wrapper['name'];
+    }
+    $form['extra']['scheme'] = array(
+      '#type' => 'radios',
+      '#title' => t('Upload destination'),
+      '#options' => $scheme_options,
+      '#default_value' => $component['extra']['scheme'],
+      '#description' => t('Private file storage has significantly more overhead than public files, but restricts file access to users who can view submissions.'),
+      '#weight' => 4,
+      '#access' => count($scheme_options) > 1,
     );
-    $form['extra']['savelocation'] = array(
+    $form['extra']['directory'] = array(
       '#type' => 'textfield',
-      '#title' => t('Upload Directory'),
-      '#default_value' => $component['extra']['savelocation'],
-      '#description' => t('Webform uploads are always saved in the site files directory. You may optionally specify a subfolder to store your files.'),
-      '#weight' => 3,
-      '#field_prefix' => file_stream_wrapper_get_instance_by_scheme(file_default_scheme())->getDirectoryPath() . '/webform/',
-      '#element_validate' => array('_webform_edit_file_check_directory'),
-      '#after_build' => array('_webform_edit_file_check_directory'),
+      '#title' => t('Upload directory'),
+      '#default_value' => $component['extra']['directory'],
+      '#description' => t('You may optionally specify a sub-directory to store your files.'),
+      '#weight' => 5,
+      '#field_prefix' => 'webform/',
+    );
+
+    $form['display']['progress_indicator'] = array(
+      '#type' => 'radios',
+      '#title' => t('Progress indicator'),
+      '#options' => array(
+        'throbber' => t('Throbber'),
+        'bar' => t('Bar with progress meter'),
+      ),
+      '#default_value' => $component['extra']['progress_indicator'],
+      '#description' => t('The throbber display does not show the status of uploads but takes up less space. The progress bar is helpful for monitoring progress on large uploads.'),
+      '#weight' => 16,
+      '#access' => file_progress_implementation(),
+      '#parents' => array('extra', 'progress_indicator'),
     );
+
+    // TODO: Make managed_file respect the "size" parameter.
+    /*
     $form['display']['width'] = array(
       '#type' => 'textfield',
       '#title' => t('Width'),
@@ -148,16 +180,25 @@ function _webform_edit_file($component) {
       '#weight' => 4,
       '#parents' => array('extra', 'width')
     );
+    */
+
     return $form;
 }
 
 /**
- * A Form API element validate function to check filesize is numeric.
+ * A Form API element validate function to check filesize is valid.
  */
 function _webform_edit_file_size_validate($element) {
   if (!empty($element['#value'])) {
-    if (!is_numeric($element['#value']) || intval($element['#value']) != $element['#value']) {
-      form_error($element, t('Max upload size must be a number in KB.'));
+    $set_filesize = parse_size($element['#value']);
+    if ($set_filesize == FALSE) {
+      form_error($element, t('File size @value is not a valid filesize. Use a value such as 2 MB or 800 KB.', array('@value' => $element['#value'])));
+    }
+    else {
+      $max_filesize = parse_size(file_upload_max_size());
+      if ($max_filesize < $set_filesize) {
+        form_error($element, t('An upload size of @value is too large, you are allow to upload files @max or less.', array('@value' => $element['#value'], '@max' => format_size($max_filesize))));
+      }
     }
   }
 }
@@ -168,19 +209,19 @@ function _webform_edit_file_size_validate($element) {
  * Ensure that the destination directory exists and is writable.
  */
 function _webform_edit_file_check_directory($element) {
-  $base_dir = file_build_uri('webform');
-  $destination_dir = file_build_uri('webform/' . $element['#value']);
+  $scheme = $element['extra']['scheme']['#value'];
+  $directory = $element['extra']['directory']['#value'];
+
+  $destination_dir = file_stream_wrapper_uri_normalize($scheme . '://' . $directory . '/webform');
 
   // Sanity check input to prevent use parent (../) directories.
-  $real_base = drupal_realpath($base_dir);
-  $real_destination = drupal_realpath($destination_dir);
-  if (strpos($real_destination, $real_base) !== 0) {
-    form_error($element, t('The save directory %directory is not valid.', array('%directory' => $destination_dir)));
+  if (preg_match('/\.\.[\/\\\]/', $destination_dir . '/')) {
+    form_error($element['extra']['directory'], t('The save directory %directory is not valid.', array('%directory' => $directory)));
   }
   else {
     $destination_success = file_prepare_directory($destination_dir, FILE_CREATE_DIRECTORY);
     if (!$destination_success) {
-      form_error($element, t('The save directory %directory could not be created. Check that the webform files directory is writtable.', array('%directory' => $destination_dir)));
+      form_error($element['extra']['directory'], t('The save directory %directory could not be created. Check that the webform files directory is writable.', array('%directory' => $directory)));
     }
   }
 
@@ -193,7 +234,7 @@ function _webform_edit_file_check_directory($element) {
  * Change the submitted values of the component so that all filtering extensions
  * are saved as a single array.
  */
-function _webform_edit_file_filtering_validate($element, &$form_state) {
+function _webform_edit_file_extensions_validate($element, &$form_state) {
   // Predefined types.
   $extensions = array();
   foreach (element_children($element['types']) as $category) {
@@ -216,304 +257,113 @@ function _webform_edit_file_filtering_validate($element, &$form_state) {
   form_set_value($element['types'], $extensions, $form_state);
 }
 
-function theme_webform_edit_file($variables) {
-  $form = $variables['form'];
-
-  // Add a little JavaScript to check all the items in one type.
-  $javascript = '
-    function check_category_boxes() {
-      var checkValue = !document.getElementById("edit-extra-filtering-types-"+arguments[0]+"-"+arguments[1]).checked;
-      for(var i=1; i < arguments.length; i++) {
-        document.getElementById("edit-extra-filtering-types-"+arguments[0]+"-"+arguments[i]).checked = checkValue;
-      }
-    }
- ';
-  drupal_add_js($javascript, 'inline');
+/**
+ * Output the list of allowed extensions as checkboxes.
+ */
+function theme_webform_edit_file_extensions($variables) {
+  $element = $variables['element'];
 
   // Format the components into a table.
-  $per_row = 6;
   $rows = array();
-  foreach (element_children($form['validation']['filtering']['types']) as $key => $filtergroup) {
+  foreach (element_children($element['types']) as $filtergroup) {
     $row = array();
     $first_row = count($rows);
-    if ($form['validation']['filtering']['types'][$filtergroup]['#type'] == 'checkboxes') {
-      // Add the title.
-      $row[] = $form['validation']['filtering']['types'][$filtergroup]['#title'];
-      $row[] = '&nbsp;';
-      // Convert the checkboxes into individual form-items.
-      $checkboxes = form_process_checkboxes($form['validation']['filtering']['types'][$filtergroup]);
-      // Render the checkboxes in two rows.
-      $checkcount = 0;
-      $jsboxes = '';
-      foreach (element_children($checkboxes) as $key) {
-        $checkbox = $checkboxes[$key];
-        if ($checkbox['#type'] == 'checkbox') {
-          $checkcount++;
-          $jsboxes .= "'" . $checkbox['#return_value'] . "',";
-          if ($checkcount <= $per_row) {
-            $row[] = array('data' => drupal_render($checkbox));
-          }
-          elseif ($checkcount == $per_row + 1) {
-            $rows[] = array('data' => $row, 'style' => 'border-bottom: none;');
-            $row = array(array('data' => '&nbsp;'), array('data' => '&nbsp;'));
-            $row[] = array('data' => drupal_render($checkbox));
-          }
-          else {
-            $row[] = array('data' => drupal_render($checkbox));
-          }
-        }
-      }
-      // Pretty up the table a little bit.
-      $current_cell = $checkcount % $per_row;
-      if ($current_cell > 0) {
-        $colspan = $per_row - $current_cell   + 1;
-        $row[$current_cell + 1]['colspan'] = $colspan;
-      }
-      // Add the javascript links.
-      $jsboxes = drupal_substr($jsboxes, 0, drupal_strlen($jsboxes) - 1);
-      $rows[] = array('data' => $row);
-      $select_link = ' <a href="javascript:check_category_boxes(\'' . $filtergroup . '\',' . $jsboxes . ')">(select)</a>';
-      $rows[$first_row]['data'][1] = array('data' => $select_link, 'width' => 40);
-      unset($form['validation']['filtering']['types'][$filtergroup]);
-    }
-    elseif ($filtergroup != 'size') {
-      // Add other fields to the table (ie. additional extensions).
-      $row[] = $form['validation']['filtering']['types'][$filtergroup]['#title'];
-      unset($form['validation']['filtering']['types'][$filtergroup]['#title']);
-      $row[] = array(
-        'data' => drupal_render($form['validation']['filtering']['types'][$filtergroup]),
-        'colspan' => $per_row + 1,
-      );
-      unset($form['validation']['filtering']['types'][$filtergroup]);
+    if ($element['types'][$filtergroup]['#type'] == 'checkboxes') {
+      $select_link = ' <a href="#" class="webform-select-link webform-select-link-' . $filtergroup . '">(' . t('select') . ')</a>';
+      $row[] = $element['types'][$filtergroup]['#title'];
+      $row[] = array('data' => $select_link, 'width' => 40);
+      $row[] = array('data' => drupal_render_children($element['types'][$filtergroup]), 'class' => array('webform-file-extensions', 'webform-select-group-' . $filtergroup));
       $rows[] = array('data' => $row);
+      unset($element['types'][$filtergroup]);
     }
   }
-  $header = array(array('data' => t('Category'), 'colspan' => '2'), array('data' => t('Types'), 'colspan' => $per_row));
+
+  // Add the row for additional types.
+  $row = array();
+  $title = $element['addextensions']['#title'];
+  $element['addextensions']['#title'] = NULL;
+  $row[] = array('data' => $title, 'colspan' => 2);
+  $row[] = drupal_render($element['addextensions']);
+  $rows[] = $row;
+
+  $header = array(array('data' => t('Category'), 'colspan' => '2'), array('data' => t('Types')));
 
   // Create the table inside the form.
-  $form['validation']['filtering']['types']['table'] = array(
+  $element['types']['table'] = array(
     '#theme' => 'table',
     '#header' => $header,
-    '#rows' => $rows
+    '#rows' => $rows,
+    '#attributes' => array('class' => array('webform-file-extensions')),
   );
 
-  $output = drupal_render_children($form);
-
-  return $output;
+  return drupal_render_children($element);
 }
 
 /**
  * Implements _webform_render_component().
  */
 function _webform_render_file($component, $value = NULL, $filter = TRUE) {
-  // Normally every file component is given a unique ID based on its key.
-  if (isset($component['nid'])) {
-    $node = node_load($component['nid']);
-    $form_key = implode('_', webform_component_parent_keys($node, $component));
-  }
-  // If being used as a default though, we don't yet have a form key.
-  else {
-    $form_key = 'default';
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
+  // Cap the upload size according to the PHP limit.
+  $max_filesize = parse_size(file_upload_max_size());
+  $set_filesize = $component['extra']['filtering']['size'];
+  if (!empty($set_filesize) && parse_size($set_filesize) < $max_filesize) {
+    $max_filesize = parse_size($set_filesize);
   }
 
-  $element[$form_key] = array(
-    '#type' => 'file',
-    //'#required' => $component['mandatory'], // Drupal core bug with required file uploads.
+  $element = array(
+    '#type' => 'managed_file',
+    '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
+    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
+    '#required' => $component['mandatory'],
+    '#default_value' => isset($value[0]) ? $value[0] : NULL,
     '#attributes' => $component['extra']['attributes'],
-    '#tree' => FALSE, // file_check_upload assumes a flat $_FILES structure.
-    '#element_validate' => array(
-      '_webform_validate_file',
-      '_webform_required_file',  // Custom required routine.
+    '#upload_validators' => array(
+      'file_validate_size' => array($max_filesize),
+      'file_validate_extensions' => array(implode(' ', $component['extra']['filtering']['types'])),
     ),
-    '#webform_component' => $component,
-    '#theme_wrappers' => array(),
-  );
-  $element['#webform_component'] = $component;
-  $element['#weight'] = $component['weight'];
-  $element['#title'] = $filter ? _webform_filter_xss($component['name']) : $component['name'];
-  $element['#title_display'] = $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before';
-  $element['#description'] = $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'];
-
-  $element['#theme'] = 'webform_render_file';
-  $element['#theme_wrappers'] = array('webform_element');
-
-  // Change the 'width' option to the correct 'size' option.
-  if ($component['extra']['width'] > 0) {
-    $element[$form_key]['#size'] = $component['extra']['width'];
-  }
-
-  // Handles the asterisk for mandatory fields. Note that this is only on the
-  // wrapper, not on the file field itself. We handle validation separately.
-  if ($component['mandatory']) {
-    $element['#required'] = TRUE;
-  }
-
-  // Add a hidden element to store the FID for new files.
-  $element['_fid'] = array(
-    '#type' => 'hidden',
-    '#default_value' => '',
-  );
-
-  // Add a hidden element to store the FID for existing files.
-  $element['_old'] = array(
-    '#type' => 'hidden',
-    '#value' => isset($value[0]) ? $value[0] : NULL,
+    '#pre_render' => array_merge(element_info_property('managed_file', '#pre_render'), array('webform_file_allow_access')),
+    '#upload_location' => $component['extra']['scheme'] . '://webform/' . $component['extra']['directory'],
+    '#progress_indicator' => $component['extra']['progress_indicator'],
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
+    '#weight' => $component['weight'],
+    '#theme_wrappers' => array('webform_element'),
+    '#translatable' => array('title', 'description'),
   );
 
   return $element;
 }
 
 /**
- * Render a File component.
+ * Implements _webform_submit_component().
  */
-function theme_webform_render_file($variables) {
-  $element = $variables['element'];
-
-  // Add information about the existing file, if any.
-  if (isset($element['#default_value'])) {
-    $element['_fid']['#value'] = $element['#default_value'];
+function _webform_submit_file($component, $value) {
+  if (is_array($value)) {
+    return !empty($value['fid']) ? $value['fid'] : '';
   }
-  $value = $element['_fid']['#value'] ? $element['_fid']['#value'] : $element['_old']['#value'];
-
-  if ($value && ($file = webform_get_file($value))) {
-    $firstchild = array_shift(array_keys($element));
-    $element[$firstchild]['#suffix'] = ' ' . l(t('Download @filename', array('@filename' => webform_file_name($file->uri))), webform_file_url($file->uri)) . (isset($element['#suffix']) ? $element['#suffix'] : '');
-    $element[$firstchild]['#description'] = '<div class="webform-newfile-message">' . t('Uploading a new file will replace the current file.') . '</div>' . (isset($element[$firstchild]['#description']) ? $element[$firstchild]['#description'] : '');
+  else {
+    return !empty($value) ? $value : '';
   }
-
-  return drupal_render_children($element);
 }
 
 /**
- * A Form API element validate function.
+ * Pre-render callback to allow access to uploaded files.
  *
- * Fix Drupal core's handling of required file fields.
- */
-function _webform_required_file($element, $form_state) {
-  $component = $element['#webform_component'];
-  $parents = $element['#array_parents'];
-  array_pop($parents);
-  $form_key = implode('_', $parents);
-
-  // Do not validate requiredness on back or draft button.
-  if (isset($form_state['clicked_button']['#validate']) && empty($form_state['clicked_button']['#validate'])) {
-    return;
-  }
-
-  // Check if a value is already set in the hidden field.
-  $values = $form_state['values'];
-  $key = array_shift($parents);
-  $found = FALSE;
-  while (isset($values[$key])) {
-    if (isset($values[$key])) {
-      $values = $values[$key];
-      $found = TRUE;
-    }
-    else {
-      $found = FALSE;
-    }
-    $key = array_shift($parents);
-  }
-
-  if (!$found || (empty($values['_fid']) && empty($values['_old']))) {
-    if (empty($_FILES['files']['name'][$form_key]) && $component['mandatory']) {
-      form_error($element, t('%field field is required.', array('%field' => $component['name'])));
-    }
-  }
-}
-
-/**
- * A Form API element validate function.
+ * Files that have not yet been saved into a submission must be accessible to
+ * the user who uploaded it, but no one else. After the submission is saved,
+ * access is granted through the file_usage table. Before then, we use a
+ * $_SESSION value to record a user's upload.
  *
- * Ensure that the uploaded file matches the specified file types.
+ * @see webform_file_download()
  */
-function _webform_validate_file($element, &$form_state) {
-  $component = $element['#webform_component'];
-  $form_key = implode('_', $element['#parents']);
-
-  if (empty($_FILES['files']['name'][$form_key]) || form_get_error($element)) {
-    return;
-  }
-
-  // Build a human readable list of extensions:
-  $extensions = $component['extra']['filtering']['types'];
-  $extension_list = '';
-  if (count($extensions) > 1) {
-    for ($n = 0; $n < count($extensions) - 1; $n++) {
-      $extension_list .= $extensions[$n] . ', ';
-    }
-    $extension_list .= 'or ' . $extensions[count($extensions) - 1];
-  }
-  elseif (!empty($extensions)) {
-    $extension_list = $extensions[0];
-  }
-
-  if (in_array('jpg', $extensions)) {
-    $extensions[] = 'jpeg';
+function webform_file_allow_access($element) {
+  if (!empty($element['#value']['fid'])) {
+    $fid = $element['#value']['fid'];
+    $_SESSION['webform_files'][$fid] = $fid;
   }
 
-  $strrpos = function_exists('mb_strrpos') ? 'mb_strrpos' : 'strrpos';
-  $dot = $strrpos($_FILES['files']['name'][$form_key], '.');
-  $extension = drupal_strtolower(drupal_substr($_FILES['files']['name'][$form_key], $dot+1));
-  $file_error = FALSE;
-  if (!empty($extensions) && !in_array($extension, $extensions)) {
-    form_error($element, t("Files with the '%ext' extension are not allowed, please upload a file with a %exts extension.", array('%ext' => $extension, '%exts' => $extension_list)));
-    $file_error = TRUE;
-  }
-
-  // Now let's check the file size (limit is set in KB).
-  if ($_FILES['files']['size'][$form_key] > $component['extra']['filtering']['size'] * 1024) {
-    form_error($element, t("The file '%filename' is too large (%filesize KB). Please upload a file %maxsize KB or smaller.", array('%filename' => $_FILES['files']['name'][$form_key], '%filesize' => (int) ($_FILES['files']['size'][$form_key]/1024), '%maxsize' => $component['extra']['filtering']['size'])));
-    $file_error = TRUE;
-  }
-
-  // Save the file to a temporary location.
-  if (!$file_error) {
-    $upload_dir = file_build_uri('webform/' . $component['extra']['savelocation']);
-    if (file_prepare_directory($upload_dir, FILE_CREATE_DIRECTORY)) {
-      // Note that the $extensions list was already validated above but needs to
-      // be passed into file_save_upload() for it to pass internal validation
-      // and not use the default extension checklist.
-      $file = file_save_upload($form_key, array('file_validate_extensions' => array(implode(' ', $extensions))), $upload_dir);
-      if ($file) {
-        // Set the hidden field value.
-        $parents = $element['#array_parents'];
-        array_pop($parents);
-        $parents[] = '_fid';
-        form_set_value(array('#parents' => $parents), $file->fid, $form_state);
-      }
-      else {
-        drupal_set_message(t('The uploaded file %filename was unable to be saved. The destination directory may not be writable.', array('%filename' => $file->filename)), 'error');
-      }
-    }
-    else {
-      drupal_set_message(t('The uploaded file was unable to be saved. The destination directory does not exist.'), 'error');
-    }
-  }
-}
-
-/**
- * Implements _webform_submit_component().
- */
-function _webform_submit_file($component, $value) {
-
-  if ($value['_fid'] && ($file = webform_get_file($value['_fid']))) {
-    // Save any new files permanently.
-    $file->status = FILE_STATUS_PERMANENT;
-    file_save($file);
-
-    // Delete any previous files.
-    if ($value['_old'] && ($existing = webform_get_file($value['_old']))) {
-      file_delete($existing);
-    }
-
-    $value = $file->fid;
-  }
-  else {
-    $value = $value['_old'] ? $value['_old'] : NULL;
-  }
-
-  return $value;
+  return $element;
 }
 
 /**
@@ -522,13 +372,13 @@ function _webform_submit_file($component, $value) {
 function _webform_display_file($component, $value, $format = 'html') {
   $fid = isset($value[0]) ? $value[0] : NULL;
   return array(
-     '#title' => $component['name'],
-     '#value' => $fid ? webform_get_file($fid) : NULL,
-     '#weight' => $component['weight'],
-     '#theme' => 'webform_display_file',
-     '#theme_wrappers' => $format == 'text' ? array('webform_element_text') : array('webform_element'),
-     '#webform_component' => $component,
-     '#format' => $format,
+    '#title' => $component['name'],
+    '#value' => $fid ? webform_get_file($fid) : NULL,
+    '#weight' => $component['weight'],
+    '#theme' => 'webform_display_file',
+    '#theme_wrappers' => $format == 'text' ? array('webform_element_text') : array('webform_element'),
+    '#format' => $format,
+    '#translatable' => array('title'),
   );
 }
 
@@ -548,11 +398,21 @@ function theme_webform_display_file($variables) {
  */
 function _webform_delete_file($component, $value) {
   // Delete an individual submission file.
-  if (isset($value[0]) && ($file = webform_get_file($value[0]))) {
+  if (!empty($value[0]) && ($file = webform_get_file($value[0]))) {
     file_delete($file);
   }
 }
 
+/**
+ * Implements _webform_attachments_component().
+ */
+function _webform_attachments_file($component, $value) {
+  $file = (array) webform_get_file($value[0]);
+  //This is necessary until the next release of mimemail is out, see [#1388786]
+  $file['filepath'] = $file['uri'];
+  $files = array($file);
+  return $files;
+}
 /**
  * Implements _webform_analysis_component().
  */
@@ -642,9 +502,30 @@ function webform_file_url($uri) {
 
 /**
  * Helper function to load a file from the database.
- *
- * @todo We can remove this entirely now the Drupal 7 has native file loading.
  */
 function webform_get_file($fid) {
-  return file_load($fid);
+  // Simple check to prevent loading of NULL values, which throws an entity
+  // system error.
+  return $fid ? file_load($fid) : FALSE;
 }
+
+/**
+ * Given a submission with file_usage set, add or remove file usage entries.
+ */
+function webform_file_usage_adjust($submission) {
+  if (isset($submission->file_usage)) {
+    $files = file_load_multiple($submission->file_usage['added_fids']);
+    foreach ($files as $file) {
+      $file->status = 1;
+      file_save($file);
+      file_usage_add($file, 'webform', 'submission', $submission->sid);
+    }
+
+    $files = file_load_multiple($submission->file_usage['deleted_fids']);
+    foreach ($files as $file) {
+      file_usage_delete($file, 'webform', 'submission', $submission->sid);
+      file_delete($file);
+    }
+  }
+}
+
diff --git a/sites/all/modules/webform/components/grid.inc b/sites/all/modules/webform/components/grid.inc
index 548999ddf4d366492b9b8450e965e15a0e240694..0ddcf115c636ed3d0c894bacd09304f45ced3e49 100644
--- a/sites/all/modules/webform/components/grid.inc
+++ b/sites/all/modules/webform/components/grid.inc
@@ -142,13 +142,15 @@ function _webform_edit_grid($component) {
  * Implements _webform_render_component().
  */
 function _webform_render_grid($component, $value = NULL, $filter = TRUE) {
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
   $element = array(
     '#type' => 'webform_grid',
     '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
     '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
     '#required' => $component['mandatory'],
     '#weight' => $component['weight'],
-    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
     '#grid_questions' => _webform_select_options_from_text($component['extra']['questions'], TRUE),
     '#grid_options' => _webform_select_options_from_text($component['extra']['options'], TRUE),
     '#optrand' => $component['extra']['optrand'],
@@ -156,7 +158,7 @@ function _webform_render_grid($component, $value = NULL, $filter = TRUE) {
     '#theme' => 'webform_grid',
     '#theme_wrappers' => array('webform_element'),
     '#process' => array('webform_expand_grid'),
-    '#webform_component' => $component,
+    '#translatable' => array('title', 'description', 'grid_options', 'grid_questions'),
   );
 
   if ($value) {
@@ -193,6 +195,7 @@ function webform_expand_grid($element) {
         // Webform handles validation manually.
         '#validated' => TRUE,
         '#webform_validated' => FALSE,
+        '#translatable' => array('title'),
       );
     }
   }
@@ -200,10 +203,10 @@ function webform_expand_grid($element) {
   $value = isset($element['#default_value']) ? $element['#default_value'] : array();
   foreach (element_children($element) as $key) {
     if (isset($value[$key])) {
-      $element[$key]['#default_value'] = ($value[$key] !== '') ? $value[$key] : FALSE;
+      $element[$key]['#default_value'] = ($value[$key] !== '') ? $value[$key] : NULL;
     }
     else {
-      $element[$key]['#default_value'] = FALSE;
+      $element[$key]['#default_value'] = NULL;
     }
   }
 
@@ -226,14 +229,15 @@ function _webform_display_grid($component, $value, $format = 'html') {
     '#theme' => 'webform_display_grid',
     '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
     '#sorted' => TRUE,
-    '#webform_component' => $component,
+    '#translatable' => array('#title', '#grid_questions', '#grid_options'),
   );
 
   foreach ($questions as $key => $question) {
     if ($question !== '') {
-      $element[$question] = array(
+      $element[$key] = array(
         '#title' => $question,
         '#value' => isset($value[$key]) ? $value[$key] : NULL,
+        '#translatable' => array('#title', '#value'),
       );
     }
   }
@@ -256,11 +260,11 @@ function theme_webform_display_grid($variables) {
     foreach ($element['#grid_options'] as $option) {
       $header[] = array('data' => _webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
     }
-    foreach (element_children($element) as $key) {
+    foreach ($element['#grid_questions'] as $question_key => $question) {
       $row = array();
-      $row[] = array('data' => _webform_filter_xss($element[$key]['#title']), 'class' => array('webform-grid-question'));
+      $row[] = array('data' => _webform_filter_xss($question), 'class' => array('webform-grid-question'));
       foreach ($element['#grid_options'] as $option_value => $option_label) {
-        if (strcmp($option_value, $element[$key]['#value']) == 0) {
+        if (strcmp($element[$question_key]['#value'], $option_value) == 0) {
           $row[] = array('data' => '<strong>X</strong>', 'class' => array('checkbox', 'webform-grid-option'));
         }
         else {
@@ -340,18 +344,16 @@ function _webform_analysis_grid($component, $sids = array()) {
  */
 function _webform_table_grid($component, $value) {
   $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
+  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
+
   $output = '';
   // Set the value as a single string.
-  if (is_array($value)) {
-    foreach ($value as $item => $value) {
-      if ($value !== '') {
-        $output .= _webform_filter_xss($questions[$item]) . ': ' . _webform_filter_xss($value) . '<br />';
-      }
+  foreach ($questions as $key => $label) {
+    if (isset($value[$key]) && isset($options[$value[$key]])) {
+      $output .= _webform_filter_xss($label) . ': ' . _webform_filter_xss($options[$value[$key]]) . '<br />';
     }
   }
-  else {
-    $output = !isset($value[0]) ? '' : _webform_filter_xss($value[0]);
-  }
+
   return $output;
 }
 
@@ -401,18 +403,14 @@ function theme_webform_grid($variables) {
 
   $rows = array();
   $header = array(array('data' => '', 'class' => array('webform-grid-question')));
-  $first = TRUE;
+  // Set the header for the table.
+  foreach ($element['#grid_options'] as $option) {
+    $header[] = array('data' => _webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
+  }
+
   foreach (element_children($element) as $key) {
     $question_element = $element[$key];
 
-    // Set the header for the table.
-    if ($first) {
-      foreach ($question_element['#options'] as $option) {
-        $header[] = array('data' => _webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
-      }
-      $first = FALSE;
-    }
-
     // Create a row with the question title.
     $row = array(array('data' => _webform_filter_xss($question_element['#title']), 'class' => array('webform-grid-question')));
 
diff --git a/sites/all/modules/webform/components/hidden.inc b/sites/all/modules/webform/components/hidden.inc
index 5930da66070b7c2ad790fc09795928c32c5079b2..e173c29c9c100b3cbefdeb82c7a1631b25fac16b 100644
--- a/sites/all/modules/webform/components/hidden.inc
+++ b/sites/all/modules/webform/components/hidden.inc
@@ -17,6 +17,7 @@ function _webform_defaults_hidden() {
     'value' => '',
     'extra' => array(
       'private' => FALSE,
+      'hidden_type' => 'value',
     ),
   );
 }
@@ -47,8 +48,18 @@ function _webform_edit_hidden($component) {
     '#rows' => 5,
     '#weight' => 0,
   );
-  $form['extra']['description'] = array(); // Hide the description box.
-  $form['display'] = array('#type' => 'markup'); // Hide the display options.
+
+  $form['display']['hidden_type'] = array(
+    '#type' => 'radios',
+    '#options' => array(
+      'value' => t('Secure value (allows use of all tokens)'),
+      'hidden' => t('Hidden element (less secure, changeable via JavaScript)'),
+    ),
+    '#title' => t('Hidden type'),
+    '#description' => t('Both types of hidden fields are not shown to end-users. Using a <em>Secure value</em> allows the use of <em>all tokens</em>, even for anonymous users.'),
+    '#default_value' => $component['extra']['hidden_type'],
+    '#parents' => array('extra', 'hidden_type'),
+  );
 
   return $form;
 }
@@ -57,15 +68,30 @@ function _webform_edit_hidden($component) {
  * Implements _webform_render_component().
  */
 function _webform_render_hidden($component, $value = NULL, $filter = TRUE) {
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
+  // Set filtering options for "value" types, which are not displayed to the
+  // end user so they do not need to be sanitized.
+  $strict = $component['extra']['hidden_type'] != 'value';
+  $allow_anonymous = $component['extra']['hidden_type'] == 'value';
+  $default_value = $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, $strict, $allow_anonymous) : $component['value'];
+  if (isset($value[0])) {
+    $default_value = $value[0];
+  }
+
   $element = array(
-    '#type' => 'hidden',
     '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
-    '#default_value' => $filter ? _webform_filter_values($component['value']) : $component['value'],
     '#weight' => $component['weight'],
+    '#translatable' => array('title'),
   );
 
-  if (isset($value[0])) {
-    $element['#default_value'] = $value[0];
+  if ($component['extra']['hidden_type'] == 'value') {
+    $element['#type'] = 'value';
+    $element['#value'] = $default_value;
+  }
+  else {
+    $element['#type'] = 'hidden';
+    $element['#default_value'] = $default_value;
   }
 
   return $element;
@@ -76,25 +102,15 @@ function _webform_render_hidden($component, $value = NULL, $filter = TRUE) {
  */
 function _webform_display_hidden($component, $value, $format = 'html') {
   $element = array(
-    '#title' => t('!name (hidden)', array('!name' => $component['name'])),
+    '#title' => $component['name'],
     '#markup' => isset($value[0]) ? $value[0] : NULL,
     '#weight' => $component['weight'],
-    '#theme' => 'webform_display_hidden',
     '#format' => $format,
     '#theme' => 'webform_display_hidden',
     '#theme_wrappers' => $format == 'text' ? array('webform_element_text') : array('webform_element'),
-    '#webform_component' => $component,
+    '#translatable' => array('title'),
   );
 
-  // TODO: This check is unusual. It shows hidden fields in e-mails but not
-  // when viewing in the browser unless you're an administrator. This should be
-  // a more logical check. See these related issues:
-  // http://drupal.org/node/313639
-  // http://drupal.org/node/781786
-  if ($format == 'html') {
-    $element['#access'] = user_access('edit all webform submissions') || user_access('access all webform results');
-  }
-
   return $element;
 }
 
@@ -159,5 +175,5 @@ function _webform_csv_headers_hidden($component, $export_options) {
  * Implements _webform_csv_data_component().
  */
 function _webform_csv_data_hidden($component, $export_options, $value) {
-  return empty($value[0]) ? '' : $value[0];
+  return isset($value[0]) ? $value[0] : '';
 }
diff --git a/sites/all/modules/webform/components/markup.inc b/sites/all/modules/webform/components/markup.inc
index 064abf565f4de77d877121127232a1303c5227f8..9bb628b68bbc8e309ad4be327cd6fc6fcd70ab47 100644
--- a/sites/all/modules/webform/components/markup.inc
+++ b/sites/all/modules/webform/components/markup.inc
@@ -37,9 +37,6 @@ function _webform_edit_markup($component) {
     '#element_validate' => array('_webform_edit_markup_validate'),
   );
 
-  $form['extra']['description'] = array(); // No description for markup.
-  $form['display'] = array('#type' => 'markup'); // Hide the display options.
-
   return $form;
 }
 
@@ -57,14 +54,16 @@ function _webform_edit_markup_validate($form, &$form_state) {
  * Implements _webform_render_component().
  */
 function _webform_render_markup($component, $value = NULL, $filter = TRUE) {
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
   $element = array(
     '#type' => 'markup',
     '#title' => $filter ? NULL : $component['name'],
     '#weight' => $component['weight'],
-    '#markup' => $filter ? _webform_filter_values(check_markup($component['value'], $component['extra']['format'], '', TRUE), NULL, NULL, NULL, FALSE) : $component['value'],
+    '#markup' => $filter ? _webform_filter_values(check_markup($component['value'], $component['extra']['format'], '', TRUE), $node, NULL, NULL, FALSE) : $component['value'],
     '#format' => $component['extra']['format'],
     '#theme_wrappers' => array('webform_element'),
-    '#webform_component' => $component,
+    '#translatable' => array('title', 'markup'),
   );
 
   // TODO: Remove when #markup becomes available in D7.
diff --git a/sites/all/modules/webform/components/number.inc b/sites/all/modules/webform/components/number.inc
new file mode 100644
index 0000000000000000000000000000000000000000..00bc7abe0158a8564e9ab308a34b3894cc497ec7
--- /dev/null
+++ b/sites/all/modules/webform/components/number.inc
@@ -0,0 +1,704 @@
+<?php
+
+/**
+ * @file
+ * Webform module number component.
+ */
+
+/**
+ * Implements _webform_defaults_component().
+ */
+function _webform_defaults_number() {
+  return array(
+    'name' => '',
+    'form_key' => NULL,
+    'pid' => 0,
+    'weight' => 0,
+    'value' => '',
+    'mandatory' => 0,
+    'extra' => array(
+      'type' => 'textfield',
+      'field_prefix' => '',
+      'field_suffix' => '',
+      'unique' => 0,
+      'title_display' => 0,
+      'description' => '',
+      'attributes' => array(),
+      'private' => FALSE,
+      'min' => '',
+      'max' => '',
+      'step' => '',
+      'decimals' => '',
+      'point' => '.',
+      'separator' => ',',
+      'integer' => 0,
+      'excludezero' => 0,
+    ),
+  );
+}
+
+/**
+ * Implements _webform_theme_component().
+ */
+function _webform_theme_number() {
+  return array(
+    'webform_number' => array(
+      'render element' => 'element',
+      'file' => 'components/number.inc',
+    ),
+    'webform_display_number' => array(
+      'render element' => 'element',
+      'file' => 'components/number.inc',
+    ),
+  );
+}
+
+/**
+ * Implements _webform_edit_component().
+ */
+function _webform_edit_number($component) {
+  $form = array();
+  $form['value'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Default value'),
+    '#default_value' => $component['value'],
+    '#description' => t('The default value of the field.') . theme('webform_token_help'),
+    '#size' => 60,
+    '#maxlength' => 1024,
+    '#weight' => 0,
+  );
+  $form['display']['type'] = array(
+    '#type' => 'radios',
+    '#title' => t('Element type'),
+    '#options' => array(
+      'textfield' => t('Text field'),
+      'select' => t('Select list'),
+    ),
+    '#default_value' => $component['extra']['type'],
+    '#description' => t('A minimum and maximum value are required if displaying as a select.'),
+    '#weight' => -1,
+    '#parents' => array('extra', 'type'),
+  );
+  $form['display']['field_prefix'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Prefix text placed to the left of the field'),
+    '#default_value' => $component['extra']['field_prefix'],
+    '#description' => t('Examples: $, #, -.'),
+    '#size' => 20,
+    '#maxlength' => 127,
+    '#weight' => 1.1,
+    '#parents' => array('extra', 'field_prefix'),
+  );
+  $form['display']['field_suffix'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Postfix text placed to the right of the field'),
+    '#default_value' => $component['extra']['field_suffix'],
+    '#description' => t('Examples: lb, kg, %.'),
+    '#size' => 20,
+    '#maxlength' => 127,
+    '#weight' => 1.2,
+    '#parents' => array('extra', 'field_suffix'),
+  );
+  $form['display']['decimals'] = array(
+    '#type' => 'select',
+    '#title' => t('Decimal places'),
+    '#options' => array('' => t('Automatic')) + drupal_map_assoc(range(0, 10)),
+    '#description' => t('Automatic will display up to @count decimals places if needed. A value of "2" is common to format currency amounts.', array('@count' => '4')),
+    '#default_value' => $component['extra']['decimals'],
+    '#weight' => 2,
+    '#parents' => array('extra', 'decimals'),
+    '#element_validate' => array('_webform_edit_number_validate'),
+  );
+  $form['display']['separator'] = array(
+    '#type' => 'select',
+    '#title' => t('Thousands separator'),
+    '#options' => array(
+      ',' => t('Comma (,)'),
+      '.' => t('Period (.)'),
+      ' ' => t('Space ( )'),
+      '' => t('None'),
+    ),
+    '#default_value' => $component['extra']['separator'],
+    '#weight' => 3,
+    '#parents' => array('extra', 'separator'),
+    '#element_validate' => array('_webform_edit_number_validate'),
+  );
+  $form['display']['point'] = array(
+    '#type' => 'select',
+    '#title' => t('Decimal point'),
+    '#options' => array(
+      ',' => t('Comma (,)'),
+      '.' => t('Period (.)'),
+    ),
+    '#default_value' => $component['extra']['point'],
+    '#weight' => 4,
+    '#parents' => array('extra', 'point'),
+    '#element_validate' => array('_webform_edit_number_validate'),
+  );
+  $form['validation']['unique'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Unique'),
+    '#return_value' => 1,
+    '#description' => t('Check that all entered values for this field are unique. The same value is not allowed to be used twice.'),
+    '#weight' => 1,
+    '#default_value' => $component['extra']['unique'],
+    '#parents' => array('extra', 'unique'),
+  );
+  $form['validation']['integer'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Integer'),
+    '#return_value' => 1,
+    '#description' => t('Permit only integer values as input. e.g. 12.34 would be invalid.'),
+    '#weight' => 1.5,
+    '#default_value' => $component['extra']['integer'],
+    '#parents' => array('extra', 'integer'),
+  );
+  $form['validation']['min'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Minimum'),
+    '#default_value' => $component['extra']['min'],
+    '#description' => t('Minimum numeric value. e.g. 0 would ensure positive numbers.'),
+    '#size' => 5,
+    '#maxlength' => 10,
+    '#weight' => 2,
+    '#parents' => array('extra', 'min'),
+    '#element_validate' => array('_webform_edit_number_validate'),
+  );
+  $form['validation']['max'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Maximum'),
+    '#default_value' => $component['extra']['max'],
+    '#description' => t('Maximum numeric value. This may also determine the display width of your field.'),
+    '#size' => 5,
+    '#maxlength' => 10,
+    '#weight' => 2,
+    '#parents' => array('extra', 'max'),
+    '#element_validate' => array('_webform_edit_number_validate'),
+  );
+  $form['validation']['step'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Step'),
+    '#default_value' => $component['extra']['step'],
+    '#description' => t('Limit options to a specific increment. e.g. a step of "5" would allow values 5, 10, 15, etc.'),
+    '#size' => 5,
+    '#maxlength' => 10,
+    '#weight' => 3,
+    '#parents' => array('extra', 'step'),
+    '#element_validate' => array('_webform_edit_number_validate'),
+  );
+  // Analysis settings.
+  $form['analysis'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Analysis'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#weight' => 10,
+  );
+  $form['analysis']['excludezero'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Exclude zero'),
+    '#return_value' => 1,
+    '#description' => t('Exclude entries of zero (or blank) when counting submissions to calculate average and standard deviation.'),
+    '#weight' => 1.5,
+    '#default_value' => $component['extra']['excludezero'],
+    '#parents' => array('extra', 'excludezero'),
+  );
+  return $form;
+}
+
+/**
+ * Theme function to render a number component.
+ */
+function theme_webform_number($variables) {
+  $element = $variables['element'];
+
+  // This IF statement is mostly in place to allow our tests to set type="text"
+  // because SimpleTest does not support type="number".
+  if (!isset($element['#attributes']['type'])) {
+    $element['#attributes']['type'] = 'number';
+  }
+
+  // Step property *must* be a full number with 0 prefix if a decimal.
+  if (!is_int($element['#step'] * 1)) {
+    $decimals = strlen($element['#step']) - strrpos($element['#step'], '.') - 1;
+    $element['#step'] = sprintf('%1.' . $decimals . 'F', $element['#step']);
+  }
+
+  // Convert properties to attributes on the element if set.
+  foreach (array('id', 'name', 'value', 'size', 'min', 'max', 'step') as $property) {
+    if (isset($element['#' . $property]) && $element['#' . $property] !== '') {
+      $element['#attributes'][$property] = $element['#' . $property];
+    }
+  }
+  _form_set_class($element, array('form-text', 'form-number'));
+
+  return '<input' . drupal_attributes($element['#attributes']) . ' />';
+}
+
+/**
+ * Implements _webform_render_component().
+ */
+function _webform_render_number($component, $value = NULL, $filter = TRUE) {
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
+  $element = array(
+    '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
+    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
+    '#default_value' => $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'],
+    '#required' => $component['mandatory'],
+    '#weight' => $component['weight'],
+    '#field_prefix' => empty($component['extra']['field_prefix']) ? NULL : ($filter ? _webform_filter_xss($component['extra']['field_prefix']) : $component['extra']['field_prefix']),
+    '#field_suffix' => empty($component['extra']['field_suffix']) ? NULL : ($filter ? _webform_filter_xss($component['extra']['field_suffix']) : $component['extra']['field_suffix']),
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
+    '#attributes' => $component['extra']['attributes'],
+    '#element_validate' => array('_webform_validate_number'),
+    '#theme_wrappers' => array('webform_element'),
+    '#min' => $component['extra']['min'],
+    '#max' => $component['extra']['max'],
+    '#step' => abs($component['extra']['step']),
+    '#integer' => $component['extra']['integer'],
+    '#translatable' => array('title', 'description'),
+  );
+
+  // Flip the min and max properties to make min less than max if needed.
+  if ($element['#min'] !== '' && $element['#max'] !== '' && $element['#min'] > $element['#max']) {
+    $max = $element['#min'];
+    $element['#min'] = $element['#max'];
+    $element['#max'] = $max;
+  }
+
+  // Ensure #step starts with a zero if a decimal.
+  if (!is_int($element['#step'] * 1)) {
+    $decimals = strlen($element['#step']) - strrpos($element['#step'], '.') - 1;
+    $element['#step'] = sprintf('%1.' . $decimals . 'F', $element['#step']);
+  }
+
+  if ($component['extra']['type'] == 'textfield') {
+    // Render as textfield.
+    $element['#type'] = 'webform_number';
+
+    // Set the size property based on #max, to ensure consistent behavior for
+    // browsers that do not support type = number.
+    if ($element['#max']) {
+      $element['#size'] =  strlen($element['#max']) + 1;
+    }
+  }
+  else {
+    // Render as select.
+    $element['#type'] = 'select';
+
+    // Create user-specified options list as an array.
+    $element['#options'] = _webform_number_select_options($component);
+
+    // Add default options if using a select list with no default. This trigger's
+    // Drupal 7's adding of the option for us. See form_process_select().
+    if ($component['extra']['type'] == 'select' && $element['#default_value'] === '') {
+      $element['#empty_value'] = '';
+    }
+  }
+
+  // Set user-entered values.
+  if (isset($value[0])) {
+    $element['#default_value'] = $value[0];
+  }
+
+  // Enforce uniqueness.
+  if ($component['extra']['unique']) {
+    $element['#element_validate'][] = 'webform_validate_unique';
+  }
+
+  return $element;
+}
+
+/**
+ * Implements _webform_display_component().
+ */
+function _webform_display_number($component, $value, $format = 'html') {
+  $empty = !isset($value[0]) || $value[0] === '';
+  return array(
+    '#title' => $component['name'],
+    '#weight' => $component['weight'],
+    '#theme' => 'webform_display_number',
+    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
+    '#field_prefix' => $empty ? '' : $component['extra']['field_prefix'],
+    '#field_suffix' => $empty ? '' : $component['extra']['field_suffix'],
+    '#format' => $format,
+    '#value' => $empty ? '' : _webform_number_format($component, $value[0]),
+    '#translatable' => array('title'),
+  );
+}
+
+/**
+ * Format the output of data for this component.
+ */
+function theme_webform_display_number($variables) {
+  $element = $variables['element'];
+  $prefix = $element['#format'] == 'html' ? filter_xss($element['#field_prefix']) : $element['#field_prefix'];
+  $suffix = $element['#format'] == 'html' ? filter_xss($element['#field_suffix']) : $element['#field_suffix'];
+  $value = $element['#format'] == 'html' ? check_plain($element['#value']) : $element['#value'];
+  return $value !== '' ? ($prefix . $value . $suffix) : ' ';
+}
+
+/**
+ * Implements _webform_analysis_component().
+ */
+function _webform_analysis_number($component, $sids = array(), $single = FALSE) {
+  $advanced_stats = $single;
+
+  $query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
+    ->fields('wsd', array('data'))
+    ->condition('nid', $component['nid'])
+    ->condition('cid', $component['cid']);
+
+  if (count($sids)) {
+    $query->condition('sid', $sids, 'IN');
+  }
+
+  $population = array();
+  $submissions = 0;
+  $nonzero = 0;
+  $not_empty = 0;
+  $sum = 0;
+
+  $result = $query->execute();
+  foreach ($result as $data) {
+    $value = trim($data['data']);
+    if ($value == '') {
+      $number = 0.0;
+    }
+    else {
+      $number = $value * 1.0;
+    }
+
+    if ($value !== '') {
+      $not_empty++;
+    }
+
+    if ($number > 0) {
+      $nonzero++;
+      $sum += $number;
+    }
+    $population[] = $number;
+    $submissions++;
+  }
+  sort($population, SORT_NUMERIC);
+
+  // Average and population count.
+  if ($component['extra']['excludezero']) {
+    $average = $nonzero ? ($sum / $nonzero) : 0;
+    $average_title = t('Average !mu excluding zeros/blanks', array('!mu' => $advanced_stats ? '(&mu;)' : ''));
+    // Sample (sub-set of total population).
+    $population_count = $nonzero - 1;
+    $sigma = 'sd';
+    $description = t('sample');
+  }
+  else {
+    $average = $submissions ? ($sum / $submissions) : 0;
+    $average_title = t('Average !mu including zeros/blanks', array('!mu' => $advanced_stats ? '(&mu;)' : ''));
+    // Population.
+    $population_count = $submissions;
+    $sigma = '&sigma;';
+    $description = t('population');
+  }
+
+  // Formatting.
+  $average = _webform_number_format($component, $average);
+  $sum = _webform_number_format($component, $sum);
+
+  $rows[0] = array(t('Zero/blank'), ($submissions - $nonzero));
+  $rows[1] = array(t('User entered value'), $not_empty);
+  $rows[2] = array(t('Sum') . ($advanced_stats ? ' (&Sigma;)' : ''), $sum);
+  $rows[3] = array($average_title, $average);
+
+  if (!$advanced_stats && $sum != 0) {
+    $rows[4] = array('', l(t('More stats »'), 'node/' . $component['nid'] . '/webform-results/analysis/' . $component['cid']));
+  }
+
+  // Normal distribution information.
+  if ($advanced_stats && $population_count && $sum != 0) {
+    // Standard deviation.
+    $stddev = 0;
+    foreach($population as $value) {
+      // Obtain the total of squared variances.
+      $stddev += pow(($value - $average), 2);
+    }
+    if ($population_count > 0) {
+      $stddev = sqrt($stddev / $population_count);
+    }
+    else {
+      $stddev = sqrt($stddev);
+    }
+
+    // Build normal distribution table rows.
+    $count = array();
+    $percent = array();
+    $limit = array();
+    $index = 0;
+
+    $count[] = 0;
+    $limit[] = $average - ($stddev * 4);
+    foreach ($population as $value) {
+      while ($value >= $limit[$index]) {
+        $percent[] = number_format($count[$index] / $population_count * 100, 2, '.', '');
+        $limit[] = $limit[$index] + $stddev;
+        $index += 1;
+        if ($limit[$index] == $average) {
+          $limit[$index] = $limit[$index] + $stddev;
+        }
+        $count[$index] = 0;
+      }
+      $count[$index] += 1;
+    }
+    $percent[] = number_format($count[$index] / $population_count * 100, 2, '.', '');
+
+    // Format normal distribution table output.
+    $stddev = _webform_number_format($component, $stddev);
+    $low = _webform_number_format($component, $population[0]);
+    $high = _webform_number_format($component, end($population));
+    foreach($limit as $key => $value) {
+      $limit[$key] = _webform_number_format($component, $value);
+    }
+
+    // Column headings (override potential theme uppercase, e.g. Seven in D7).
+    $header = array(
+      t('Normal Distribution'),
+      array('data' => '-4' . $sigma, 'style' => 'text-transform: lowercase;',),
+      array('data' => '-3' . $sigma, 'style' => 'text-transform: lowercase;',),
+      array('data' => '-2' . $sigma, 'style' => 'text-transform: lowercase;',),
+      array('data' => '-1' . $sigma, 'style' => 'text-transform: lowercase;',),
+      array('data' => '+1' . $sigma, 'style' => 'text-transform: lowercase;',),
+      array('data' => '+2' . $sigma, 'style' => 'text-transform: lowercase;',),
+      array('data' => '+3' . $sigma, 'style' => 'text-transform: lowercase;',),
+      array('data' => '+4' . $sigma, 'style' => 'text-transform: lowercase;',),
+    );
+
+    // Insert row labels.
+    array_unshift($limit, t('Boundary'));
+    array_unshift($count, t('Count'));
+    array_unshift($percent, t('% of !description', array('!description' => $description)));
+
+    $output = theme('table', array('header' => $header, 'rows' => array($limit, $count, $percent)));
+
+    $rows[4] = array(t('Range'), t('!low to !high', array('!low' => $low, '!high' => $high)));
+    $rows[5] = array(t('Standard deviation (!sigma)', array('!sigma' => $sigma)), $stddev);
+    $rows[6] = array(array('data' => $output, 'colspan' => 2));
+  }
+
+  return $rows;
+}
+
+/**
+ * Implements _webform_table_component().
+ */
+function _webform_table_number($component, $value) {
+  return isset($value[0]) ? _webform_number_format($component, $value[0]) : '';
+}
+
+/**
+ * Implements _webform_csv_headers_component().
+ */
+function _webform_csv_headers_number($component, $export_options) {
+  $header = array();
+  $header[0] = '';
+  $header[1] = '';
+  $header[2] = $component['name'];
+  return $header;
+}
+
+/**
+ * Implements _webform_csv_data_component().
+ */
+function _webform_csv_data_number($component, $export_options, $value) {
+  if (isset($value[0]) && $component['extra']['decimals'] !== '') {
+    $value[0] = number_format($value[0], $component['extra']['decimals'], '.', '');
+  }
+  return isset($value[0]) ? $value[0] : '';
+}
+
+/**
+ * A Drupal Form API Validation function. Validates the entered values from
+ * number components on the client-side form.
+ *
+ * @param $element
+ *   The form element. May either be a select or a webform_number element.
+ * @param $form_state
+ *   The full form state for the webform.
+ * @return
+ *   None. Calls a form_set_error if the number is not valid.
+ */
+function _webform_validate_number($element, &$form_state) {
+  $value = trim($element['#value']);
+  form_set_value($element, $value, $form_state);
+
+  if ($value != '') {
+    // Numeric test.
+    if (is_numeric($value)) {
+      // Range test.
+      if ($element['#min'] != '' && $element['#max'] != '') {
+        // Flip minimum and maximum if needed.
+        if ($element['#max'] > $element['#min']) {
+          $min = $element['#min'];
+          $max = $element['#max'];
+        }
+        else {
+          $min = $element['#max'];
+          $max = $element['#min'];
+        }
+        if ($value > $max || $value < $min) {
+          form_error($element, t('%name field value of @value should be in the range @min to @max.', array('%name' => $element['#title'], '@value' => $value, '@min' => $min, '@max' => $max)));
+        }
+      }
+      elseif ($element['#max'] != '' && $value > $element['#max']) {
+        form_error($element, t('%name field value must be less than @max.', array('%name' => $element['#title'], '@max' => $element['#max'])));
+      }
+      elseif ($element['#min'] != '' && $value < $element['#min']) {
+        form_error($element, t('%name field value must be greater than @min.', array('%name' => $element['#title'], '@min' => $element['#min'])));
+      }
+
+      // Integer test.
+      if ($element['#integer'] && !is_int($value * 1)) {
+        form_error($element, t('%name field value of @value must be an integer.', array('%name' => $element['#title'], '@value' => $value)));
+      }
+
+      // Step test.
+      $starting_number = $element['#min'] ? $element['#min'] : 0;
+      if ($element['#step'] != 0 && fmod($element['#value'] - $starting_number, $element['#step']) != 0) {
+        $samples = array(
+          $starting_number,
+          $starting_number + ($element['#step'] * 1),
+          $starting_number + ($element['#step'] * 2),
+          $starting_number + ($element['#step'] * 3),
+        );
+        if ($starting_number) {
+          form_error($element, t('%name field value must be @start plus a multiple of @step. i.e. @samples, etc.', array('%name' => $element['#title'], '@start' => $element['#min'], '@step' => $element['#step'], '@samples' => implode(', ', $samples))));
+        }
+        else {
+          form_error($element, t('%name field value must be a multiple of @step. i.e. @samples, etc.', array('%name' => $element['#title'], '@step' => $element['#step'], '@samples' => implode(', ', $samples))));
+        }
+      }
+    }
+    else {
+      form_error($element, t('%name field value of @value must be numeric.', array('%name' => $element['#title'], '@value' => $value)));
+    }
+  }
+
+}
+
+/**
+ * Validation of number edit form items.
+ */
+function _webform_edit_number_validate($element, &$form_state) {
+  // Shorten field names.
+  $values = $form_state['values']['extra'];
+
+  switch ($element['#name']) {
+    case 'extra[min]':
+      if ($values['min'] == '') {
+        if ($values['type'] == 'select') {
+          form_error($element, t('Minimum is required when using a select list element.'));
+        }
+      }
+      else {
+        if (!is_numeric($values['min'])) {
+          form_error($element, t('Minimum must be numeric.'));
+        }
+        if ($values['integer'] && !is_int($values['min'] * 1)) {
+          form_error($element, t('Minimum must have an integer value.'));
+        }
+      }
+      break;
+    case 'extra[max]':
+      if ($values['max'] == '') {
+        if ($values['type'] == 'select') {
+          form_error($element, t('Maximum is required when using a select list element.'));
+        }
+      }
+      else {
+        if (!is_numeric($values['max'])) {
+          form_error($element, t('Maximum must be numeric.'));
+        }
+        if ($values['integer'] && !is_int($values['max'] * 1)) {
+          form_error($element, t('Maximum must have an integer value.'));
+        }
+      }
+      break;
+    case 'extra[step]':
+      if ($values['step'] != '') {
+        if (!is_numeric($values['step'])) {
+          form_error($element, t('Step must be numeric.'));
+        }
+        else {
+          if ($values['integer'] && !is_int($values['step'] * 1)) {
+            form_error($element, t('Step must have an integer value.'));
+          }
+        }
+      }
+      break;
+  }
+  return TRUE;
+}
+
+/**
+ * Generate select list options.
+ */
+function _webform_number_select_options($component) {
+  $options = array();
+  $step = abs($component['extra']['step']);
+
+  // Step is optional and defaults to 1.
+  $step = empty($step) ? 1 : $step;
+
+  // Generate list in correct direction.
+  $min = $component['extra']['min'];
+  $max = $component['extra']['max'];
+  $flipped = FALSE;
+  if ($max < $min) {
+    $min = $component['extra']['max'];
+    $max = $component['extra']['min'];
+    $flipped = TRUE;
+  }
+
+  for ($f = $min; $f <= $max; $f += $step) {
+    $options[$f . ''] = $f . '';
+  }
+
+  // TODO: HTML5 browsers apparently do not include the max value if it does
+  // not line up with step. Restore this if needed in the future.
+  // Add end limit if it's been skipped due to step.
+  //if (end($options) != $max) {
+  //  $options[$f] = $max;
+  //}
+
+  if ($flipped) {
+    $options = array_reverse($options, TRUE);
+  }
+
+  // Apply requisite number formatting.
+  foreach ($options as $key => $value) {
+    $options[$key] = _webform_number_format($component, $value);
+  }
+
+  return $options;
+}
+
+/**
+ * Apply number format.
+ */
+function _webform_number_format($component, $value) {
+  // If no decimal places are specified, do a best guess length of decimals.
+  $decimals = $component['extra']['decimals'];
+  if ($decimals === '') {
+    // If it's an integer, no decimals needed.
+    if (is_int(($value . '') * 1)) {
+      $decimals = 0;
+    }
+    else {
+      $decimals = strlen($value) - strrpos($value, '.') - 1;
+    }
+    if ($decimals > 4) {
+      $decimals = 4;
+    }
+  }
+
+  return number_format($value, $decimals, $component['extra']['point'], $component['extra']['separator']);
+}
diff --git a/sites/all/modules/webform/components/pagebreak.inc b/sites/all/modules/webform/components/pagebreak.inc
index 95c838cfd9b244a6a7e0a1fe65330c43e09e9b58..269f2adf26de48bf236fbf70076d5b2320a8dc3e 100644
--- a/sites/all/modules/webform/components/pagebreak.inc
+++ b/sites/all/modules/webform/components/pagebreak.inc
@@ -16,6 +16,8 @@ function _webform_defaults_pagebreak() {
     'weight' => 0,
     'extra' => array(
       'private' => FALSE,
+      'next_page_label' => '',
+      'prev_page_label' => '',
     ),
   );
 }
@@ -43,9 +45,23 @@ function _webform_edit_pagebreak($component) {
     '#value' => '0',
   );
 
-  $form['extra']['description'] = array();  // No description.
   $form['display'] = array('#type' => 'markup'); // Hide the display options.
 
+  $form['extra']['next_page_label'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Next page button label'),
+    '#description' => t('This is used for the <em>Next Page</em> button on the page before this page break. Default: <em>Next Page &gt;</em>'),
+    '#default_value' => $component['extra']['next_page_label'],
+    '#size' => 30,
+  );
+  $form['extra']['prev_page_label'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Prev page button label'),
+    '#description' => t('This is used for the <em>Prev Page</em> button on the page after this page break. Default: <em>&lt; Prev Page</em>'),
+    '#default_value' => $component['extra']['prev_page_label'],
+    '#size' => 30,
+  );
+
   return $form;
 }
 
@@ -70,7 +86,7 @@ function _webform_display_pagebreak($component, $value = NULL, $format = 'html')
     '#title' => $component['name'],
     '#weight' => $component['weight'],
     '#format' => $format,
-    '#webform_component' => $component,
+    '#translatable' => array('title'),
   );
   return $element;
 }
diff --git a/sites/all/modules/webform/components/select.inc b/sites/all/modules/webform/components/select.inc
index 5f32b7251a811195c6fac52c0060c73a198fb4e2..aeeb41d6123478798914c073cb462414f4847e46 100644
--- a/sites/all/modules/webform/components/select.inc
+++ b/sites/all/modules/webform/components/select.inc
@@ -96,7 +96,7 @@ function _webform_edit_select($component) {
   }
 
   if (module_exists('options_element')) {
-    $options = _webform_select_options($component);
+    $options = _webform_select_options($component, FALSE, FALSE);
 
     $form['items'] = array(
       '#type' => 'fieldset',
@@ -115,10 +115,11 @@ function _webform_edit_select($component) {
       '#multiple_toggle' => t('Multiple'),
       '#default_value' => $component['value'],
       '#options' => $options,
+      '#options_readonly' => !empty($component['extra']['options_source']),
       '#key_type' => 'mixed',
       '#key_type_toggle' => t('Customize keys (Advanced)'),
       '#key_type_toggled' => $component['extra']['custom_keys'],
-      '#disabled' => !empty($component['extra']['options_source']),
+      '#default_value_pattern' => '^%.+\[.+\]$',
       '#weight' => 1,
     );
 
@@ -165,7 +166,7 @@ function _webform_edit_select($component) {
     '#type' => 'checkbox',
     '#title' => t('Listbox'),
     '#default_value' => $component['extra']['aslist'],
-    '#description' => t('Check this option if you want the select component to be of listbox type instead of radio buttons or checkboxes.'),
+    '#description' => t('Check this option if you want the select component to be displayed as a select list box instead of radio buttons or checkboxes. Option groups (nested options) are only supported with listbox components.'),
     '#parents' => array('extra', 'aslist'),
   );
   $form['display']['optrand'] = array(
@@ -231,6 +232,11 @@ function _webform_edit_validate_select($element, &$form_state) {
       form_error($element, t('Options within the select list must be unique. The following keys have been used multiple times:') . theme('item_list', array('items' => $duplicate_keys)));
     }
 
+    // Set the listbox option if needed.
+    if (empty($missing_keys) && empty($long_keys) && empty($duplicate_keys)) {
+      $options = _webform_select_options_from_text($element['#value']);
+      _webform_edit_validate_set_aslist($options, $form_state);
+    }
   }
 
   return TRUE;
@@ -251,6 +257,9 @@ function _webform_edit_validate_options($element, &$form_state) {
     $form_state['values']['extra']['multiple'] = $element_options['multiple'];
     $form_state['values']['extra']['custom_keys'] = $element_options['custom_keys'];
     $form_state['values']['value'] = is_array($element_options['default_value']) ? implode(', ', $element_options['default_value']) : $element_options['default_value'];
+
+    // Set the listbox option if needed.
+    _webform_edit_validate_set_aslist($element_options['options'], $form_state);
   }
   // Options saved for grid components.
   else {
@@ -258,24 +267,41 @@ function _webform_edit_validate_options($element, &$form_state) {
   }
 }
 
+/**
+ * Ensure "aslist" is used for option groups. Called from options validations.
+ */
+function _webform_edit_validate_set_aslist($options, &$form_state) {
+  if (empty($form_state['values']['extra']['aslist']) && !empty($options)) {
+    foreach ($options as $option) {
+      if (is_array($option)) {
+        $form_state['values']['extra']['aslist'] = 1;
+        drupal_set_message(t('The component %name has automatically been set to display as a listbox in order to support option groups.', array('%name' => $form_state['values']['name'])), 'warning');
+        break;
+      }
+    }
+  }
+}
+
 /**
  * Implements _webform_render_component().
  */
 function _webform_render_select($component, $value = NULL, $filter = TRUE) {
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
   $element = array(
     '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
     '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
     '#required' => $component['mandatory'],
     '#weight' => $component['weight'],
-    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
     '#theme_wrappers' => array('webform_element'),
     '#pre_render' => array(), // Needed to disable double-wrapping of radios and checkboxes.
-    '#webform_component' => $component,
+    '#translatable' => array('title', 'description', 'options'),
   );
 
   // Convert the user-entered options list into an array.
-  $default_value = $filter ? _webform_filter_values($component['value'], NULL, NULL, NULL, FALSE) : $component['value'];
-  $options = _webform_select_options($component, $filter);
+  $default_value = $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'];
+  $options = _webform_select_options($component, !$component['extra']['aslist'], $filter);
 
   if ($component['extra']['optrand']) {
     _webform_shuffle_options($options);
@@ -287,12 +313,6 @@ function _webform_render_select($component, $value = NULL, $filter = TRUE) {
     $element['#empty_value'] = '';
   }
 
-  // Add default options if using a select list with no default. This trigger's
-  // Drupal 7's adding of the option for us. See @form_process_select().
-  if ($component['extra']['aslist'] && !$component['extra']['multiple'] && $default_value === '') {
-    $element['#empty_value'] = '';
-  }
-
   // Set the component options.
   $element['#options'] = $options;
 
@@ -331,17 +351,18 @@ function _webform_render_select($component, $value = NULL, $filter = TRUE) {
   elseif ($component['extra']['multiple']) {
     $element['#default_value'] = array();
   }
-  else {
-    $element['#default_value'] = FALSE;
-  }
 
   if ($component['extra']['other_option'] && module_exists('select_or_other')) {
     // Set display as a select_or_other element:
     $element['#type'] = 'select_or_other';
     $element['#other'] = !empty($component['extra']['other_text']) ? check_plain($component['extra']['other_text']) : t('Other...');
+    $element['#other_title'] = $element['#title'] . ' ' . $element['#other'];
+    $element['#other_title_display'] = 'invisible';
     $element['#other_unknown_defaults'] = 'other';
     $element['#other_delimiter'] = ', ';
-    $element['#process'] = array('select_or_other_element_process', 'webform_expand_select_or_other');
+    // Merge in Webform's #process function for Select or other.
+    $element['#process'] = array_merge(element_info_property('select_or_other', '#process'), array('webform_expand_select_or_other'));
+
     if ($component['extra']['multiple']) {
       $element['#multiple'] = TRUE;
       $element['#select_type'] = 'checkboxes';
@@ -367,14 +388,18 @@ function _webform_render_select($component, $value = NULL, $filter = TRUE) {
       // Set display as a checkbox set.
       $element['#type'] = 'checkboxes';
       $element['#theme_wrappers'] = array_merge(array('checkboxes'), $element['#theme_wrappers']);
-      // Drupal 6 hack to properly render on multipage forms.
-      $element['#process'] = array('webform_expand_checkboxes', 'webform_expand_select_ids');
+      $element['#process'] = array_merge(element_info_property('checkboxes', '#process'), array('webform_expand_select_ids'));
+
+      // Entirely replace the normal expand checkboxes with our custom version.
+      // This helps render checkboxes in multipage forms.
+      $process_key = array_search('form_process_checkboxes', $element['#process']);
+      $element['#process'][$process_key] = 'webform_expand_checkboxes';
     }
     else {
       // Set display as a radio set.
       $element['#type'] = 'radios';
       $element['#theme_wrappers'] = array_merge(array('radios'), $element['#theme_wrappers']);
-      $element['#process'] = array('form_process_radios', 'webform_expand_select_ids');
+      $element['#process'] = array_merge(element_info_property('radios', '#process'), array('webform_expand_select_ids'));
     }
   }
 
@@ -392,6 +417,10 @@ function webform_expand_select_or_other($element) {
   $element['other']['#validated'] = TRUE;
   $element['other']['#webform_validated'] = FALSE;
 
+  // The Drupal FAPI does not support #title_display inline so we need to move
+  // to a supported value here to be compatible with select_or_other.
+  $element['select']['#title_display'] = $element['#title_display'] === 'inline' ? 'before' : $element['#title_display'];
+
   // If the default value contains "select_or_other" (the key of the select
   // element for the "other..." choice), discard it and set the "other" value.
   if (is_array($element['#default_value']) && in_array('select_or_other', $element['#default_value'])) {
@@ -401,6 +430,11 @@ function webform_expand_select_or_other($element) {
     $element['other']['#default_value'] = implode(', ', $element['#default_value']);
   }
 
+  // Sanitize the options in Select or other check boxes and radio buttons.
+  if ($element['#select_type'] == 'checkboxes' || $element['#select_type'] == 'radios') {
+    $element['select']['#process'] = array_merge(element_info_property($element['#select_type'], '#process'), array('webform_expand_select_ids'));
+  }
+
   return $element;
 }
 
@@ -454,16 +488,15 @@ function webform_expand_select_ids($element) {
  * Implements _webform_display_component().
  */
 function _webform_display_select($component, $value, $format = 'html') {
-  $value = (array) $value;
-  ksort($value);
   return array(
     '#title' => $component['name'],
     '#weight' => $component['weight'],
     '#theme' => 'webform_display_select',
     '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
     '#format' => $format,
-    '#value' => $value,
-    '#webform_component' => $component,
+    '#options' => _webform_select_options($component, !$component['extra']['aslist']),
+    '#value' => (array) $value,
+    '#translatable' => array('title', 'options'),
   );
 }
 
@@ -474,29 +507,18 @@ function _webform_display_select($component, $value, $format = 'html') {
  */
 function _webform_submit_select($component, $value) {
   // Build a list of all valid keys expected to be submitted.
-  $options = _webform_select_options($component);
-  $keys = array();
-  foreach ($options as $option_key => $option_value) {
-    if (is_array($option_key)) {
-      foreach ($option_key as $option_subkey => $option_subvalue) {
-        $keys[$option_subkey] = $option_subkey;
-      }
-    }
-    else {
-      $keys[$option_key] = $option_key;
-    }
-  }
+  $options = _webform_select_options($component, TRUE);
 
   $return = NULL;
   if (is_array($value)) {
     $return = array();
     foreach ($value as $key => $option_value) {
       // Handle options that are specified options.
-      if ($option_value !== '' && isset($keys[$key])) {
+      if ($option_value !== '' && isset($options[$option_value])) {
         // Checkboxes submit an integer value of 0 when unchecked. A checkbox
         // with a value of '0' is valid, so we can't use empty() here.
         if ($option_value === 0 && !$component['extra']['aslist'] && $component['extra']['multiple']) {
-          unset($value[$key]);
+          unset($value[$option_value]);
         }
         else {
           $return[] = $option_value;
@@ -523,8 +545,19 @@ function theme_webform_display_select($variables) {
   $element = $variables['element'];
   $component = $element['#webform_component'];
 
-  // Convert submitted 'safe' values to un-edited, original form.
-  $options = _webform_select_options($component);
+  // Flatten the list of options so we can get values easily. These options
+  // may be translated by hook_webform_display_component_alter().
+  $options = array();
+  foreach ($element['#options'] as $key => $value) {
+    if (is_array($value)) {
+      foreach ($value as $subkey => $subvalue) {
+        $options[$subkey] = $subvalue;
+      }
+    }
+    else {
+      $options[$key] = $value;
+    }
+  }
 
   $items = array();
   if ($component['extra']['multiple']) {
@@ -532,11 +565,11 @@ function theme_webform_display_select($variables) {
       if ($option_value !== '') {
         // Administer provided values.
         if (isset($options[$option_value])) {
-          $items[] = _webform_filter_xss($options[$option_value]);
+          $items[] = $element['#format'] == 'html' ? _webform_filter_xss($options[$option_value]) : $options[$option_value];
         }
         // User-specified in the "other" field.
         else {
-          $items[] = $option_value;
+          $items[] = $element['#format'] == 'html' ? check_plain($option_value) : $option_value;
         }
       }
     }
@@ -576,7 +609,7 @@ function theme_webform_display_select($variables) {
  * Implements _webform_analysis_component().
  */
 function _webform_analysis_select($component, $sids = array(), $single = FALSE) {
-  $options = _webform_select_options($component);
+  $options = _webform_select_options($component, TRUE);
   $show_other_results = $single;
 
   $sid_placeholders = count($sids) ? array_fill(0, count($sids), "'%s'") : array();
@@ -640,19 +673,24 @@ function _webform_analysis_select($component, $sids = array(), $single = FALSE)
  * Implements _webform_table_component().
  */
 function _webform_table_select($component, $value) {
-  $output = '';
+  // Convert submitted 'safe' values to un-edited, original form.
+  $options = _webform_select_options($component, TRUE);
+
+  $value = (array) $value;
+  $items = array();
   // Set the value as a single string.
-  if (is_array($value)) {
-    foreach ($value as $option_value) {
-      if ($option_value !== '') {
-        $output .= _webform_filter_xss($option_value) . '<br />';
+  foreach ($value as $option_value) {
+    if ($option_value !== '') {
+      if (isset($options[$option_value])) {
+        $items[] = _webform_filter_xss($options[$option_value]);
+      }
+      else {
+        $items[] = check_plain($option_value);
       }
     }
   }
-  else {
-    $output .= empty($value[0]) ? '' : _webform_filter_xss($value[0]);
-  }
-  return $output;
+
+  return implode('<br />', $items);
 }
 
 /**
@@ -668,7 +706,7 @@ function _webform_csv_headers_select($component, $export_options) {
   if ($component['extra']['multiple'] && $export_options['select_format'] == 'separate') {
     $headers[0][] = '';
     $headers[1][] = $component['name'];
-    $items = _webform_select_options($component);
+    $items = _webform_select_options($component, TRUE, FALSE);
     if ($component['extra']['other_option']) {
       $other_label = !empty($component['extra']['other_text']) ? check_plain($component['extra']['other_text']) : t('Other...');
       $items[$other_label] = $other_label;
@@ -701,7 +739,7 @@ function _webform_csv_headers_select($component, $export_options) {
  * Implements _webform_csv_data_component().
  */
 function _webform_csv_data_select($component, $export_options, $value) {
-  $options = _webform_select_options($component);
+  $options = _webform_select_options($component, TRUE, FALSE);
   $return = array();
 
   if ($component['extra']['multiple']) {
@@ -751,7 +789,7 @@ function webform_select_options_ajax($source_name = '') {
 
   $component['extra']['options_source'] = $source_name;
   if ($source_name && isset($info[$source_name])) {
-    $options = _webform_select_options_to_text(_webform_select_options($component, FALSE));
+    $options = _webform_select_options_to_text(_webform_select_options($component, !$component['extra']['aslist'], FALSE));
   }
   else {
     $options = '';
@@ -768,12 +806,12 @@ function webform_select_options_ajax($source_name = '') {
 /**
  * Generate a list of options for a select list.
  */
-function _webform_select_options($component, $filter = TRUE) {
+function _webform_select_options($component, $flat = FALSE, $filter = TRUE) {
   if ($component['extra']['options_source']) {
-    $options = _webform_select_options_callback($component['extra']['options_source'], $component);
+    $options = _webform_select_options_callback($component['extra']['options_source'], $component, $flat, $filter);
   }
   else {
-    $options = _webform_select_options_from_text($component['extra']['items'], !$component['extra']['aslist'], $filter);
+    $options = _webform_select_options_from_text($component['extra']['items'], $flat, $filter);
   }
 
   return isset($options) ? $options : array();
@@ -804,10 +842,10 @@ function _webform_select_options_info() {
  *
  * @param $name
  *   The name of the options group.
- * @param $type
- *   The callback to be executed, with "form" or "options".
  * @param $component
  *   The full Webform component.
+ * @param $flat
+ *   Whether the information returned should exclude any nested groups.
  * @param $filter
  *   Whether information returned should be sanitized. Defaults to TRUE.
  */
@@ -894,7 +932,6 @@ function _webform_select_options_from_text($text, $flat = FALSE, $filter = TRUE)
   return $option_cache[$flat][$md5];
 }
 
-
 /**
  * Convert an array of options into text.
  */
diff --git a/sites/all/modules/webform/components/textarea.inc b/sites/all/modules/webform/components/textarea.inc
index b60c38295cbb2f0aa0b1df043c390713e2dd7d33..eb56ec77399c7021ea1277e3fbca6273af724673 100644
--- a/sites/all/modules/webform/components/textarea.inc
+++ b/sites/all/modules/webform/components/textarea.inc
@@ -60,7 +60,7 @@ function _webform_edit_textarea($component) {
     '#type' => 'textfield',
     '#title' => t('Width'),
     '#default_value' => $component['extra']['cols'],
-    '#description' => t('Width of the textarea.') . ' ' . t('Leaving blank will use the default size.'),
+    '#description' => t('Width of the textarea in columns. This property might not have a visual impact depending on the CSS of your site.') . ' ' . t('Leaving blank will use the default size.'),
     '#size' => 5,
     '#maxlength' => 10,
     '#parents' => array('extra', 'cols'),
@@ -69,7 +69,7 @@ function _webform_edit_textarea($component) {
     '#type' => 'textfield',
     '#title' => t('Height'),
     '#default_value' => $component['extra']['rows'],
-    '#description' => t('Height of the textarea.') . ' ' . t('Leaving blank will use the default size.'),
+    '#description' => t('Height of the textarea in rows.') . ' ' . t('Leaving blank will use the default size.'),
     '#size' => 5,
     '#maxlength' => 10,
     '#parents' => array('extra', 'rows'),
@@ -98,24 +98,31 @@ function _webform_edit_textarea($component) {
  * Implements _webform_render_component().
  */
 function _webform_render_textarea($component, $value = NULL, $filter = TRUE) {
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
   $element = array(
     '#type' => 'textarea',
     '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
     '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
-    '#default_value' => $filter ? _webform_filter_values($component['value']) : $component['value'],
+    '#default_value' => $filter ? _webform_filter_values($component['value'], $node) : $component['value'],
     '#required' => $component['mandatory'],
     '#weight' => $component['weight'],
-    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
     '#rows' => !empty($component['extra']['rows']) ? $component['extra']['rows'] : 5,
     '#cols' => !empty($component['extra']['cols']) ? $component['extra']['cols'] : 60,
     '#attributes' => $component['extra']['attributes'],
     '#resizable' => (bool) $component['extra']['resizable'], // MUST be FALSE to disable.
     '#theme_wrappers' => array('webform_element'),
-    '#webform_component' => $component,
+    '#translatable' => array('title', 'description'),
   );
 
   if ($component['extra']['disabled']) {
-    $element['#attributes']['readonly'] = 'readonly';
+    if ($filter) {
+      $element['#attributes']['readonly'] = 'readonly';
+    }
+    else {
+      $element['#disabled'] = TRUE;
+    }
   }
 
   if (isset($value)) {
@@ -136,7 +143,7 @@ function _webform_display_textarea($component, $value, $format = 'html') {
     '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
     '#format' => $format,
     '#value' => isset($value[0]) ? $value[0] : '',
-    '#webform_component' => $component,
+    '#translatable' => array('title'),
   );
 }
 
@@ -145,7 +152,7 @@ function _webform_display_textarea($component, $value, $format = 'html') {
  */
 function theme_webform_display_textarea($variables) {
   $element = $variables['element'];
-  $output = $element['#format'] == 'html' ? str_replace("\n", '<br />', check_plain($element['#value'])) : $element['#value'];
+  $output = $element['#format'] == 'html' ? nl2br(check_plain($element['#value'])) : $element['#value'];
   if (drupal_strlen($output) > 80) {
     $output = ($element['#format'] == 'html') ? '<div class="webform-long-answer">' . $output . '</div>' : $output;
   }
diff --git a/sites/all/modules/webform/components/textfield.inc b/sites/all/modules/webform/components/textfield.inc
index 7c45881010c3374013bd913faad8290a7c0d75ab..11e11ab0167109a193adb7c1141f88e404e423a2 100644
--- a/sites/all/modules/webform/components/textfield.inc
+++ b/sites/all/modules/webform/components/textfield.inc
@@ -69,7 +69,7 @@ function _webform_edit_textfield($component) {
   );
   $form['display']['field_prefix'] = array(
     '#type' => 'textfield',
-    '#title' => t('Label placed to the left of the textfield'),
+    '#title' => t('Prefix text placed to the left of the textfield'),
     '#default_value' => $component['extra']['field_prefix'],
     '#description' => t('Examples: $, #, -.'),
     '#size' => 20,
@@ -79,7 +79,7 @@ function _webform_edit_textfield($component) {
   );
   $form['display']['field_suffix'] = array(
     '#type' => 'textfield',
-    '#title' => t('Label placed to the right of the textfield'),
+    '#title' => t('Postfix text placed to the right of the textfield'),
     '#default_value' => $component['extra']['field_suffix'],
     '#description' => t('Examples: lb, kg, %.'),
     '#size' => 20,
@@ -122,23 +122,30 @@ function _webform_edit_textfield($component) {
  * Implements _webform_render_component().
  */
 function _webform_render_textfield($component, $value = NULL, $filter = TRUE) {
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
   $element = array(
     '#type' => 'textfield',
     '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
     '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
-    '#default_value' => $filter ? _webform_filter_values($component['value'], NULL, NULL, NULL, FALSE) : $component['value'],
+    '#default_value' => $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'],
     '#required' => $component['mandatory'],
     '#weight' => $component['weight'],
     '#field_prefix' => empty($component['extra']['field_prefix']) ? NULL : ($filter ? _webform_filter_xss($component['extra']['field_prefix']) : $component['extra']['field_prefix']),
     '#field_suffix' => empty($component['extra']['field_suffix']) ? NULL : ($filter ? _webform_filter_xss($component['extra']['field_suffix']) : $component['extra']['field_suffix']),
-    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
     '#attributes' => $component['extra']['attributes'],
     '#theme_wrappers' => array('webform_element'),
-    '#webform_component' => $component,
+    '#translatable' => array('title', 'description', 'field_prefix', 'field_suffix'),
   );
 
   if ($component['extra']['disabled']) {
-    $element['#attributes']['readonly'] = 'readonly';
+    if ($filter) {
+      $element['#attributes']['readonly'] = 'readonly';
+    }
+    else {
+      $element['#disabled'] = TRUE;
+    }
   }
 
   // Enforce uniqueness.
@@ -174,7 +181,7 @@ function _webform_display_textfield($component, $value, $format = 'html') {
     '#field_suffix' => $component['extra']['field_suffix'],
     '#format' => $format,
     '#value' => isset($value[0]) ? $value[0] : '',
-    '#webform_component' => $component,
+    '#translatable' => array('title', 'field_prefix', 'field_suffix'),
   );
 }
 
diff --git a/sites/all/modules/webform/components/time.inc b/sites/all/modules/webform/components/time.inc
index f417020700987154476d3279f8a31f6b35cc76cd..f1489a9e8f57d33b68ad6acdd013580422124d6a 100644
--- a/sites/all/modules/webform/components/time.inc
+++ b/sites/all/modules/webform/components/time.inc
@@ -22,6 +22,7 @@ function _webform_defaults_time() {
     'extra' => array(
       'timezone' => 'user',
       'hourformat' => '12-hour',
+      'minuteincrements' => 1,
       'title_display' => 0,
       'description' => '',
       'private' => FALSE,
@@ -62,7 +63,7 @@ function _webform_edit_time($component) {
   $form['extra']['timezone'] = array(
     '#type' => 'radios',
     '#title' => t('Default value timezone'),
-    '#default_value' => empty($component['extra']['timezone']) ? 'user' : $component['extra']['timezone'],
+    '#default_value' => $component['extra']['timezone'],
     '#description' => t('If using relative dates for a default value (e.g. "now") base the current time on this timezone.'),
     '#options' => array('user' => t('User timezone'), 'site' => t('Website timezone')),
     '#weight' => 2,
@@ -70,13 +71,26 @@ function _webform_edit_time($component) {
   );
   $form['display']['hourformat'] = array(
     '#type' => 'radios',
-    '#title' => t('Time Format'),
-    '#default_value' => isset($component['extra']['hourformat']) ? $component['extra']['hourformat'] : '12-hour',
-    '#description' => t('Format the display of the time in 12 or 24 hours.'),
+    '#title' => t('Time format'),
+    '#default_value' => $component['extra']['hourformat'],
     '#options' => array('12-hour' => t('12-hour (am/pm)'), '24-hour' => t('24-hour')),
     '#weight' => 2,
     '#parents' => array('extra', 'hourformat'),
   );
+  $form['display']['minuteincrements'] = array(
+    '#type' => 'select',
+    '#title' => t('Minute increments'),
+    '#default_value' => $component['extra']['minuteincrements'],
+    '#options' => array(
+      1 => t('1 minute'),
+      5 => t('5 minute'),
+      10 => t('10 minute'),
+      15 => t('15 minute'),
+      30 => t('30 minute'),
+    ),
+    '#weight' => 3,
+    '#parents' => array('extra', 'minuteincrements'),
+  );
   return $form;
 }
 
@@ -84,21 +98,24 @@ function _webform_edit_time($component) {
  * Implements _webform_render_component().
  */
 function _webform_render_time($component, $value = NULL, $filter = TRUE) {
+  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
+
   $element = array(
     '#type' => 'webform_time',
     '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
     '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
     '#required' => $component['mandatory'],
     '#weight' => $component['weight'],
-    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
+    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
     '#element_validate' => array('webform_validate_time'),
     '#hourformat' => $component['extra']['hourformat'],
-    '#default_value' => $filter ? _webform_filter_values($component['value'], NULL, NULL, NULL, FALSE) : $component['value'],
+    '#minuteincrements' => $component['extra']['minuteincrements'],
+    '#default_value' => $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'],
     '#timezone' => $component['extra']['timezone'],
     '#process' => array('webform_expand_time'),
     '#theme' => 'webform_time',
     '#theme_wrappers' => array('webform_element'),
-    '#webform_component' => $component,
+    '#translatable' => array('title', 'description'),
   );
 
   // Set the value from Webform if available.
@@ -145,10 +162,43 @@ function webform_expand_time($element) {
   // Generate the choices for drop-down selects.
   $hours[''] = t('hour');
   $minutes[''] = t('minute');
-  for ($i = $first_hour; $i <= $last_hour; $i++) $hours[$i] = $i;
-  for ($i = 0; $i <= 59; $i++) $minutes[$i] = $i < 10 ? "0$i" : $i;
+  for ($i = $first_hour; $i <= $last_hour; $i++) {
+    $hours[$i] = $i;
+  }
+  for ($i = 0; $i <= 59; $i += $element['#minuteincrements']) {
+    $minutes[$i] = $i < 10 ? "0$i" : $i;
+  }
   $ampms = array('am' => t('am'), 'pm' => t('pm'));
 
+  // Adjust the default for minutes if needed, rounding up to the closest value.
+  if (!isset($minutes[$default_values['minute']])) {
+    foreach ($minutes as $minute => $padded_minute) {
+      if ($minute > $default_values['minute']) {
+        $default_values['minute'] = $minute;
+        break;
+      }
+    }
+  }
+
+  // If the above loop didn't set a value, it's because rounding up would go to
+  // the next hour. This gets quite a bit more complicated, since we need to
+  // deal with looping around on hours, as well as flipping am/pm.
+  if (!isset($minutes[$default_values['minute']])) {
+    $default_values['minute'] = 0;
+    $default_values['hour']++;
+    // If the hour rolls over also, set hour to the first hour in the list.
+    if (!isset($hours[$default_values['hour']])) {
+      $default_values['hour'] = $element['#hourformat'] == '12-hour' ? 1 : 0;
+    }
+    // If the hour has been incremented to 12:00 in 12-hour format, flip am/pm.
+    // Note that technically midnight and noon are neither am or pm, but common
+    // convention (and US standard) is to represent 12:00am as midnight.
+    // See http://en.wikipedia.org/wiki/Midnight#Start_and_end_of_day.
+    if ($element['#hourformat'] == '12-hour' && $default_values['hour'] == 12) {
+      $default_values['ampm'] = $default_values['ampm'] == 'am' ? 'pm' : 'am';
+    }
+  }
+
   $element['hour'] = array(
     '#prefix' => '',
     '#type' => 'select',
@@ -245,7 +295,7 @@ function _webform_display_time($component, $value, $format = 'html') {
     '#format' => $format,
     '#hourformat' => $component['extra']['hourformat'],
     '#value' => $value,
-    '#webform_component' => $component,
+    '#translatable' => array('title'),
   );
 }
 
@@ -365,6 +415,7 @@ function webform_time_convert($array, $format) {
     }
     elseif ($format == '24-hour' && isset($array['ampm'])) {
       $array['hour'] = ($array['hour'] < 12 && $array['ampm'] == 'pm') ? $array['hour'] + 12 : (int) $array['hour'];
+      $array['hour'] = ($array['hour'] == 12 && $array['ampm'] == 'am') ? 0 : $array['hour'];
     }
   }
 
diff --git a/sites/all/modules/webform/css/webform-admin.css b/sites/all/modules/webform/css/webform-admin.css
index 76f7c2f8678520ec5306d6d95631ea2aee287729..793e25fa9d2286cce3800c5a1c22798e47163b99 100644
--- a/sites/all/modules/webform/css/webform-admin.css
+++ b/sites/all/modules/webform/css/webform-admin.css
@@ -1,4 +1,9 @@
+/**
+ * @file
+ * Styles that are used when viewing results or modifying webform settings.
+ */
 
+/* Submission view page */
 .webform-submission-info {
   padding: 10px;
 }
@@ -18,6 +23,8 @@
 .webform-submission-next {
   margin-left: 20px;
 }
+
+/* Element for selecting components, i.e. included components for e-mails. */
 .webform-component-select-wrapper {
   max-height: 300px;
   overflow: auto;
@@ -53,6 +60,8 @@ tr.webform-pagebreak td {
 td.webform-pagebreak {
   font-weight: bold;
 }
+
+/* Special theming for the options element widget (if installed) */
 .webform-options-element thead {
   display: none;
 }
@@ -65,6 +74,23 @@ td.webform-pagebreak {
 .webform-options-element fieldset legend {
   display: none;
 }
+
+/* Checkboxes for allowed file extensions */
+table.webform-file-extensions td {
+  vertical-align: top;
+}
+table.webform-file-extensions td .description {
+  white-space: normal;
+}
+table.webform-file-extensions .form-type-checkbox {
+  width: 5em;
+  float: left;
+}
+table.webform-file-extensions input.form-text {
+  width: 95%;
+}
+
+/* General styles */
 .webform-checkbox {
   text-align: center;
   width: 40px;
@@ -79,6 +105,8 @@ td.webform-pagebreak {
 .webform-results-per-page a.selected {
   font-weight: bold;
 }
+
+/* Display of adding/editing components */
 html.js fieldset.webform-position,
 html.js div.webform-position {
   display: none;
diff --git a/sites/all/modules/webform/css/webform.css b/sites/all/modules/webform/css/webform.css
index cd379d005d8718ce67238e914043d63a9e40a2c8..036d199a0e24e4f27a32071ecbaab155ebd693d7 100644
--- a/sites/all/modules/webform/css/webform.css
+++ b/sites/all/modules/webform/css/webform.css
@@ -1,12 +1,15 @@
-
 /**
+ * @file
  * Front-end styling for the display of webforms.
  */
-
 input.webform-calendar {
+  display: none;
   padding: 3px;
   vertical-align: top;
 }
+html.js input.webform-calendar {
+  display: inline;
+}
 .webform-container-inline label {
   display: inline;
   margin-right: 1em;
@@ -18,3 +21,10 @@ input.webform-calendar {
 .webform-container-inline div.description {
   display: block;
 }
+.webform-container-inline div.messages {
+  display: block;
+  float: left;
+}
+.webform-container-inline div.ajax-progress-bar div {
+  display: inherit;
+}
diff --git a/sites/all/modules/webform/includes/webform.components.inc b/sites/all/modules/webform/includes/webform.components.inc
index a0edc75c1e301dbed76041676b7ffdb7b39e9a17..2bc6134eeb56ad466f1189b2fca145c9fde6a4a3 100644
--- a/sites/all/modules/webform/includes/webform.components.inc
+++ b/sites/all/modules/webform/includes/webform.components.inc
@@ -83,6 +83,7 @@ function webform_components_form($form, $form_state, $node) {
   $form['add']['name'] = array(
     '#type' => 'textfield',
     '#size' => 24,
+    '#maxlength' => 255,
   );
 
   $form['add']['type'] = array(
@@ -215,7 +216,7 @@ function theme_webform_components_form($variables) {
       // Add each component to a table row.
       $row_data = array(
         $indents . filter_xss($component['name']),
-        t($component['type']),
+        $form['add']['type']['#options'][$component['type']],
         ($component['value'] == '') ? '-' : $component['value'],
         drupal_render($form['components'][$cid]['mandatory']),
         drupal_render($form['components'][$cid]['cid']) . drupal_render($form['components'][$cid]['pid']) . drupal_render($form['components'][$cid]['weight']),
@@ -339,6 +340,9 @@ function webform_components_form_submit($form, &$form_state) {
   }
 }
 
+/**
+ * Form to configure a webform component.
+ */
 function webform_component_edit_form($form, $form_state, $node, $component, $clone = FALSE) {
   drupal_set_title(t('Edit component: @name', array('@name' => $component['name'])), PASS_THROUGH);
 
@@ -363,15 +367,19 @@ function webform_component_edit_form($form, $form_state, $node, $component, $clo
     '#type' => 'value',
     '#value' => $clone,
   );
-  $form['name'] = array(
-    '#type' => 'textfield',
-    '#default_value' => $component['name'],
-    '#title' => t('Label'),
-    '#description' => t('This is used as a descriptive label when displaying this form element.'),
-    '#required' => TRUE,
-    '#weight' => -10,
-    '#maxlength' => 255,
-  );
+
+  if (webform_component_feature($component['type'], 'title')) {
+    $form['name'] = array(
+      '#type' => 'textfield',
+      '#default_value' => $component['name'],
+      '#title' => t('Label'),
+      '#description' => t('This is used as a descriptive label when displaying this form element.'),
+      '#required' => TRUE,
+      '#weight' => -10,
+      '#maxlength' => 255,
+    );
+  }
+
   $form['form_key'] = array(
     '#type' => 'textfield',
     '#default_value' => empty($component['form_key']) ? _webform_safe_name($component['name']) : $component['form_key'],
@@ -380,13 +388,17 @@ function webform_component_edit_form($form, $form_state, $node, $component, $clo
     '#required' => TRUE,
     '#weight' => -9,
   );
-  $form['extra']['description'] = array(
-    '#type' => 'textarea',
-    '#default_value' => isset($component['extra']['description']) ? $component['extra']['description'] : '',
-    '#title' => t('Description'),
-    '#description' => t('A short description of the field used as help for the user when he/she uses the form.') . theme('webform_token_help'),
-    '#weight' => -1,
-  );
+
+  $form['extra'] = array();
+  if (webform_component_feature($component['type'], 'description')) {
+    $form['extra']['description'] = array(
+      '#type' => 'textarea',
+      '#default_value' => isset($component['extra']['description']) ? $component['extra']['description'] : '',
+      '#title' => t('Description'),
+      '#description' => t('A short description of the field used as help for the user when he/she uses the form.') . theme('webform_token_help'),
+      '#weight' => -1,
+    );
+  }
 
   // Display settings.
   $form['display'] = array(
@@ -414,7 +426,7 @@ function webform_component_edit_form($form, $form_state, $node, $component, $clo
       $form['display']['title_display'] = array(
         '#type' => 'checkbox',
         '#title' => t('Hide label'),
-        '#default_value' => !empty($component['extra']['title_display']),
+        '#default_value' => strcmp($component['extra']['title_display'], 'none') === 0,
         '#return_value' => 'none',
         '#description' => t('Do not display the label of this component.'),
       );
@@ -505,8 +517,8 @@ function webform_component_edit_form($form, $form_state, $node, $component, $clo
     }
     if (webform_component_feature($test_component['type'], 'conditional')) {
       $conditional_components[$cid] = $test_component;
+      $counter++;
     }
-    $counter++;
   }
   if ($component['type'] != 'pagebreak') {
     $fieldset_description = t('Create a rule to control whether or not to skip this page.');
@@ -609,6 +621,9 @@ function webform_component_edit_form_validate($form, &$form_state) {
   }
 }
 
+/**
+ * Submit handler for webform_component_edit_form().
+ */
 function webform_component_edit_form_submit($form, &$form_state) {
   // Ensure a webform record exists.
   $node = node_load($form_state['values']['nid']);
@@ -617,7 +632,7 @@ function webform_component_edit_form_submit($form, &$form_state) {
   // Remove empty extra values.
   if (isset($form_state['values']['extra'])) {
     foreach ($form_state['values']['extra'] as $key => $value) {
-      if ($value  === '') {
+      if ($value  === '' && !isset($form['display'][$key]['#options'][''])) {
         unset($form_state['values']['extra'][$key]);
       }
     }
@@ -658,6 +673,9 @@ function webform_component_edit_form_submit($form, &$form_state) {
   $form_state['redirect'] = array('node/' . $node->nid . '/webform/components', isset($cid) ? array('query' => array('cid' => $cid)) : array());
 }
 
+/**
+ * Form to confirm deletion of a component.
+ */
 function webform_component_delete_form($form, $form_state, $node, $component) {
   $cid = $component['cid'];
 
@@ -683,6 +701,9 @@ function webform_component_delete_form($form, $form_state, $node, $component) {
   return confirm_form($form, $question, 'node/' . $node->nid . '/webform/components', $description, t('Delete'));
 }
 
+/**
+ * Submit handler for webform_component_delete_form().
+ */
 function webform_component_delete_form_submit($form, &$form_state) {
   // Delete the component.
   $node = $form_state['values']['node'];
@@ -840,6 +861,7 @@ function webform_component_delete($node, $component) {
 
 /**
  * Recursively insert components into the database.
+ *
  * @param $node
  *   The node object containing the current webform.
  * @param $component
@@ -847,8 +869,9 @@ function webform_component_delete($node, $component) {
  */
 function webform_component_clone(&$node, &$component) {
   $original_cid = $component['cid'];
-  unset($component['cid']);
+  $component['cid'] = NULL;
   $new_cid = webform_component_insert($component);
+  $component['cid'] = $new_cid;
   if (webform_component_feature($component['type'], 'group')) {
     foreach ($node->webform['components'] as $cid => $child_component) {
       if ($child_component['pid'] == $original_cid) {
@@ -869,10 +892,13 @@ function webform_component_feature($type, $feature) {
   $components = webform_components();
   $defaults = array(
     'csv' => TRUE,
+    'default_value' => TRUE,
+    'description' => TRUE,
     'email' => TRUE,
     'email_address' => FALSE,
     'email_name' => FALSE,
     'required' => TRUE,
+    'title' => TRUE,
     'title_display' => TRUE,
     'title_inline' => TRUE,
     'conditional' => TRUE,
@@ -949,8 +975,9 @@ function webform_component_list($node, $component_filter = NULL, $indent = TRUE,
 function webform_component_select($element) {
   // Split the select list into checkboxes.
   foreach ($element['#options'] as $key => $label) {
-    $indents = 0;
-    $label = preg_replace('/^([\-])+/', '', $label, -1, $indents);
+    $label_length = strlen($label);
+    $label = preg_replace('/^(\-)+/', '', $label);
+    $indents = $label_length - strlen($label);
     $element[$key] = array(
       '#title' => $label,
       '#type' => 'checkbox',
@@ -1056,15 +1083,16 @@ function webform_validate_unique($element, $form_state) {
   if ($element['#value'] !== '') {
     $nid = $form_state['values']['details']['nid'];
     $sid = $form_state['values']['details']['sid'];
-    $count = db_select('webform_submitted_data')
+    $query = db_select('webform_submitted_data')
       ->fields('webform_submitted_data', array('sid'))
       ->condition('nid', $nid)
       ->condition('cid', $element['#webform_component']['cid'])
-      ->condition('sid', $sid, '<>')
       ->condition('data', $element['#value'])
-      ->range(0, 1) // More efficient than using countQuery() for data checks.
-      ->execute()
-      ->fetchField();
+      ->range(0, 1); // More efficient than using countQuery() for data checks.
+    if ($sid) {
+      $query->condition('sid', $sid, '<>');
+    }
+    $count = $query->execute()->fetchField();
     if ($count) {
       form_error($element, t('The value %value has already been submitted once for the %title field. You may have already submitted this form, or you need to use a different value.', array('%value' => $element['#value'], '%title' => $element['#title'])));
     }
diff --git a/sites/all/modules/webform/includes/webform.emails.inc b/sites/all/modules/webform/includes/webform.emails.inc
index 4c44a019e98f7ff6178bc131e31c6d92f1c3bb12..cfd7cb5706657221f6eb166db95d4e7f0f4d0994 100644
--- a/sites/all/modules/webform/includes/webform.emails.inc
+++ b/sites/all/modules/webform/includes/webform.emails.inc
@@ -484,7 +484,7 @@ function webform_email_delete_form($form, $form_state, $node, $email) {
 }
 
 /**
- * Submit handler for webform_component_delete_form().
+ * Submit handler for webform_email_delete_form().
  */
 function webform_email_delete_form_submit($form, &$form_state) {
   // Delete the e-mail settings.
diff --git a/sites/all/modules/webform/includes/webform.options.inc b/sites/all/modules/webform/includes/webform.options.inc
index c968bead371ae1a9e47d0a280c2884ff2d62e322..0e9bffb3ecc2d19d1ffa356f994aeda3f5e3086c 100644
--- a/sites/all/modules/webform/includes/webform.options.inc
+++ b/sites/all/modules/webform/includes/webform.options.inc
@@ -37,7 +37,7 @@ function _webform_options_info() {
 /**
  * Option list containing the days of the week.
  */
-function webform_options_days() {
+function webform_options_days($component, $flat, $filter, $arguments) {
   $days = array(
     'sunday' => t('Sunday'),
     'monday' => t('Monday'),
@@ -60,7 +60,7 @@ function webform_options_days() {
 /**
  * Options list containing country names.
  */
-function webform_options_countries() {
+function webform_options_countries($component, $flat, $filter, $arguments) {
   include_once DRUPAL_ROOT . '/includes/locale.inc';
   return country_get_list();
 }
@@ -68,7 +68,7 @@ function webform_options_countries() {
 /**
  * Options list containing United States states and territories.
  */
-function webform_options_united_states() {
+function webform_options_united_states($component, $flat, $filter, $arguments) {
   return array(
     'AL' => t('Alabama'),
     'AK' => t('Alaska'),
diff --git a/sites/all/modules/webform/includes/webform.pages.inc b/sites/all/modules/webform/includes/webform.pages.inc
index f75250bf7e7d66875a83c3c8f70c6de04c88d4f2..97c9395d9f446d7a59198c695d95f498fdf613ff 100644
--- a/sites/all/modules/webform/includes/webform.pages.inc
+++ b/sites/all/modules/webform/includes/webform.pages.inc
@@ -12,6 +12,13 @@
 function webform_configure_form($form, &$form_state, $node) {
   $form['#attached']['library'][] = array('webform', 'admin');
 
+  $form['#node'] = $node;
+
+  $form['#submit'] = array(
+    'webform_configure_form_submit',
+    'webform_configure_form_submit_save',
+  );
+
   $form['nid'] = array(
     '#type' => 'value',
     '#value' => $node->nid,
@@ -76,16 +83,48 @@ function webform_configure_form($form, &$form_state, $node) {
     '#maxlength' => 255,
   );
 
-  // Submission limit settings.
+  // Submission limit settings for all submissions.
+  $form['submission']['total_submit_limit'] = array(
+    '#type' => 'item',
+    '#title' => t('Total submissions limit'),
+    '#theme' => 'webform_advanced_total_submit_limit_form',
+    '#description' => t('Limit the total number of allowed submissions.'),
+  );
+  $form['submission']['total_submit_limit']['enforce_total_limit'] = array(
+    '#type' => 'radios',
+    '#options' => array('no' => t('Unlimited'), 'yes' => 'Limit to !count total submission(s) !timespan'),
+    '#default_value' => $node->webform['total_submit_limit'] == -1 ? 'no' : 'yes',
+    '#parents' => array('enforce_total_limit'),
+  );
+  $form['submission']['total_submit_limit']['total_submit_limit'] = array(
+    '#type' => 'textfield',
+    '#maxlength' => 8,
+    '#size' => 8,
+    '#default_value' => $node->webform['total_submit_limit'] != -1 ? $node->webform['total_submit_limit'] : '',
+    '#parents' => array('total_submit_limit'),
+  );
+  $form['submission']['total_submit_limit']['total_submit_interval'] = array(
+    '#type' => 'select',
+    '#options' => array(
+      '-1' => t('ever'),
+      '3600' => t('every hour'),
+      '86400' => t('every day'),
+      '604800' => t('every week'),
+    ),
+    '#default_value' => $node->webform['total_submit_interval'],
+    '#parents' => array('total_submit_interval'),
+  );
+
+  // Submission limit per user settings.
   $form['submission']['submit_limit'] = array(
     '#type' => 'item',
-    '#title' => t('Submission limit'),
+    '#title' => t('Per user submission limit'),
     '#theme' => 'webform_advanced_submit_limit_form',
     '#description' => t('Limit the number of submissions <em>per user</em>. A user is identified by their user login if logged-in, or by their IP Address and Cookie if anonymous. Use of cookies may be modified in the global <a href="!url">Webform settings</a>.', array('!url' => url('admin/config/content/webform'))),
   );
   $form['submission']['submit_limit']['enforce_limit'] = array(
     '#type' => 'radios',
-    '#options' => array('no' => t('Unlimited'), 'yes' => 'Limit to !count submission(s) !timespan'),
+    '#options' => array('no' => t('Unlimited'), 'yes' => 'Limit each user to !count submission(s) !timespan'),
     '#default_value' => $node->webform['submit_limit'] == -1 ? 'no' : 'yes',
     '#parents' => array('enforce_limit'),
   );
@@ -191,10 +230,14 @@ function webform_configure_form($form, &$form_state, $node) {
   );
   /* End Advanced Settings Form */
 
-  $form['submit'] = array(
+  $form['actions'] = array(
+    '#type' => 'actions',
+    '#weight' => 300,
+  );
+
+  $form['actions']['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Save configuration'),
-    '#weight' => 300,
   );
 
   return $form;
@@ -240,7 +283,8 @@ function webform_configure_form_validate($form, &$form_state) {
  * Submit handler for webform_configure_form().
  */
 function webform_configure_form_submit($form, &$form_state) {
-  $node = node_load($form_state['values']['nid']);
+  // Edit the node by reference just to shorten it up.
+  $node = &$form['#node'];
 
   // Save the confirmation.
   $node->webform['confirmation'] = $form_state['values']['confirmation']['value'];
@@ -277,14 +321,31 @@ function webform_configure_form_submit($form, &$form_state) {
     $node->webform['submit_interval'] = $form_state['values']['submit_interval'];
   }
 
+  // Set the total submit limit to -1 if set to unlimited.
+  if ($form_state['values']['enforce_total_limit'] == 'no') {
+    $node->webform['total_submit_limit'] = -1;
+    $node->webform['total_submit_interval'] = -1;
+  }
+  else {
+    $node->webform['total_submit_limit'] = $form_state['values']['total_submit_limit'];
+    $node->webform['total_submit_interval'] = $form_state['values']['total_submit_interval'];
+  }
+
   // Set submit notice.
   $node->webform['submit_notice'] = $form_state['values']['submit_notice'];
 
   // Set submit button text.
   $node->webform['submit_text'] = $form_state['values']['submit_text'];
+}
 
-  node_save($node);
-
+/**
+ * Submit handler for webform_configure_form() that saves the node.
+ *
+ * This is separate from webform_configure_form_submit() to allow other modules
+ * to add properties if needed into the $form['#node'] object before save.
+ */
+function webform_configure_form_submit_save($form, &$form_state) {
+  node_save($form['#node']);
   drupal_set_message(t('The form settings have been updated.'));
 }
 
@@ -326,8 +387,31 @@ function theme_webform_advanced_submit_limit_form($variables) {
 
   $form['enforce_limit']['no']['#theme_wrappers'] = array('webform_inline_radio');
   $form['enforce_limit']['yes']['#title'] = NULL;
-  $form['enforce_limit']['yes']['#inline_element'] = t('Limit to !count submission(s) !timespan', $replacements);
+  $form['enforce_limit']['yes']['#inline_element'] = t('Limit each user to !count submission(s) !timespan', $replacements);
   $form['enforce_limit']['yes']['#theme_wrappers'] = array('webform_inline_radio');
 
   return drupal_render_children($form);
 }
+
+/**
+ * Theme the total submit limit fieldset on the webform node form.
+ */
+function theme_webform_advanced_total_submit_limit_form($variables) {
+  $form = $variables['form'];
+  $form['total_submit_limit']['#attributes']['class'] = array('webform-set-active');
+  $form['total_submit_interval']['#attributes']['class'] = array('webform-set-active');
+  // Remove div wrappers around limit options.
+  $form['total_submit_limit']['#theme_wrappers'] = array();
+  $form['total_submit_interval']['#theme_wrappers'] = array();
+  $replacements = array(
+    '!count' => drupal_render($form['total_submit_limit']),
+    '!timespan' => drupal_render($form['total_submit_interval']),
+  );
+
+  $form['enforce_total_limit']['no']['#theme_wrappers'] = array('webform_inline_radio');
+  $form['enforce_total_limit']['yes']['#title'] = NULL;
+  $form['enforce_total_limit']['yes']['#inline_element'] = t('Limit to !count total submission(s) !timespan', $replacements);
+  $form['enforce_total_limit']['yes']['#theme_wrappers'] = array('webform_inline_radio');
+
+  return drupal_render_children($form);
+}
diff --git a/sites/all/modules/webform/includes/webform.report.inc b/sites/all/modules/webform/includes/webform.report.inc
index 157888f350ac199816f088925d5a1f9d34ac671e..8ceb920a37f1aaff5512e36cca71f97bf0ab9bba 100644
--- a/sites/all/modules/webform/includes/webform.report.inc
+++ b/sites/all/modules/webform/includes/webform.report.inc
@@ -45,7 +45,7 @@ function webform_results_submissions($node, $user_filter, $pager_count) {
   foreach ($submissions as $sid => $submission) {
     $row = array(
       $submission->is_draft ? t('@sid (draft)', array('@sid' => $sid)) : $sid,
-      format_date($submission->submitted, 'small'),
+      format_date($submission->submitted, 'short'),
     );
     if (webform_results_access($node, $user)) {
       $row[] = theme('username', array('account' => $submission));
@@ -231,7 +231,7 @@ function theme_webform_results_table($variables) {
   // Generate a row for each submission.
   foreach ($submissions as $sid => $submission) {
     $cell[] = l($sid, 'node/' . $node->nid . '/submission/' . $sid);
-    $cell[] = format_date($submission->submitted, 'small');
+    $cell[] = format_date($submission->submitted, 'short');
     $cell[] = theme('username', array('account' => $submission));
     $cell[] = $submission->remote_addr;
     $component_headers = array();
@@ -398,45 +398,50 @@ function webform_results_download_form($form, &$form_state, $node) {
     '#type' => 'fieldset',
     '#title' => t('Download range options'),
     '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-    '#tree' => FALSE,
-    '#theme' => 'webform_results_download_form',
+    '#collapsed' => TRUE,
+    '#tree' => TRUE,
+    '#theme' => 'webform_results_download_range',
+    '#element_validate' => array('webform_results_download_range_validate'),
+    '#after_build' => array('webform_results_download_range_after_build'),
   );
 
-  $form['range']['type'] = array(
+  $form['range']['range_type'] = array(
     '#type' => 'radios',
     '#options' => array(
-      0 => t('All submissions'),
-      1 => t('Only new submissions since your last download'),
-      2 => t('Only the latest'),
-      3 => t('All submissions starting from'),
+      'all' => t('All submissions'),
+      'new' => t('Only new submissions since your last download'),
+      'latest' => t('Only the latest'),
+      'range' => t('All submissions starting from'),
     ),
-    '#default_value' => isset($form_state['values']['type']) ? $form_state['values']['type'] : 0,
-    '#description' => t('Select or specify a range of submissions to download.'),
-    '#after_build' => array('webform_download_get_totals'),
+    '#default_value' => 'all',
   );
   $form['range']['latest'] = array(
     '#type' => 'textfield',
     '#size' => 5,
     '#maxlength' => 8,
     '#default_value' => isset($form_state['values']['latest']) ? $form_state['values']['latest'] : '',
-    '#description' => t('submissions'),
   );
   $form['range']['start'] = array(
     '#type' => 'textfield',
     '#size' => 5,
     '#maxlength' => 8,
-    '#description' => t(' to (optional) end:'),
-    '#default_value' => isset($form_state['values']['start']) ? $form_state['values']['start'] : '',
+    '#default_value' => '',
   );
   $form['range']['end'] = array(
     '#type' => 'textfield',
     '#size' => 5,
     '#maxlength' => 8,
-    '#default_value' => isset($form_state['values']['end']) ? $form_state['values']['end'] : '',
+    '#default_value' => '',
     '#description' => '',
   );
 
+  // By default results are downloaded. User can override this value if
+  // programmatically submitting this form.
+  $form['download'] = array(
+    '#type' => 'value',
+    '#default_value' => TRUE
+  );
+
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Download'),
@@ -445,97 +450,156 @@ function webform_results_download_form($form, &$form_state, $node) {
   return $form;
 }
 
-function webform_results_download_form_validate(&$form, &$form_state) {
-  switch ($form['range']['type']['#value']) {
-    case 2:
+/**
+ * FormAPI element validate function for the range fieldset.
+ */
+function webform_results_download_range_validate($element, $form_state) {
+  switch ($element['range_type']['#value']) {
+    case 'latest':
       // Download latest x submissions.
-      if ($form['range']['latest']['#value'] == '') {
-        form_error($form['range']['latest'], t('Latest number of submissions field is required'));
+      if ($element['latest']['#value'] == '') {
+        form_error($element['latest'], t('Latest number of submissions field is required.'));
       }
       else{
-        if (!is_numeric($form['range']['latest']['#value'])) {
-          form_error($form['range']['latest'], t('Latest number of submissions must be numeric'));
+        if (!is_numeric($element['latest']['#value'])) {
+          form_error($element['latest'], t('Latest number of submissions must be numeric.'));
         }
         else{
-          if ($form['range']['latest']['#value'] <= 0) {
-            form_error($form['range']['latest'], t('Latest number of submissions must be greater than 0'));
+          if ($element['latest']['#value'] <= 0) {
+            form_error($element['latest'], t('Latest number of submissions must be greater than 0.'));
           }
         }
       }
-    break;
-    case 3:
+      break;
+    case 'range':
       // Download Start-End range of submissions.
       // Start submission number.
-      if ($form['range']['start']['#value'] == '') {
-        form_error($form['range']['start'], t('Start submission number is required'));
+      if ($element['start']['#value'] == '') {
+        form_error($element['start'], t('Start submission number is required.'));
       }
       else{
-        if (!is_numeric($form['range']['start']['#value'])) {
-          form_error($form['range']['start'], t('Start submission number must be numeric'));
+        if (!is_numeric($element['start']['#value'])) {
+          form_error($element['start'], t('Start submission number must be numeric.'));
         }
         else{
-          if ($form['range']['start']['#value'] <= 0) {
-            form_error($form['range']['start'], t('Start submission number must be greater than 0'));
+          if ($element['start']['#value'] <= 0) {
+            form_error($element['start'], t('Start submission number must be greater than 0.'));
           }
         }
       }
       // End submission number.
-      if ($form['range']['end']['#value'] != '') {
-        if (!is_numeric($form['range']['end']['#value'])) {
-          form_error($form['range']['end'], t('End submission number must be numeric'));
+      if ($element['end']['#value'] != '') {
+        if (!is_numeric($element['end']['#value'])) {
+          form_error($element['end'], t('End submission number must be numeric.'));
         }
         else{
-          if ($form['range']['end']['#value'] <= 0) {
-            form_error($form['range']['end'], t('End submission number must be greater than 0'));
+          if ($element['end']['#value'] <= 0) {
+            form_error($element['end'], t('End submission number must be greater than 0.'));
           }
           else{
-            if ($form['range']['end']['#value'] < $form['range']['start']['#value']) {
-              form_error($form['range']['end'], t('End submission number may not be smaller than Start submission number'));
+            if ($element['end']['#value'] < $element['start']['#value']) {
+              form_error($element['end'], t('End submission number may not be less than Start submission number.'));
             }
           }
         }
       }
-    break;
+      break;
   }
 
 }
 
+/**
+ * Validate handler for webform_results_download_form().
+ */
 function webform_results_download_form_submit(&$form, &$form_state) {
-  // Retrieve the list of required sid's.
-  $sids = webform_download_sids($form_state);
-
   $options = array(
     'delimiter' => $form_state['values']['delimiter'],
     'components' => array_keys(array_filter($form_state['values']['components'])),
     'select_keys' => $form_state['values']['select_keys'],
     'select_format' => $form_state['values']['select_format'],
-    'type' => $form_state['values']['type'],
-    'sids' => $sids,
+    'range_type' => $form_state['values']['range']['range_type'],
+    'download' => $form_state['values']['download'],
   );
-  webform_results_download($form_state['values']['node'], $form_state['values']['format'], $options);
+
+  // Retrieve the list of required SIDs.
+  if ($options['range_type'] != 'all') {
+    $options['sids'] = webform_download_sids($form_state['values']['node']->nid, $form_state['values']['range']);
+  }
+
+  $export_info = webform_results_export($form_state['values']['node'], $form_state['values']['format'], $options);
+
+  // If webform result file should be downloaded, send the file to the browser,
+  // otherwise save information about the created file in $form_state.
+  if ($options['download']) {
+    webform_results_download($form_state['values']['node'], $export_info);
+  }
+  else {
+    $form_state['export_info'] = $export_info;
+  }
 }
 
 /**
- * Theme the output of the export form.
+ * FormAPI after build function for the download range fieldset.
  */
-function theme_webform_results_download_form($variables) {
+function webform_results_download_range_after_build($element, &$form_state) {
+  $node = $form_state['values']['node'];
+
+  // Build a list of counts of new and total submissions.
+  $count = webform_get_submission_count($node->nid);
+  $sids = webform_download_sids($node->nid, array('range_type' => 'new'));
+
+  $last_download = webform_download_last_download_info($node->nid);
+
+  $element['#webform_download_info']['sid'] = $last_download ? $last_download['sid'] : 0;
+  $element['#webform_download_info']['requested'] = $last_download ? $last_download['requested'] : $node->created;
+  $element['#webform_download_info']['total'] = $count;
+  $element['#webform_download_info']['new'] = count($sids);
+
+  return $element;
+}
+
+/**
+ * Theme the output of the export range fieldset.
+ */
+function theme_webform_results_download_range($variables) {
   drupal_add_library('webform', 'admin');
 
-  $form = $variables['form'];
+  $element = $variables['element'];
+  $download_info = $element['#webform_download_info'];
+
+  // Set description for total of all submissions.
+  $element['range_type']['all']['#theme_wrappers'] = array('webform_inline_radio');
+  $element['range_type']['all']['#description'] = '(' . t('@count total', array('@count' => $download_info['total'])) . ')';
+
+  // Set description for "New submissions since last download".
+  $format = webform_date_format('short');
+  $requested_date = format_date($download_info['requested'], 'custom', $format);
+  $element['range_type']['new']['#theme_wrappers'] = array('webform_inline_radio');
+  $element['range_type']['new']['#description'] = '(' . t('@count new since @date', array('@count' => $download_info['new'], '@date' => $requested_date)) . ')';
+
+
+  // Disable option if there are no new submissions.
+  if ($download_info['new'] == 0) {
+    $element['range_type']['new']['#attributes']['disabled'] = 'disabled';
+  }
 
-  // All submissions option.
-  $form['type']['0']['#theme_wrappers'] = array('webform_inline_radio');
-  // Only since last download option.
-  $form['type']['1']['#theme_wrappers'] = array('webform_inline_radio');
   // Render latest x submissions option.
-  $form['type']['2']['#theme_wrappers'] = array('webform_inline_radio');
-  $form['type']['2']['#inline_element'] = drupal_render($form['latest']);
+  $element['latest']['#attributes']['class'] = array('webform-set-active');
+  $element['range_type']['latest']['#theme_wrappers'] = array('webform_inline_radio');
+  $element['range_type']['latest']['#inline_element'] = t('Only the latest !number submissions', array('!number' => drupal_render($element['latest'])));
+  $element['range_type']['latest']['#title'] = NULL;
+
   // Render Start-End submissions option.
-  $form['type']['3']['#theme_wrappers'] = array('webform_inline_radio');
-  $form['type']['3']['#inline_element'] = drupal_render($form['start']) . drupal_render($form['end']);
+  $element['start']['#attributes']['class'] = array('webform-set-active');
+  $element['end']['#attributes']['class'] = array('webform-set-active');
+  $element['range_type']['range']['#theme_wrappers'] = array('webform_inline_radio');
+  $element['range_type']['range']['#inline_element'] = t('All submissions starting from: !start and optionally to: !end', array('!start' => drupal_render($element['start']), '!end' => drupal_render($element['end'])));
+  $element['range_type']['range']['#title'] = NULL;
 
-  return drupal_render_children($form);
+  $last_sid = $download_info['sid'] ? $download_info['sid'] : drupal_placeholder(t('none'));
+  $element['range_type']['range']['#description'] = '(' . t('Use submission IDs for the range. Last downloaded end SID: !sid.', array('!sid' => $last_sid)) . ')';
 
+  return drupal_render_children($element);
 }
 
 /**
@@ -608,7 +672,7 @@ function theme_webform_results_download_select_format($variables) {
  *   27 Feb 2005       ,1035,56 ,212   ,X         ,        ,        ,..,       ,X          ,X       ,X       ,..,X       ,How is this?
  *
  */
-function webform_results_download($node, $format = 'delimited', $options = array()) {
+function webform_results_export($node, $format = 'delimited', $options = array()) {
   global $user;
   module_load_include('inc', 'webform', 'includes/webform.export');
   module_load_include('inc', 'webform', 'includes/webform.components');
@@ -629,9 +693,8 @@ function webform_results_download($node, $format = 'delimited', $options = array
       'components' => array_merge(array_keys($submission_information), array_keys(webform_component_list($node, 'csv', TRUE))),
       'select_keys' => 0,
       'select_format' => 'separate',
-      'type' => 0,
+      'range_type' => 'all',
     );
-    $options['sids'] = webform_download_sids(array('values' => array('node' => $node, 'type' => 0)));
   }
   else {
     foreach ($submission_information as $key => $label) {
@@ -698,7 +761,7 @@ function webform_results_download($node, $format = 'delimited', $options = array
       $row[] = $sid;
     }
     if (isset($submission_information['time'])) {
-      $row[] = format_date($submission->submitted, 'small');
+      $row[] = format_date($submission->submitted, 'short');
     }
     if (isset($submission_information['draft'])) {
       $row[] = $submission->is_draft;
@@ -724,7 +787,7 @@ function webform_results_download($node, $format = 'delimited', $options = array
             $row = array_merge($row, array_values($data));
           }
           else {
-            $row[] = empty($data) ? '' : $data;
+            $row[] = isset($data) ? $data : '';
           }
         }
       }
@@ -740,13 +803,34 @@ function webform_results_download($node, $format = 'delimited', $options = array
   // Close the file.
   @fclose($handle);
 
+  $export_info['options'] = $options;
+  $export_info['file_name'] = $file_name;
+  $export_info['exporter'] = $exporter;
+  $export_info['row_count'] = $row_count;
+  $export_info['last_sid'] = $sid;
+
+  return $export_info;
+}
+
+/**
+ * Send a generated webform results file to the user's browser.
+ *
+ * @param $node
+ *   The webform node.
+ * @param $export_info
+ *   Export information array retrieved from webform_results_export().
+ */
+function webform_results_download($node, $export_info) {
+  global $user;
+
+  // $exporter, $file_name, $row_count
   $export_name = _webform_safe_name($node->title);
-  $exporter->set_headers($export_name);
-  @readfile($file_name);  // The @ makes it silent.
-  @unlink($file_name);  // Clean up, the @ makes it silent.
+  $export_info['exporter']->set_headers($export_name);
+  @readfile($export_info['file_name']);  // The @ makes it silent.
+  @unlink($export_info['file_name']);  // Clean up, the @ makes it silent.
 
   // Update user last downloaded sid if required.
-  if ($options['type'] < 2 && $row_count > 0) {
+  if ($export_info['options']['range_type'] != 'range' && $export_info['row_count'] > 0) {
     // Delete existing record.
     db_delete('webform_last_download')
       ->condition('nid', $node->nid)
@@ -757,8 +841,8 @@ function webform_results_download($node, $format = 'delimited', $options = array
       ->fields(array(
         'nid' => $node->nid,
         'uid' => $user->uid,
-        'sid' => $sid,
-        'requested' => time(),
+        'sid' => $export_info['last_sid'],
+        'requested' => REQUEST_TIME,
       ))
       ->execute();
   }
@@ -843,117 +927,79 @@ function theme_webform_results_analysis($variables) {
   return theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('class' => array('webform-results-analysis'))));
 }
 
-// Obtain list of required sid's.
-function webform_download_sids($form_state) {
+/**
+ * Given a set of range options, retrieve a set of SIDs for a webform node.
+ */
+function webform_download_sids($nid, $range_options, $uid = NULL) {
   $query = db_select('webform_submissions', 'ws')
     ->fields('ws', array('sid'))
-    ->condition('nid', $form_state['values']['node']->nid);
+    ->condition('nid', $nid);
 
-  switch ($form_state['values']['type']) {
-    case 0:
-      // All Submissions
+  switch ($range_options['range_type']) {
+    case 'all':
+      // All Submissions.
       $query->orderBy('sid', 'ASC');
-    break;
-    case 1:
-      // All Since Last Download
-      $last = webform_download_last_downloaded_sid($form_state['values']['node']->nid, 'sid');
-      $query->condition('sid', $last, '>')
+      break;
+    case 'new':
+      // All Since Last Download.
+      $download_info = webform_download_last_download_info($nid, $uid);
+      $last_sid = $download_info ? $download_info['sid'] : 0;
+      $query
+        ->condition('sid', $last_sid, '>')
         ->orderBy('sid', 'ASC');
-    break;
-    case 2:
-      // Last x Submissions
-      $query->orderBy('sid', 'DESC')
-        ->range(0, $form_state['values']['latest']);
-    break;
-    case 3:
-      // Submissions Start-End
-      if (!is_numeric($form_state['values']['end'])){
-        // Set End to maximum integer value (assumed 32-bit).
-        $form_state['values']['end'] = 2147483647;
+      break;
+    case 'latest':
+      // Last x Submissions.
+      $query
+        ->orderBy('sid', 'DESC')
+        ->range(0, $range_options['latest']);
+      break;
+    case 'range':
+      // Submissions Start-End.
+      $query->condition('sid', $range_options['start'], '>=');
+      if ($range_options['end']){
+        $query->condition('sid', $range_options['end'], '<=');
       }
-      $query->condition('sid', $form_state['values']['start'], '>=')
-        ->condition('sid', $form_state['values']['end'], '<=')
-        ->orderBy('sid', 'ASC');
-    break;
+      $query->orderBy('sid', 'ASC');
+      break;
   }
 
-  $results = $query->execute()
-    ->fetchAll(PDO::FETCH_ASSOC);
+  $sids = $query->execute()->fetchCol();
 
-  $sids = array();
-  if (!$results) {
-    return $sids;
-  }
-  // Cleanup array.
-  foreach ($results as $key => $sid) {
-    $sids[] = $sid['sid'];
-  }
-  // Resequence the DESCending query if neccessary.
-  if ($form_state['values']['type'] == 2) {
+  // The last x submissions option has SIDs that are in reverse order.
+  if ($range_options['range_type'] == 'latest') {
     $sids = array_reverse($sids);
   }
 
   return $sids;
 }
 
-// Get this user's last downloaded sid.
-function webform_download_last_downloaded_sid($nid, $field = 'sid') {
-  global $user;
-
-  // Last downloaded sid.
-  if ($field == 'sid') {
-    $last = db_select('webform_last_download', 'wld')
-      ->fields('wld', array('sid'))
-      ->condition('nid', $nid)
-      ->condition('uid', $user->uid)
-      ->execute()
-      ->fetchField();
-
-    if (!$last) {
-      $last = 0;
-    }
-    return $last;
-  }
-
-  if ($field == 'requested') {
-    $last = db_select('webform_last_download', 'wld')
-      ->fields('wld', array('requested'))
-      ->condition('nid', $nid)
-      ->condition('uid', $user->uid)
-      ->execute()
-      ->fetchField();
-    if (!$last) {
-      // Use node creation timestamp instead.
-      $last = db_select('node', 'wld')
-      ->fields('wld', array('created'))
-      ->condition('nid', $nid)
-      ->execute()
-      ->fetchField();
-    }
-    return $last;
-  }
-
-}
-
-function webform_download_get_totals($element, &$form_state) {
-  // All submissions.
-  $count = webform_get_submission_count($form_state['values']['node']->nid);
-  $element['0']['#description'] = t('(' . $count . ' total)');
+/**
+ * Get this user's last download information, including the SID and timestamp.
+ *
+ * This function provides an array of information about the last download that
+ * a user had for a particular Webform node. Currently it only returns an array
+ * with two keys:
+ *  - sid: The last submission ID that was downloaded.
+ *  - requested: The timestamp of the last download request.
+ *
+ * @param $nid
+ *   The Webform NID.
+ * @param $uid
+ *   The user account ID for which to retrieve download information.
+ * @return
+ *   An array of download information or FALSE if this user has never downloaded
+ *   results for this particular node.
+ */
+function webform_download_last_download_info($nid, $uid = NULL) {
+  $uid = isset($uid) ? $uid : $GLOBALS['user']->uid;
 
-  // Since last download.
-  // Requested timestamp.
-  $format = webform_date_format('short');
-  $requested = webform_download_last_downloaded_sid($form_state['values']['node']->nid, 'requested');
-  $requested = format_date($requested, 'user', $format, 'UTC');
-  // Number of new submissions.
-  $sids = webform_download_sids(array('values' => array('node' => $form_state['values']['node'], 'type' => 1)));
-  $count = count($sids);
-  // Set description.
-  $element['1']['#description'] = t('(') . $count . t(' new since ') . $requested . t(')');
-  if(!$count) {
-    // Disable 'Only new submissions since...' if there are no new submissions.
-    $element['1']['#attributes']['disabled'] = NULL;
-  }
+  $info = db_select('webform_last_download', 'wld')
+    ->fields('wld')
+    ->condition('nid', $nid)
+    ->condition('uid', $uid)
+    ->execute()
+    ->fetchAssoc();
 
-  return $element;
+  return $info;
 }
diff --git a/sites/all/modules/webform/includes/webform.submissions.inc b/sites/all/modules/webform/includes/webform.submissions.inc
index 86b00c6c515aa10635d1b8d2ba3c1e64266cd1c3..925aff557d7605dcc10ed5ed17194ecb7d102c9d 100644
--- a/sites/all/modules/webform/includes/webform.submissions.inc
+++ b/sites/all/modules/webform/includes/webform.submissions.inc
@@ -56,23 +56,18 @@ function webform_submission_update($node, $submission) {
   }
 
   // Update the main submission info.
-  db_update('webform_submissions')
-    ->fields(array(
-      'uid' => $submission->uid,
-      'submitted' => $submission->submitted,
-      'remote_addr' => $submission->remote_addr,
-      'is_draft' => $submission->is_draft,
-    ))
-    ->condition('sid', $submission->sid)
-    ->execute();
+  drupal_write_record('webform_submissions', $submission, 'sid');
 
   // If is draft, only delete data for components submitted, to
   // preserve any data from form pages not visited in this submission.
   if ($submission->is_draft) {
-    db_delete('webform_submitted_data')
-      ->condition('sid', $submission->sid)
-      ->condition('cid', array_keys($submission->data), 'IN')
-      ->execute();
+    $submitted_cids = array_keys($submission->data);
+    if ($submitted_cids) {
+      db_delete('webform_submitted_data')
+        ->condition('sid', $submission->sid)
+        ->condition('cid', $submitted_cids, 'IN')
+        ->execute();
+    }
   }
   else {
     db_delete('webform_submitted_data')
@@ -107,30 +102,21 @@ function webform_submission_insert($node, $submission) {
       $function = $module . '_webform_submission_presave';
       $function($node, $submission);
     }
-
-    $submission->sid = db_insert('webform_submissions')
-      ->fields(array(
-        'nid' => $node->nid,
-        'uid' => $submission->uid,
-        'submitted' => $submission->submitted,
-        'remote_addr' => $submission->remote_addr,
-        'is_draft' => $submission->is_draft,
-      ))
-      ->execute();
+    $submission->nid = $node->webform['nid'];
+    drupal_write_record('webform_submissions', $submission);
     $is_new = TRUE;
   }
 
   foreach ($submission->data as $cid => $values) {
     foreach ($values['value'] as $delta => $value) {
-      db_insert('webform_submitted_data')
-        ->fields(array(
-          'nid' => $node->nid,
-          'sid' => $submission->sid,
-          'cid' => $cid,
-          'no' => $delta,
-          'data' => is_null($value) ? '' : $value,
-        ))
-        ->execute();
+      $data = array(
+        'nid' => $node->webform['nid'],
+        'sid' => $submission->sid,
+        'cid' => $cid,
+        'no' => $delta,
+        'data' => is_null($value) ? '' : $value,
+      );
+      drupal_write_record('webform_submitted_data', $data);
     }
   }
 
@@ -279,6 +265,7 @@ function webform_submission_send_mail($node, $submission, $emails = NULL) {
         'headers' => $email['headers'],
         'node' => $node,
         'submission' => $submission,
+        'email' => $email,
       );
 
       if (webform_email_html_capable()) {
@@ -288,9 +275,11 @@ function webform_submission_send_mail($node, $submission, $emails = NULL) {
           webform_component_include('file');
           foreach ($node->webform['components'] as $component) {
             if (webform_component_feature($component['type'], 'attachment') && !empty($submission->data[$component['cid']]['value'][0])) {
-              $file = webform_get_file($submission->data[$component['cid']]['value'][0]);
-              if ($file && ($file->filepath = drupal_realpath($file->uri))) {
-                $attachments[] = $file;
+              if (webform_component_implements($component['type'], 'attachments')) {
+                $files = webform_component_invoke($component['type'], 'attachments', $component, $submission->data[$component['cid']]['value']);
+                if ($files) {
+                  $attachments = array_merge($attachments, $files);
+                }
               }
             }
           }
@@ -402,10 +391,10 @@ function webform_submission_page($node, $submission, $format) {
 
   // Determine the mode in which we're displaying this submission.
   $mode = ($format != 'form') ? 'display' : 'form';
-  if (strpos($_SERVER['REQUEST_URI'], 'print/') !== FALSE) {
+  if (strpos(request_uri(), 'print/') !== FALSE) {
     $mode = 'print';
   }
-  if (strpos($_SERVER['REQUEST_URI'], 'printpdf/') !== FALSE) {
+  if (strpos(request_uri(), 'printpdf/') !== FALSE) {
     $mode = 'pdf';
   }
 
@@ -631,6 +620,11 @@ function webform_get_submissions($filters = array(), $header = NULL, $pager_coun
       $pager_query->condition($column, $value);
     }
 
+    if (isset($filters['u.uid']) || !empty($header)) {
+      // Join to the users table for sorting by user name.
+      $pager_query->leftJoin('users', 'u', 'u.uid = ws.uid');
+    }
+
     if (isset($filters['u.uid']) && $filters['u.uid'] === 0) {
       if (!empty($_SESSION['webform_submission'])) {
         $anonymous_sids = array_keys($_SESSION['webform_submission']);
@@ -642,9 +636,6 @@ function webform_get_submissions($filters = array(), $header = NULL, $pager_coun
     }
 
     if (is_array($header)) {
-      // Join to the users table for sorting by user name.
-      $pager_query->leftJoin('users', 'u', 'u.uid = ws.uid');
-
       // Extending the query instatiates a new query object.
       $pager_query = $pager_query->extend('TableSort');
       $pager_query->orderByHeader($header);
@@ -673,17 +664,24 @@ function webform_get_submissions($filters = array(), $header = NULL, $pager_coun
   }
 
   // Query the required submission data.
-  $query = db_select('webform_submissions', 's');
-  $query->leftJoin('webform_submitted_data', 'sd', 'sd.sid = s.sid');
+  $query = db_select('webform_submitted_data', 'sd');
+  $query->leftJoin('webform_submissions', 's', 's.sid = sd.sid');
   $query->leftJoin('users', 'u', 'u.uid = s.uid');
   $query
     ->fields('s')
     ->fields('sd', array('cid', 'no', 'data'))
     ->fields('u', array('name'))
-    ->condition('s.sid', $sids, 'IN')
+    ->condition('sd.sid', $sids, 'IN')
     ->orderBy('sd.sid', 'ASC')
     ->orderBy('sd.cid', 'ASC')
     ->orderBy('sd.no', 'ASC');
+
+  // By adding the NID to this query we allow MySQL to use the primary key on
+  // in webform_submitted_data for sorting (nid_sid_cid_no).
+  if (isset($filters['nid'])) {
+    $query->condition('sd.nid', $filters['nid']);
+  }
+
   $result = $query->execute();
 
   // Convert the queried rows into submissions.
@@ -698,8 +696,12 @@ function webform_get_submissions($filters = array(), $header = NULL, $pager_coun
       $submissions[$row->sid]->uid = $row->uid;
       $submissions[$row->sid]->name = $row->name;
       $submissions[$row->sid]->is_draft = $row->is_draft;
+      $submissions[$row->sid]->data = array();
+    }
+    // CID may be NULL if this submission does not actually contain any data.
+    if ($row->cid) {
+      $submissions[$row->sid]->data[$row->cid]['value'][$row->no] = $row->data;
     }
-    $submissions[$row->sid]->data[$row->cid]['value'][$row->no] = $row->data;
     $previous = $row->sid;
   }
 
@@ -725,16 +727,24 @@ function webform_get_submission_count($nid, $uid = NULL, $reset = FALSE) {
   static $counts;
 
   if (!isset($counts[$nid][$uid]) || $reset) {
-    $query = db_select('webform_submissions')
-      ->condition('nid', $nid)
-      ->condition('is_draft', 0);
+    $query = db_select('webform_submissions', 'ws')
+      ->addTag('webform_get_submission_count')
+      ->condition('ws.nid', $nid)
+      ->condition('ws.is_draft', 0);
     $arguments = array($nid);
     if ($uid !== NULL) {
-      $query->condition('uid', $uid);
+      $query->condition('ws.uid', $uid);
     }
     if ($uid === 0) {
-      $submissions = isset($_SESSION['webform_submission']) ? $_SESSION['webform_submission'] : array(0);
-      $query->condition('sid', $submissions, 'IN');
+      $submissions = isset($_SESSION['webform_submission']) ? $_SESSION['webform_submission'] : NULL;
+      if ($submissions) {
+        $query->condition('ws.sid', $submissions, 'IN');
+      }
+      else {
+        // Intentionally never match anything if the anonymous user has no
+        // submissions.
+        $query->condition('ws.sid', 0);
+      }
     }
 
     $counts[$nid][$uid] = $query->countQuery()->execute()->fetchField();
@@ -757,13 +767,8 @@ function webform_get_submission($nid, $sid, $reset = FALSE) {
 
   // Load the submission if needed.
   if (!isset($submissions[$sid])) {
-    $new_submissions = webform_get_submissions(array('sid' => $sid));
-    $submissions[$sid] = $new_submissions[$sid];
-  }
-
-  // Ensure that the requested NID matches the submission NID.
-  if ($submissions[$sid]->nid != $nid) {
-    return FALSE;
+    $new_submissions = webform_get_submissions(array('nid' => $nid, 'sid' => $sid));
+    $submissions[$sid] = isset($new_submissions[$sid]) ? $new_submissions[$sid] : FALSE;
   }
 
   return $submissions[$sid];
@@ -786,7 +791,7 @@ function _webform_submission_spam_check($to, $subject, $from, $headers = array()
  * @return
  *   Boolean TRUE if the user has exceeded their limit. FALSE otherwise.
  */
-function _webform_submission_limit_check($node) {
+function _webform_submission_user_limit_check($node) {
   global $user;
 
   // Check if submission limiting is enabled.
@@ -822,7 +827,8 @@ function _webform_submission_limit_check($node) {
       foreach ($_COOKIE[$cookie_name] as $key => $timestamp) {
         if ($node->webform['submit_interval'] != -1 && $timestamp <= REQUEST_TIME - $node->webform['submit_interval']) {
           // Remove the cookie if past the required time interval.
-          setcookie($cookie_name . '[' . $key . ']', '', 0);
+          $params = session_get_cookie_params();
+          setcookie($cookie_name . '[' . $key . ']', '', 0, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
         }
       }
       // Count the number of submissions recorded in cookies.
@@ -842,6 +848,42 @@ function _webform_submission_limit_check($node) {
   return FALSE;
 }
 
+/**
+ * Check if the total number of submissions has exceeded the limit on this form.
+ *
+ * @param $node
+ *   The webform node to be checked.
+ * @return
+ *   Boolean TRUE if the form has exceeded it's limit. FALSE otherwise.
+ */
+function _webform_submission_total_limit_check($node) {
+
+  // Check if submission limiting is enabled.
+  if ($node->webform['total_submit_limit'] == '-1') {
+    return FALSE; // No check enabled.
+  }
+
+  // Retrieve submission data from the database.
+  $query = db_select('webform_submissions')
+    ->condition('nid', $node->nid)
+    ->condition('is_draft', 0);
+
+  if ($node->webform['total_submit_interval'] != -1) {
+    $query->condition('submitted', REQUEST_TIME - $node->webform['total_submit_interval'], '>');
+  }
+
+  // Fetch all the entries from the database within the submit interval.
+  $num_submissions_database = $query->countQuery()->execute()->fetchField();
+
+  if ($num_submissions_database >= $node->webform['total_submit_limit']) {
+    // Limit exceeded.
+    return TRUE;
+  }
+
+  // Limit not exceeded.
+  return FALSE;
+}
+
 /**
  * Preprocess function for webform-submission.tpl.php.
  */
diff --git a/sites/all/modules/webform/js/webform-admin.js b/sites/all/modules/webform/js/webform-admin.js
index 26219bdefd371022f01ddc302815ca949db950ad..a8e7c9a414ceb623c3ade8ad17f3dbec3b300d79 100644
--- a/sites/all/modules/webform/js/webform-admin.js
+++ b/sites/all/modules/webform/js/webform-admin.js
@@ -12,6 +12,8 @@ Drupal.behaviors.webformAdmin.attach = function(context) {
   Drupal.webform.setActive(context);
   // Update the template select list upon changing a template.
   Drupal.webform.updateTemplate(context);
+  // Select all link for file extensions.
+  Drupal.webform.selectCheckboxesLink(context);
   // Enhance the normal tableselect.js file to support indentations.
   Drupal.webform.tableSelectIndentation(context);
 }
@@ -83,6 +85,20 @@ Drupal.webform.updateTemplate = function(context) {
   $templateSelect.change(updateTemplateText);
 }
 
+Drupal.webform.selectCheckboxesLink = function(context) {
+  function selectCheckboxes() {
+    var group = this.className.replace(/.*?webform-select-link-([^ ]*).*/, '$1');
+    var $checkboxes = $('.webform-select-group-' + group + ' input[type=checkbox]');
+    var reverseCheck = !$checkboxes[0].checked;
+    $checkboxes.each(function() {
+      this.checked = reverseCheck;
+    });
+    $checkboxes.trigger('change');
+    return false;
+  }
+  $('a.webform-select-link', context).click(selectCheckboxes);
+}
+
 Drupal.webform.tableSelectIndentation = function(context) {
   var $tables = $('th.select-all', context).parents('table');
   $tables.find('input.form-checkbox').change(function() {
diff --git a/sites/all/modules/webform/js/webform.js b/sites/all/modules/webform/js/webform.js
index 35d2f9fac4eebd56bb04a828584eb2062d8f7b8e..70ac37a8719f880186b0eeeca16c047e2aeb7cf7 100644
--- a/sites/all/modules/webform/js/webform.js
+++ b/sites/all/modules/webform/js/webform.js
@@ -21,7 +21,6 @@ Drupal.webform.datepicker = function(context) {
     var startDate = $calendar[0].className.replace(/.*webform-calendar-start-(\d{4}-\d{2}-\d{2}).*/, '$1').split('-');
     var endDate = $calendar[0].className.replace(/.*webform-calendar-end-(\d{4}-\d{2}-\d{2}).*/, '$1').split('-');
     var firstDay = $calendar[0].className.replace(/.*webform-calendar-day-(\d).*/, '$1');
-
     // Convert date strings into actual Date objects.
     startDate = new Date(startDate[0], startDate[1] - 1, startDate[2]);
     endDate = new Date(endDate[0], endDate[1] - 1, endDate[2]);
@@ -78,4 +77,4 @@ Drupal.webform.datepicker = function(context) {
   });
 }
 
-})(jQuery);
\ No newline at end of file
+})(jQuery);
diff --git a/sites/all/modules/webform/templates/webform-form.tpl.php b/sites/all/modules/webform/templates/webform-form.tpl.php
index 2a2cfa4eeddaef0a9262d410fdcf9263f684b499..d839083cba72b9e72c7be93b3869cdc2e58293eb 100644
--- a/sites/all/modules/webform/templates/webform-form.tpl.php
+++ b/sites/all/modules/webform/templates/webform-form.tpl.php
@@ -18,12 +18,6 @@
  */
 ?>
 <?php
-  // If editing or viewing submissions, display the navigation at the top.
-  if (isset($form['submission_info']) || isset($form['navigation'])) {
-    print drupal_render($form['navigation']);
-    print drupal_render($form['submission_info']);
-  }
-
   // Print out the main part of the form.
   // Feel free to break this up and move the pieces within the array.
   print drupal_render($form['submitted']);
@@ -31,9 +25,3 @@
   // Always print out the entire $form. This renders the remaining pieces of the
   // form that haven't yet been rendered above.
   print drupal_render_children($form);
-
-  // Print out the navigation again at the bottom.
-  if (isset($form['submission_info']) || isset($form['navigation'])) {
-    unset($form['navigation']['#printed']);
-    print drupal_render($form['navigation']);
-  }
diff --git a/sites/all/modules/webform/tests/submission.test b/sites/all/modules/webform/tests/submission.test
index ef12701b470341cf5abdee8ceab1bfbdf508dc24..84255a8a86792c92a6429dc434d867b2c8de0a25 100644
--- a/sites/all/modules/webform/tests/submission.test
+++ b/sites/all/modules/webform/tests/submission.test
@@ -53,6 +53,16 @@ class WebformSubmissionTestCase extends WebformTestCase {
     $this->drupalLogout();
   }
 
+  /**
+   * Test validation errors on each component that has specialized validation.
+   */
+  function testWebformSubmissionValidate() {
+    $this->drupalLogin($this->webform_users['admin']);
+    $this->webformReset();
+    $this->webformSubmissionValidateExecute();
+    $this->drupalLogout();
+  }
+
   /**
    * Test that required fields with no default value can't be submitted as-is.
    */
@@ -128,4 +138,37 @@ class WebformSubmissionTestCase extends WebformTestCase {
     }
   }
 
+  /**
+   * Execute a validation check for a single component.
+   *
+   * @param $value_type
+   *   The values to be submitted to the webform. Either "sample" or "default".
+   */
+  function webformSubmissionValidateExecute() {
+    $path = drupal_get_path('module', 'webform');
+    module_load_include('inc', 'webform', 'includes/webform.submissions');
+
+    // Create a new Webform test node.
+    $node = $this->testWebformForm();
+
+    // Visit the node page.
+    $this->drupalGet('node/' . $node->nid);
+
+    foreach ($this->testWebformComponents() as $key => $component_info) {
+      if (isset($component_info['error values'])) {
+        foreach ($component_info['error values'] as $value => $error_message) {
+          $submission_values = array();
+          $submission_values["submitted[$key]"] = $value;
+
+          // Submit our test data.
+          $this->drupalPost('node/' . $node->nid, $submission_values, 'Submit', array(), array(), 'webform-client-form-' . $node->nid);
+
+          // Confirm that the validation error occurred and the submission did not save.
+          $this->assertRaw($error_message, t('Validation message properly thrown: "%message".', array('%message' => $error_message)), t('Webform'));
+
+          $this->assertFalse(preg_match('/sid=([0-9]+)/', $this->getUrl()), t('Submission not saved.'));
+        }
+      }
+    }
+  }
 }
diff --git a/sites/all/modules/webform/tests/webform.test b/sites/all/modules/webform/tests/webform.test
index 03a307e9adc14fd9fd1499fb2bee0b54fa83d867..fd20046a45c9e8f7ec190cf0ea72bad4910b3c37 100644
--- a/sites/all/modules/webform/tests/webform.test
+++ b/sites/all/modules/webform/tests/webform.test
@@ -118,10 +118,8 @@ class WebformTestCase extends DrupalWebTestCase {
             'end_date' => '+2 years',
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-15',
-          'page_num' => 1,
         ),
         'sample values' => array('day' => '30', 'month' => '9', 'year' => '1982'),
         'database values' => array('1982-09-30'),
@@ -140,10 +138,8 @@ class WebformTestCase extends DrupalWebTestCase {
             'options' => "0|øne\n1|twö\n2|ǼBƇ\n3|€Euro", // Top
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '2',
           'weight' => '-19',
-          'page_num' => 1,
         ),
         'sample values' => array('0' => '0', '1' => '1', '2' => '2'),
         'database values' => array('0' => '0', '1' => '1', '2' => '2'),
@@ -160,10 +156,8 @@ class WebformTestCase extends DrupalWebTestCase {
             'options' => "one|Option one\ntwo|Option 2\nthree| Three is me", // Top
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-15',
-          'page_num' => 1,
         ),
         'sample values' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
         'database values' => array('one' => 'one', 'two' => 'two', 'three' => 'three'),
@@ -180,13 +174,10 @@ class WebformTestCase extends DrupalWebTestCase {
           'extra' => array(
             'items' => "one|one\ntwo|two\nthree|three",
             'multiple' => 1,
-            'email' => 0,
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-15',
-          'page_num' => 1,
         ),
         'sample values' => array('one' => TRUE, 'two' => FALSE, 'three' => TRUE),
         'database values' => array('one', 'three'),
@@ -201,13 +192,10 @@ class WebformTestCase extends DrupalWebTestCase {
           'extra' => array(
             'items' => "0|zero\n1|one\n2|two",
             'multiple' => 1,
-            'email' => 0,
           ),
           'mandatory' => '1',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-9',
-          'page_num' => 1,
         ),
         'sample values' => array('0' => TRUE),
         'database values' => array('0'),
@@ -221,13 +209,10 @@ class WebformTestCase extends DrupalWebTestCase {
           'value' => 'two',
           'extra' => array(
             'items' => "one|one\ntwo|two\nthree|three",
-            'email' => 0,
           ),
           'mandatory' => '1',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-9',
-          'page_num' => 1,
         ),
         'sample values' => 'one',
         'database values' => array('one'),
@@ -241,13 +226,10 @@ class WebformTestCase extends DrupalWebTestCase {
           'value' => '0',
           'extra' => array(
             'items' => "0|zero\n1|one\n2|two",
-            'email' => 0,
           ),
           'mandatory' => '1',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-9',
-          'page_num' => 1,
         ),
         'sample values' => '0',
         'database values' => array('0'),
@@ -260,16 +242,13 @@ class WebformTestCase extends DrupalWebTestCase {
           'type' => 'select',
           'value' => 'one',
           'extra' => array(
-            'description' => '<p>Description here</p>',
+            'description' => 'Description here',
             'items' => "one|one\ntwo|two\nthree|three\nfour|four\nfive|five\nsix|six",
             'aslist' => 1,
-            'email' => 0,
           ),
           'mandatory' => '1',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-15',
-          'page_num' => 1,
         ),
         'sample values' => 'two',
         'database values' => array('two'),
@@ -282,16 +261,13 @@ class WebformTestCase extends DrupalWebTestCase {
           'type' => 'select',
           'value' => '0',
           'extra' => array(
-            'description' => '<p>Tests saving zero as a value.</p>',
+            'description' => 'Tests saving zero as a value.',
             'items' => "0|zero\n1|one\n2|two",
             'aslist' => 1,
-            'email' => 0,
           ),
           'mandatory' => '1',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-15',
-          'page_num' => 1,
         ),
         'sample values' => '0',
         'database values' => array('0'),
@@ -304,16 +280,13 @@ class WebformTestCase extends DrupalWebTestCase {
           'type' => 'select',
           'value' => '',
           'extra' => array(
-            'description' => '<p>Description here</p>',
+            'description' => 'Description here',
             'items' => "one|one\ntwo|two\nthree|three\nfour|four\nfive|five\nsix|six",
             'aslist' => 1,
-            'email' => 0,
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-15',
-          'page_num' => 1,
         ),
         'sample values' => 'two',
         'database values' => array('two'),
@@ -326,16 +299,13 @@ class WebformTestCase extends DrupalWebTestCase {
           'type' => 'select',
           'value' => '',
           'extra' => array(
-            'description' => '<p>Tests saving zero as a value.</p>',
+            'description' => 'Tests saving zero as a value.',
             'items' => "0|zero\n1|one\n2|two",
             'aslist' => 1,
-            'email' => 0,
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-15',
-          'page_num' => 1,
         ),
         'sample values' => '0',
         'database values' => array('0'),
@@ -348,16 +318,13 @@ class WebformTestCase extends DrupalWebTestCase {
           'type' => 'select',
           'value' => 'option 1-2',
           'extra' => array(
-            'description' => '<p>Tests saving zero as a value.</p>',
+            'description' => 'Tests saving zero as a value.',
             'items' => "<Group 1>\noption 1-1|option 1-1\noption 1-2|option 1-2\noption 1-3|option 1-3\n<Group 2>\noption 2-1|option 2-1\noption 2-2|option 2-2\noption 2-3|option 2-3",
             'aslist' => 1,
-            'email' => 0,
           ),
           'mandatory' => '1',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-15',
-          'page_num' => 1,
         ),
         'sample values' => 'option 2-2',
         'database values' => array('option 2-2'),
@@ -371,13 +338,10 @@ class WebformTestCase extends DrupalWebTestCase {
           'value' => 'nate@localhost.localhost',
           'extra' => array(
             'items' => "nate@localhost.localhost|one\nadmin@localhost.localhost|two",
-            'email' => 3,
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '2',
           'weight' => '-17',
-          'page_num' => 1,
         ),
         'sample values' => 'admin@localhost.localhost',
         'database values' => array('admin@localhost.localhost'),
@@ -393,13 +357,10 @@ class WebformTestCase extends DrupalWebTestCase {
             'items' => "one|one\ntwo|two\nthree|three",
             'multiple' => 1,
             'aslist' => 1,
-            'email' => 0,
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-10',
-          'page_num' => 1,
         ),
         // TODO: I'd like to test a value, but SimpleTest can't set multiple values.
         'sample values' => NULL,
@@ -421,10 +382,8 @@ class WebformTestCase extends DrupalWebTestCase {
             'year_textfield' => 1,
           ),
           'mandatory' => '1',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-7',
-          'page_num' => 1,
         ),
         'sample values' => array('day' => '30', 'month' => '9', 'year' => '1982'),
         'database values' => array('1982-09-30'),
@@ -438,14 +397,13 @@ class WebformTestCase extends DrupalWebTestCase {
           'name' => 'E-mail',
           'type' => 'email',
           'value' => '%useremail',
+          'mandatory' => '0',
           'extra' => array(
-            'email' => 19,
+            // SimpleTest does not support type="email" input fields.
+            'attributes' => array('type' => 'text'),
           ),
-          'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-5',
-          'page_num' => 1,
         ),
         'sample values' => 'admin@localhost.localhost',
         'database values' => array('admin@localhost.localhost'),
@@ -459,14 +417,9 @@ class WebformTestCase extends DrupalWebTestCase {
           'name' => 'Hidden',
           'type' => 'hidden',
           'value' => 'default hidden value',
-          'extra' => array(
-            'email' => 0,
-          ),
           'mandatory' => '1',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-4',
-          'page_num' => 1,
         ),
         'sample values' => NULL,
         'database values' => array('default hidden value'),
@@ -482,10 +435,8 @@ class WebformTestCase extends DrupalWebTestCase {
           'value' => 'sample textarea default value',
           'extra' => array(),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '15',
-          'page_num' => 1,
         ),
         'sample values' => 'sample textarea value',
         'database values' => array('sample textarea value'),
@@ -503,10 +454,8 @@ class WebformTestCase extends DrupalWebTestCase {
             'disabled' => 1,
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-15',
-          'page_num' => 1,
         ),
         'sample values' => NULL,
         'database values' => array('bar'),
@@ -522,10 +471,8 @@ class WebformTestCase extends DrupalWebTestCase {
             'width' => '20',
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '-6',
-          'page_num' => 1,
         ),
         'sample values' => 'Female',
         'database values' => array('Female'),
@@ -544,10 +491,8 @@ class WebformTestCase extends DrupalWebTestCase {
             'hourformat' => '12-hour',
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '16',
-          'page_num' => 1,
         ),
         'sample values' => array('hour' => '5', 'minute' => '0', 'ampm' => 'am'),
         'database values' => array('05:00:00'),
@@ -564,15 +509,139 @@ class WebformTestCase extends DrupalWebTestCase {
             'hourformat' => '24-hour',
           ),
           'mandatory' => '0',
-          'email' => '1',
           'pid' => '0',
           'weight' => '17',
-          'page_num' => 1,
         ),
         'sample values' => array('hour' => '5', 'minute' => '0'),
         'database values' => array('05:00:00'),
         'database default values' => array('22:30:00'),
       ),
+
+      // Test number components.
+      'integer' => array(
+        'component' => array(
+          'form_key' => 'integer',
+          'name' => 'Integer',
+          'type' => 'number',
+          'value' => '1',
+          'extra' => array(
+            'type' => 'textfield',
+            'integer' => 1,
+            'max' => '100',
+            // SimpleTest does not support type="number" input fields.
+            'attributes' => array('type' => 'text'),
+          ),
+          'mandatory' => '0',
+          'pid' => '0',
+          'weight' => '18',
+        ),
+        'sample values' => '2',
+        'database values' => array('2'),
+        'database default values' => array('1'),
+        'error values' => array(
+          '1.5' => t('%name field value of @value must be an integer.', array('%name' => 'Integer', '@value' => '1.5')),
+          '101' => t('%name field value must be less than @max.', array('%name' => 'Integer', '@max' => '100')),
+        ),
+      ),
+      'integer_range' => array(
+        'component' => array(
+          'form_key' => 'integer_range',
+          'name' => 'Integer Range',
+          'type' => 'number',
+          'value' => '50',
+          'extra' => array(
+            'type' => 'select',
+            'min' => '10',
+            'max' => '50',
+            'step' => 5,
+            'integer' => 1,
+          ),
+          'mandatory' => '0',
+          'pid' => '0',
+          'weight' => '19',
+        ),
+        'sample values' => '10',
+        'database values' => array('10'),
+        'database default values' => array('50'),
+      ),
+      'decimal_positive' => array(
+        'component' => array(
+          'form_key' => 'decimal_positive',
+          'name' => 'Decimal positive',
+          'type' => 'number',
+          'value' => '1',
+          'extra' => array(
+            'type' => 'textfield',
+            'field_prefix' => '$',
+            'field_suffix' => 'lbs',
+            'min' => '0',
+            'decimals' => '2',
+            'point' => '.',
+            'separator' => ',',
+            // SimpleTest does not support type="number" input fields.
+            'attributes' => array('type' => 'text'),
+          ),
+          'mandatory' => '0',
+          'pid' => '0',
+          'weight' => '20',
+        ),
+        'sample values' => '2.00',
+        'database values' => array('2.00'),
+        'database default values' => array('1'),
+        'error values' => array(
+          '-1' => t('%name field value must be greater than @min.', array('%name' => 'Decimal positive', '@min' => '0')),
+        ),
+      ),
+      'decimal_range' => array(
+        'component' => array(
+          'form_key' => 'decimal_range',
+          'name' => 'Decimal range',
+          'type' => 'number',
+          'value' => '1',
+          'extra' => array(
+            'type' => 'textfield',
+            'field_prefix' => '$',
+            'field_suffix' => 'lbs',
+            'min' => '1',
+            'max' => '12',
+            'step' => '1.5',
+            // SimpleTest does not support type="number" input fields.
+            'attributes' => array('type' => 'text'),
+          ),
+          'mandatory' => '0',
+          'pid' => '0',
+          'weight' => '21',
+        ),
+        'sample values' => '11.5',
+        'database values' => array('11.5'),
+        'database default values' => array('1'),
+        'error values' => array(
+          '2' => t('%name field value must be @start plus a multiple of @step.', array('%name' => 'Decimal range', '@start' => '1', '@step' => '1.5')),
+          '13' => t('%name field value of @value should be in the range @min to @max.', array('%name' => 'Decimal range', '@value' => '13', '@min' => '1', '@max' => '12')),
+        ),
+      ),
+      'decimal_range_select' => array(
+        'component' => array(
+          'form_key' => 'decimal_range_select',
+          'name' => 'Decimal range select',
+          'type' => 'number',
+          'value' => '1',
+          'extra' => array(
+            'type' => 'select',
+            'field_prefix' => '$',
+            'field_suffix' => 'lbs',
+            'min' => '1',
+            'max' => '12',
+            'step' => '1.5',
+          ),
+          'mandatory' => '0',
+          'pid' => '0',
+          'weight' => '21',
+        ),
+        'sample values' => '11.5',
+        'database values' => array('11.5'),
+        'database default values' => array('1'),
+      ),
     );
 
     return $this->_webform_components;
@@ -627,7 +696,9 @@ class WebformTestCase extends DrupalWebTestCase {
     return $this->_webform_node;
   }
 
-
+  /**
+   * Generate a list of all values that would result in a valid submission.
+   */
   function testWebformPost() {
     $edit = array();
     foreach ($this->testWebformComponents() as $key => $component_info) {
diff --git a/sites/all/modules/webform/views/webform.views.inc b/sites/all/modules/webform/views/webform.views.inc
index f8e7c6fbd356c23c03fa05068e1e673bce351fe5..dab3fe3b20a99ad6af238ee4ed9c60028c873b2a 100644
--- a/sites/all/modules/webform/views/webform.views.inc
+++ b/sites/all/modules/webform/views/webform.views.inc
@@ -6,6 +6,37 @@
  */
 
 function webform_views_data() {
+
+  /**
+   * Webform table definitions.
+   */
+  $data['webform']['table']['group'] = t('Webform');
+  $data['webform']['table']['join'] = array(
+    'node' => array(
+      'left_field' => 'nid',
+      'field' => 'nid',
+      'type' => 'INNER',
+    ),
+  );
+
+  // status
+  $data['webform']['status'] = array(
+    'title' => t('Status'),
+    'help' => t('The open or closed status of a webform.'),
+    'field' => array(
+      'handler' => 'webform_handler_field_webform_status',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'label' => t('Status'),
+      'handler' => 'webform_handler_filter_webform_status',
+      'type' => 'open-closed',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
   /**
    * Submissions table definitions.
    */
@@ -31,29 +62,32 @@ function webform_views_data() {
     'sort' => array(
       'handler' => 'views_handler_sort',
     ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+    ),
   );
 
   // nid
   $data['webform_submissions']['nid'] = array(
     'title' => t('Node'),
-    'help' => t('The node these submissions were generated from.'),
+    'help' => t('The webform node this submission was generated from.'),
     'relationship' => array(
       'base' => 'node',
+      'field' => 'nid',
       'handler' => 'views_handler_relationship',
-      'label' => t('Node'),
-      'skip base' => array('node', 'node_revisions'),
+      'label' => t('Webform Node'),
     ),
   );
 
   // uid
   $data['webform_submissions']['uid'] = array(
     'title' => t('User'),
-    'help' => t('The users who submitted these submissions.'),
+    'help' => t('The user who sent the webform submission.'),
     'relationship' => array(
       'base' => 'users',
+      'field' => 'uid',
       'handler' => 'views_handler_relationship',
-      'label' => t('User'),
-      'skip base' => array('users', 'node', 'node_revisions'),
+      'label' => t('Webform Submission User'),
     ),
   );
 
@@ -144,8 +178,26 @@ function webform_views_data() {
  * Implements hook_views_data_alter().
  */
 function webform_views_data_alter(&$data) {
+  // Webform submission from node.
+  $data['node']['webform_submission'] = array(
+    'title' => t('Webform submission'),
+    'help' => t('Webform submissions of the given Webform node.'),
+    'real field' => 'nid',
+    'relationship' => array(
+      'base' => 'webform_submissions',
+      'base field' => 'nid',
+      'handler' => 'views_handler_relationship',
+      'label' => t('Webform Submission'),
+    ),
+  );
+  $data['node']['table']['join']['webform_submissions'] = array(
+    'field' => 'nid',
+    'left_field' => 'nid',
+    'left_table' => 'webform_submissions',
+  );
   // Submission count (node).
   $data['node']['webform_submission_count_node'] = array(
+    'group' => t('Webform'),
     'field' => array(
       'title' => t('Webform submission count'),
       'help' => t('The number of webform submissions on this node.'),
@@ -154,6 +206,19 @@ function webform_views_data_alter(&$data) {
     ),
   );
 
+
+  // Webform submission of user.
+  $data['users']['webform_submission'] = array(
+    'title' => t('Webform submission'),
+    'help' => t('Webform submissions of the given user.'),
+    'real field' => 'uid',
+    'relationship' => array(
+      'base' => 'webform_submissions',
+      'base field' => 'uid',
+      'handler' => 'views_handler_relationship',
+      'label' => t('Webform Submission'),
+    ),
+  );
   // Submission count (user).
   $data['users']['webform_submission_count_user'] = array(
     'field' => array(
@@ -166,6 +231,7 @@ function webform_views_data_alter(&$data) {
 
   // Link for editing the webform.
   $data['node']['webform_edit'] = array(
+    'group' => t('Webform'),
     'field' => array(
       'title' => t('Webform edit link'),
       'help' => t('Provide a simple link to edit the webform components and configuration.'),
@@ -175,6 +241,7 @@ function webform_views_data_alter(&$data) {
 
   // Link for viewing webform results.
   $data['node']['webform_results'] = array(
+    'group' => t('Webform'),
     'field' => array(
       'title' => t('Webform results link'),
       'help' => t('Provide a simple link to view the results of a webform.'),
@@ -184,6 +251,7 @@ function webform_views_data_alter(&$data) {
 
   // Webform form content.
   $data['node']['webform_form_body'] = array(
+    'group' => t('Webform'),
     'field' => array(
       'title' => t('Webform form body'),
       'help' => t('The Webform form body display for this node.'),
@@ -227,6 +295,14 @@ function webform_views_handlers() {
         'parent' => 'views_handler_filter_in_operator',
         'file' => 'webform_handler_filter_is_draft.inc',
       ),
+      'webform_handler_field_webform_status' => array(
+        'parent' => 'views_handler_field_boolean',
+        'file' => 'webform_handler_field_webform_status.inc',
+      ),
+      'webform_handler_filter_webform_status' => array(
+        'parent' => 'views_handler_filter_boolean_operator',
+        'file' => 'webform_handler_filter_webform_status.inc',
+      ),
     ),
   );
 }
\ No newline at end of file
diff --git a/sites/all/modules/webform/views/webform_handler_field_form_body.inc b/sites/all/modules/webform/views/webform_handler_field_form_body.inc
index 4eb62d0d81b8627b588312f09256ba60bae86b4c..4c8b206a5dfad52869dbf040e521c9bcffaebe9d 100644
--- a/sites/all/modules/webform/views/webform_handler_field_form_body.inc
+++ b/sites/all/modules/webform/views/webform_handler_field_form_body.inc
@@ -29,7 +29,9 @@ class webform_handler_field_form_body extends views_handler_field {
     $node = node_load($values->{$this->aliases['nid']});
 
     if (node_access('view', $node)) {
-      $form_body = drupal_render(node_view($node));
+      // Populate $node->content['webform'] by reference.
+      webform_node_view($node, 'full');
+      $form_body = isset($node->content['webform']) ? drupal_render($node->content['webform']) : NULL;
     }
     else {
       return;
diff --git a/sites/all/modules/webform/views/webform_handler_field_node_link_edit.inc b/sites/all/modules/webform/views/webform_handler_field_node_link_edit.inc
index 8fb2c3fa07aa60d354f8e26a177e736d99d3ec5d..1a385feaaf91b1e0498ebe3f80e017b8c0c1984c 100644
--- a/sites/all/modules/webform/views/webform_handler_field_node_link_edit.inc
+++ b/sites/all/modules/webform/views/webform_handler_field_node_link_edit.inc
@@ -9,27 +9,22 @@
  * Field handler to present a link node edit.
  */
 class webform_handler_field_node_link_edit extends views_handler_field_node_link {
-  function construct() {
-    parent::construct();
-    $this->additional_fields['uid'] = 'uid';
-    $this->additional_fields['type'] = 'type';
-    $this->additional_fields['format'] = array('table' => 'node_revisions', 'field' => 'format');
-  }
 
-  function render($values) {
-    // ensure user has access to edit this node.
-    $node = new stdClass();
-    $node->nid = $values->{$this->aliases['nid']};
-    $node->uid = $values->{$this->aliases['uid']};
-    $node->type = $values->{$this->aliases['type']};
-    $node->format = $values->{$this->aliases['format']};
-    $node->status = 1; // unpublished nodes ignore access control
+  /**
+   * Renders the link.
+   */
+  function render_link($node, $values) {
+    // Ensure user has access to edit this node.
     if (!node_access('update', $node)) {
       return;
     }
 
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['path'] = "node/$node->nid/webform";
+
     $text = !empty($this->options['text']) ? $this->options['text'] : t('edit webform');
-    return l($text, "node/$node->nid/webform");
+    return $text;
   }
+
 }
 
diff --git a/sites/all/modules/webform/views/webform_handler_field_node_link_results.inc b/sites/all/modules/webform/views/webform_handler_field_node_link_results.inc
index 11bde99e3cc590a1691e4de88af600dbcd543bb2..79398b3cb80b81fd7a3f07c04e5e90daa8efdfee 100644
--- a/sites/all/modules/webform/views/webform_handler_field_node_link_results.inc
+++ b/sites/all/modules/webform/views/webform_handler_field_node_link_results.inc
@@ -9,27 +9,22 @@
  * Field handler to present a link node edit.
  */
 class webform_handler_field_node_link_results extends views_handler_field_node_link {
-  function construct() {
-    parent::construct();
-    $this->additional_fields['uid'] = 'uid';
-    $this->additional_fields['type'] = 'type';
-    $this->additional_fields['format'] = array('table' => 'node_revisions', 'field' => 'format');
-  }
 
-  function render($values) {
-    // ensure user has access to edit this node.
-    $node = new stdClass();
-    $node->nid = $values->{$this->aliases['nid']};
-    $node->uid = $values->{$this->aliases['uid']};
-    $node->type = $values->{$this->aliases['type']};
-    $node->format = $values->{$this->aliases['format']};
-    $node->status = 1; // unpublished nodes ignore access control
+  /**
+   * Renders the link.
+   */
+  function render_link($node, $values) {
+    // Ensure user has access to edit this node.
     if (!webform_results_access($node)) {
       return;
     }
 
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['path'] = "node/$node->nid/webform-results";
+
     $text = !empty($this->options['text']) ? $this->options['text'] : t('results');
-    return l($text, "node/$node->nid/webform-results");
+    return $text;
   }
+
 }
 
diff --git a/sites/all/modules/webform/views/webform_handler_field_submission_link.inc b/sites/all/modules/webform/views/webform_handler_field_submission_link.inc
index 3ae6a3fbbc3331d72bd5d7105530b2cf7037605c..e369e26b74e230854b0dbb77088c897a1353867d 100644
--- a/sites/all/modules/webform/views/webform_handler_field_submission_link.inc
+++ b/sites/all/modules/webform/views/webform_handler_field_submission_link.inc
@@ -70,7 +70,7 @@ class webform_handler_field_submission_link extends views_handler_field {
 
     switch ($this->link_type) {
       case 'view':
-        $text = !empty($this->options['text']) ? $this->options['text'] : t('delete');
+        $text = !empty($this->options['text']) ? $this->options['text'] : t('view');
         $link = l($text, "node/$submission->nid/submission/$submission->sid");
         $access = webform_submission_access($node, $submission, 'view');
         break;
@@ -80,7 +80,7 @@ class webform_handler_field_submission_link extends views_handler_field {
         $access = webform_submission_access($node, $submission, 'edit');
         break;
       case 'delete':
-        $text = !empty($this->options['text']) ? $this->options['text'] : t('view');
+        $text = !empty($this->options['text']) ? $this->options['text'] : t('delete');
         $path = drupal_get_path_alias($_GET['q']);
         $link = l($text, "node/$submission->nid/submission/$submission->sid/delete", array('query' => array('destination' => $path)));
         $access = webform_submission_access($node, $submission, 'delete');
diff --git a/sites/all/modules/webform/views/webform_handler_field_webform_status.inc b/sites/all/modules/webform/views/webform_handler_field_webform_status.inc
new file mode 100644
index 0000000000000000000000000000000000000000..cae02cdba46470d1a186c438cd8e7b81774dde64
--- /dev/null
+++ b/sites/all/modules/webform/views/webform_handler_field_webform_status.inc
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Views handler to display the open or closed status of a webform.
+ */
+class webform_handler_field_webform_status extends views_handler_field_boolean {
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['type']['#options'] = array('open-closed' => t('Open/Closed')) + $form['type']['#options'];
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['type']['default'] = 'open-closed';
+    return $options;
+  }
+
+  function render($values) {
+    $value = $values->{$this->field_alias};
+    if (!empty($this->options['not'])) {
+      $value = !$value;
+    }
+    switch ($this->options['type']) {
+      case 'yes-no':
+        return $value ? t('Yes') : t('No');
+      case 'true-false':
+        return $value ? t('True') : t('False');
+      case 'on-off':
+        return $value ? t('On') : t('Off');
+      case 'open-closed':
+      default:
+        return $value ? t('Open') : t('Closed');
+    }
+  }
+}
+
diff --git a/sites/all/modules/webform/views/webform_handler_filter_webform_status.inc b/sites/all/modules/webform/views/webform_handler_filter_webform_status.inc
new file mode 100644
index 0000000000000000000000000000000000000000..429fc248505991f120f065637a89f091aec5ce70
--- /dev/null
+++ b/sites/all/modules/webform/views/webform_handler_filter_webform_status.inc
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Views handler to filter webforms by open or closed status.
+ */
+class webform_handler_filter_webform_status extends views_handler_filter_boolean_operator {
+  function get_value_options() {
+    if (!isset($this->value_options)) {
+      $this->value_title = t('Status');
+      $options = array('1' => t('Open'), '0' => t('Closed'));
+      $this->value_options = $options;
+    }
+  }
+}
diff --git a/sites/all/modules/webform/webform_hooks.php b/sites/all/modules/webform/webform.api.php
similarity index 87%
rename from sites/all/modules/webform/webform_hooks.php
rename to sites/all/modules/webform/webform.api.php
index a90a732d7f1cbe451c7673ecdc9b2f235c9a204c..7a21ba4bdc601e1004779d17cc3fc5562a6eeb8b 100644
--- a/sites/all/modules/webform/webform_hooks.php
+++ b/sites/all/modules/webform/webform.api.php
@@ -16,6 +16,14 @@
 /**
  * Define callbacks that can be used as select list options.
  *
+ * When users create a select component, they may select a pre-built list of
+ * certain options. Webform core provides a few of these lists such as the
+ * United States, countries of the world, and days of the week. This hook
+ * provides additional lists that may be utilized.
+ *
+ * @see webform_options_example()
+ * @see hook_webform_select_options_info_alter()
+ *
  * @return
  *   An array of callbacks that can be used for select list options. This array
  *   should be keyed by the "name" of the pre-defined list. The values should
@@ -38,6 +46,51 @@ function hook_webform_select_options_info() {
   return $items;
 }
 
+/**
+ * Alter the list of select list options provided by Webform and other modules.
+ *
+ * @see hook_webform_select_options_info().
+ */
+function hook_webform_select_options_info_alter(&$items) {
+  // Remove the days of the week options.
+  unset($items['days']);
+}
+
+/**
+ * This is an example function to demonstrate a webform options callback.
+ *
+ * This function returns a list of options that Webform may use in a select
+ * component. In order to be called, the function name
+ * ("webform_options_example" in this case), needs to be specified as a callback
+ * in hook_webform_select_options_info().
+ *
+ * @param $component
+ *   The Webform component array for the select component being displayed.
+ * @param $flat
+ *   Boolean value indicating whether the returned list needs to be a flat array
+ *   of key => value pairs. Select components support up to one level of
+ *   nesting, but when results are displayed, the list needs to be returned
+ *   without the nesting.
+ * @param $filter
+ *   Boolean value indicating whether the included options should be passed
+ *   through the _webform_filter_values() function for token replacement (only)
+ *   needed if your list contains tokens).
+ * @param $arguments
+ *   The "options arguments" specified in hook_webform_select_options_info().
+ * @return
+ *   An array of key => value pairs suitable for a select list's #options
+ *   FormAPI property.
+ */
+function webform_options_example($component, $flat, $filter, $arguments) {
+  $options = array(
+    'one' => t('Pre-built option one'),
+    'two' => t('Pre-built option two'),
+    'three' => t('Pre-built option three'),
+  );
+
+  return $options;
+}
+
 /**
  * Respond to the loading of Webform submissions.
  *
@@ -311,6 +364,12 @@ function hook_webform_component_info() {
       // Add content to CSV downloads. Defaults to TRUE.
       'csv' => TRUE,
 
+      // This component supports default values. Defaults to TRUE.
+      'default_value' => FALSE,
+
+      // This component supports a description field. Defaults to TRUE.
+      'description' => FALSE,
+
       // Show this component in e-mailed submissions. Defaults to TRUE.
       'email' => TRUE,
 
@@ -325,6 +384,9 @@ function hook_webform_component_info() {
       // This component may be toggled as required or not. Defaults to TRUE.
       'required' => TRUE,
 
+      // This component supports a title attribute. Defaults to TRUE.
+      'title' => FALSE,
+
       // This component has a title that can be toggled as displayed or not.
       'title_display' => TRUE,
 
@@ -369,6 +431,36 @@ function hook_webform_component_info_alter(&$components) {
   $components['textarea']['label'] = t('Text box');
 }
 
+/**
+ * Return an array of files associated with the component.
+ *
+ * The output of this function will be used to attach files to e-mail messages.
+ *
+ * @param $component
+ *   A Webform component array.
+ * @param $value
+ *   An array of information containing the submission result, directly
+ *   correlating to the webform_submitted_data database schema.
+ * @return
+ *   An array of files, each file is an array with following keys:
+ *     - filepath: The relative path to the file.
+ *     - filename: The name of the file including the extension.
+ *     - filemime: The mimetype of the file.
+ *   This will result in an array looking something like this:
+ *   @code
+ *   array[0] => array(
+ *     'filepath' => '/sites/default/files/attachment.txt',
+ *     'filename' => 'attachment.txt',
+ *     'filemime' => 'text/plain',
+ *   );
+ *   @endcode
+ */
+function _webform_attachments_component($component, $value) {
+  $files = array();
+  $files[] = (array) file_load($value[0]);
+  return $files;
+}
+
 /**
  * @}
  */
@@ -592,10 +684,12 @@ function _webform_help_component($section) {
 function _webform_theme_component() {
   return array(
     'webform_grid' => array(
-      'arguments' => array('grid_element' => NULL),
+      'render element' => 'element',
+      'file' => 'components/grid.inc',
     ),
-    'webform_mail_grid' => array(
-      'arguments' => array('component' => NULL, 'value' => NULL),
+    'webform_display_grid' => array(
+      'render element' => 'element',
+      'file' => 'components/grid.inc',
     ),
   );
 }
diff --git a/sites/all/modules/webform/webform.info b/sites/all/modules/webform/webform.info
index 4331c40f6bd4b4c962100860067eef2bab73c088..308009bed2eae35f140f815d3936a4b0c4deab0c 100644
--- a/sites/all/modules/webform/webform.info
+++ b/sites/all/modules/webform/webform.info
@@ -14,7 +14,9 @@ files[] = views/webform_handler_field_node_link_edit.inc
 files[] = views/webform_handler_field_node_link_results.inc
 files[] = views/webform_handler_field_submission_count.inc
 files[] = views/webform_handler_field_submission_link.inc
+files[] = views/webform_handler_field_webform_status.inc
 files[] = views/webform_handler_filter_is_draft.inc
+files[] = views/webform_handler_filter_webform_status.inc
 files[] = views/webform.views.inc
 
 files[] = tests/components.test
@@ -22,9 +24,9 @@ files[] = tests/permissions.test
 files[] = tests/submission.test
 files[] = tests/webform.test
 
-; Information added by drupal.org packaging script on 2011-08-31
-version = "7.x-3.13"
+; Information added by drupal.org packaging script on 2012-05-13
+version = "7.x-3.18"
 core = "7.x"
 project = "webform"
-datestamp = "1314806221"
+datestamp = "1336890411"
 
diff --git a/sites/all/modules/webform/webform.install b/sites/all/modules/webform/webform.install
index 67b37b8ad0586807824fed0414477eae84af5ee0..19dacf42b1e2512665b23c3704c531562bf368d5 100644
--- a/sites/all/modules/webform/webform.install
+++ b/sites/all/modules/webform/webform.install
@@ -97,6 +97,18 @@ function webform_schema() {
         'not null' => TRUE,
         'default' => -1,
       ),
+      'total_submit_limit' => array(
+        'description' => 'The total number of submissions allowed within an interval. -1 is unlimited.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => -1,
+      ),
+      'total_submit_interval' => array(
+        'description' => 'The amount of time in seconds that must pass before another submission can be submitted within the set limit.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => -1,
+      ),
     ),
     'primary key' => array('nid'),
   );
@@ -310,6 +322,7 @@ function webform_schema() {
     ),
     'indexes' => array(
       'nid_uid_sid' => array('nid', 'uid', 'sid'),
+      'nid_sid' => array('nid', 'sid'),
     ),
   );
 
@@ -408,19 +421,21 @@ function webform_install() {
     ->fields(array('weight' => -1))
     ->execute();
 
-  // Create the default webform type.
-  $webform_type = array(
-    'type' => 'webform',
-    'name' => st('Webform'),
-    'base' => 'node_content',
-    'description' => st('Create a new form or questionnaire accessible to users. Submission results and statistics are recorded and accessible to privileged users.'),
-    'custom' => TRUE,
-    'modified' => TRUE,
-    'locked' => FALSE,
-  );
-  $webform_type = node_type_set_defaults($webform_type);
-  node_type_save($webform_type);
-  node_add_body_field($webform_type);
+  // Optionally create the default webform type.
+  if (variable_get('webform_install_create_content_type', TRUE)) {
+    $webform_type = array(
+      'type' => 'webform',
+      'name' => st('Webform'),
+      'base' => 'node_content',
+      'description' => st('Create a new form or questionnaire accessible to users. Submission results and statistics are recorded and accessible to privileged users.'),
+      'custom' => TRUE,
+      'modified' => TRUE,
+      'locked' => FALSE,
+    );
+    $webform_type = node_type_set_defaults($webform_type);
+    node_type_save($webform_type);
+    node_add_body_field($webform_type);
+  }
 }
 
 /**
@@ -464,10 +479,42 @@ function webform_update_last_removed() {
 }
 
 /**
- * Ensure that the confirmation format column is correctly using size = 'tiny'.
+ * Allow the confirmation format column to have a NULL value.
  */
 function webform_update_7301() {
-  db_change_field('webform', 'confirmation_format', 'confirmation_format', array('type' => 'int', 'size' => 'tiny', 'not null' => TRUE, 'default' => 0));
+  // These changes are modeled after user_update_7010().
+  db_change_field('webform', 'confirmation_format', 'confirmation_format', array(
+    'description' => 'The {filter_format}.format of the confirmation message.',
+    'type' => 'int',
+    'unsigned' => TRUE,
+    'not null' => FALSE,
+  ));
+  db_update('webform')
+    ->fields(array('confirmation_format' => NULL))
+    ->condition('confirmation', '')
+    ->condition('confirmation_format', 0)
+    ->execute();
+  $existing_formats = db_query("SELECT format FROM {filter_format}")->fetchCol();
+  $default_format = variable_get('filter_default_format', 1);
+
+  // Since Webform may be updated separately from Drupal core, not all format
+  // names may be numbers when running this update.
+  $numeric_formats = array();
+  foreach ($existing_formats as $format_name) {
+    if (is_numeric($format_name)) {
+      $numeric_formats[] = (int) $format_name;
+    }
+  }
+
+  $query = db_update('webform')
+    ->fields(array('confirmation_format' => $default_format))
+    ->isNotNull('confirmation_format');
+
+  if (!empty($numeric_formats)) {
+    $query->condition('confirmation_format', $numeric_formats, 'NOT IN');
+  }
+
+  $query->execute();
 }
 
 /**
@@ -524,39 +571,8 @@ function webform_update_7306() {
  * Update the confirmation_format column for default text format changes.
  */
 function webform_update_7307() {
-  // These changes are modeled after user_update_7010().
-  db_change_field('webform', 'confirmation_format', 'confirmation_format', array(
-    'description' => 'The {filter_format}.format of the confirmation message.',
-    'type' => 'int',
-    'unsigned' => TRUE,
-    'not null' => FALSE,
-  ));
-  db_update('webform')
-    ->fields(array('confirmation_format' => NULL))
-    ->condition('confirmation', '')
-    ->condition('confirmation_format', 0)
-    ->execute();
-  $existing_formats = db_query("SELECT format FROM {filter_format}")->fetchCol();
-  $default_format = variable_get('filter_default_format', 1);
-
-  // Since Webform may be updated separately from Drupal core, not all format
-  // names may be numbers when running this update.
-  $numeric_formats = array();
-  foreach ($existing_formats as $format_name) {
-    if (is_numeric($format_name)) {
-      $numeric_formats[] = (int) $format_name;
-    }
-  }
-
-  $query = db_update('webform')
-    ->fields(array('confirmation_format' => $default_format))
-    ->isNotNull('confirmation_format');
-
-  if (!empty($numeric_formats)) {
-    $query->condition('confirmation_format', $numeric_formats, 'NOT IN');
-  }
-
-  $query->execute();
+  // Update removed and moved to webform_update_7301().
+  // See http://drupal.org/node/976102.
 }
 
 /**
@@ -600,7 +616,7 @@ function webform_update_7310() {
 }
 
 /**
- * Add an index for sid_nid_uid to webform_submissions.
+ * Add an index for nid_uid_sid to webform_submissions.
  */
 function webform_update_7311() {
   if (!db_index_exists('webform_submissions', 'nid_uid_sid')) {
@@ -649,6 +665,11 @@ function webform_update_7313() {
  * Add webform_last_download table to store last downloaded sid per user.
  */
 function webform_update_7314() {
+  // Safety check to prevent recreating the webform_last_download table.
+  if (db_table_exists('webform_last_download')) {
+    return;
+  }
+
   $schema['webform_last_download'] = array(
     'description' => 'Stores last submission number per user download.',
     'fields' => array(
@@ -687,3 +708,126 @@ function webform_update_7315() {
     db_add_field('webform_last_download', 'requested', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0,));
   }
 }
+
+/**
+ * Add additional columns for total submission limit.
+ */
+function webform_update_7316() {
+  if (!db_field_exists('webform', 'total_submit_limit')) {
+    db_add_field('webform', 'total_submit_limit', array('type' => 'int', 'not null' => TRUE, 'default' => -1));
+  }
+
+  if (!db_field_exists('webform', 'total_submit_interval')) {
+    db_add_field('webform', 'total_submit_interval', array('type' => 'int', 'not null' => TRUE, 'default' => -1));
+  }
+}
+
+/**
+ * Add an index for 'nid_sid' to webform_submissions.
+ */
+function webform_update_7317() {
+  // Even though we already have an index 'nid_uid_sid', adding the index for
+  // 'nid_sid' saves us a tablesort on the node/x/webform-results page.
+  if (!db_index_exists('webform_submissions', 'nid_sid')) {
+    db_add_index('webform_submissions', 'nid_sid', array('nid', 'sid'));
+  }
+}
+
+/**
+ * Upgrade file components to support the new AJAX-upload element.
+ */
+function webform_update_7318() {
+  $result = db_select('webform_component', 'wc', array('fetch' => PDO::FETCH_ASSOC))
+    ->fields('wc')
+    ->condition('type', 'file')
+    ->execute();
+  foreach ($result as $component) {
+    $component['extra'] = unserialize($component['extra']);
+    if (!isset($component['extra']['directory'])) {
+      $component['extra']['directory'] = $component['extra']['savelocation'];
+      $component['extra']['scheme'] = file_default_scheme();
+      $component['extra']['filtering']['size'] = $component['extra']['filtering']['size'] . ' KB';
+      unset($component['extra']['savelocation']);
+      $component['extra'] = serialize($component['extra']);
+      drupal_write_record('webform_component', $component, array('nid', 'cid'));
+    }
+  }
+
+  return t('File components updated to support AJAX uploading.');
+}
+
+/**
+ * Add file usage entries for all files uploaded through Webform.
+ */
+function webform_update_7319(&$sandbox) {
+  if (!isset($sandbox['progress'])) {
+    // Initialize batch update information.
+    $sandbox['progress'] = 0;
+    $sandbox['last_fid_processed'] = -1;
+    $sandbox['max'] = db_select('file_managed')
+      ->condition('uri', '%' . db_like('://webform/') . '%', 'LIKE')
+      ->countQuery()
+      ->execute()
+      ->fetchField();
+  }
+
+  // Process all files attached to a given revision during the same batch.
+  $limit = variable_get('webform_update_batch_size', 100);
+  $files = db_select('file_managed', 'f')
+    ->fields('f')
+    ->condition('uri', '%' . db_like('://webform/') . '%', 'LIKE')
+    ->condition('fid', $sandbox['last_fid_processed'], '>')
+    ->orderBy('fid', 'ASC')
+    ->range(0, $limit)
+    ->execute()
+    ->fetchAllAssoc('fid', PDO::FETCH_ASSOC);
+
+  // Determine each submission with which a file is associated.
+  if (!empty($files)) {
+    foreach ($files as $fid => $file) {
+      $file = (object) $file;
+      $sids = db_query('SELECT wsd.sid FROM {webform_component} wc INNER JOIN {webform_submitted_data} wsd ON wc.nid = wsd.nid AND wc.type = :file WHERE data = :fid', array(':file' => 'file', ':fid' => $file->fid))->fetchAllAssoc('sid', PDO::FETCH_ASSOC);
+      foreach ($sids as $sid => $row) {
+        // We use a db_merge() instead of file_usage_add() to prevent problems
+        // in the event this update was run twice. No file provided by Webform
+        // should ever be in use more than once at this point.
+        db_merge('file_usage')
+          ->key(array(
+            'fid' => $file->fid,
+            'type' => 'submission',
+            'module' => 'webform',
+            'id' => $sid,
+          ))
+          ->fields(array(
+            'count' => 1,
+          ))
+          ->execute();
+      }
+
+      // Update our progress information for the batch update.
+      $sandbox['progress']++;
+      $sandbox['last_fid_processed'] = $file->fid;
+    }
+  }
+
+  // If less than limit was processed, the update process is finished.
+  if (count($files) < $limit || $sandbox['progress'] == $sandbox['max']) {
+    $finished = TRUE;
+  }
+
+  // If there's no max value then there's nothing to update and we're finished.
+  if (empty($sandbox['max']) || isset($finished)) {
+    return t('Webform file entries created in the file_usage table.');
+  }
+  else {
+    // Indicate our current progress to the batch update system.
+    $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max'];
+  }
+}
+
+/**
+ * Mark files uploaded through Webform that report active usage permanent.
+ */
+function webform_update_7320() {
+  db_query("UPDATE {file_managed} SET status = 1 WHERE fid IN (SELECT fid FROM {file_usage} WHERE module = :module_name)", array(':module_name' => 'webform'));
+}
diff --git a/sites/all/modules/webform/webform.module b/sites/all/modules/webform/webform.module
index 23a35bdadf86d4fa27f68c92d0542e0b83eee6a6..6ff3c856fd3781d817be5019d498d1f2793fcaf2 100644
--- a/sites/all/modules/webform/webform.module
+++ b/sites/all/modules/webform/webform.module
@@ -120,6 +120,7 @@ function webform_menu() {
     'file' => 'includes/webform.components.inc',
     'weight' => 1,
     'type' => MENU_LOCAL_TASK,
+    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
   );
   $items['node/%webform_menu/webform/components'] = array(
     'title' => 'Form components',
@@ -178,6 +179,7 @@ function webform_menu() {
     'page arguments' => array('webform_component_edit_form', 1, 4, FALSE),
     'access callback' => 'node_access',
     'access arguments' => array('update', 1),
+    'file' => 'includes/webform.components.inc',
     'type' => MENU_LOCAL_TASK,
   );
   $items['node/%webform_menu/webform/components/%webform_menu_component/clone'] = array(
@@ -186,6 +188,7 @@ function webform_menu() {
     'page arguments' => array('webform_component_edit_form', 1, 4, TRUE),
     'access callback' => 'node_access',
     'access arguments' => array('update', 1),
+    'file' => 'includes/webform.components.inc',
     'type' => MENU_LOCAL_TASK,
   );
   $items['node/%webform_menu/webform/components/%webform_menu_component/delete'] = array(
@@ -194,6 +197,7 @@ function webform_menu() {
     'page arguments' => array('webform_component_delete_form', 1, 4),
     'access callback' => 'node_access',
     'access arguments' => array('update', 1),
+    'file' => 'includes/webform.components.inc',
     'type' => MENU_LOCAL_TASK,
   );
 
@@ -217,6 +221,7 @@ function webform_menu() {
     'file' => 'includes/webform.report.inc',
     'weight' => 2,
     'type' => MENU_LOCAL_TASK,
+    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
   );
   $items['node/%webform_menu/webform-results/submissions'] = array(
     'title' => 'Submissions',
@@ -502,15 +507,12 @@ function webform_permission() {
     ),
     'access own webform submissions' => array(
       'title' => t('Access own webform submissions'),
-      'description' => t('This permission has no effect for anonymous users.'),
     ),
     'edit own webform submissions' => array(
       'title' => t('Edit own webform submissions'),
-      'description' => t('This permission has no effect for anonymous users.'),
     ),
     'delete own webform submissions' => array(
       'title' => t('Delete own webform submissions'),
-      'description' => t('This permission has no effect for anonymous users.'),
     ),
   );
 }
@@ -525,7 +527,7 @@ function webform_theme() {
       'render element' => 'webform',
     ),
     'webform_view_messages' => array(
-      'variables' => array('node' => NULL, 'teaser' => NULL, 'page' => NULL, 'submission_count' => NULL, 'limit_exceeded' => NULL, 'allowed_roles' => NULL, 'closed' => NULL, 'cached' => NULL),
+      'variables' => array('node' => NULL, 'teaser' => NULL, 'page' => NULL, 'submission_count' => NULL, 'user_limit_exceeded' => NULL, 'total_limit_exceeded' => NULL, 'allowed_roles' => NULL, 'closed' => NULL, 'cached' => NULL),
     ),
     'webform_form' => array(
       'render element' => 'form',
@@ -602,6 +604,10 @@ function webform_theme() {
       'render element' => 'form',
       'file' => 'includes/webform.pages.inc',
     ),
+    'webform_advanced_total_submit_limit_form' => array(
+      'render element' => 'form',
+      'file' => 'includes/webform.pages.inc',
+    ),
     // webform.report.inc.
     'webform_results_per_page' => array(
       'variables' => array('total_count' => NULL, 'pager_count' => NULL),
@@ -624,8 +630,8 @@ function webform_theme() {
       'variables' => array('node' => NULL, 'components' => NULL, 'submissions' => NULL, 'node' => NULL, 'total_count' => NULL, 'pager_count' => NULL),
       'file' => 'includes/webform.report.inc',
     ),
-    'webform_results_download_form' => array(
-      'render element' => 'form',
+    'webform_results_download_range' => array(
+      'render element' => 'element',
       'file' => 'includes/webform.report.inc',
     ),
     'webform_results_download_select_format' => array(
@@ -706,6 +712,20 @@ function webform_element_info() {
   // files because of the unnecessary loading that it would require.
   $elements['webform_time'] = array('#input' => 'TRUE');
   $elements['webform_grid'] = array('#input' => 'TRUE');
+
+  $elements['webform_email'] = array(
+    '#input' => TRUE,
+    '#theme' => 'webform_email',
+    '#size' => 60,
+  );
+  $elements['webform_number'] = array(
+    '#input' => TRUE,
+    '#theme' => 'webform_number',
+    '#min' => NULL,
+    '#max' => NULL,
+    '#step' => NULL,
+  );
+
   return $elements;
 }
 
@@ -713,7 +733,7 @@ function webform_element_info() {
  * Implements hook_webform_component_info().
  */
 function webform_webform_component_info() {
-  return array(
+  $component_info = array(
     'date' => array(
       'label' => t('Date'),
       'description' => t('Presents month, day, and year fields.'),
@@ -736,6 +756,7 @@ function webform_webform_component_info() {
       'description' => t('Fieldsets allow you to organize multiple fields into groups.'),
       'features' => array(
         'csv' => FALSE,
+        'default_value' => FALSE,
         'required' => FALSE,
         'conditional' => FALSE,
         'group' => TRUE,
@@ -743,20 +764,12 @@ function webform_webform_component_info() {
       ),
       'file' => 'components/fieldset.inc',
     ),
-    'file' => array(
-      'label' => t('File'),
-      'description' => t('Allow users to upload files of configurable types.'),
-      'features' => array(
-        'conditional' => FALSE,
-        'attachment' => TRUE,
-      ),
-      'file' => 'components/file.inc',
-    ),
     'grid' => array(
       'label' => t('Grid'),
       'description' => t('Allows creation of grid questions, denoted by radio buttons.'),
       'features' => array(
         'conditional' => FALSE,
+        'default_value' => FALSE,
         'title_inline' => FALSE,
       ),
       'file' => 'components/grid.inc',
@@ -767,9 +780,11 @@ function webform_webform_component_info() {
       'file' => 'components/hidden.inc',
       'features' => array(
         'required' => FALSE,
+        'description' => FALSE,
         'email_address' => TRUE,
         'email_name' => TRUE,
         'title_display' => FALSE,
+        'private' => FALSE,
       ),
     ),
     'markup' => array(
@@ -777,18 +792,31 @@ function webform_webform_component_info() {
       'description' => t('Displays text as HTML in the form; does not render a field.'),
       'features' => array(
         'csv' => FALSE,
+        'default_value' => FALSE,
+        'description' => FALSE,
         'email' => FALSE,
         'required' => FALSE,
         'conditional' => FALSE,
         'title_display' => FALSE,
+        'private' => FALSE,
       ),
       'file' => 'components/markup.inc',
     ),
+    'number' => array(
+      'label' => t('Number'),
+      'description' => t('A numeric input field (either as textfield or select list).'),
+      'features' => array(
+      ),
+      'file' => 'components/number.inc',
+    ),
     'pagebreak' => array(
       'label' => t('Page break'),
       'description' => t('Organize forms into multiple pages.'),
       'features' => array(
         'csv' => FALSE,
+        'default_value' => FALSE,
+        'description' => FALSE,
+        'private' => FALSE,
         'required' => FALSE,
         'title_display' => FALSE,
       ),
@@ -799,6 +827,7 @@ function webform_webform_component_info() {
       'description' => t('Allows creation of checkboxes, radio buttons, or select menus.'),
       'file' => 'components/select.inc',
       'features' => array(
+        'default_value' => FALSE,
         'email_address' => TRUE,
         'email_name' => TRUE,
       ),
@@ -830,6 +859,21 @@ function webform_webform_component_info() {
       'file' => 'components/time.inc',
     ),
   );
+
+  if (module_exists('file')) {
+    $component_info['file'] = array(
+      'label' => t('File'),
+      'description' => t('Allow users to upload files of configurable types.'),
+      'features' => array(
+        'conditional' => FALSE,
+        'default_value' => FALSE,
+        'attachment' => TRUE,
+      ),
+      'file' => 'components/file.inc',
+    );
+  }
+
+  return $component_info;
 }
 
 /**
@@ -875,7 +919,7 @@ function webform_webform_submission_actions($node, $submission) {
     );
   }
 
-  if (webform_results_access($node)) {
+  if (webform_results_access($node) && count($node->webform['emails'])) {
     $actions['resend'] = array(
       'title' => t('Resend e-mails'),
       'href' => 'node/' . $node->nid . '/submission/' . $submission->sid . '/resend',
@@ -886,47 +930,129 @@ function webform_webform_submission_actions($node, $submission) {
   return $actions;
 }
 
+/**
+ * Implements hook_webform_submission_update().
+ *
+ * We implement our own hook here to facilitate the File component, which needs
+ * to clean up manage file usage records and delete files from submissions that
+ * have been edited if necessary.
+ */
+function webform_webform_submission_presave($node, &$submission) {
+  // Check if there are any file components in this submission and if any of
+  // them currently contain files.
+  $has_file_components = FALSE;
+  $new_fids = array();
+  $old_fids = array();
+
+  foreach ($node->webform['components'] as $cid => $component) {
+    if ($component['type'] == 'file') {
+      $has_file_components = TRUE;
+      if (!empty($submission->data[$cid]['value'])) {
+        $new_fids = array_merge($new_fids, $submission->data[$cid]['value']);
+      }
+    }
+  }
+
+  if ($has_file_components) {
+    // If we're updating a submission, build a list of previous files.
+    if (isset($submission->sid)) {
+      $old_submission = webform_get_submission($node->nid, $submission->sid, TRUE);
+
+      foreach ($node->webform['components'] as $cid => $component) {
+        if ($component['type'] == 'file') {
+          if (!empty($old_submission->data[$cid]['value'])) {
+            $old_fids = array_merge($old_fids, $old_submission->data[$cid]['value']);
+          }
+        }
+      }
+    }
+
+    // Save the list of added or removed files so we can add usage in
+    // hook_webform_submission_insert() or _update().
+    $submission->file_usage = array(
+      // Diff the old against new to determine what files were deleted.
+      'deleted_fids' => array_diff($old_fids, $new_fids),
+      // Diff the new files against old to determine new uploads.
+      'added_fids' => array_diff($new_fids, $old_fids)
+    );
+  }
+}
+
+/**
+ * Implements hook_webform_submission_insert().
+ */
+function webform_webform_submission_insert($node, $submission) {
+  if (isset($submission->file_usage)) {
+    webform_component_include('file');
+    webform_file_usage_adjust($submission);
+  }
+}
+
+/**
+ * Implements hook_webform_submission_update().
+ */
+function webform_webform_submission_update($node, $submission) {
+  if (isset($submission->file_usage)) {
+    webform_component_include('file');
+    webform_file_usage_adjust($submission);
+  }
+}
+
+/**
+ * Implements hook_webform_submission_render_alter().
+ */
+function webform_webform_submission_render_alter(&$renderable) {
+  // If displaying a submission to end-users who are viewing their own
+  // submissions (and not through an e-mail), do not show hidden values.
+  // This needs to be implemented at the level of the entire submission, since
+  // individual components do not get contextual information about where they
+  // are being displayed.
+  $node = $renderable['#node'];
+  $is_admin = webform_results_access($node);
+  if (empty($renderable['#email']) && !$is_admin) {
+    // Find and hide the display of all hidden components.
+    foreach ($node->webform['components'] as $cid => $component) {
+      if ($component['type'] == 'hidden') {
+        $parents = webform_component_parent_keys($node, $component);
+        $element = &$renderable;
+        foreach ($parents as $pid) {
+          $element = &$element[$pid];
+        }
+        $element['#access'] = FALSE;
+      }
+    }
+  }
+}
+
 /**
  * Implements hook_file_download().
  *
  * Only allow users with view webform submissions to download files.
  */
 function webform_file_download($uri) {
-  global $user;
+  module_load_include('inc', 'webform', 'includes/webform.submissions');
 
-  // Determine whether this file was a webform upload. If it was, retrieve file
-  // information, plus the user id of the uploader.
-  $file = db_query("SELECT ws.uid, f.* FROM {file_managed} f INNER JOIN {webform_submitted_data} wsd ON f.fid = wsd.data INNER JOIN {webform_submissions} ws ON ws.sid = wsd.sid WHERE f.uri = :uri", array('uri' => $uri))->fetchObject();
-  if ($file) {
-    // Allow file access for admins, or for users who are viewing their own
-    // submissions.
-    if (user_access('access all webform results') || ($user->uid == $file->uid && user_access('access own webform results'))) {
-      // TODO: This is a copy/paste from file_file_download. Switch to using
-      // file_get_content_headers() instead if http://drupal.org/node/943112
-      // gets committed.
-      $name = mime_header_encode($file->filename);
-      $type = mime_header_encode($file->filemime);
-      // Serve images, text, and flash content for display rather than download.
-      $inline_types = variable_get('file_inline_types', array('^text/', '^image/', 'flash$'));
-      $disposition = 'attachment';
-      foreach ($inline_types as $inline_type) {
-        // Exclamation marks are used as delimiters to avoid escaping slashes.
-        if (preg_match('!' . $inline_type . '!', $file->filemime)) {
-          $disposition = 'inline';
-        }
-      }
-      return array(
-        'Content-Type' => $type . '; name="' . $name . '"',
-        'Content-Length' => $file->filesize,
-        'Content-Disposition' => $disposition . '; filename="' . $name . '"',
-        'Cache-Control' => 'private',
-      );
+  // Determine whether this file was a webform upload.
+  $row = db_query("SELECT fu.id as sid, f.fid FROM {file_managed} f LEFT JOIN {file_usage} fu ON f.fid = fu.fid AND fu.module = :webform AND fu.type = :submission WHERE f.uri = :uri", array('uri' => $uri, ':webform' => 'webform', ':submission' => 'submission'))->fetchObject();
+  if ($row) {
+    $file = file_load($row->fid);
+  }
+  if (!empty($row->sid)) {
+    $submissions = webform_get_submissions(array('sid' => $row->sid));
+    $submission = reset($submissions);
+  }
+
+  // Grant access based on access to the submission.
+  if (!empty($submission)) {
+    $node = node_load($submission->nid);
+    if (webform_submission_access($node, $submission)) {
+      return file_get_content_headers($file);
     }
-    // This is a webform-controlled file, but the user doesn't have access.
-    return -1;
   }
-  // This is not a webform-controlled file.
-  return NULL;
+  // Grant access to files uploaded by a user before the submission is saved.
+  elseif (!empty($file) && !empty($_SESSION['webform_files'][$file->fid])) {
+    return file_get_content_headers($file);
+  }
 }
 
 /**
@@ -1136,6 +1262,8 @@ function webform_node_defaults() {
     'submit_text' => '',
     'submit_limit' => '-1',
     'submit_interval' => '-1',
+    'total_submit_limit' => '-1',
+    'total_submit_interval' => '-1',
     'status' => '1',
     'record_exists' => FALSE,
     'roles' => array('1', '2'),
@@ -1156,16 +1284,6 @@ function webform_node_prepare($node) {
   }
 }
 
-/**
- * Implements hook_node_prepare_translation().
- */
-function webform_node_prepare_translation(&$node) {
-  // Copy all Webform settings over to translated versions of this node.
-  if (isset($node->translation_source)) {
-    $source_node = node_load($node->translation_source->nid);
-    $node->webform = $source_node->webform;
-  }
-}
 
 /**
  * Implements hook_node_load().
@@ -1329,10 +1447,17 @@ function webform_node_view($node, $view_mode) {
   $submission_count = 0;
   $enabled = TRUE;
   $logging_in = FALSE;
-  $limit_exceeded = FALSE;
+  $total_limit_exceeded = FALSE;
+  $user_limit_exceeded = FALSE;
   $closed = FALSE;
   $allowed_roles = array();
 
+  // If a teaser, tell the form to load subsequent pages on the node page.
+  if ($teaser && !isset($node->webform['action'])) {
+    $query = array_diff_key($_GET, array('q' => ''));
+    $node->webform['action'] = url('node/' . $node->nid, array('query' => $query));
+  }
+
   // When logging in using a form on the same page as a webform node, suppress
   // output messages so that they don't show up after the user has logged in.
   // See http://drupal.org/node/239343.
@@ -1376,7 +1501,18 @@ function webform_node_view($node, $view_mode) {
     module_load_include('inc', 'webform', 'includes/webform.submissions');
 
     // Disable the form if the limit is exceeded and page cache is not active.
-    if (($limit_exceeded = _webform_submission_limit_check($node)) && !$cached) {
+    if (($user_limit_exceeded = _webform_submission_user_limit_check($node)) && !$cached) {
+      $enabled = FALSE;
+    }
+  }
+
+  // Check if the user can add another submission if there is a limit on total
+  // submissions.
+  if ($node->webform['total_submit_limit'] != -1) { // -1: Submissions are never throttled.
+    module_load_include('inc', 'webform', 'includes/webform.submissions');
+
+    // Disable the form if the limit is exceeded and page cache is not active.
+    if (($total_limit_exceeded = _webform_submission_total_limit_check($node)) && !$cached) {
       $enabled = FALSE;
     }
   }
@@ -1403,7 +1539,7 @@ function webform_node_view($node, $view_mode) {
 
   // Print out messages for the webform.
   if (empty($node->in_preview) && !isset($node->webform_block) && !$logging_in) {
-    theme('webform_view_messages', array('node' => $node, 'teaser' => $teaser, 'page' => $page, 'submission_count' => $submission_count, 'limit_exceeded' => $limit_exceeded, 'allowed_roles' => $allowed_roles, 'closed' => $closed, 'cached' => $cached));
+    theme('webform_view_messages', array('node' => $node, 'teaser' => $teaser, 'page' => $page, 'submission_count' => $submission_count, 'user_limit_exceeded' => $user_limit_exceeded, 'total_limit_exceeded' => $total_limit_exceeded, 'allowed_roles' => $allowed_roles, 'closed' => $closed, 'cached' => $cached));
   }
 
   // Add the output to the node.
@@ -1451,8 +1587,10 @@ function theme_webform_view($variables) {
  * @param $submission_count
  *   The number of submissions this user has already submitted. Not calculated
  *   for anonymous users.
- * @param $limit_exceeded
+ * @param $user_limit_exceeded
  *   Boolean value if the submission limit for this user has been exceeded.
+ * @param $total_limit_exceeded
+ *   Boolean value if the total submission limit has been exceeded.
  * @param $allowed_roles
  *   A list of user roles that are allowed to submit this webform.
  * @param $closed
@@ -1465,7 +1603,8 @@ function theme_webform_view_messages($variables) {
   $teaser = $variables['teaser'];
   $page = $variables['page'];
   $submission_count = $variables['submission_count'];
-  $limit_exceeded = $variables['limit_exceeded'];
+  $user_limit_exceeded = $variables['user_limit_exceeded'];
+  $total_limit_exceeded = $variables['total_limit_exceeded'];
   $allowed_roles = $variables['allowed_roles'];
   $closed = $variables['closed'];
   $cached = $variables['cached'];
@@ -1499,7 +1638,7 @@ function theme_webform_view_messages($variables) {
   }
 
   // If the user has exceeded the limit of submissions, explain the limit.
-  elseif ($limit_exceeded && !$cached) {
+  elseif ($user_limit_exceeded && !$cached) {
     if ($node->webform['submit_interval'] == -1 && $node->webform['submit_limit'] > 1) {
       $message = t('You have submitted this form the maximum number of times (@count).', array('@count' => $node->webform['submit_limit']));
     }
@@ -1511,6 +1650,14 @@ function theme_webform_view_messages($variables) {
     }
     $type = 'error';
   }
+  elseif ($total_limit_exceeded && !$cached) {
+    if ($node->webform['total_submit_interval'] == -1 && $node->webform['total_submit_limit'] > 1) {
+      $message = t('This form has received the maximum number of entries.');
+    }
+    else {
+      $message = t('You may not submit another entry at this time.');
+    }
+  }
 
   // If the user has submitted before, give them a link to their submissions.
   if ($submission_count > 0 && $node->webform['submit_notice'] == 1 && !$cached) {
@@ -1597,6 +1744,15 @@ function webform_block_view($delta = '') {
   // Use the node title for the block title.
   $subject = $node->title;
 
+  // If not displaying pages in the block, set the #action property on the form.
+  if ($settings['pages_block']) {
+    $node->webform['action'] = FALSE;
+  }
+  else {
+    $query = array_diff_key($_GET, array('q' => ''));
+    $node->webform['action'] = url('node/' . $node->nid, array('query' => $query));
+  }
+
   // Generate the content of the block based on display settings.
   if ($settings['display'] == 'form') {
     webform_node_view($node, 'full');
@@ -1607,10 +1763,17 @@ function webform_block_view($delta = '') {
     $content = node_view($node, $teaser);
   }
 
+  // Add contextual links for the webform node if they aren't already there.
+  if (!isset($content['#contextual_links']['node'])) {
+    $content['#contextual_links']['node'] = array('node', array($node->nid));
+  }
+
   // Create the block.
+  // Note that we render the content immediately here rather than passing back
+  // a renderable so that if the block is empty it is hidden.
   $block = array(
     'subject' => $subject,
-    'content' => $content,
+    'content' => drupal_render($content),
   );
   return $block;
 }
@@ -1687,7 +1850,7 @@ function webform_block_save($delta = '', $edit = array()) {
  *   building the form. Values need to be unfiltered to be editable by
  *   Form Builder.
  */
-function webform_client_form($form, $form_state, $node, $submission, $is_draft = FALSE, $filter = TRUE) {
+function webform_client_form($form, &$form_state, $node, $submission, $is_draft = FALSE, $filter = TRUE) {
   global $user;
 
   // Attach necessary JavaScript and CSS.
@@ -1695,8 +1858,12 @@ function webform_client_form($form, $form_state, $node, $submission, $is_draft =
     'css' => array(drupal_get_path('module', 'webform') . '/css/webform.css'),
     'js' => array(drupal_get_path('module', 'webform') . '/js/webform.js'),
   );
-  module_load_include('inc', 'webform', 'includes/webform.components');
-  module_load_include('inc', 'webform', 'includes/webform.submissions');
+  form_load_include($form_state, 'inc', 'webform', 'includes/webform.components');
+  form_load_include($form_state, 'inc', 'webform', 'includes/webform.submissions');
+
+  $form['#process'] = array(
+    'webform_client_form_includes',
+  );
 
   // If in a multi-step form, a submission ID may be specified in form state.
   // Load this submission. This allows anonymous users to use auto-save.
@@ -1720,21 +1887,10 @@ function webform_client_form($form, $form_state, $node, $submission, $is_draft =
   // Set the encoding type (necessary for file uploads).
   $form['#attributes']['enctype'] = 'multipart/form-data';
 
-  // If this is a webform block, load the block-specific configuration settings.
-  $pages_in_node = TRUE;
-  if (isset($node->webform_block)) {
-    $webform_blocks = variable_get('webform_blocks', array());
-    $delta = 'client-block-' . $node->nid;
-    $block_settings = isset($webform_blocks[$delta]) ? $webform_blocks[$delta] : array();
-    $pages_in_node = empty($block_settings['pages_block']);
-  }
-
-  // Set the form action to the node ID in case this is being displayed on the
-  // teaser or in a block, subsequent pages should be on the node page directly.
-  if ($pages_in_node && empty($submission)) {
-    $query = $_GET;
-    unset($query['q']);
-    $form['#action'] = url('node/' . $node->nid, array('query' => $query));
+  // Sometimes when displaying a webform as a teaser or block, a custom action
+  // property is set to direct the user to the node page.
+  if (!empty($node->webform['action'])) {
+    $form['#action'] = $node->webform['action'];
   }
 
   $form['#submit'] = array('webform_client_form_pages', 'webform_client_form_submit');
@@ -1767,10 +1923,20 @@ function webform_client_form($form, $form_state, $node, $submission, $is_draft =
     $page_count = $form_state['webform']['page_count'];
     $page_num = $form_state['webform']['page_num'];
 
-    // Recursively add components to the form.
+    if ($page_count > 1) {
+      $next_page_labels = array();
+      $prev_page_labels = array();
+    }
+
+    // Recursively add components to the form. The unfiltered version of the
+    // form (typically used in Form Builder), includes all components.
     foreach ($component_tree['children'] as $cid => $component) {
       $component_value = isset($form_state['values']['submitted'][$cid]) ? $form_state['values']['submitted'][$cid] : NULL;
-      if (_webform_client_form_rule_check($node, $component, $page_num, $form_state)) {
+      if ($filter == FALSE || _webform_client_form_rule_check($node, $component, $page_num, $form_state)) {
+        if ($component['type'] == 'pagebreak') {
+          $next_page_labels[$component['page_num'] - 1] = !empty($component['extra']['next_page_label']) ? $component['extra']['next_page_label'] : t('Next Page >');
+          $prev_page_labels[$component['page_num']] = !empty($component['extra']['prev_page_label']) ? $component['extra']['prev_page_label'] : t('< Previous Page');
+        }
         _webform_client_form_add_component($node, $component, $component_value, $form['submitted'], $form, $form_state, $submission, 'form', $page_num, $filter);
       }
     }
@@ -1814,20 +1980,19 @@ function webform_client_form($form, $form_state, $node, $submission, $is_draft =
         '#value' => t('Save Draft'),
         '#weight' => -2,
         '#validate' => array(),
+        '#attributes' => array('formnovalidate' => 'formnovalidate'),
       );
     }
 
     if ($page_count > 1) {
-      $next_page = t('Next Page >');
-      $prev_page = t('< Previous Page');
-
       // Add the submit button(s).
       if ($page_num > 1) {
         $form['actions']['previous'] = array(
           '#type' => 'submit',
-          '#value' => $prev_page,
+          '#value' => $prev_page_labels[$page_num],
           '#weight' => 5,
           '#validate' => array(),
+          '#attributes' => array('formnovalidate' => 'formnovalidate'),
         );
       }
       if ($page_num == $page_count) {
@@ -1840,7 +2005,7 @@ function webform_client_form($form, $form_state, $node, $submission, $is_draft =
       elseif ($page_num < $page_count) {
         $form['actions']['next'] = array(
           '#type' => 'submit',
-          '#value' => $next_page,
+          '#value' => $next_page_labels[$page_num],
           '#weight' => 10,
         );
       }
@@ -1858,6 +2023,19 @@ function webform_client_form($form, $form_state, $node, $submission, $is_draft =
   return $form;
 }
 
+/**
+ * Process function for webform_client_form().
+ *
+ * Include all the enabled components for this form to ensure availability.
+ */
+function webform_client_form_includes($form, $form_state) {
+  $components = webform_components();
+  foreach ($components as $component_type => $component) {
+    webform_component_include($component_type);
+  }
+  return $form;
+}
+
 /**
  * Check if a component should be displayed on the current page.
  */
@@ -1960,6 +2138,12 @@ function _webform_client_form_add_component($node, $component, $component_value,
     // This component is display only.
     $data = empty($submission->data[$cid]['value']) ? NULL : $submission->data[$cid]['value'];
     if ($display_element = webform_component_invoke($component['type'], 'display', $component, $data, $format)) {
+      // Ensure the component is added as a property.
+      $display_element['#webform_component'] = $component;
+
+      // Allow modules to modify a "display only" webform component.
+      drupal_alter('webform_component_display', $display_element, $component);
+
       // The form_builder() function usually adds #parents and #id for us, but
       // because these are not marked for #input, we need to add them manually.
       if (!isset($display_element['#parents'])) {
@@ -1970,13 +2154,24 @@ function _webform_client_form_add_component($node, $component, $component_value,
       if (!isset($display_element['#id'])) {
         $display_element['#id'] = drupal_clean_css_identifier('edit-' . implode('-', $display_element['#parents']));
       }
+
+      // Add the element into the proper parent in the display.
       $parent_fieldset[$component['form_key']] = $display_element;
     }
   }
-  elseif ($component['page_num'] == $page_num) {
+  // Show the component only on its form page, or if building an unfiltered
+  // version of the form (such as for Form Builder).
+  elseif ($component['page_num'] == $page_num || $filter == FALSE) {
     // Add this user-defined field to the form (with all the values that are always available).
     $data = isset($submission->data[$cid]['value']) ? $submission->data[$cid]['value'] : NULL;
     if ($element = webform_component_invoke($component['type'], 'render', $component, $data, $filter)) {
+      // Ensure the component is added as a property.
+      $element['#webform_component'] = $component;
+
+      // Allow modules to modify a webform component that is going to be render in a form.
+      drupal_alter('webform_component_render', $element, $component);
+
+      // Add the element into the proper parent in the form.
       $parent_fieldset[$component['form_key']] = $element;
 
       // Override the value if one already exists in the form state.
@@ -2017,16 +2212,29 @@ function webform_client_form_validate($form, &$form_state) {
   $node = node_load($form_state['values']['details']['nid']);
   $finished = $form_state['values']['details']['finished'];
 
+  // Check that the submissions have not exceeded the total submission limit.
+  if ($node->webform['total_submit_limit'] != -1) {
+    module_load_include('inc', 'webform', 'includes/webform.submissions');
+    // Check if the total number of entries was reached before the user submitted
+    // the form.
+    if (!$finished && $total_limit_exceeded = _webform_submission_total_limit_check($node)) {
+      // Show the user the limit has exceeded.
+      theme('webform_view_messages', array('node' => $node, 'teaser' => 0, 'page' => 1, 'submission_count' => 0, 'total_limit_exceeded' => $total_limit_exceeded, 'allowed_roles' => array_keys(user_roles()), 'closed' => FALSE, 'cached' => FALSE));
+      form_set_error('', NULL);
+      return;
+    }
+  }
+
   // Check that the user has not exceeded the submission limit.
   // This usually will only apply to anonymous users when the page cache is
   // enabled, because they may submit the form even if they do not have access.
   if ($node->webform['submit_limit'] != -1) { // -1: Submissions are never throttled.
     module_load_include('inc', 'webform', 'includes/webform.submissions');
 
-    if (!$finished && $limit_exceeded = _webform_submission_limit_check($node)) {
+    if (!$finished && $user_limit_exceeded = _webform_submission_user_limit_check($node)) {
       // Assume that webform_view_messages will print out the necessary message,
       // then stop the processing of the form with an empty form error.
-      theme('webform_view_messages', array('node' => $node, 'teaser' => 0, 'page' => 1, 'submission_count' => 0, 'limit_exceeded' => $limit_exceeded, 'allowed_roles' => array_keys(user_roles()), 'closed' => FALSE, 'cached' => FALSE));
+      theme('webform_view_messages', array('node' => $node, 'teaser' => 0, 'page' => 1, 'submission_count' => 0, 'user_limit_exceeded' => $user_limit_exceeded, 'allowed_roles' => array_keys(user_roles()), 'closed' => FALSE, 'cached' => FALSE));
       form_set_error('', NULL);
       return;
     }
@@ -2135,9 +2343,6 @@ function webform_client_form_pages($form, &$form_state) {
   $submit_op = !empty($form['actions']['submit']['#value']) ? $form['actions']['submit']['#value'] : t('Submit');
   $draft_op = !empty($form['actions']['draft']['#value']) ? $form['actions']['draft']['#value'] : t('Save Draft');
   if (!in_array($form_state['values']['op'], array($submit_op, $draft_op))) {
-    // Checkboxes need post-processing to maintain their values.
-    _webform_client_form_submit_process($node, $form_state['values']['submitted'], array('select', 'grid'));
-
     // Store values from the current page in the form state storage.
     if (is_array($form_state['values']['submitted'])) {
       foreach ($form_state['values']['submitted'] as $key => $val) {
@@ -2220,7 +2425,7 @@ function webform_client_form_pages($form, &$form_state) {
   }
   else {
     // Remove the form state storage now that we're done with the pages.
-    unset($form_state['rebuild']);
+    $form_state['rebuild'] = FALSE;
     unset($form_state['storage']);
   }
 }
@@ -2256,7 +2461,7 @@ function webform_client_form_submit($form, &$form_state) {
   }
   else {
     // To maintain time and user information, load the existing submission.
-    $submission = webform_get_submission($node->nid, $sid);
+    $submission = webform_get_submission($node->webform['nid'], $sid);
     $submission->is_draft = $is_draft;
 
     // Merge with new submission data. The + operator maintains numeric keys.
@@ -2266,6 +2471,13 @@ function webform_client_form_submit($form, &$form_state) {
     $submission->data = $new_data + $submission->data;
   }
 
+  // If there is no data to be saved (such as on a multipage form with no fields
+  // on the first page), process no further. Submissions with no data cannot
+  // be loaded from the database as efficiently, so we don't save them at all.
+  if (empty($submission->data)) {
+    return;
+  }
+
   // Save the submission to the database.
   if (!$sid) {
     // No sid was found thus insert it in the dataabase.
@@ -2276,8 +2488,9 @@ function webform_client_form_submit($form, &$form_state) {
     // The cookie expires in the length of the interval plus a day to compensate for different timezones.
     if (variable_get('webform_use_cookies', 0)) {
       $cookie_name = 'webform-' . $node->nid;
-      $time = time();
-      setcookie($cookie_name . '[' . $time . ']', $time, $time + $node->webform['submit_interval'] + 86400);
+      $time = REQUEST_TIME;
+      $params = session_get_cookie_params();
+      setcookie($cookie_name . '[' . $time . ']', $time, $time + $node->webform['submit_interval'] + 86400, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
     }
 
     // Save session information about this submission for anonymous users,
@@ -2294,7 +2507,7 @@ function webform_client_form_submit($form, &$form_state) {
 
   // Check if this form is sending an email.
   if (!$is_draft && !$form_state['values']['details']['finished']) {
-    $submission = webform_get_submission($node->nid, $sid, TRUE);
+    $submission = webform_get_submission($node->webform['nid'], $sid, TRUE);
     webform_submission_send_mail($node, $submission);
   }
 
@@ -2445,6 +2658,19 @@ function template_preprocess_webform_mail_message(&$vars) {
   $vars['ip_address'] = ip_address();
 }
 
+/**
+ * A Form API #pre_render function. Sets display based on #title_display.
+ *
+ * This function is used regularly in D6 for all elements, but specifically for
+ * fieldsets in D7, which don't support #title_display natively.
+ */
+function webform_element_title_display($element) {
+  if (isset($element['#title_display']) && strcmp($element['#title_display'], 'none') === 0) {
+    $element['#title'] = NULL;
+  }
+  return $element;
+}
+
 /**
  * Replacement for theme_form_element().
  */
@@ -2461,20 +2687,22 @@ function theme_webform_element($variables) {
     $type = 'display';
   }
   else {
-    $type = (isset($element['#type']) && !in_array($element['#type'], array('markup', 'textfield'))) ? $element['#type'] : $element['#webform_component']['type'];
+    $type = (isset($element['#type']) && !in_array($element['#type'], array('markup', 'textfield', 'webform_email', 'webform_number'))) ? $element['#type'] : $element['#webform_component']['type'];
   }
-  $parents = str_replace('_', '-', implode('--', array_slice($element['#parents'], 1)));
+
+  // Convert the parents array into a string, excluding the "submitted" wrapper.
+  $nested_level = $element['#parents'][0] == 'submitted' ? 1 : 0;
+  $parents = str_replace('_', '-', implode('--', array_slice($element['#parents'], $nested_level)));
 
   $wrapper_classes = array(
    'form-item',
    'webform-component',
    'webform-component-' . $type,
   );
-  if (isset($element['#title_display']) && $element['#title_display'] == 'inline') {
+  if (isset($element['#title_display']) && strcmp($element['#title_display'], 'inline') === 0) {
     $wrapper_classes[] = 'webform-container-inline';
   }
   $output = '<div class="' . implode(' ', $wrapper_classes) . '" id="webform-component-' . $parents . '">' . "\n";
-  $required = !empty($element['#required']) ? '<span class="form-required" title="' . t('This field is required.') . '">*</span>' : '';
 
   // If #title is not set, we don't display any label or required marker.
   if (!isset($element['#title'])) {
@@ -2590,8 +2818,8 @@ function theme_webform_inline_radio($variables) {
 
   // Add container-inline to all elements.
   $class[] = 'webform-container-inline';
-  if (isset($element['#inline_element'])) {
-    $variables['element']['#title'] = $variables['element']['#title'] . ': ';
+  if (isset($element['#inline_element']) && isset($variables['element']['#title'])) {
+    $variables['element']['#title'] .= ': ';
   }
 
   $output = '<div class="' . implode(' ', $class) . '">' . "\n";
@@ -2701,7 +2929,7 @@ function _webform_filter_values($string, $node = NULL, $submission = NULL, $emai
 
   // Submission replacements.
   if (isset($submission) && !isset($replacements['email'][$format])) {
-    module_load_include('inc', 'webform', 'includes/webform.components.inc');
+    module_load_include('inc', 'webform', 'includes/webform.components');
 
     // Set the submission ID.
     $replacements['unsafe']['%sid'] = $submission->sid;
@@ -2717,6 +2945,10 @@ function _webform_filter_values($string, $node = NULL, $submission = NULL, $emai
       $parents = webform_component_parent_keys($node, $component);
       $form_key = implode('][', $parents);
       $display_element = webform_component_invoke($component['type'], 'display', $component, $value['value'], $format);
+
+      // Ensure the component is added as a property.
+      $display_element['#webform_component'] = $component;
+
       if (empty($display_element['#parents'])) {
         $display_element['#parents'] = array_merge(array('submitted'), $parents);
       }
@@ -2794,7 +3026,10 @@ function _webform_filter_values($string, $node = NULL, $submission = NULL, $emai
             $replacement = webform_strtodate(webform_date_format(), $value['month'] . '/' . $value['day'] . '/' . $value['year'], 'UTC');
           }
           else {
-            $replacement = (!is_array($value) && !is_object($value)) ? $value : '';
+            // Checking for complex types (arrays and objects) fails here with
+            // incomplete objects (see http://php.net/is_object), so we check
+            // for simple types instead.
+            $replacement = (is_string($value) || is_bool($value) || is_numeric($value)) ? $value : '';
           }
           $replacements[$safe_state][$token . '[' . $key . ']'] = $replacement;
         }
@@ -3468,7 +3703,8 @@ function webform_strtodate($format, $string, $timezone_name = NULL) {
   if (variable_get('configurable_timezones', 1) && $timezone_name == 'user') {
     $timezone_name = isset($GLOBALS['user']->timezone) ? $GLOBALS['user']->timezone : 'UTC';
   }
-  elseif (empty($timezone_name) || $timezone_name == 'user') {
+  // If the timezone is still empty or not set, use the site timezone.
+  if (empty($timezone_name) || $timezone_name == 'user') {
     $timezone_name = variable_get('date_default_timezone', 'UTC');
   }
 
@@ -3501,11 +3737,15 @@ function webform_strtotime($date) {
 }
 
 /**
- * Wrapper function for tt() if i18nstrings enabled.
+ * Wrapper function for i18n_string() if i18nstrings enabled.
  */
 function webform_tt($name, $string, $langcode = NULL, $update = FALSE) {
-  if (function_exists('tt')) {
-    return tt($name, $string, $langcode, $update);
+  if (function_exists('i18n_string')) {
+    $options = array(
+      'langcode' => $langcode,
+      'update' => $update,
+    );
+    return i18n_string($name, $string, $options);
   }
   else {
     return $string;
diff --git a/sites/all/modules/webform_alt_ui/LICENSE.txt b/sites/all/modules/webform_alt_ui/LICENSE.txt
deleted file mode 100644
index 2c095c8d3f42488e8168f9710a4ffbfc4125a159..0000000000000000000000000000000000000000
--- a/sites/all/modules/webform_alt_ui/LICENSE.txt
+++ /dev/null
@@ -1,274 +0,0 @@
-GNU GENERAL PUBLIC LICENSE
-
-              Version 2, June 1991
-
-Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
-Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
-verbatim copies of this license document, but changing it is not allowed.
-
-                  Preamble
-
-The licenses for most software are designed to take away your freedom to
-share and change it. By contrast, the GNU General Public License is
-intended to guarantee your freedom to share and change free software--to
-make sure the software is free for all its users. This General Public License
-applies to most of the Free Software Foundation's software and to any other
-program whose authors commit to using it. (Some other Free Software
-Foundation software is covered by the GNU Library General Public License
-instead.) You can apply it to your programs, too.
-
-When we speak of free software, we are referring to freedom, not price. Our
-General Public Licenses are designed to make sure that you have the
-freedom to distribute copies of free software (and charge for this service if
-you wish), that you receive source code or can get it if you want it, that you
-can change the software or use pieces of it in new free programs; and that
-you know you can do these things.
-
-To protect your rights, we need to make restrictions that forbid anyone to
-deny you these rights or to ask you to surrender the rights. These restrictions
-translate to certain responsibilities for you if you distribute copies of the
-software, or if you modify it.
-
-For example, if you distribute copies of such a program, whether gratis or for
-a fee, you must give the recipients all the rights that you have. You must make
-sure that they, too, receive or can get the source code. And you must show
-them these terms so they know their rights.
-
-We protect your rights with two steps: (1) copyright the software, and (2)
-offer you this license which gives you legal permission to copy, distribute
-and/or modify the software.
-
-Also, for each author's protection and ours, we want to make certain that
-everyone understands that there is no warranty for this free software. If the
-software is modified by someone else and passed on, we want its recipients
-to know that what they have is not the original, so that any problems
-introduced by others will not reflect on the original authors' reputations.
-
-Finally, any free program is threatened constantly by software patents. We
-wish to avoid the danger that redistributors of a free program will individually
-obtain patent licenses, in effect making the program proprietary. To prevent
-this, we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-
-The precise terms and conditions for copying, distribution and modification
-follow.
-
-           GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
-               MODIFICATION
-
-0. This License applies to any program or other work which contains a notice
-placed by the copyright holder saying it may be distributed under the terms
-of this General Public License. The "Program", below, refers to any such
-program or work, and a "work based on the Program" means either the
-Program or any derivative work under copyright law: that is to say, a work
-containing the Program or a portion of it, either verbatim or with
-modifications and/or translated into another language. (Hereinafter, translation
-is included without limitation in the term "modification".) Each licensee is
-addressed as "you".
-
-Activities other than copying, distribution and modification are not covered
-by this License; they are outside its scope. The act of running the Program is
-not restricted, and the output from the Program is covered only if its contents
-constitute a work based on the Program (independent of having been made
-by running the Program). Whether that is true depends on what the Program
-does.
-
-1. You may copy and distribute verbatim copies of the Program's source
-code as you receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice and
-disclaimer of warranty; keep intact all the notices that refer to this License
-and to the absence of any warranty; and give any other recipients of the
-Program a copy of this License along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and you
-may at your option offer warranty protection in exchange for a fee.
-
-2. You may modify your copy or copies of the Program or any portion of it,
-thus forming a work based on the Program, and copy and distribute such
-modifications or work under the terms of Section 1 above, provided that you
-also meet all of these conditions:
-
-a) You must cause the modified files to carry prominent notices stating that
-you changed the files and the date of any change.
-
-b) You must cause any work that you distribute or publish, that in whole or in
-part contains or is derived from the Program or any part thereof, to be
-licensed as a whole at no charge to all third parties under the terms of this
-License.
-
-c) If the modified program normally reads commands interactively when run,
-you must cause it, when started running for such interactive use in the most
-ordinary way, to print or display an announcement including an appropriate
-copyright notice and a notice that there is no warranty (or else, saying that
-you provide a warranty) and that users may redistribute the program under
-these conditions, and telling the user how to view a copy of this License.
-(Exception: if the Program itself is interactive but does not normally print such
-an announcement, your work based on the Program is not required to print
-an announcement.)
-
-These requirements apply to the modified work as a whole. If identifiable
-sections of that work are not derived from the Program, and can be
-reasonably considered independent and separate works in themselves, then
-this License, and its terms, do not apply to those sections when you distribute
-them as separate works. But when you distribute the same sections as part
-of a whole which is a work based on the Program, the distribution of the
-whole must be on the terms of this License, whose permissions for other
-licensees extend to the entire whole, and thus to each and every part
-regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest your rights to
-work written entirely by you; rather, the intent is to exercise the right to
-control the distribution of derivative or collective works based on the
-Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of a
-storage or distribution medium does not bring the other work under the scope
-of this License.
-
-3. You may copy and distribute the Program (or a work based on it, under
-Section 2) in object code or executable form under the terms of Sections 1
-and 2 above provided that you also do one of the following:
-
-a) Accompany it with the complete corresponding machine-readable source
-code, which must be distributed under the terms of Sections 1 and 2 above
-on a medium customarily used for software interchange; or,
-
-b) Accompany it with a written offer, valid for at least three years, to give
-any third party, for a charge no more than your cost of physically performing
-source distribution, a complete machine-readable copy of the corresponding
-source code, to be distributed under the terms of Sections 1 and 2 above on
-a medium customarily used for software interchange; or,
-
-c) Accompany it with the information you received as to the offer to distribute
-corresponding source code. (This alternative is allowed only for
-noncommercial distribution and only if you received the program in object
-code or executable form with such an offer, in accord with Subsection b
-above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source code
-means all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation and
-installation of the executable. However, as a special exception, the source
-code distributed need not include anything that is normally distributed (in
-either source or binary form) with the major components (compiler, kernel,
-and so on) of the operating system on which the executable runs, unless that
-component itself accompanies the executable.
-
-If distribution of executable or object code is made by offering access to
-copy from a designated place, then offering equivalent access to copy the
-source code from the same place counts as distribution of the source code,
-even though third parties are not compelled to copy the source along with the
-object code.
-
-4. You may not copy, modify, sublicense, or distribute the Program except as
-expressly provided under this License. Any attempt otherwise to copy,
-modify, sublicense or distribute the Program is void, and will automatically
-terminate your rights under this License. However, parties who have received
-copies, or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
-5. You are not required to accept this License, since you have not signed it.
-However, nothing else grants you permission to modify or distribute the
-Program or its derivative works. These actions are prohibited by law if you
-do not accept this License. Therefore, by modifying or distributing the
-Program (or any work based on the Program), you indicate your acceptance
-of this License to do so, and all its terms and conditions for copying,
-distributing or modifying the Program or works based on it.
-
-6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the original
-licensor to copy, distribute or modify the Program subject to these terms and
-conditions. You may not impose any further restrictions on the recipients'
-exercise of the rights granted herein. You are not responsible for enforcing
-compliance by third parties to this License.
-
-7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues), conditions
-are imposed on you (whether by court order, agreement or otherwise) that
-contradict the conditions of this License, they do not excuse you from the
-conditions of this License. If you cannot distribute so as to satisfy
-simultaneously your obligations under this License and any other pertinent
-obligations, then as a consequence you may not distribute the Program at all.
-For example, if a patent license would not permit royalty-free redistribution
-of the Program by all those who receive copies directly or indirectly through
-you, then the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply and
-the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any patents or
-other property right claims or to contest validity of any such claims; this
-section has the sole purpose of protecting the integrity of the free software
-distribution system, which is implemented by public license practices. Many
-people have made generous contributions to the wide range of software
-distributed through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing to
-distribute software through any other system and a licensee cannot impose
-that choice.
-
-This section is intended to make thoroughly clear what is believed to be a
-consequence of the rest of this License.
-
-8. If the distribution and/or use of the Program is restricted in certain
-countries either by patents or by copyrighted interfaces, the original copyright
-holder who places the Program under this License may add an explicit
-geographical distribution limitation excluding those countries, so that
-distribution is permitted only in or among countries not thus excluded. In such
-case, this License incorporates the limitation as if written in the body of this
-License.
-
-9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will be
-similar in spirit to the present version, but may differ in detail to address new
-problems or concerns.
-
-Each version is given a distinguishing version number. If the Program specifies
-a version number of this License which applies to it and "any later version",
-you have the option of following the terms and conditions either of that
-version or of any later version published by the Free Software Foundation. If
-the Program does not specify a version number of this License, you may
-choose any version ever published by the Free Software Foundation.
-
-10. If you wish to incorporate parts of the Program into other free programs
-whose distribution conditions are different, write to the author to ask for
-permission. For software which is copyrighted by the Free Software
-Foundation, write to the Free Software Foundation; we sometimes make
-exceptions for this. Our decision will be guided by the two goals of
-preserving the free status of all derivatives of our free software and of
-promoting the sharing and reuse of software generally.
-
-               NO WARRANTY
-
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
-PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
-STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
-PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
-NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
-AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
-ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
-SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OR INABILITY TO USE THE
-PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
-OR DATA BEING RENDERED INACCURATE OR LOSSES
-SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
-PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
-IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
-THE POSSIBILITY OF SUCH DAMAGES.
-
-          END OF TERMS AND CONDITIONS
diff --git a/sites/all/modules/webform_alt_ui/css/webform_alt_ui.client.css b/sites/all/modules/webform_alt_ui/css/webform_alt_ui.client.css
deleted file mode 100644
index 034499ec44c09716175159443790d46df04c1810..0000000000000000000000000000000000000000
--- a/sites/all/modules/webform_alt_ui/css/webform_alt_ui.client.css
+++ /dev/null
@@ -1,8 +0,0 @@
-
-.webform-client-form .form-actions input + input {
-  margin-left: 10px;
-}
-
-.webform-client-form input {
-  max-width: 98%;
-}
diff --git a/sites/all/modules/webform_alt_ui/css/webform_alt_ui.css b/sites/all/modules/webform_alt_ui/css/webform_alt_ui.css
deleted file mode 100644
index 2d4b6de8f08bc67e2f80b3afef978f2503937c79..0000000000000000000000000000000000000000
--- a/sites/all/modules/webform_alt_ui/css/webform_alt_ui.css
+++ /dev/null
@@ -1,559 +0,0 @@
-
-/* @group Form Settings */
-
-#form-builder > h3 {
-  display: none;
-}
-
-#edit-ui-wrapper .horizontal-tabs {
-  float: left;
-}
-
-#edit-ui-wrapper .horizontal-tabs-pane > .fieldset-wrapper {
-  padding: 1em 0 0;
-}
-
-#edit-ui-wrapper .horizontal-tabs-pane > .fieldset-wrapper .pane-header,
-#edit-ui-wrapper .horizontal-tabs-pane > .fieldset-wrapper .pane {
-  border-left: medium none;
-  border-right: medium none;
-}
-
-#edit-ui-wrapper .horizontal-tabs-pane > .fieldset-wrapper > .pane-header:last-child {
-  border-bottom: medium none;
-}
-
-#edit-ui-wrapper {
-  border: 1px solid #ccc;
-  display: inline-block;
-  margin-top: 45px;
-  padding: 0;
-  width: 100%;
-}
-
-#edit-ui-wrapper .horizontal-tabs-pane input.form-text {
-  width: 100%;
-}
-
-#edit-ui-wrapper .horizontal-tabs {
-  margin: -27px -1px -1px;
-  width: 242px;
-}
-
-#edit-settings-container {
-  padding-left: 1.2em;
-}
-
-/* @end */
-
-/* @group Form builder layout */
-
-#form-builder-wrapper {
-  border-left: 1px solid #ccc;
-  padding: 0;
-}
-
-#form-builder {
-  padding: 8px 22px 11px 0;
-  position: relative;
-}
-
-.horizontal-tabs-processed .horizontal-tabs-pane {
-  border: none;
-  border-left: 1px solid #ccc;
-  margin-bottom: 0;
-}
-
-.horizontal-tabs-panes.horizontal-tabs-processed {
-  border-right: 1px solid #ccc;
-  margin-left: 1px;
-  margin-top: 26px;
-}
-
-.horizontal-tabs fieldset.form-wrapper {
-  border: none;
-  margin: 0;
-  padding: 0;
-}
-
-.horizontal-tabs fieldset.form-wrapper .fieldset-wrapper {
-  padding: 0;
-}
-
-#form-builder-field-remove,
-.field-settings-message {
-  padding: 0 11px
-}
-
-/* @end */
-
-/* @group Form builder palette */
-
-#form-builder-field-palette {
-  padding: 0 11px;
-}
-
-#form-builder-field-palette h3 {
-  margin-bottom: 0.5em;
-}
-
-#form-builder-field-palette ul.form-builder-fields {
-  margin: 0;
-  width: 100%;
-}
-
-#form-builder-field-palette ul li,
-#form-builder-wrapper > li {
-  background-color: #dddddd;
-  border: medium none;
-  -moz-border-radius: 5px;
-  -webkit-border-radius: 5px;
-  border-radius: 5px;
-  float: none;
-  margin-top: 8px;
-  width: auto;
-}
-
-#form-builder-field-palette ul li:hover {
-  background-color: #f2efc3;
-}
-
-#form-builder-field-palette ul .first {
-  margin-top: 0;
-}
-
-#form-builder-field-palette ul li.ui-draggable,
-#form-builder-wrapper > li.ui-draggable {
-  background-image: none;
-  list-style: none;
-  padding: 3px;
-}
-
-#form-builder-field-palette ul li.ui-draggable a,
-#form-builder-wrapper > li.ui-draggable a {
-  background: url(../images/draggable-states.png) no-repeat scroll left 6px transparent;
-  color: #000;
-  display: block;
-  font-size: 13px;
-  margin-left: 3px;
-  padding: 2px 10px 2px 19px;
-  white-space: nowrap;
-}
-
-#form-builder-field-palette ul li.ui-draggable-dragging:hover,
-#form-builder-wrapper > li.ui-draggable-dragging:hover {
-  background-color: #dddddd;
-}
-
-#form-builder-field-palette ul li.ui-draggable:hover a,
-#form-builder-field-palette ul li.ui-draggable-dragging a,
-#form-builder-wrapper > li.ui-draggable:hover a,
-#form-builder-wrapper > li.ui-draggable-dragging a{
-  background-position: left -14px;
-}
-
-/* @end */
-
-/* @group Form builder field configure */
-
-#form-builder-field-configure .confirmation input[type=submit] {
-  display: inline-block;
-}
-
-#form-builder-field-configure .options-widget + fieldset > legend {
-  display: none;
-}
-
-#form-builder-field-configure .option-actions-cell {
-  width: 20px;
-}
-
-/* @end */
-
-/* @group Form builder preview */
-
-#form-builder h3 {
-  margin: 0 0 20px;
-}
-
-#form-builder .form-item label,
-#form-builder .form-item label.option {
-  font-size: 13px;
-}
-
-#form-builder-wrapper .form-builder-element .form-builder-preview-hidden-webform-element,
-#form-builder-wrapper .form-builder-element .form-builder-preview-pagebreak-webform-element {
-  padding-top: 4px;
-}
-
-#form-builder-wrapper .form-builder-preview-pagebreak-webform-element {
-  text-align: center;
-}
-
-#form-builder-wrapper .form-builder-preview-pagebreak-webform-element * {
-  margin: 0;
-  white-space: nowrap;
-}
-
-/* @group Form elements */
-
-.form-builder-title-bar {
-  display: block !important;
-}
-
-#form-builder .form-builder-wrapper .form-builder-wrapper {
-  margin: 0;
-}
-
-#form-builder .form-builder-element {
-  margin: 0;
-  padding-left: 21px;
-}
-
-#form-builder .form-builder-element .form-item {
-  padding: 10px 10px 30px 35px;
-}
-
-#form-builder .form-builder-element .form-type-checkbox,
-#form-builder .form-builder-element .form-type-radio {
-  margin-left: 0;
-  padding: 5px 0;
-}
-
-#form-builder .form-builder-element .fieldset-color-wrapper {
-  background: #fff;
-  padding: 10px 10px 10px 20px;
-}
-
-.fieldset-color-wrapper > fieldset {
-  padding-left: 15px;
-}
-
-#form-builder .form-builder-wrapper,
-#form-builder .form-builder-active {
-  border: none;
-  padding: 0;
-}
-
-#form-builder .form-builder-active > .form-builder-element {
-  background: url(../images/yellow_arrow.png) no-repeat left 14px transparent;
-}
-
-#form-builder .form-builder-active > .form-builder-element > .form-item {
-  background: #F4ECC7;
-}
-
-#form-builder .form-builder-active > .form-builder-element-fieldset {
-  background: url(../images/green_arrow.png) no-repeat left 14px transparent;
-}
-
-#form-builder .form-builder-active > .form-builder-element-fieldset > .fieldset-color-wrapper {
-  background: #E0EFCC;
-}
-
-#form-builder .webform-component {
-  padding: 0;
-}
-
-#form-builder label {
-  font-weight: normal;
-}
-
-#form-builder .form-builder-placeholder.over {
-  min-height: 30px;
-  padding: 4px;
-}
-
-#form-builder .form-builder-placeholder.over + .form-builder-wrapper .form-builder-placeholder {
-  height: 0px !important;
-}
-
-div.form-builder-hover {
-  border: none;
-}
-
-.form-builder-placeholder.over,
-#form-builder .form-builder-empty-placeholder.over {
-  background: #f0f0f0;
-}
-
-#form-builder .form-builder-placeholder.over + .form-builder-wrapper .form-builder-empty-placeholder.over,
-#form-builder .form-builder-placeholder.over + .original + .form-builder-wrapper .form-builder-empty-placeholder.over,
-#form-builder .form-builder-placeholder.over + .form-builder-wrapper .form-builder-placeholder.over,
-#form-builder .form-builder-placeholder.over + .original + .form-builder-wrapper .form-builder-placeholder.over {
-  background: none;
-}
-
-.form-builder-placeholder {
-  margin-left: 25px;
-}
-
-#form-builder-wrapper > .form-builder-wrapper {
-  max-height: 80px;
-}
-
-#form-builder-wrapper > .form-builder-wrapper .fieldset-wrapper {
-  display: none;
-}
-
-/* @end */
-
-/* @group Fieldsets */
-
-#form-builder .form-builder-wrapper.form-builder-empty-placeholder {
-  padding: 40px;
-}
-
-#form-builder .ui-sortable-placeholder + .form-builder-wrapper.form-builder-empty-placeholder,
-#form-builder .form-builder-wrapper.form-builder-empty-placeholder + .form-builder-wrapper.form-builder-empty-placeholder {
-  padding: 0 0 40px;
-}
-
-#form-builder .ui-sortable-placeholder + .form-builder-wrapper.form-builder-empty-placeholder span {
-  display: none;
-}
-
-#form-builder .form-builder-wrapper.form-builder-empty-placeholder span {
-  margin: 0;
-}
-
-#form-builder fieldset {
-  border: 2px solid #ccc;
-  padding-bottom: 20px;
-  padding-right: 11px;
-}
-
-#form-builder fieldset legend {
-  margin-left: -7px;
-}
-
-#form-builder fieldset .fieldset-legend {
-  font-weight: normal;
-  padding: 0 5px;
-  position: static;
-  margin: 0;
-  text-transform: none;
-}
-
-#form-builder fieldset.collapsible .fieldset-legend {
-  padding-left: 15px;
-}
-
-#form-builder #webform-component-live-preview--submit-preview {
-  background-image: none;
-}
-
-#form-builder .button {
-  background-color: #666666;
-  background-image: none;
-  border: medium none;
-  -moz-border-radius: 0;
-  -webkit-border-radius: 0;
-  border-radius: 0;
-  color: #FFFFFF;
-  display: inline-block;
-  font-size: 0.9286em;
-  font-weight: normal;
-  padding: 0.6667em 2em;
-}
-
-#form-builder .button:hover {
-  cursor: default;
-}
-
-#form-builder > .empty-form + .form-builder-wrapper {
-  display: none;
-}
-
-#form-builder > .empty-form {
-  margin: -1em 0 0;
-  position: absolute;
-  text-align: center;
-  top: 50%;
-  width: 100%;
-}
-
-/* @end */
-
-/* @group Links */
-
-#form-builder-wrapper .form-builder-links {
-  display: none;
-  position: absolute;
-  text-align: right;
-  left: auto;
-  top: auto;
-  bottom: 2px;
-  right: 11px;
-  z-index: 1;
-}
-
-#form-builder-wrapper .form-builder-wrapper:hover > * > .webform-component,
-#form-builder-wrapper .form-builder-wrapper:hover > * > .fieldset-color-wrapper > .webform-component {
-  background-image: url('../images/draggable.png');
-  background-position: 4px 4px;
-  background-repeat: no-repeat;
-  border: 1px solid #ccc;
-  margin: -1px;
-  position: relative;
-  z-index: 1;
-}
-
-#form-builder-wrapper .form-builder-active:hover > * > .webform-component {
-  border: none;
-  margin: 0;
-}
-
-#form-builder-wrapper .form-builder-wrapper:hover > * > .form-builder-links,
-#form-builder-wrapper .form-builder-wrapper:hover > * > .fieldset-color-wrapper > .form-builder-links {
-  display: block;
-}
-
-#form-builder .fieldset-color-wrapper > .form-builder-links {
-  position: static;
-}
-
-#form-builder .form-builder-active > .form-builder-element > .form-builder-links,
-#form-builder .form-builder-active > .form-builder-element > .fieldset-color-wrapper > .form-builder-links {
-  display: block;
-}
-
-.form-builder-links li {
-  display: inline-block;
-}
-
-.form-builder-links li + li {
-  margin-left: 1em;
-}
-
-/* @end */
-
-/* @end */
-
-.disabled > label {
-  color: #ddd;
-}
-
-#edit-ui-wrapper .vertical-accordion label {
-  display: inline;
-  font-size: 13px;
-  font-weight: bold;
-}
-
-.webform-response td + td {
-  text-align: right;
-}
-
-.webform-upload-file-types {
-  outline: 1px solid red;
-  overflow: hidden;
-}
-
-#edit-webform-file-filtering-types-type-groups,
-#edit-webform-file-filtering-types-file-types {
-  margin-bottom: 10px;
-  overflow: hidden;
-}
-
-#edit-webform-file-filtering-types-type-groups .form-item,
-#edit-webform-file-filtering-types-file-types .form-item {
-  float: left;
-  margin: 1px 0;
-  padding: 0;
-  width: 25%;
-}
-
-#edit-webform-file-filtering-types-type-groups .form-item {
-  width: 50%;
-}
-
-#edit-webform-file-filtering-types-type-groups .form-item:first-child {
-  width: 100%;
-}
-
-/* @group Vertical tabs */
-
-div.vertical-tabs fieldset {
-  border: 1px solid #ccc;
-  margin: 1em 0;
-  padding: 2.5em 1em 0;
-  position: relative;
-}
-
-div.vertical-tabs .vertical-tabs-panes legend {
-  display: block;
-}
-
-div.vertical-tabs-panes > fieldset {
-  border: none;
-  margin: 0;
-  padding: 0;
-}
-
-div.vertical-tabs .vertical-tabs-panes > fieldset > legend {
-  display: none;
-}
-
-.vertical-tabs-panes .limit-wrapper {
-  font-size: 13px;
-}
-
-.vertical-tabs-panes .limit-wrapper .form-item {
-  display: inline-block;
-}
-
-.vertical-tabs-panes .limit-wrapper .form-item .form-text {
-  width: auto;
-}
-
-.vertical-tabs-panes .horizontal-tabs-pane .form-item-redirect-url .form-text {
-  width: 70%;
-}
-
-/* @end Vertical tabs */
-
-.webform-submission-navigation {
-  color: #ccc;
-}
-
-.webform-user {
-    border: 1px solid #CCCCCC;
-    margin-bottom: 20px;
-    padding: 0 12px 6px;
-}
-
-.webform-user .user-picture {
-    float: left;
-    margin-right: 10px;
-}
-
-.webform-user .label {
-  font-weight: bold;
-}
-
-.webform-submission .webform-component label,
-.webform-submission .webform-component input {
-  display: inline-block;
-  font-size: 1em;
-}
-
-.webform-submission .webform-component label {
-  font-weight: bold;
-  vertical-align: top;
-  width: 12em;
-}
-
-.webform-alt-ui-simplified-text-format .form-type-select {
-  text-align: right;
-}
-
-div.options-widget a.add:hover,
-div.options-widget a.remove:hover,
-div.form-option-add a:hover {
-  background-position: 0 0;
-}
-
-div.options-widget a.add,
-div.form-option-add a {
-  background-image: url(../images/add.png);
-}
diff --git a/sites/all/modules/webform_alt_ui/images/add.png b/sites/all/modules/webform_alt_ui/images/add.png
deleted file mode 100644
index e96107242ecc48e713486ef5390aeb8b25f0fde5..0000000000000000000000000000000000000000
Binary files a/sites/all/modules/webform_alt_ui/images/add.png and /dev/null differ
diff --git a/sites/all/modules/webform_alt_ui/images/draggable-states.png b/sites/all/modules/webform_alt_ui/images/draggable-states.png
deleted file mode 100644
index 93d20d60d504041b9841a35d285d4ba5eaaf6167..0000000000000000000000000000000000000000
Binary files a/sites/all/modules/webform_alt_ui/images/draggable-states.png and /dev/null differ
diff --git a/sites/all/modules/webform_alt_ui/images/draggable.png b/sites/all/modules/webform_alt_ui/images/draggable.png
deleted file mode 100644
index de9724df8fc80275a767e76a2c99aebe5ae42a68..0000000000000000000000000000000000000000
Binary files a/sites/all/modules/webform_alt_ui/images/draggable.png and /dev/null differ
diff --git a/sites/all/modules/webform_alt_ui/images/green_arrow.png b/sites/all/modules/webform_alt_ui/images/green_arrow.png
deleted file mode 100644
index 4b3622ffc1c29ef97a970c024601e4148921fc07..0000000000000000000000000000000000000000
Binary files a/sites/all/modules/webform_alt_ui/images/green_arrow.png and /dev/null differ
diff --git a/sites/all/modules/webform_alt_ui/images/yellow_arrow.png b/sites/all/modules/webform_alt_ui/images/yellow_arrow.png
deleted file mode 100644
index a47d8afa478aa5660dc204ef5b3509eaaed0422f..0000000000000000000000000000000000000000
Binary files a/sites/all/modules/webform_alt_ui/images/yellow_arrow.png and /dev/null differ
diff --git a/sites/all/modules/webform_alt_ui/includes/webform_alt_ui.components.inc b/sites/all/modules/webform_alt_ui/includes/webform_alt_ui.components.inc
deleted file mode 100644
index ecebaadf55fd657e5d4e1fa4fc2f9ef31caa78e0..0000000000000000000000000000000000000000
--- a/sites/all/modules/webform_alt_ui/includes/webform_alt_ui.components.inc
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-
-/**
- * @file Alters the configuration forms for webform components
- */
-
-/**
- * Alters the configuration form for textfields
- */
-function _webform_alt_ui_textfield_configure($form) {
-
-  return $form;
-}
-
-/**
- * Alters the configuration form for textareas
- */
-function _webform_alt_ui_textarea_configure($form) {
-
-  return $form;
-}
-
-/**
- * Alters the configuration form for radios
- */
-function _webform_alt_ui_radios_configure($form) {
-  $form = _webform_alt_ui_option_configure($form);
-
-  return $form;
-}
-
-/**
- * Alters the configuration form for checkboxes
- */
-function _webform_alt_ui_checkboxes_configure($form) {
-  $form = _webform_alt_ui_option_configure($form);
-
-  return $form;
-}
-
-/**
- * Alters the configuration form for selects
- */
-function _webform_alt_ui_select_configure($form) {
-  $form = _webform_alt_ui_option_configure($form);
-
-  return $form;
-}
-
-/**
- * Alters the configuration form for emails
- */
-function _webform_alt_ui_email_configure($form) {
-
-  return $form;
-}
-
-/**
- * Alters the configuration form for file uploads
- */
-function _webform_alt_ui_file_configure($form) {
-  // Deny access to fields we don't want configured
-  $form['webform_file_savelocation']['#access'] = FALSE;
-  $form['webform_file_filtering']['addextensions']['#access'] = FALSE;
-
-  // Alterations for the webform_file_width field
-  $form['webform_file_width']['#title'] = 'Size';
-  $form['webform_file_width']['#description'] = NULL;
-
-  $groups = element_children($form['webform_file_filtering']['types']);
-
-  $form['webform_file_filtering']['types']['#prefix'] = '<label>Allow the following types:</label>';
-
-  $options = array();
-  $defaults = array();
-  $settings = array('all' => array());
-
-  $form['webform_file_filtering']['types']['type_groups'] = array(
-    '#type' => 'checkboxes',
-    '#options' => array('all' => 'All'),
-    '#attributes' => array('class' => array('type-groups')),
-  );
-
-  foreach($groups as $key) {
-    // Remove disallowed extensions from the options.
-    // @todo Is it appropriate for this code to be in webform_alt_ui module, or
-    //   is it really more of a product/hosting decision?
-    foreach($form['webform_file_filtering']['types'][$key]['#options'] as $extension) {
-      if (in_array($extension, array('jar', 'dmg'))) {
-        unset($form['webform_file_filtering']['types'][$key]['#options'][$extension]);
-      }
-    }
-    $options = array_merge($options, $form['webform_file_filtering']['types'][$key]['#options']);
-    $defaults = array_merge($defaults, $form['webform_file_filtering']['types'][$key]['#default_value']);
-
-    $form['webform_file_filtering']['types']['type_groups']['#options'][$key] = 'All ' . str_replace('image', ' image', $key);
-    $settings[$key] = $form['webform_file_filtering']['types'][$key]['#options'];
-    $settings['all'] = array_merge($settings['all'], $form['webform_file_filtering']['types'][$key]['#options']);
-    unset($form['webform_file_filtering']['types'][$key]);
-  }
-
-  $form['webform_file_filtering']['types']['type_groups']['#default_value'] = 'webimages';
-
-  $form['webform_file_filtering']['types']['file_types'] = array(
-    '#type' => 'checkboxes',
-    '#options' => $options,
-    '#default_value' => $defaults,
-    '#attributes' => array('class' => array('file-types')),
-  );
-
-  // Set an absolute size limit and a new default.
-  // @todo It's possible that the #default_value line below is no longer needed
-  //   due to webform_alt_ui_form_builder_types_alter(), but needs more testing
-  //   before it can be removed. The default must be altered in the other
-  //   function, because by the time we get here, we can't distinguish between
-  //   the webform module default and a prior saved configuration value for this
-  //   component.
-  $form['webform_file_filtering']['size']['#default_value'] = isset($form['#_edit_element']['#webform_file_filtering']['size']) ? $form['#_edit_element']['#webform_file_filtering']['size'] : 1000;
-  $form['webform_file_filtering']['size']['#element_validate'][] = 'webform_alt_ui_file_size_validate';
-  $form['webform_file_filtering']['size']['#description'] = t('Enter the max file size (in KB) a user may upload (limit 20,000KB).');
-
-  drupal_add_js(array('webform_alt_ui' => $settings), 'setting');
-
-  $form['#attached']['js'][] = drupal_get_path('module', 'webform_alt_ui') . '/js/webform_alt_ui.file.js';
-
-  return $form;
-}
-
-/**
- * Alters the configuration form for markup
- */
-function _webform_alt_ui_markup_configure($form) {
-  // Hide the title options.
-  $form['title']['#access'] = FALSE;
-  $form['title_display']['#access'] = FALSE;
-
-  // Modify the title of the markup field.
-  $form['markup']['#title'] = t('Formatted content');
-
-  // Prevent the markup field from being hidden behind a checkbox.
-  $form['markup']['#checkbox'] = FALSE;
-
-  // Hide parts of the text format selector.
-  _webform_alt_ui_add_text_format_simplification($form['markup']);
-
-  return $form;
-}
-
-/**
- * Alters the configuration form for fieldsets
- */
-function _webform_alt_ui_fieldset_configure($form) {
-  $form['description']['#access'] = FALSE;
-
-  return $form;
-}
-
-/**
- * Alters the configuration form for hidden fields
- */
-function _webform_alt_ui_hidden_configure($form) {
-
-  return $form;
-}
-
-/*
- * Alters the configuration form for all option elements.
- * 
- * Applies to select, checkboxes, and radios elements.
- */
-function _webform_alt_ui_option_configure($form) {
-  $form['options']['#process'] = array('form_options_expand', 'webform_alt_ui_option_process');
-
-  return $form;
-}
diff --git a/sites/all/modules/webform_alt_ui/js/webform_alt_ui.file.js b/sites/all/modules/webform_alt_ui/js/webform_alt_ui.file.js
deleted file mode 100644
index e71cd3bc9879f6e38e953e7c6c49d957816698da..0000000000000000000000000000000000000000
--- a/sites/all/modules/webform_alt_ui/js/webform_alt_ui.file.js
+++ /dev/null
@@ -1,37 +0,0 @@
-
-(function ($) {
-
-/**
- * Control the visibility of additional configuration options
- */
-Drupal.behaviors.webformAltUI_file_field = {
-  attach: function (context) {
-    $('.type-groups', context).once('type-groups', function () {
-      $(this).find('input[type=checkbox]').bind('click', Drupal.behaviors.webformAltUI_file_field.groupToggle);
-    });
-    $('.file-types', context).once('file-types', function () {
-      $(this).find('input[type=checkbox]').bind('click', Drupal.behaviors.webformAltUI_file_field.checkToggle);
-    });
-  },
-  groupToggle: function (event) {
-    var $this = $(this);
-    $.each(Drupal.settings.webform_alt_ui[$this.val()], function (index, value) {
-      $('input[value=' + value + ']').attr('checked', $this.attr('checked'));
-    });
-    Drupal.behaviors.webformAltUI_file_field.checkToggle();
-  },
-  checkToggle: function () {
-    var $this = $(this);
-    $.each(Drupal.settings.webform_alt_ui, function(index, value) {
-      var checked = true;
-      $.each(value, function(index2, value2) {
-        if ($('.file-types input[value=' + value2 + ']').attr('checked') == false) {
-          checked = false;
-        }
-      });
-      $('.type-groups input[value=' + index + ']').attr('checked', checked);
-    });
-  }
-};
-
-})(jQuery);
diff --git a/sites/all/modules/webform_alt_ui/webform_alt_ui.info b/sites/all/modules/webform_alt_ui/webform_alt_ui.info
deleted file mode 100644
index ed132d894fb7de75938cff32db289e9b1f2a2b86..0000000000000000000000000000000000000000
--- a/sites/all/modules/webform_alt_ui/webform_alt_ui.info
+++ /dev/null
@@ -1,15 +0,0 @@
-name = Webform Alternate UI
-description = Provides an alternate user experience for the Webform module.
-package = Webform
-core = 7.x
-dependencies[] = webform
-dependencies[] = form_builder
-dependencies[] = form_builder_webform
-dependencies[] = ux_elements
-
-; Information added by drupal.org packaging script on 2011-07-21
-version = "7.x-1.x-dev"
-core = "7.x"
-project = "webform_alt_ui"
-datestamp = "1311208906"
-
diff --git a/sites/all/modules/webform_alt_ui/webform_alt_ui.install b/sites/all/modules/webform_alt_ui/webform_alt_ui.install
deleted file mode 100644
index 02212bc8d14bd9832a2d0c13fe0034586ce86bea..0000000000000000000000000000000000000000
--- a/sites/all/modules/webform_alt_ui/webform_alt_ui.install
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-/**
- * @file
- * Install file for webform_alt_ui.
- */
-
-/**
- * This sets the default delimiter for webform export to be a comma.
- */
-function webform_alt_ui_enable() {
-  variable_set('webform_csv_delimiter', ',');
-
-  $type = node_type_load('webform');
-  if ($type) {
-    $type->description = 'Create a new form or questionnaire. Submission results and statistics are recorded and accessible to privileged users.';
-    node_type_save($type);
-  }
-
-  // Turn off comments by default for webform nodes.
-  variable_set('comment_webform', COMMENT_NODE_CLOSED);
-  // Disable the AddThis block by default.
-  variable_set('addthis_nodetype_webform', 0);
-  // Hide the submitted by text by default
-  variable_set('node_submitted_webform', FALSE);
-}
diff --git a/sites/all/modules/webform_alt_ui/webform_alt_ui.js b/sites/all/modules/webform_alt_ui/webform_alt_ui.js
deleted file mode 100644
index bff6e325a3aed537bf8b5c1304d86fc570fc0c16..0000000000000000000000000000000000000000
--- a/sites/all/modules/webform_alt_ui/webform_alt_ui.js
+++ /dev/null
@@ -1,190 +0,0 @@
-
-(function ($) {
-
-/**
- * Control the visibility of additional configuration options
- */
-Drupal.behaviors.webformAltUI = {
-  attach: function (context) {
-    $('.check-expand', context).children().not(':first-child').hide();
-    $('.check-expander', context)
-      .bind('click', Drupal.behaviors.webformAltUI.toggleInputs)
-      .each(Drupal.behaviors.webformAltUI.toggleInputs);
-    if (Drupal.formBuilder) {
-      Drupal.formBuilder.fieldConfigureForm = $('#form-builder-field-configure');
-    }
-
-    // Add checkboxes before the labels for fields in the field configure form
-    Drupal.behaviors.webformAltUI.fieldSettingsCheckboxes(context);
-
-    // Because runs all behaviors on every AJAX callback unset and set clicks.
-    $('#form-builder .form-builder-links a')
-      .unbind('click')
-      .bind('click', Drupal.formBuilder.editField)
-      .bind('click', Drupal.behaviors.webformAltUI.showFieldSettings);
-    $('.form-builder-element')
-      .unbind('click')
-      .bind('click', Drupal.behaviors.webformAltUI.showFieldSettings)
-      .bind('click', Drupal.formBuilder.clickField);
-    $('.form-builder-element label').unbind('click');
-    $('#form-builder .form-builder-links a.delete')
-      .unbind('click')
-      .bind('click', Drupal.behaviors.webformAltUI.removeField);
-
-    // Enable the scroll for the active tabs.
-    $('.horizontal-tabs-pane').bind('horizontalTabActivate', Drupal.behaviors.webformAltUI.tabActivated);
-    $(window).bind('scroll', Drupal.behaviors.webformAltUI.windowScroll);
-    if (!Drupal.behaviors.webformAltUI.activeTab) {
-      var tab = {};
-      tab.fieldset = $('.horizontal-tabs-pane:visible');
-      if (tab.fieldset.length) {
-        Drupal.behaviors.webformAltUI.activeTab = tab;
-        Drupal.behaviors.webformAltUI.tabActivated({}, tab);
-      }
-    }
-
-    // Bind event handlers to update the submit button text.
-    $('input[name=submit_button]').bind('blur keyup', Drupal.behaviors.webformAltUI.submitTextChange);
-
-    // Check to see if the form is empty and need explanatory text
-    Drupal.behaviors.webformAltUI.checkForm(true);
-
-    // Remove useless links from the options_element configuration
-    $('#edit-options-options-field-widget a.add').remove();
-    $('.form-options-manual').remove();
-
-    // Disable dragging on the submit button
-    $('a.configure.button').closest('.form-builder-wrapper').draggable('destroy');
-
-    // Remove the field settings form from inside the node form before
-    // submitting the node form.
-    $('#webform-node-form').bind('submit', Drupal.behaviors.webformAltUI.removeNestedForms);
-  },
-  toggleInputs: function (event) {
-    if ($(this).attr('checked')) {
-      $(this).closest('.check-expand').children().not(':first-child').slideDown();
-    } else {
-      $(this).closest('.check-expand').children().not(':first-child').slideUp();
-    }
-  },
-  fieldSettingsCheckboxes: function (context) {
-    $('.check-toggle:visible', context).once('check-toggle', function() {
-      // Keep track of, and hide the input itself.
-      var input = $(this).is('textarea') ? $(this).parent() : $(this);
-
-      var wrapper = input.parent();
-
-      // Add the checkbox and bind its behavior.
-      var checkbox = $('<input type="checkbox" />');
-      checkbox
-        .attr('id', $(this).attr('name') + '-checkbox')
-        .bind('click', input, Drupal.behaviors.webformAltUI.fieldSettingsCheckToggle)
-        .prependTo(wrapper);
-
-      // If there is already a value here, check the box, otherwise hide the input
-      if ($(this).val()) {
-        checkbox.attr('checked', true);
-      } else {
-        wrapper.children().not(checkbox).not('label').hide();
-      }
-      // Link the label to the new checkbox so that clicking on it selects the
-      // checkbox.
-      wrapper.find('label').attr('for', checkbox.attr('id'));
-    });
-  },
-  fieldSettingsCheckToggle: function (event) {
-    var input = event.data;
-    if ($(event.target).attr('checked') == true) {
-      // Show the field.
-      input.parent().children().not(event.target).not('label').slideDown();
-    } else {
-      // Clear the field and hide it.
-      input.parent().find('input, textarea').val('').text('').trigger('change');
-      input.parent().children().not(event.target).not('label').slideUp();
-    }
-  },
-  showFieldSettings: function (event) {
-    // Trigger a click on the field settings tab
-    $('#edit-ui-wrapper .horizontal-tabs-list > .last:not(.selected) a').click();
-  },
-  tabActivated: function (event, tab) {
-    tab.offset = tab.fieldset.offset().top;
-    if (typeof Drupal.toolbar != 'undefined') {
-      tab.offset = tab.offset - Drupal.toolbar.height();
-    }
-    Drupal.behaviors.webformAltUI.activeTab = tab;
-    Drupal.behaviors.webformAltUI.scrollFieldset();
-
-    $('#form-builder').css('min-height', tab.fieldset.height());
-  },
-  windowScroll: function (event) {
-    if (Drupal.behaviors.webformAltUI.timeout) {
-      clearTimeout(Drupal.behaviors.webformAltUI.timeout);
-    }
-    Drupal.behaviors.webformAltUI.timeout = setTimeout(Drupal.behaviors.webformAltUI.scrollFieldset, 100);
-  },
-  scrollFieldset: function () {
-    var fieldset = Drupal.behaviors.webformAltUI.activeTab.fieldset;
-    var offset = Drupal.behaviors.webformAltUI.activeTab.offset;
-    // Do not move the palette while dragging a field.
-    if (Drupal.formBuilder.activeDragUi) {
-      return;
-    }
-
-    var windowOffset = $(window).scrollTop();
-    var blockHeight = fieldset.height();
-    var formBuilderHeight = $('#form-builder').height();
-    if (windowOffset - offset > 0) {
-      // Do not scroll beyond the bottom of the editing area.
-      var toolbarOffset = parseInt($('body').css('padding-top')) + parseInt($('body').css('margin-top')) + 10;
-      var newTop = Math.min(windowOffset - offset + toolbarOffset, formBuilderHeight - blockHeight);
-      fieldset.animate({'margin-top': (newTop + 'px')}, 'fast');
-    }
-    else {
-      fieldset.animate({'margin-top': '0px'}, 'fast');
-    }
-  },
-  removeField: function (event) {
-    event.preventDefault();
-    event.stopPropagation();
-    Drupal.formBuilder.setActive($(event.target).parents('.form-builder-wrapper').get(0), event.target);
-    Drupal.formBuilder.ajaxOptions = {
-      url: $(this).attr('href'),
-      type: 'POST',
-      dataType: 'json',
-      data: 'js=1',
-      success: Drupal.behaviors.webformAltUI.removeFieldCallback,
-      error: Drupal.formBuilder.ajaxError,
-      errorMessage: Drupal.t('Field could not be deleted at this time.  Please try again later.'),
-      maxTry: 3,
-      tryCount: 0
-    };
-    // Submit the form via ajax
-    $.ajax(Drupal.formBuilder.ajaxOptions);
-  },
-  removeFieldCallback: function (response) {
-    Drupal.formBuilder.deleteField(Drupal.behaviors.webformAltUI.checkForm);
-  },
-  submitTextChange: function (e) {
-    // Put the value of this field into the submit button.
-    var text = $(this).val() ? $(this).val() : Drupal.t('Submit');
-    $('#form-builder .button').text(text);
-    // Put the value into the hidden field in the form settings advanced tab
-    $('input[name=submit_text]').val($(this).val());
-  },
-  checkForm: function () {
-    var fb = $('#form-builder');
-    if (fb.children().length <= 1) {
-      $('<div class="form-builder-placeholder empty-form">' + Drupal.t('Drag a field from the Add field tab to add it to your webform') + '</div>').prependTo(fb);
-    } else {
-      // Ensure that the submit button is always at the bottom of the form
-      fb.find('.button').closest('.form-builder-wrapper').appendTo(fb);
-    }
-  },
-  removeNestedForms: function (submitEvent) {
-    $(submitEvent.target).find('form').remove();
-    return true;
-  }
-};
-
-})(jQuery);
diff --git a/sites/all/modules/webform_alt_ui/webform_alt_ui.module b/sites/all/modules/webform_alt_ui/webform_alt_ui.module
deleted file mode 100644
index cdcc409b62a8353030995b842a495c853308fd45..0000000000000000000000000000000000000000
--- a/sites/all/modules/webform_alt_ui/webform_alt_ui.module
+++ /dev/null
@@ -1,1680 +0,0 @@
-<?php
-
-/**
- * @file
- * Improves the UX of the webform module by adding the form building tools to
- * the node edit screen.
- */
-
-define('WEBFORM_ALT_UI_FILE_WIDTH', 30);
-
-/**
- * Implements hook_init()
- */
-function webform_alt_ui_init() {
-  drupal_add_css(drupal_get_path('module', 'webform_alt_ui') . '/css/webform_alt_ui.client.css', array('every_page' => TRUE));
-}
-
-/**
- * Implements hook_menu().
- */
-function webform_alt_ui_menu() {
-  $items = array();
-
-  $items['admin/webform_alt_ui/submit_button_form'] = array(
-    'title' => 'Webform submit button form',
-    'description' => 'Callback for the webform submit button form.',
-    'page callback' => 'webform_alt_ui_submit_button_page',
-    'access callback' => TRUE,
-    'type' => MENU_CALLBACK,
-  );
-
-  return $items;
-}
-
-/**
- * Implements hook_menu_alter().
- */
-function webform_alt_ui_menu_alter(&$items) {
-  // Remove these items from the local tasks. We make these actions available
-  // as buttons at the bottom of the page.
-  $items['node/%webform_menu/webform-results/download']['type'] = MENU_CALLBACK;
-  $items['node/%webform_menu/webform-results/clear']['type'] = MENU_CALLBACK;
-
-  // Override result listing callback so we can add form elements.
-  $items['node/%webform_menu/webform-results']['page callback'] = 'webform_alt_ui_results_submissions';
-  unset($items['node/%webform_menu/webform-results']['file']);
-
-  // Remove access to the webform tab.
-  $items['node/%webform_menu/webform']['access callback'] = FALSE;
-
-  // Change the callback for removing a form element.
-  $items['admin/build/form-builder/remove'] = array(
-    'title' => 'Remove field',
-    'description' => 'Remove a field from a form.',
-    'page callback' => 'webform_alt_ui_remove_element',
-    'access callback' => 'form_builder_menu_field_access',
-    'access arguments' => array('remove', 4, 5, 6),
-    'type' => MENU_CALLBACK,
-  );
-
-  // Hide the Table view from the results page
-  $items['node/%webform_menu/webform-results/table']['access callback'] = FALSE;
-
-  // Alter the link description on the admin/config page.
-  $items['admin/config/content/webform']['description'] = 'Configure webform settings and defaults.';
-
-  // Alter the confirmation page.
-  $items['node/%webform_menu/done']['page callback'] = '_webform_alt_ui_confirmation';
-}
-
-/*
- * The form_builder_positions form needs to be on the page but not within the
- * node edit form.
- */
-function webform_alt_ui_page_alter(&$page) {
-  if (isset($page['content']['system_main']['#node_edit_form']) && isset($page['content']['system_main']['webform'])) {
-    // If this is a new node, there will be no nid, so a temporary form_builder id
-    // is created from the form token.
-    $nid = isset($page['content']['system_main']['nid']['#value']) ? $page['content']['system_main']['nid']['#value'] : $page['content']['system_main']['#form_builder_token'];
-
-    // Set the active form
-    form_builder_active_form('webform', $nid);
-    // Load the current state of the form, or create a new cache if needed.
-    $form_structure = form_builder_cache_load('webform', $nid);
-    if (!$form_structure) {
-      $form_structure = form_builder_load_form('webform', $nid);
-      form_builder_cache_save('webform', $nid, $form_structure);
-    }
-
-    $page['content'][] = drupal_get_form('form_builder_positions', $form_structure, 'webform', $nid);
-  }
-}
-
-/**
- * Implements hook_modules_installed().
- */
-function webform_alt_ui_modules_installed($modules) {
-  // The Webform module creates a body field for the webform content type, but
-  // we don't want that in our UI by default since we put the form for adding
-  // components on the main node edit page, and it gets in the way of that.
-  if (in_array('webform', $modules) && ($instance = field_info_instance('node', 'body', 'webform'))) {
-    field_delete_instance($instance);
-  }
-}
-
-/**
- * Implements hook_theme().
- */
-function webform_alt_ui_theme() {
-  return array(
-    'webform_alt_ui_field_configure' => array(
-      'render element' => 'form',
-    ),
-    'webform_alt_ui_field_palette' => array(
-      'variables' => array('fields' => NULL, 'groups' => NULL, 'form_type' => NULL, 'form_id' => NULL),
-    ),
-    'webform_alt_ui_element_links' => array(
-      'render element' => 'element',
-    ),
-    'webform_alt_ui_fieldset_wrapper' => array(
-      'render element' => 'element',
-    ),
-    'webform_alt_ui_element_markup' => array(
-      'render element' => 'element',
-    ),
-    'webform_alt_ui_check_expand_wrapper' => array(
-      'render element' => 'element',
-    ),
-    'webform_alt_ui_confirmation' => array(
-      'variables' => array('node' => NULL, 'sid' => NULL, 'link_to_form' => TRUE),
-    ),
-    'webform_alt_ui_text_format_wrapper' => array(
-      'render element' => 'element',
-    ),
-    'webform_alt_ui_admin_settings' => array(
-      'render element' => 'element',
-    ),
-    'webform_alt_ui_submission_navigation' => array(
-      'variables' => array('node' => NULL, 'submission' => NULL, 'mode' => NULL),
-    ),
-    'webform_alt_ui_submission_information' => array(
-      'variables' => array('node' => NULL, 'submission' => NULL),
-    ),
-  );
-}
-
-/*
- * Implements hook_element_info_alter();
- */
-function webform_alt_ui_element_info_alter(&$type) {
-  $type['options']['#pre_render'][] = 'webform_alt_ui_pre_render_option';
-}
-
-/*
- * Implements hook_form_alter().
- *
- * This form alter adds the fields and handling for the separate webform_configure_form
- * to the node edit form
- */
-function webform_alt_ui_form_alter(&$form, &$form_state, $form_id) {
-  // Perform the same check as webform_form_alter().
-  if (isset($form['#node']->type) && $form_id == $form['#node']->type . '_node_form' && in_array($form['#node']->type, webform_variable_get('webform_node_types'))) {
-
-    form_load_include($form_state, 'inc', 'form_builder', 'includes/form_builder.cache');
-    form_load_include($form_state, 'inc', 'form_builder', 'includes/form_builder.admin');
-    form_load_include($form_state, 'inc', 'form_builder', 'includes/form_builder.api');
-    form_load_include($form_state, 'inc', 'webform', 'includes/webform.pages');
-    form_load_include($form_state, 'inc', 'webform', 'includes/webform.components');
-
-    // Modify the form.
-    _webform_alt_ui_horizontal_tabs($form, $form_state);
-    _webform_alt_ui_webform_settings($form, $form_state);
-    _webform_alt_ui_webform_email($form, $form_state);
-    _webform_alt_ui_webform_form($form, $form_state);
-
-    // Add validation and submission handlers. (Our custom validation must go
-    // at the beginning, since it is responsible for adding some elements to
-    // the $form_state['values'] array based on other form values which were
-    // submitted.)
-    $form['#validate'][] = 'webform_configure_form_validate';
-    $form['#validate'] = array_merge(array('webform_alt_ui_pre_validate'), $form['#validate']);
-    $form['actions']['submit']['#submit'][] = 'webform_alt_ui_prepare_configure_form_submit';
-    $form['actions']['submit']['#submit'][] = 'webform_configure_form_submit';
-    $form['actions']['submit']['#submit'][] = 'webform_alt_ui_submit';
-
-    // Add a pre-render function to reorganize the form before it is displayed.
-    $form['#pre_render'][] = 'webform_alt_ui_pre_render_node_form';
-
-    // Attach our custom CSS and JavaScript.
-    $css_path = drupal_get_path('module', 'webform_alt_ui') . '/css/webform_alt_ui.css';
-    $form['#attached']['css'][$css_path] = array('preprocess' => FALSE, 'group' => CSS_DEFAULT, 'weight' => 2);
-    $form['#attached']['css'][] = drupal_get_path('module', 'webform') . '/css/webform.css';
-    $form['#attached']['js'][] = drupal_get_path('module', 'webform_alt_ui') . '/webform_alt_ui.js';
-    $form['#attached']['js'][] = drupal_get_path('module', 'webform_alt_ui') . '/js/webform_alt_ui.file.js';
-
-    // Need to add the vertical accordion files here because form_builder
-    // does not use D7's AJAX framework.
-    drupal_add_js(drupal_get_path('module', 'ux_elements') . '/js/vertical_accordion.js', array('group' => 'JS_DEFAULT', 'weight' => 50));
-    drupal_add_css(drupal_get_path('module', 'ux_elements') . '/css/vertical_accordion.css');
-    drupal_add_library('system', 'ui.accordion');
-
-    // Remove the preview button and add a cancel button
-    unset($form['actions']['preview']);
-    $form['actions']['cancel'] = array(
-      '#type' => 'button',
-      '#value' => t('Cancel'),
-      '#weight' => 6,
-      '#submit' => array('webform_alt_ui_click_cancel'),
-      '#limit_validation_errors' => array(),
-      '#executes_submit_callback' => TRUE,
-    );
-
-    // Add the form_builder cache clear to the delete action
-    $form['actions']['delete']['#submit'][] = 'webform_alt_ui_clear_cache';
-  }
-}
-
-/**
- * Validation handler for webform_node_form.
- *
- * This function puts the appropriate values into $form_state['values'] based
- * on our custom controls, so that they can be appropriately handled by
- * validation and submission handlers that run later.
- *
- * @todo Should this be moved to an #after_build callback instead?
- */
-function webform_alt_ui_pre_validate($form, &$form_state) {
-  // If the "customize confirmation" checkbox was unchecked, revert to default
-  // values of everything inside it.
-  if (empty($form_state['values']['confirm_redirect_toggle'])) {
-    $form_state['values']['confirmation']['value'] = webform_alt_ui_default_confirmation_text();
-    $form_state['values']['redirect'] = 'confirmation';
-    // Keep the text format the same as whatever was passed in; it doesn't make
-    // sense to revert that to filter_default_format() since the default format
-    // can be different for different users who might be editing this form.
-    // (Given that our default text doesn't have any formatting, this should
-    // work fine anyway.)
-  }
-  else {
-    // If we are redirecting to a confirmation page, store the message that was
-    // entered for the content of that page.
-    if ($form_state['values']['redirect'] == 'confirmation') {
-      $form_state['values']['confirmation'] = $form_state['values']['confirmation_page_content'];
-    }
-    // Otherwise, if the confirmation was toggled off, do not save it so as to
-    // force there to be no confirmation.
-    elseif (empty($form_state['values']['confirmation_toggle'])) {
-      $form_state['values']['confirmation']['value'] = '';
-    }
-  }
-
-  // Use the values of the submit limit toggle to set the value of the "enforce
-  // limit" setting.
-  $form_state['values']['enforce_limit'] = $form_state['values']['submit_limit_toggle'] ? 'yes' : 'no';
-}
-
-/**
- * Submit handler that prepares for the webform configuration submit handler.
- *
- * This submit handler runs before webform_configure_form_submit() and prepares
- * the submitted form values for the expectations of that function.
- */
-function webform_alt_ui_prepare_configure_form_submit($form, &$form_state) {
-  // There is a conflict in the expected form values, since 'status' is used by
-  // the node form and also by the webform configuration form which we attach
-  // to it. So we use a different key in the form, and therefore need to switch
-  // the submitted form values here so that webform's submit handler receives
-  // what it expects. It is OK to overload 'status' in the submitted form
-  // values at this point, since the node form submit handler has already run.
-  // See _webform_alt_ui_webform_settings().
-  $form_state['values']['status'] = $form_state['values']['allow_submissions'];
-  unset($form_state['values']['allow_submissions']);
-}
-
-/**
- * Submit handler for webform_node_form.
- */
-function webform_alt_ui_submit($form, &$form_state) {
-  // Save the form builder form associated with the node.
-  $nid = $form_state['values']['nid'];
-  $node = node_load($nid);
-
-  // Custom implementation of form_builder_webform_save_node().  This is necessary
-  // because form_builder presumes the node to already exist when it is saving.
-  // The cache key has already been set as $form['#form_builder_token'] during
-  // the form alter process, so we can use that to properly get the cached form
-  // for the save process.
-  $form_cache = form_builder_cache_load('webform', $form['#form_builder_token']);
-  $element_ids = form_builder_preview_prepare($form_cache, 'webform', $form['#form_builder_token']);
-
-  // Save modified or created components.
-  foreach ($element_ids as $id) {
-    form_builder_webform_save_component($node, $id, $form_cache);
-  }
-
-  // Delete components that have been removed.
-  foreach ($node->webform['components'] as $component) {
-    $element_id = 'cid_' . $component['cid'];
-    if (!in_array($element_id, $element_ids)) {
-      webform_component_delete($node, $component);
-    }
-  }
-
-  // Reset the node cache, since $node->webform['components'] has changed.
-  entity_get_controller('node')->resetCache(array($node->nid));
-
-  // Save submission email settings.
-  _webform_alt_ui_save_submission_email($form, $form_state, $node);
-
-  // Handle Mollom spam protection.
-  if (module_exists('mollom')) {
-    $mollom_form_id = _webform_alt_ui_mollom_form_id($nid);
-    $mollom_form = mollom_form_load($mollom_form_id);
-    // Turn spam protection on when requested to do so and it's currently off.
-    if ($form_state['values']['spam_protection'] && !$mollom_form) {
-      $mollom_form = mollom_form_new($mollom_form_id);
-      mollom_form_save($mollom_form);
-    }
-    // Turn spam protection off when requested to do so and it's currently on.
-    elseif (!$form_state['values']['spam_protection'] && $mollom_form) {
-      mollom_form_delete($mollom_form_id);
-    }
-    // If the webform already has spam protection and is keeping it, update the
-    // protection based on the components that were added or removed.
-    elseif ($form_state['values']['spam_protection']) {
-      // New Mollom forms protect all available fields that are allowed to have
-      // spam protection, so use that to determine what's available to be
-      // enabled.
-      $new_form = mollom_form_new($mollom_form_id);
-      $mollom_fields_not_yet_enabled = array_diff($new_form['enabled_fields'], $mollom_form['enabled_fields']);
-      if (!empty($mollom_fields_not_yet_enabled)) {
-        // Enable the available fields only if they correspond to a webform
-        // component that was just added (otherwise the administrator turned
-        // Mollom off for this field on purpose, so we don't want to turn it
-        // back on). Note that the original $node was loaded before the new
-        // components were saved, so we can use that for comparison.
-        $new_node = node_load($nid);
-        $components_added = array_diff_key($new_node->webform['components'], $node->webform['components']);
-        foreach ($mollom_fields_not_yet_enabled as $field) {
-          $field_keys = explode('][', $field);
-          $form_key = end($field_keys);
-          foreach ($components_added as $component) {
-            if ($form_key == $component['form_key']) {
-              // If this is the first field we are adding Mollom protection to
-              // and there aren't any analysis checks saved for the form, add
-              // the default spam checking.
-              if (empty($mollom_form['enabled_fields']) && empty($mollom_form['checks'])) {
-                $mollom_form['checks'] = array('spam');
-              }
-              // Add the new field and move on to the next available one that
-              // isn't enabled.
-              $mollom_form['enabled_fields'][] = $field;
-              break 1;
-            }
-          }
-        }
-      }
-      // Remove protection for any fields that are no longer able to be
-      // protected (most likely because the webform component associated with
-      // it was removed).
-      $mollom_form['enabled_fields'] = array_values(array_intersect($mollom_form['enabled_fields'], $new_form['enabled_fields']));
-      // Save the updated form.
-      mollom_form_save($mollom_form);
-    }
-  }
-
-  // Remove the cached form_builder form.
-  form_builder_cache_delete('webform', $form['#form_builder_token']);
-
-  $form_state['redirect'] = 'node/' . $nid;
-  // The message set by node_form_submit() is first and most relevant so we
-  // reduce the messages to that.
-  $_SESSION['messages']['status'] = array(array_shift($_SESSION['messages']['status']));
-}
-
-/**
- * Helper function to save submission email settings.
- */
-function _webform_alt_ui_save_submission_email(&$form, &$form_state, &$node) {
-  module_load_include('inc', 'webform', 'includes/webform.emails');
-  $email = $form_state['values']['submission_email'];
-  $email['nid'] = $node->nid;
-  $email['from_name'] = 'default';
-  $email['from_address'] = 'default';
-  $email['excluded_components'] = array();
-  $email['html'] = FALSE;
-  $email['attachments'] = 0;
-
-  $send_email = $form_state['values']['submission_email_checkbox'];
-  if ($send_email) {
-    empty($email['eid']) ? webform_email_insert($email) : webform_email_update($email);
-  }
-  else {
-    if (isset($email['eid'])) {
-      webform_email_delete($node, $email);
-    }
-  }
-}
-
-/**
- * Helper function to determine the Mollom form ID for a webform client form.
- *
- * This needs to be kept in sync with the value used by the Webform module
- * itself in webform_mollom_form_list().
- *
- * @param $nid
- *   The node ID of the form.
- *
- * @return
- *   The Mollom form ID associated with the form.
- */
-function _webform_alt_ui_mollom_form_id($nid) {
-  return "webform_client_form_$nid";
-}
-
-/**
- * Adds an initial set of horizontal tabs to the node edit form.
- */
-function _webform_alt_ui_horizontal_tabs(&$form, &$form_state) {
-  $form['ui-wrapper'] = array(
-    '#type' => 'item',
-  );
-  $form['ui-wrapper']['h-tabs'] = array(
-    '#type' => 'horizontal_tabs',
-  );
-}
-
-/**
- * Adds the configuration settings tab to the node edit form.
- */
-function _webform_alt_ui_webform_settings(&$form, &$form_state) {
-  // Add a tab to hold the form settings.
-  $form['form_settings'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Form settings'),
-    '#group' => 'additional_settings',
-    '#weight' => $form['menu']['#weight'] -1,
-  );
-
-  // Add the default webform configuration form to the node edit form. We will
-  // alter what we just added in the rest of this function below.
-  $node = $form['#node'];
-  $form += webform_configure_form($form, $form_state, $node);
-
-  // Collapse the submission settings fieldset by default and remove the submit
-  // button, since this section will be transformed into a secondary item
-  // attached to the overall node form.
-  $form['submission']['#collapsed'] = TRUE;
-  unset($form['submit']);
-
-  // Perform adjustments to each section of the form.
-  _webform_alt_ui_alter_confirm_redirect_settings($form, $form_state, $node);
-  _webform_alt_ui_alter_submit_limit_settings($form, $form_state, $node);
-  _webform_alt_ui_add_custom_submission_settings($form, $form_state, $node);
-  _webform_alt_ui_alter_role_control_settings($form, $form_state, $node);
-  _webform_alt_ui_alter_advanced_settings($form, $form_state, $node);
-
-  // Avoid a conflict between the 'status' field on the node form and the one
-  // added by the webform configuration form which we are attaching. See
-  // webform_alt_ui_prepare_configure_form_submit().
-  $form['submission']['allow_submissions'] = $form['submission']['status'];
-  unset($form['submission']['allow_submissions']['#parents']);
-  unset($form['submission']['status']);
-  // @todo: Show this (somewhere) once we have a plan to integrate it into this
-  //   module's UI.
-  $form['submission']['allow_submissions']['#access'] = FALSE;
-}
-
-/**
- * Helper function for altering part of the webform settings form.
- */
-function _webform_alt_ui_alter_confirm_redirect_settings(&$form, &$form_state, $node) {
-  // Remove all theming from the redirection settings; for us it is just an
-  // array container to hold other form elements that will be displayed.
-  foreach (element_properties($form['submission']['redirection']) as $property) {
-    unset($form['submission']['redirection'][$property]);
-  }
-
-  // Transform the radio buttons for the redirect options into a select list,
-  // with our custom labels.
-  $element = &$form['submission']['redirection']['redirect'];
-  $element['#type'] = 'select';
-  $element['#options']['confirmation'] = t('Show standard confirmation page');
-  $element['#options']['url'] = t('Redirect to a different page');
-  $element['#options']['none'] = t('Stay on the same page');
-
-  // Make cosmetic adjustments to the "Redirect URL" textfield.
-  $element = &$form['submission']['redirection']['redirect_url'];
-  $element['#title_display'] = 'invisible';
-  $element['#description'] = NULL;
-  $element['#field_prefix'] = t('Path:');
-  // Make it appear only when the appropriate redirect option is chosen.
-  $element['#states'] = array(
-    'visible' => array(
-      ':input[name="redirect"]' => array('value' => 'url'),
-    ),
-  );
-
-  // Make cosmetic adjustments to the "Confirmation message" textrea.
-  $confirmation = &$form['submission']['confirmation'];
-  $confirmation['#title_display'] = 'invisible';
-  $confirmation['#description'] = NULL;
-  $confirmation['#rows'] = 3;
-
-  // For a new webform, default both the confirmation message and confirmation
-  // page content elements to a standard message.
-  $confirmation_default = webform_alt_ui_default_confirmation_text();
-  if (_webform_alt_ui_node_webform_is_new($node)) {
-    $confirmation['#default_value'] = $confirmation_default;
-    $confirmation_page_default = $confirmation_default;
-  }
-  else {
-    // Otherwise, inherit the same text for the confirmation page content as
-    // the confirmation message itself (since they share a database field).
-    $confirmation_page_default = $confirmation['#default_value'];
-  }
-
-  // Create a container for the redirection and confirmation settings to be
-  // displayed together. They will actually be moved into the container during
-  // the pre-render stage; see webform_alt_ui_pre_render_node_form().
-  $container_info = element_info('container');
-  $form['submission']['confirm_redirect'] = array(
-    '#type' => 'container',
-    '#weight' => -10,
-    // Add a checkbox at the top level of this container. This will toggle the
-    // entire set of confirmation and redirection settings.
-    '#theme_wrappers' => array_merge(array('webform_alt_ui_check_expand_wrapper'), $container_info['#theme_wrappers']),
-    'confirm_redirect_toggle' => array(
-      '#type' => 'checkbox',
-      '#title' => t('Customize confirmation'),
-      '#default_value' => !_webform_alt_ui_node_webform_is_new($node) && ($node->webform['confirmation'] != $confirmation_default || $node->webform['redirect_url'] != '<confirmation>'),
-      '#attributes' => array('class' => array('check-expander')),
-    ),
-    // Add a container for the settings themselves. Since this is the only
-    // other element in the top level of the container (besides the toggle
-    // itself), everything in here will be automatically hidden when the
-    // checkbox is toggled.
-    'settings_container' => array(
-      '#type' => 'container',
-      // The redirect options will be moved in here during the pre-render
-      // stage.
-      'redirection' => array(),
-      // Add a container for the confirmation message.
-      'confirmation_message_container' => array(
-        '#type' => 'container',
-        // Hide this container when the appropriate redirect option is chosen.
-        '#states' => array(
-          'invisible' => array(
-            ':input[name="redirect"]' => array('value' => 'confirmation'),
-          ),
-        ),
-        // Add a checkbox that toggles the "Confirmation message" textarea.
-        '#theme_wrappers' => array_merge(array('webform_alt_ui_check_expand_wrapper'), $container_info['#theme_wrappers']),
-        'confirmation_toggle' => array(
-          '#type' => 'checkbox',
-          '#title' => t('Show a confirmation message'),
-          '#default_value' => !empty($confirmation['#default_value']),
-          '#attributes' => array('class' => array('check-expander')),
-        ),
-        // The confirmation textarea will be moved in here during the
-        // pre-render stage.
-        'confirmation' => array(),
-      ),
-      // Add a container for the confirmation message.
-      'confirmation_page_container' => array(
-        '#type' => 'container',
-        // Hide this container when the appropriate redirect option is chosen.
-        '#states' => array(
-          'visible' => array(
-            ':input[name="redirect"]' => array('value' => 'confirmation'),
-          ),
-        ),
-        // Duplicate the above textarea into one that will store the page body
-        // (for the case where we are redirecting to a standard confirmation
-        // page).
-        'confirmation_page_content' => array_merge($form['submission']['confirmation'], array(
-          '#title_display' => 'before',
-          '#title' => t('Page body'),
-          '#default_value' => $confirmation_page_default,
-          '#parents' => array('confirmation_page_content'),
-        )),
-      ),
-    ),
-  );
-}
-
-/**
- * Helper function for altering part of the webform settings form.
- */
-function _webform_alt_ui_alter_submit_limit_settings(&$form, &$form_state, $node) {
-  // Remove all theming from the submission limit settings; for us it is just
-  // an array container to hold other form elements that will be displayed.
-  foreach (element_properties($form['submission']['submit_limit']) as $property) {
-    unset($form['submission']['submit_limit'][$property]);
-  }
-
-  // Add a checkbox that toggles the submissions limit, and hide the existing
-  // radio selector.
-  $form['submission']['submit_limit']['#theme_wrappers'][] = 'webform_alt_ui_check_expand_wrapper';
-  $form['submission']['submit_limit']['submit_limit_toggle'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Limit submissions'),
-    '#default_value' => $node->webform['submit_limit'] != -1,
-    '#weight' => -5,
-    '#attributes' => array('class' => array('check-expander')),
-  );
-  $form['submission']['submit_limit']['enforce_limit']['#access'] = FALSE;
-
-  // Have the default limit be 1
-  $form['submission']['submit_limit']['submit_limit']['#default_value'] = $node->webform['submit_limit'] != -1 ? $node->webform['submit_limit'] : 1;
-
-  // Other cosmetic adjustments.
-  $form['submission']['submit_limit']['submit_limit']['#prefix'] = '<div class="limit-wrapper">' . t('Limit to: ');
-  $form['submission']['submit_limit']['submit_interval']['#prefix'] = ' ' . t('submission(s)') . ' ';
-  $form['submission']['submit_limit']['submit_interval']['#suffix'] = '</div>';
-}
-
-/**
- * Helper function for adding custom submission settings to the webform form.
- */
-function _webform_alt_ui_add_custom_submission_settings(&$form, &$form_state, $node) {
-  $mollom_enabled = module_exists('mollom');
-  $form['submission']['spam_protection'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Enable spam protection (<a href="@url">Mollom</a>)', array('@url' => url('admin/help/mollom'))),
-    // New webforms have spam protection enabled by default.
-    '#default_value' => _webform_alt_ui_node_webform_is_new($node) || ($mollom_enabled && mollom_form_load(_webform_alt_ui_mollom_form_id($node->nid))),
-    // If Mollom is off it doesn't matter what this checkbox is set to, since
-    // the form submit handler won't do anything with it anyway. So just hide
-    // it.
-    '#access' => $mollom_enabled,
-    '#weight' => -8,
-  );
-
-  _webform_alt_ui_add_submission_email_settings($form, $form_state, $node);
-
-  $form['submission']['#collapsible'] = FALSE;
-  $form['submission']['#collapsed'] = FALSE;
-}
-
-/**
- * Helper function to add basic submission email settings to the form.
- */
-function _webform_alt_ui_add_submission_email_settings(&$form, &$form_state, &$node) {
-  $existing_email = reset($node->webform['emails']);
-  $form['submission']['submission_email_checkbox'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Send a confirmation e-mail'),
-    '#default_value' => !empty($existing_email),
-  );
-  $dependent_on_checkbox = array(
-    'visible' => array(
-      ':input[name="submission_email_checkbox"]' => array('checked' => TRUE),
-    ),
-  );
-
-  $form['submission']['submission_email']['#tree'] = TRUE;
-  $form['submission']['submission_email']['eid'] = array(
-    '#type' => 'value',
-    '#value' => ($existing_email ? $existing_email['eid'] : NULL),
-  );
-  $form['submission']['submission_email']['email'] = array(
-    '#type' => 'textfield',
-    '#title' => t('To'),
-    '#default_value' => $existing_email ? $existing_email['email'] : variable_get('site_mail', ''),
-    '#states' => $dependent_on_checkbox,
-  );
-  $form['submission']['submission_email']['subject'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Subject'),
-    '#default_value' => $existing_email ? $existing_email['subject']: t('Webform submission received'),
-    '#states' => $dependent_on_checkbox,
-  );
-  $form['submission']['submission_email']['template'] = array(
-    '#type' => 'textarea',
-    '#title' => t('Body'),
-    '#default_value' => $existing_email ? $existing_email['template'] : t('A visitor completed a webform on your site. Please visit your website and click the webform\'s "Results" tab to review the submission.'),
-    '#states' => $dependent_on_checkbox,
-  );
-  $form['#validate'][] = '_webform_alt_ui_validate_submission_email';
-
-}
-
-/**
- * Validation function for the email address in the submission settings section.
- */
-function _webform_alt_ui_validate_submission_email(&$form, &$form_state) {
-  if ($form_state['values']['submission_email_checkbox'] && !valid_email_address($form_state['values']['submission_email']['email'])) {
-    form_set_error('submission_email][email', t('The email address %mail is not valid.', array('%mail' => $form_state['values']['submission_email']['email'])));
-  }
-}
-
-/**
- * Helper function for altering part of the webform settings form.
- */
-function _webform_alt_ui_alter_role_control_settings(&$form, &$form_state, $node) {
-  // Cosmetic adjustments.
-  $form['role_control']['#collapsed'] = TRUE;
-  $form['role_control']['#description'] = NULL;
-  $form['role_control']['roles']['#title'] = t('Permit submission from:');
-  $form['role_control']['roles']['#description'] = NULL;
-}
-
-/**
- * Helper function for altering part of the webform settings form.
- */
-function _webform_alt_ui_alter_advanced_settings(&$form, &$form_state, $node) {
-  // Hide descriptions from all checkboxes within the advanced settings
-  // fieldset.
-  foreach (element_children($form['advanced']) as $key) {
-    $form['advanced'][$key]['#description'] = NULL;
-  }
-
-  // Alter titles
-  $form['advanced']['submit_notice']['#title'] = t("Display a link to previous submissions");
-  $form['advanced']['block']['#title'] = t("Create a block");
-
-  // Hide options
-  $form['advanced']['allow_draft']['#access'] = FALSE;
-  $form['advanced']['auto_save']['#access'] = FALSE;
-
-  // Make cosmetic adjustments to the "Submit button text" textfield.
-  $form['advanced']['submit_text']['#default_value'] = !empty($node->webform['submit_text']) ? $node->webform['submit_text'] : t('Submit');
-  $form['advanced']['submit_text']['#type'] = 'hidden';
-}
-
-/**
- * Adds the email form to the Form settings tab
- */
-function _webform_alt_ui_webform_email(&$form, &$form_state) {
-  // This is just a stub function.  The email form has not been implemented yet.
-}
-
-/**
- * Adds the Add field and Field settings tabs and the live preview
- */
-function _webform_alt_ui_webform_form(&$form, &$form_state) {
-  // If this is a new node, there will be no nid, so a temporary form_builder id
-  // is created for the user.  This does mean that a user can only create 1 webform
-  // concurrently.
-  $nid = isset($form['#node']->nid) ? $form['#node']->nid : substr($form['form_token']['#default_value'], 0 , 32);
-  $form['#form_builder_token'] = $nid;
-
-  // Load the current state of the form, or create a new cache if needed.
-  $form_structure = form_builder_cache_load('webform', $nid);
-  if (!$form_structure) {
-    $form_structure = form_builder_load_form('webform', $nid);
-    form_builder_cache_save('webform', $nid, $form_structure);
-  }
-
-  // Add the preview to the form. We need to manually call our alter hook on it
-  // since we are not using drupal_get_form() to load it (we are already inside
-  // a different form).
-  // @todo: Refactor this code to remove that restriction.
-  $form_builder_preview_form = form_builder_preview($form, $form_state, $form_structure, 'webform', $nid);
-  $form_id = 'form_builder_preview';
-  drupal_alter(array('form', "form_{$form_id}"), $form_builder_preview_form, $form_state, $form_id);
-  $form['ui-wrapper']['live_preview'] = $form_builder_preview_form;
-
-  // Prevent all form elements in the "live preview" from being validated when
-  // this form is submitted.
-  webform_alt_ui_prevent_validation($form['ui-wrapper']['live_preview']);
-
-  // Add a submit button to the preview.
-  $button_text = $form['webform']['#value']['submit_text'] ? check_plain($form['webform']['#value']['submit_text']) : t('Submit');
-  $path = 'admin/webform_alt_ui/submit_button_form';
-  if (isset($form['#node']->nid)) {
-    $path .= '/' . $form['#node']->nid;
-  }
-  $form['ui-wrapper']['live_preview']['submit-preview'] = array(
-    '#type' => 'markup',
-    '#markup' => l($button_text, $path, array('attributes' => array('class' => array('configure', 'button')))),
-    '#weight' => count(element_children($form['ui-wrapper']['live_preview'])) + 1000,
-    '#theme_wrappers' => array('webform_element', 'form_builder_element_wrapper'),
-    '#form_builder' => array(
-      'configurable' => FALSE,
-      'removable' => FALSE,
-    ),
-  );
-
-  // Add a tab for Add field
-  $form['add_field'] = array(
-    '#type' => 'fieldset',
-    '#title' => 'Add field',
-    '#weight' => 1,
-    '#group' => 'h-tabs',
-  );
-
-  // Load the form_builder fields into the tab
-  $fields = form_builder_get_form_type('webform');
-  $groups = module_invoke_all('form_builder_palette_groups');
-  // TODO: We shouldn't have to clear the cache here.
-  $active_fields = form_builder_get_element_ids($form_structure);
-  foreach ($fields as $key => $field) {
-    if ($field['unique'] && in_array($key, $active_fields)) {
-      $fields[$key]['in_use'] = TRUE;
-    }
-    if ($field['addable'] == FALSE) {
-      unset($fields[$key]);
-    }
-  }
-
-  $form['add_field']['fields'] = array(
-    '#markup' => theme('webform_alt_ui_field_palette', array('fields' => $fields, 'groups' => $groups, 'form_type' => 'webform', 'form_id' => $nid)),
-  );
-
-  // Add a tab for Field settings
-  $form['field_settings'] = array(
-    '#type' => 'fieldset',
-    '#title' => 'Field settings',
-    '#weight' => 2,
-    '#group' => 'h-tabs',
-  );
-
-  $form['field_settings']['placeholder'] = array(
-    '#markup' => '<div id="form-builder-field-configure" class="form-builder-field-configure"><div class="field-settings-message">' . t('No field selected') . '</div></div>',
-  );
-}
-
-/**
- * Pre-render function to reorganize the webform node form before theming it.
- *
- * This module significantly alters the structure of the webform node form, but
- * we do not want to alter the structure while the form is being built (since
- * that would invalidate the code that runs within existing webform submit
- * handlers, etc). So we only alter the structure immediately before the form
- * is rendered.
- */
-function webform_alt_ui_pre_render_node_form($form) {
-  // Put the redirection and confirmation settings in the correct place within
-  // their overall container.
-  $form['submission']['confirm_redirect']['settings_container']['redirection'] = $form['submission']['redirection'];
-  unset($form['submission']['redirection']);
-  $form['submission']['confirm_redirect']['settings_container']['confirmation_message_container']['confirmation'] = $form['submission']['confirmation'];
-  unset($form['submission']['confirmation']);
-
-  // Put the submission settings, submission access settings, and advanced
-  // settings inside the form settings horizontal tab.
-  foreach (array('submission', 'role_control', 'advanced') as $key) {
-    $form['form_settings'][$key] = $form[$key];
-    $form[$key]['#printed'] = TRUE;
-  }
-
-  return $form;
-}
-
-/**
- * Returns default text for the webform confirmation message/page content.
- */
-function webform_alt_ui_default_confirmation_text() {
-  return t('Thank you, your submission has been received.');
-}
-
-/**
- * Determines if a node's webform is being edited for the first time.
- *
- * This function is intended to be called from within the webform alternate UI
- * to determine if the node has been saved from this UI previously.
- *
- * @param $node
- *   The fully-loaded node object.
- *
- * @return
- *   TRUE for new nodes, or nodes that are being edited for the first time
- *   after their node type has become webform-enabled.
- */
-function _webform_alt_ui_node_webform_is_new($node) {
-  // For now, the best "flag" we have to check for an existing node which is
-  // being edited for the first time after it was webform-enabled is to check
-  // the confirmation format, since this is null by default for new webforms
-  // but non-null after the user has saved the form and made a choice. This
-  // means the function will (usually) return false if the node has only been
-  // saved programmatically since becoming webform-enabled (and never saved via
-  // the UI), which is what we want.
-  //
-  // @todo Come up with a cleaner and more foolproof way to detect this
-  //   condition.
-  return empty($node->nid) || !isset($node->webform['confirmation_format']);
-}
-
-/**
- * Traverse a form array and set all elements within it to skip validation.
- *
- * This is done recursively, so that, for example, elements within fieldsets
- * are also found.
- */
-function webform_alt_ui_prevent_validation(&$form) {
-  $form['#validated'] = TRUE;
-  foreach (element_children($form) as $key) {
-    webform_alt_ui_prevent_validation($form[$key]);
-  }
-}
-
-/**
- * Helper function; adds a process function to simplify text format selectors.
- *
- * @param $element
- *   The 'text_format' element to which the process function will be attached.
- */
-function _webform_alt_ui_add_text_format_simplification(&$element) {
-  $element['#process'][] = 'webform_alt_ui_simplify_text_format_selector';
-  $info = element_info('text_format');
-  if (!empty($info['#process'])) {
-    $element['#process'] = array_merge($info['#process'], $element['#process']);
-  }
-}
-
-/**
- * Form process function to deny access to parts of a text format selector.
- *
- * This runs after an element of type '#text_format' is processed, and prevents
- * parts of the format selector from actually displaying (except those that we
- * want to display).
- */
-function webform_alt_ui_simplify_text_format_selector($element) {
-  // Simplify the format selector (e.g., remove the formatting guidelines).
-  $element['format'] = $element['format']['format'];
-
-  // Allow the format selector to inherit JavaScript behaviors from the overall
-  // element.
-  // @todo: Determine if this should be in core (as a bugfix)?
-  if (isset($element['#states'])) {
-    $element['format'] += array('#states' => array());
-    $element['format']['#states'] = array_merge($element['#states'], $element['format']['#states']);
-  }
-
-  // Remove custom theming and rendering from the overall element.
-  unset($element['#theme_wrappers']);
-  unset($element['#pre_render']);
-
-  // Add a custom theme wrapper.
-  $element['#theme_wrappers'][] = 'webform_alt_ui_text_format_wrapper';
-
-  return $element;
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- *
- * Reorganize the Field settings tab.
- *
- * This adds a pre_render callback to display the form as a vertical_accordion.
- * Grouping and strings for properties are changed as well as adding checkboxes
- * to toggle the display of the inputs for the appropriate properties.
- */
-function webform_alt_ui_form_form_builder_field_configure_alter(&$form, &$form_state, $form_id) {
-  // Restring labels.
-  $form['title']['#title'] = t('Label');
-  $form['title_display']['#title'] = t('Label alignment');
-  $form['description']['#title'] = t('Help text');
-  // Alter the groupings.
-  $form['weight']['#form_builder']['property_group'] = 'default';
-  // Add a pre_render callback that will convert the property groups into
-  // vertical_accordions.
-  $form['#pre_render'][] = 'webform_alt_ui_pre_render_field_configure';
-
-  // Set a default of showing a checkbox for the properties in this form.
-  $holder = array();
-  $keys = element_children($form);
-  foreach($keys as $key) {
-    if (!in_array($form[$key]['#type'], array('checkbox', 'hidden', 'button', 'submit')) && !$form[$key]['#required']) {
-      $form[$key]['#checkbox'] = TRUE;
-    }
-  }
-
-  // Call functions that alter the field configuration form specific to the field type
-  form_load_include($form_state, 'inc', 'webform_alt_ui', 'includes/webform_alt_ui.components');
-  $func = '_webform_alt_ui_' . $form['#_edit_element']['#type'] . '_configure';
-  if (function_exists($func)) {
-    $form = call_user_func($func, $form);
-  }
-
-  // Add a class to mark the appropriate properties to receive a checkbox
-  foreach($keys as $key) {
-    if (!empty($form[$key]['#checkbox'])) {
-      $form[$key]['#attributes']['class'][] = 'check-toggle';
-    }
-  }
-}
-
-/**
- * Add the property groups in the field configure form to a vertical accordion.
- */
-function webform_alt_ui_pre_render_field_configure($form) {
-  $keys = element_children($form);
-
-  // Hide the form_key value
-  $form['default_property_group']['key']['#access'] = FALSE;
-
-  // Create the vertical accordion.
-  $form['vertical_accordion'] = array(
-    '#type' => 'vertical_accordion',
-  );
-
-  // Iterate through the form's children.
-  foreach($keys as $key) {
-    $element = $form[$key];
-    // If the child is a fieldset, add it to the vertical_accordion.
-    if (isset($element['#type']) && $element['#type'] == 'fieldset') {
-      $form['vertical_accordion'][$key] = $element;
-      // Remove the original element this duplicates.
-      unset($form[$key]);
-    }
-  }
-
-  return $form;
-}
-
-/**
- * Theme function to wrap our simplified text format selector with a class.
- */
-function theme_webform_alt_ui_text_format_wrapper($variables) {
-  return '<div class="webform-alt-ui-simplified-text-format">' . $variables['element']['#children'] . '</div>';
-}
-
-/**
- * In order to restring "Add a field" to "Fields" we need to re-implement this
- * theme function.
- *
- * @todo: We should eventually patch the form_builder version of this theme
- *   function to call theme('item_list__form_builder_field_palette') instead of
- *   the generic theme('item_list'); then we can delete the function below and
- *   instead implement a preprocess hook for theme_item_list() which modifies
- *   $variables['title'] for this item list only. However, currently it is not
- *   possible to do that effectively, so we should revisit this issue once
- *   http://drupal.org/node/956520 is resolved.
- */
-function theme_webform_alt_ui_field_palette($variables) {
-  extract($variables);
-
-  $output = '';
-  $lists = array();
-  foreach ($fields as $field_name => $field) {
-    $class = array('field-' . $field_name);
-    $style = '';
-
-    // If a field is unique, add a special class to identify it.
-    if ($field['unique']) {
-      $class[] = 'form-builder-unique';
-      $class[] = 'form-builder-element-' . $field_name;
-
-      // If already in use, do not display it in the list.
-      if (!empty($field['in_use'])) {
-        $style = 'display: none;';
-      }
-    }
-
-    $lists[$field['palette_group']]['#weight'] = $groups[$field['palette_group']]['weight'];
-    $lists[$field['palette_group']][] = array(
-      'data' => l($field['title'], 'admin/build/form-builder/add/' . $form_type . '/' . $form_id . '/' . $field_name, array('query' => drupal_get_destination())),
-      'class' => $class,
-      'style' => $style,
-    );
-  }
-
-  // Sort the lists by weight.
-  uasort($lists, 'element_sort');
-
-  $output .= '<div id="form-builder-field-palette">';
-  foreach ($lists as $group => $list) {
-    unset($list['#weight']);
-    $output .= theme('item_list', array('items' => $list, 'title' => (count($lists) > 1) ? $groups[$group]['title'] : t('Fields'), 'type' => 'ul', 'attributes' => array('class' => array('form-builder-fields', 'clearfix'))));
-  }
-  $output .= '</div>';
-
-  return $output;
-}
-
-/*
- * Disable the form_builder default links and add theme wrappers to customize
- * the markup of the form_builder preview elements
- */
-function webform_alt_ui_form_builder_preview_alter(&$element, $form_type, $form_id) {
-  // Disable the remove and configure links.
-  $element['#form_builder']['removable'] = FALSE;
-  $element['#form_builder']['configurable'] = FALSE;
-
-  // Adjust the theme wrappers depending on the item type.
-  if ($element['#type'] == 'fieldset') {
-    $key = array_search('fieldset', $element['#theme_wrappers']);
-    array_splice($element['#theme_wrappers'], $key+1, 0, 'webform_alt_ui_element_links');
-    array_splice($element['#theme_wrappers'], $key+2, 0, 'webform_alt_ui_fieldset_wrapper');
-  }
-  else {
-    // If there is a special theme wrapper for this element type, add it.
-    if (function_exists('theme_webform_alt_ui_element_' . $element['#type'])) {
-      array_unshift($element['#theme_wrappers'], 'webform_alt_ui_element_' . $element['#type']);
-    }
-    $key = array_search('webform_element', $element['#theme_wrappers']);
-    array_splice($element['#theme_wrappers'], $key+1, 0, 'webform_alt_ui_element_links');
-  }
-
-  if ($element['#type'] == 'file') {
-    $element['#size'] = $element['#webform_file_width'];
-  }
-}
-
-/**
- * Adds links after the contents of an element to trigger actions
- *
- * The duplicate link is currently inactive.
- */
-function theme_webform_alt_ui_element_links(&$vars) {
-  $element = $vars['element'];
-
-  // Add a list of links after the content of this element
-  $output = $element['#children'];
-  $output .= '<ul class="form-builder-links">';
-
-  // @todo: Add duplicate functionality
-  //$output .= '<li>'. l(t('Duplicate'), '#', array('html' => TRUE, 'attributes' => array('class' => array('duplicate'), 'title' => t('Duplicate')))) .'</li>';
-
-  $output .= '<li>'. l(t('Delete'), 'admin/build/form-builder/remove/' . $element['#form_builder']['form_type'] . '/' . $element['#form_builder']['form_id'] . '/' . $element['#form_builder']['element_id'], array('html' => TRUE, 'attributes' => array('class' => array('delete'), 'title' => t('Delete')))) . '</li>';
-  $output .= '<li class="element-invisible">'. l(t('Configure'), 'admin/build/form-builder/configure/' . $element['#form_builder']['form_type'] . '/' . $element['#form_builder']['form_id'] . '/' . $element['#form_builder']['element_id'], array('html' => TRUE, 'attributes' => array('class' => array('configure'), 'title' => t('Configure')))) .'</li>';
-  $output .= '</ul>';
-
-  return $output;
-}
-
-/**
- * Themes markup webform elements.
- */
-function theme_webform_alt_ui_element_markup($vars) {
-  return '<div class="markup-wrapper">' . $vars['element']['#children'] . '</div>';
-}
-
-/**
- * Adds a wrapper around fieldsets to create the highlight color but not affect the border
- */
-function theme_webform_alt_ui_fieldset_wrapper($vars) {
-  return '<div class="fieldset-color-wrapper">' . $vars['element']['#children'] . '</div>';
-}
-
-/**
- * Adds a wrapper to make an element expand based on the status of its first checkbox.
- */
-function theme_webform_alt_ui_check_expand_wrapper($variables) {
-  $element = $variables['element'];
-  $output = '<div class="check-expand">' . $element['#children'] . '</div>';
-  return $output;
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- */
-function webform_alt_ui_form_form_builder_preview_alter(&$form, &$form_state) {
-  $form['#pre_render'][] = 'webform_alt_ui_pre_process_preview';
-
-  // The Webform module uses webform_component_include() to lazy-load component
-  // functions when they're needed, but it fails to ensure that those files are
-  // also included when a cached form is processed (e.g., during
-  // form_builder_field_render()).
-  // @todo This should be fixed within Webform module, but is non-trivial,
-  //   because webform_component_include() gets called from form and non-form
-  //   contexts. When time permits, submit an appropriate patch to the Webform
-  //   project.
-  if ($form_state['build_info']['args'][1] === 'webform') {
-    // @todo When the fix is moved to the Webform module, it should be possible
-    //   to lazy-load files for only the component types used by the current
-    //   form. But from within here, it's hard to determine what those are, so
-    //   include all of them.
-    foreach (webform_components() as $component_info) {
-      // Copied from webform_component_include(), but replacing
-      // module_load_include() with form_load_include().
-      if (isset($component_info['file'])) {
-        $pathinfo = pathinfo($component_info['file']);
-        $basename = basename($pathinfo['basename'], '.' . $pathinfo['extension']);
-        $path = (!empty($pathinfo['dirname']) ? $pathinfo['dirname'] . '/' : '') . $basename;
-        form_load_include($form_state, $pathinfo['extension'], $component_info['module'], $path);
-      }
-    }
-  }
-}
-
-function webform_alt_ui_pre_process_preview($form) {
-  // Hide the title
-  unset($form['#title']);
-
-  // Disable the field palette we've already added it to the Add field tab.
-  $form['#block_enabled'] = TRUE;
-
-  return $form;
-}
-
-// == Page overrides ===========================================================
-
-/**
- * Overrides webform_results_submissions() from webform.report.inc.
- *
- * This lets us tie in a form in the page generation process.
- */
-function webform_alt_ui_results_submissions($node, $user_filter, $pager_count) {
-  // This callback is invoked by node/NID/webform-results and by
-  // node/NID/submissions. The latter is available to people who may not have
-  // access to view all submissions for this webform, so protect the CSV file
-  // accordingly.
-  // @todo Might be a UI improvement for the form generated from
-  //   node/NID/submissions to trigger a CSV file that contains the current
-  //   user's submissions only, so that it matches what is displayed on the
-  //   page. However, webform_results_download() does not currently support
-  //   filters.
-  $form = webform_results_access($node) ? drupal_get_form('webform_alt_ui_result_buttons', $node) : array();
-
-  module_load_include('inc', 'webform', 'includes/webform.report');
-  $page = webform_results_submissions($node, $user_filter, $pager_count);
-
-  // Line up the page components in order.
-  return array(array('#type' => 'markup', '#markup' => $page), $form);
-}
-
-/**
- * Form for our overriden webforms result page.
- */
-function webform_alt_ui_result_buttons($form, &$form_state, $node) {
-  return array(
-    '#node' => $node,
-    'buttons' => array(
-      'download' => array(
-        '#type' => 'submit',
-        '#value' => t('Download file'),
-      ),
-      'clear' => array(
-        '#type' => 'submit',
-        '#value' => t('Clear'),
-      ),
-    )
-  );
-}
-
-/**
- * Form submission for our overriden webforms result page.
- */
-function webform_alt_ui_result_buttons_submit($form, &$form_state) {
-  if ($form_state['values']['op'] == $form_state['values']['clear']) {
-    $form_state['redirect'] = 'node/' . $form['#node']->nid . '/webform-results/clear';
-  }
-  elseif ($form_state['values']['op'] == $form_state['values']['download']) {
-    form_load_include($form_state, 'inc', 'webform', 'includes/webform.report');
-    webform_results_download($form['#node']);
-  }
-}
-
-/**
- * Menu callback for removing a field.
- */
-function webform_alt_ui_remove_element($form_type, $form_id, $element_id) {
-  module_load_include('inc', 'form_builder', 'includes/form_builder.admin');
-
-  // Remove the field from the cache.
-  form_builder_cache_field_delete($form_type, $form_id, $element_id);
-
-  // Attempt to load the field.  If it has been successfully deleted this returns false.
-  $error = form_builder_cache_field_load($form_type, $form_id, $element_id) ? TRUE : FALSE;
-
-  // Create the JSON data to be sent back to the caller.
-  $data = array(
-    'formType' => $form_type,
-    'formId' => $form_id,
-    'elementId' => $element_id,
-    'html' => form_builder_field_render($form_type, $form_id, $element_id),
-    'time' => time(),
-    'error' => $error,
-  );
-
-  drupal_json_output($data);
-  exit();
-
-  return '';
-}
-
-/*
- * Function for clicking cancel on the form.
- */
-function webform_alt_ui_click_cancel(&$form, &$form_state) {
-  // Delete the form cache.
-  webform_alt_ui_clear_cache($form, $form_state);
-
-  // Set a default destination of the Add content page.
-  $destination = 'node/add';
-  // If the node exists set the destination to the view tab.
-  if (isset($form_state['node']->nid)) {
-    drupal_set_message(t('Changes to your webform have been cancelled.'));
-    $destination = 'node/' . $form_state['node']->nid;
-  }
-
-  // The presence of a destination in the query string will supercede the previous
-  // desitination value.
-  if (!$_GET['destination']) {
-    drupal_goto($destination);
-  }
-}
-
-/**
- * Clears the webform cache
- */
-function webform_alt_ui_clear_cache(&$form, &$form_state) {
-  form_builder_cache_delete('webform', $form['#form_builder_token']);
-}
-
-/**
- * Alter the render array for the option_element config form.
- */
-function webform_alt_ui_pre_render_option($element, $form_state) {
-  $keys = element_children($element['settings']);
-
-  // Remove the settings from their fieldset and eliminate their description text.
-  foreach($keys as $key) {
-    $element[$key] = $element['settings'][$key];
-    unset($element[$key]['#description']);
-  }
-  unset($element['settings']);
-
-  return $element;
-}
-
-
-/**
- * Implements hook_form_builder_types_alter().
- *
- * Function to re-order the form elements and change their titles.
- */
-function webform_alt_ui_form_builder_types_alter(&$types) {
-  $fields = $types['webform'];
-
-  // Build an array of titles keyed by element type.
-  $new_order = _webform_alt_ui_component_names();
-
-  // Create the new array of form elements altering the title when needed.
-  $order = array();
-  foreach($new_order as $field_name => $title) {
-    $order[$field_name] = $fields[$field_name];
-    if ($title) {
-      $order[$field_name]['title'] = $title;
-    }
-    unset($fields[$field_name]);
-  }
-
-  // Merge and store the form element arrays.  This means that any fields that
-  // were omitted from the $new_order list will still be included.
-  $types['webform'] = array_merge($order, $fields);
-
-  // Alter _webform_defaults_COMPONENT() defaults.
-  if (isset($types['webform']['file'])) {
-    $types['webform']['file']['default']['#webform_file_filtering']['size'] = 1000;
-  }
-}
-
-/*
- * Define the new order and titles for form elements.
- */
-function _webform_alt_ui_component_names() {
-  return array(
-    'textfield' => t('Text field'),
-    'textarea' => t('Multi-line text field'),
-    'radios' => t('Radio buttons'),
-    'checkboxes' => t('Check boxes'),
-    'select' => t('Drop-down list'),
-    'email' => t('E-mail'),
-    'file' => t('File upload'),
-    'pagebreak' => t('Page break'),
-    'markup' => t('Formatted content'),
-    'fieldset' => t('Fieldset'),
-    'hidden' => t('Hidden field'),
-  );
-}
-
-/**
- * This retitles the form components to match the names in the field palette.
- */
-function webform_alt_ui_form_builder_add_element_alter(&$element, $form_type, $form_id) {
-  $titles = _webform_alt_ui_component_names();
-  $type = $element['#form_builder']['element_type'];
-
-  if ($titles[$type]) {
-    $element['#title'] = $titles[$type];
-  }
-  else {
-    $element['#title'] = ucfirst($type);
-  }
-}
-
-/**
- * Implements hook_block_view_DELTA_alter().
- */
-function webform_alt_ui_block_view_system_help_alter(&$data, $block) {
-  // Replace the system help text for the current page, if applicable.
-  $item = menu_get_item();
-  if ($item['path'] == 'admin/config/content/webform') {
-    $data['content'] = t('Webforms are forms or questionnaires that can optionally be attached to other content types. <a href="@url">Create a webform</a>.', array('@url' => url('node/add/webform')));
-  }
-}
-
-/**
- * This function alters access and text strings to some of the options on the
- * webform admin configuration page
- */
-function webform_alt_ui_form_webform_admin_settings_alter(&$form, &$form_state, $form_id) {
-  $form['advanced']['#title'] = t('Advanced');
-
-  $form['advanced']['webform_use_cookies']['#title'] = t('Allow cookies to track submissions');
-
-  // Hide some options from the UI
-  $form['advanced']['webform_email_address_format']['#access'] = FALSE;
-  $form['advanced']['webform_submission_access_control']['#access'] = FALSE;
-
-  $form['advanced']['webform_export_format']['#title'] = t('Default format for downloading webform results');
-
-  $form['advanced']['webform_csv_delimiter']['#title'] = t('Character to use for delimited text export format');
-  $form['advanced']['webform_csv_delimiter']['#description'] = t('Using tabs in the export is the most reliable method for preserving non-latin characters. You may want to change this to another character depending on the program with which you anticipate importing results.');
-  $form['advanced']['webform_csv_delimiter']['#states'] = array(
-    'invisible' => array(
-      'input[name=webform_export_format]' => array('checked' => FALSE),
-    ),
-  );
-  
-  $form['components']['file']['#title'] = t('File upload');
-  $form['components']['hidden']['#title'] = t('Hidden field');
-  $form['components']['textarea']['#title'] = t('Multi-line textfield');
-  $form['components']['textarea']['#description'] = t('A large textfield that allows for multiple lines of input.');
-  $form['components']['email']['#description'] = t('A special textfield that accepts an e-mail address.');
-  $form['components']['select']['#description'] = t('Allows creation of checkboxes, radio buttons, or dropdown menus.');
-
-  // Disable options that don't work with form_builder
-  $form['components']['grid']['#printed'] = TRUE;
-  $form['components']['grid']['#default_value'] = FALSE;
-  $form['components']['date']['#printed'] = TRUE;
-  $form['components']['date']['#default_value'] = FALSE;
-  $form['components']['time']['#printed'] = TRUE;
-  $form['components']['time']['#default_value'] = FALSE;
-
-  // Hide the email settings
-  $form['email']['#access'] = FALSE;
-
-  // Retheme the table
-  $form['#theme'] = array('webform_alt_ui_admin_settings');
-}
-
-function theme_webform_alt_ui_admin_settings($variables) {
-  $form = $variables['element'];
-
-  // Format the components into a table.
-  foreach (element_children($form['components']) as $key) {
-    if (!$form['components'][$key]['#printed']) {
-      $row = array();
-      $row[] = $form['components'][$key]['#title'];
-      $row[] = $form['components'][$key]['#description'];
-      $form['components'][$key]['#title'] = NULL;
-      $form['components'][$key]['#description'] = NULL;
-      $row[] = array('data' => drupal_render($form['components'][$key]), 'align' => 'center');
-      $rows[] = $row;
-    }
-  }
-  $header = array(t('Field'), t('Description'), array('data' => t('Enabled'), 'class' => array('checkbox')));
-
-  // Create the table inside the form.
-  $form['components']['table'] = array(
-    '#theme' => 'table',
-    '#header' => $header,
-    '#rows' => $rows,
-  );
-
-  return drupal_render_children($form);
-}
-
-/**
- * Prints the confirmation message after a successful submission.
- */
-function _webform_alt_ui_confirmation($node) {
-  drupal_set_title($node->title);
-  webform_set_breadcrumb($node);
-  return theme('webform_alt_ui_confirmation', array('node' => $node, 'sid' => $_GET['sid']));
-}
-
-/**
- * Themes the output of the default confirmation page.
- */
-function theme_webform_alt_ui_confirmation($vars) {
-  $confirmation_message = $vars['confirmation_message'];
-  $link_to_form = $vars['link_to_form'];
-  $node = $vars['node'];
-
-  // Because we put a default confirmation message in the textbox in our UI, if
-  // someone leaves it blank they probably meant to do so, so we do not output
-  // a default confirmation here, just use whatever we were provided with.
-  $output = '<div class="webform-confirmation">' . $confirmation_message . '</div>';
-
-  if ($link_to_form) {
-    $output .= '<div class="links">' . l(t('Go back to the form'), 'node/' . $node->nid) . '</div>';
-  }
-
-  return $output;
-}
-
-/**
- * Preprocess function for the webform confirmation; repeat webform's steps.
- */
-function webform_alt_ui_preprocess_webform_alt_ui_confirmation(&$vars) {
-  template_preprocess_webform_confirmation($vars);
-}
-
-function webform_alt_ui_preprocess_webform_submission_page(&$vars) {
-  if (isset($vars['submission_content']['#type']) && $vars['submission_content']['#type'] == 'form') {
-    foreach(element_children($vars['submission_content']['submitted']) as $key) {
-      $vars['submission_content']['submitted'][$key]['#title'] .= ':';
-    }
-  }
-}
-
-/**
- * Implements module_preprocess_hook().
- *
- * Alter the theme_hook_suggestions for the navigation so we can retheme it on
- * the module layer.
- */
-function webform_alt_ui_preprocess_webform_submission_navigation(&$vars) {
-  $vars['theme_hook_suggestions'][] = 'webform_alt_ui_submission_navigation';
-}
-
-/**
- * Themes the previous | next links on individual webform submissions
- */
-function theme_webform_alt_ui_submission_navigation($vars) {
-  $next = $vars['next'];
-  $previous = $vars['previous'];
-  $previous_url = $vars['previous_url'];
-  $next_url = $vars['next_url'];
-  
-  $output = '<div class="webform-submission-navigation">';
-
-  drupal_add_css(drupal_get_path('module', 'webform_alt_ui') . '/css/webform_alt_ui.css');
-
-  if ($previous) {
-    $output .= l(t('Previous'), $previous_url, array('attributes' => array('class' => array('webform-submission-previous')), 'query' => ($mode == 'form' ? array('destination' => $previous_url) : NULL)));
-  } else {
-    $output .= '<span class="webform-submission-previous">' . t('Previous') . '</span>';
-  }
-
-  if ($next) {
-    $output .= l(t('Next'), $next_url, array('attributes' => array('class' => array('webform-submission-next')), 'query' => ($mode == 'form' ? array('destination' => $next_url) : NULL)));
-  } else {
-    $output .= '<span class="webform-submission-next">' . t('Next') . '</span>';
-  }
-
-  $output .= '</div>';
-    
-  return $output;
-}
-
-function webform_alt_ui_preprocess_webform_submission_information(&$vars) {
-  $vars['theme_hook_suggestions'][] = 'webform_alt_ui_submission_information';
-
-  $vars['count'] = array();
-  $query = db_select('webform_submissions')
-    ->condition('nid', $vars['node']->nid)
-    ->condition('sid', $vars['submission']->sid, '<=');
-  $vars['count']['current'] = $query->countQuery()->execute()->fetchField();
-  
-  $vars['count']['total'] = webform_get_submission_count($vars['node']->nid);
-}
-
-function theme_webform_alt_ui_submission_information(&$vars) {
-  $node = $vars['node'];
-  $account = $vars['account'];
-  $submission = $vars['submission'];
-  $count = $vars['count'];
-
-  $output = '<div class="webform-user clearfix">';
-  $output .= '<h5>' . t('Submission information') . '</h5>';
-  $output .= theme('user_picture', array('account' => $account));
-  $output .= '
-    <div class="bd">
-      <div><span class="label">' . t('Form:') . '</span> ' .  l($node->title, 'node/' . $node->nid) . '</div>
-      <div><span class="label">' . t('Submitted by:') . '</span> '. theme('username', array('account' => $account)) . '</div>
-      <div><span class="label">' . t('Date:') . '</span> '. format_date($submission->submitted, 'large') . '</div>
-      <div><span class="label">' . t('IP address:') . '</span> ' . $submission->remote_addr . '</div>
-      <div>' . t('!current of !total', array('!current' => $count['current'], '!total' => $count['total'])) . '</div>
-    </div>';
-  $output .= '</div>';
-
-  return $output;
-}
-
-function webform_alt_ui_webform_submission_render_alter(&$renderable) {
-  // Recursively append a colon to each element's title
-  webform_alt_ui_append_colon($renderable);
-}
-
-function webform_alt_ui_append_colon(&$element) {
-  foreach(element_children($element) as $key) {
-    if ($element[$key]['#type'] != 'fieldset') {
-      $element[$key]['#title'] .= ':';
-    }
-    webform_alt_ui_append_colon($element[$key]);
-  }
-}
-
-/*
- * Hides the custom keys option for checkboxes, select, and radios
- */
-function webform_alt_ui_option_process(&$vars, $hook) {
-  $vars['custom_keys']['#access'] = FALSE;
-
-  return $vars;
-}
-
-/**
- * Additional file size validation for file upload fields.
- */
-function webform_alt_ui_file_size_validate($element, &$form_state) {
-  if ($element['#value'] > 20000) {
-    form_error($element, t('The maximum size must be less than 20,000 KB.'));
-  }
-  elseif ($element['#value'] <= 0) {
-    form_error($element, t('The maximum upload size must be a positive number.'));
-  }
-}
-
-/**
- * Preprocess function for webform file components
- *
- * Sets the #size attribute to a custom default
- */
-function webform_alt_ui_preprocess_webform_render_file(&$vars) {
-  $keys = element_children($vars['element']);
-  $key = array_shift($keys);
-
-  if (!$vars['element']['#webform_component']['extra']['width']) {
-    $vars['element'][$key]['#size'] = WEBFORM_ALT_UI_FILE_WIDTH;
-  }
-}
-
-function webform_alt_ui_submit_button_page($nid = NULL) {
-  $form = drupal_get_form('webform_alt_ui_submit_button_form', $nid);
-
-  $output = render($form);
-
-  if ($_REQUEST['js']) {
-    $data = array(
-      'html' => $output,
-    );
-
-    drupal_json_output($data);
-    return;
-  }
-
-  return $output;
-}
-
-
-function webform_alt_ui_submit_button_form($form, &$form_state, $nid) {
-  // Handle the case where the node we are configuring doesn't exist, in
-  // addition to the case where it does.
-  if (!empty($nid)) {
-    $node = node_load($nid);
-  }
-  if (empty($node)) {
-    $node = new stdClass();
-  }
-
-  $form['vertical_wrapper'] = array(
-    '#type' => 'vertical_accordion',
-  );
-
-  $form['vertical_wrapper']['wrapper'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Properties'),
-  );
-
-  $form['vertical_wrapper']['wrapper']['submit_button'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Submit button text'),
-    '#default_value' => !empty($node->webform['submit_text']) ? $node->webform['submit_text'] : t('Submit'),
-  );
-
-  // Note: This form deliberately has no submit button! It has no access
-  // control (so it would not be safe to allow it to be submitted); it only
-  // exists so that it can be displayed and used by JavaScript.
-
-  return $form;
-}
diff --git a/sites/all/themes/unl_wdn/codemirror/unl.js b/sites/all/themes/unl_wdn/codemirror/unl.js
index 36910a53bdd8aac740a59e47d0a981fd57dcec5d..7d3912b1f015e314457d2f073fecc1e4e6051ecb 100644
--- a/sites/all/themes/unl_wdn/codemirror/unl.js
+++ b/sites/all/themes/unl_wdn/codemirror/unl.js
@@ -1,5 +1,5 @@
 /**
- * Adds links to enable syntax highlighting to CSS and JS textareas 
+ * Adds links to enable syntax highlighting to CSS and JS textareas
  *   under admin/appearance/settings/unl_wdn
  * This code from cpn (Code Per Node) module.
  */
@@ -30,6 +30,7 @@
           });
           $(this).data('editor', editor);
           $(this).text(Drupal.t('Disable syntax highlighting')).addClass('enabled');
+          $.cookie('codeHighlight', true);
         }
 
         // Disable
@@ -37,10 +38,16 @@
           $(this).data('editor').toTextArea();
           $grippie.show();
           $(this).text(Drupal.t('Enable syntax highlighting')).removeClass('enabled');
+          $.cookie('codeHighlight', null);
         }
         return false;
       });
 
+      // Enable on page load if cookie is set
+      if ($.cookie('codeHighlight')) {
+        $('.codemirror-toggle').click();
+      }
+
     }
 
   };
diff --git a/sites/all/themes/unl_wdn/theme-settings.php b/sites/all/themes/unl_wdn/theme-settings.php
index dfa53a45383e570b10319a68ac9389ebcfcad83e..2d057fb1d494ef6d1e90bdc5d9ad972e986026bc 100644
--- a/sites/all/themes/unl_wdn/theme-settings.php
+++ b/sites/all/themes/unl_wdn/theme-settings.php
@@ -11,31 +11,31 @@ function unl_wdn_form_system_theme_settings_alter(&$form, &$form_state) {
   $form['theme_settings'] += array(
     'toggle_unl_banner' => array(
       '#type' => 'checkbox',
-      '#title' => t('UNL Affiliate Banner'),
+      '#title' => t('UNL affiliate banner'),
       '#default_value' => theme_get_setting('toggle_unl_banner'),
       '#access' => theme_get_setting('unl_affiliate'),
     ),
     'toggle_unl_branding' => array(
       '#type' => 'checkbox',
-      '#title' => t('UNL Branding Elements'),
+      '#title' => t('UNL branding elements'),
       '#default_value' => theme_get_setting('toggle_unl_branding'),
       '#access' => theme_get_setting('unl_affiliate'),
     ),
     'toggle_unl_breadcrumb' => array(
       '#type' => 'checkbox',
-      '#title' => t('UNL Breadcrumb'),
+      '#title' => t('UNL breadcrumb'),
       '#default_value' => theme_get_setting('toggle_unl_breadcrumb'),
       '#access' => theme_get_setting('unl_affiliate'),
     ),
     'toggle_unl_search' => array(
       '#type' => 'checkbox',
-      '#title' => t('UNL Search box'),
+      '#title' => t('UNL search box'),
       '#default_value' => theme_get_setting('toggle_unl_search'),
       '#access' => theme_get_setting('unl_affiliate'),
     ),
     'toggle_unl_tools' => array(
       '#type' => 'checkbox',
-      '#title' => t('UNL Tools'),
+      '#title' => t('UNL tools'),
       '#default_value' => theme_get_setting('toggle_unl_tools'),
       '#access' => theme_get_setting('unl_affiliate'),
     ),
@@ -43,11 +43,11 @@ function unl_wdn_form_system_theme_settings_alter(&$form, &$form_state) {
 
   $form['intermediate_breadcrumbs'] = array(
     '#type' => 'fieldset',
-    '#title' => t('Intermediate Breadcrumbs'),
+    '#title' => t('Intermediate breadcrumbs'),
     '#description' => t('Breadcrumbs that are displayed between the UNL breadcrumb and this site\'s breadcrumb'),
     'site_name_abbreviation' => array(
       '#type' => 'textfield',
-      '#title' => t('Site Name Abbreviation'),
+      '#title' => t('Site name abbreviation'),
       '#default_value' => theme_get_setting('site_name_abbreviation'),
       '#description' => t('An abbreviated version of your site\'s name to use in breadcrumbs when not on the front page.'),
       '#weight' => 10,
@@ -73,7 +73,7 @@ function unl_wdn_form_system_theme_settings_alter(&$form, &$form_state) {
 
   $form['unl_head'] = array(
     '#type' => 'fieldset',
-    '#title' => t('Site Specific CSS and JavaScript'),
+    '#title' => t('Site specific CSS and JavaScript'),
     '#weight' => -45,
     'unl_css' => array(
       '#title' => t('CSS'),
@@ -100,35 +100,35 @@ function unl_wdn_form_system_theme_settings_alter(&$form, &$form_state) {
 
   $form['advanced_settings'] = array(
     '#type' => 'fieldset',
-    '#title' => t('Advanced Settings'),
+    '#title' => t('Advanced settings'),
     'sidebar_first_width' => array(
       '#type' => 'textfield',
-      '#title' => t('Sidebar first Grid Size'),
+      '#title' => t('Sidebar first grid size'),
       '#default_value' => theme_get_setting('sidebar_first_width'),
       '#description' => t('Enter only the numeral, for grid4 just enter 4.'),
     ),
     'sidebar_second_width' => array(
       '#type' => 'textfield',
-      '#title' => t('Sidebar second Grid Size'),
+      '#title' => t('Sidebar second grid size'),
       '#default_value' => theme_get_setting('sidebar_second_width'),
       '#description' => t('Enter only the numeral, for grid4 just enter 4.'),
     ),
     'zen_forms' => array(
       '#type' => 'checkbox',
-      '#title' => t('Use Zen Forms'),
+      '#title' => t('Use zen forms'),
       '#default_value' => theme_get_setting('zen_forms'),
       '#description' => t('Transforms all forms into the list-based zen forms.'),
     ),
     'wdn_beta' => array(
       '#type' => 'checkbox',
-      '#title' => t('Use WDN Beta/Development CSS and JavaScript'),
+      '#title' => t('Use WDN beta/development CSS and JavaScript'),
       '#default_value' => theme_get_setting('wdn_beta'),
       '#description' => t('Replaces the links in &lt;head&gt; to the stable /wdn directory with the latest development versions.'),
       '#access' => _unl_wdn_use_wdn_beta(),
     ),
     'unl_affiliate' => array(
       '#type' => 'checkbox',
-      '#title' => t('Affiliate Site'),
+      '#title' => t('Affiliate site'),
       '#default_value' => theme_get_setting('unl_affiliate'),
       '#description' => t('Grants access to the Color scheme picker, Logo image settings, Shortcut icon settings on this page for customizing the UNL template.'),
     ),
@@ -144,17 +144,18 @@ function unl_wdn_form_system_theme_settings_submit($form, &$form_state) {
   // Delete existing files, then save them.
   foreach (array('css', 'js') as $type) {
     _unl_wdn_delete_file('custom.' . $type);
-    _unl_wdn_save_file($form_state['values']['unl_' . $type], 'custom.' . $type);
+    if (drupal_strlen(trim($form_state['values']['unl_' . $type])) !== 0) {
+      _unl_wdn_save_file($form_state['values']['unl_' . $type], 'custom.' . $type);
+      drupal_set_message('File saved to custom/custom.' . $type . ' and will be automatically included on all pages.');
+    }
   }
+  drupal_flush_all_caches();
 }
 
 /**
  * Saves CSS & Javascript in the file system (but only if not empty).
  */
 function _unl_wdn_save_file($data, $filename) {
-  if (!drupal_strlen(trim($data))) {
-    return FALSE;
-  }
   $path = variable_get('unl_custom_code_path', 'public://custom');
   file_prepare_directory($path, FILE_CREATE_DIRECTORY);
   return file_unmanaged_save_data($data, $path . '/' . $filename, FILE_EXISTS_REPLACE);