You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by dh...@apache.org on 2026/10/06 10:00:50 UTC

(ranger) 01/01: RANGER-5268 : Remove Backbone JS code base from Ranger security-admin module

This is an automated email from the ASF dual-hosted git repository.

dhavaljrajpara pushed a commit to branch RANGER-5268-2.10
in repository https://gitbox.apache.org/repos/asf/ranger.git

commit 3e479be0890c8786735e8a367ef350d3e8bfbe51
Author: Mugdha Varadkar <mu...@apache.org>
AuthorDate: Tue Oct 6 15:29:58 2026 +0530

    RANGER-5268 : Remove Backbone JS code base from Ranger security-admin module
---
 .travis.yml                                        |     3 +-
 README.md                                          |    17 +-
 security-admin/pom.xml                             |   150 -
 security-admin/src/main/webapp/backbone-index.html |   139 -
 .../libs/bower/backbone-forms/css/bootstrap.css    |    43 -
 .../webapp/libs/bower/backbone-forms/css/old.css   |   140 -
 .../libs/bower/backbone-forms/js/backbone-forms.js |  2527 ---
 .../bower/backbone-forms/js/backbone-forms.min.js  |     1 -
 .../libs/bower/backbone-forms/js/bootstrap.js      |    83 -
 .../webapp/libs/bower/backbone-forms/js/list.js    |   658 -
 .../libs/bower/backbone-forms/js/list.min.js       |     1 -
 .../webapp/libs/bower/backbone-forms/js/old.js     |    99 -
 .../backbone-pageable/js/backbone-pageable.js      |  1327 --
 .../backbone-pageable/js/backbone-pageable.min.js  |     8 -
 .../backbone.babysitter/js/backbone.babysitter.js  |   178 -
 .../js/backbone.babysitter.min.js                  |    10 -
 .../js/backbone.bootstrap-modal.js                 |   291 -
 .../backbone.localstorage/backbone.localStorage.js |   222 -
 .../backbone.marionette/js/backbone.marionette.js  |  1959 --
 .../js/backbone.marionette.min.js                  |    20 -
 .../libs/bower/backbone.wreqr/js/backbone.wreqr.js |   277 -
 .../bower/backbone.wreqr/js/backbone.wreqr.min.js  |    11 -
 .../webapp/libs/bower/backbone/js/backbone-min.js  |     2 -
 .../main/webapp/libs/bower/backbone/js/backbone.js |  2096 --
 .../bower/backgrid-filter/css/backgrid-filter.css  |   149 -
 .../bower/backgrid-filter/js/backgrid-filter.js    |   463 -
 .../backgrid-paginator/css/backgrid-paginator.css  |    58 -
 .../backgrid-paginator/js/backgrid-paginator.js    |   366 -
 .../webapp/libs/bower/bootprompt/bootprompt.js     |  1138 --
 .../bootstrap-notify/css/bootstrap-notify.css      |    31 -
 .../bower/bootstrap-notify/js/bootstrap-notify.js  |   366 -
 .../webapp/libs/bower/bootstrap/js/bootstrap.js    |  7033 -------
 .../libs/bower/bootstrap/js/bootstrap.min.js       |     7 -
 .../src/main/webapp/libs/bower/esprima/esprima.js  |  5599 ------
 .../main/webapp/libs/bower/globalize/.bower.json   |    15 -
 .../main/webapp/libs/bower/globalize/.gitignore    |     9 -
 .../main/webapp/libs/bower/globalize/.npmignore    |     1 -
 .../webapp/libs/bower/globalize/lib/globalize.js   |  1586 --
 .../libs/bower/jquery-toggles/css/toggles.css      |    22 -
 .../libs/bower/jquery-toggles/js/toggles.min.js    |    11 -
 .../moment/js/moment-timezone-with-data.min.js     |     1 -
 .../bower/moment/js/moment-with-locales.min.js     |     2 -
 .../require-handlebars-plugin/js/Handlebars.js     |  6026 ------
 .../libs/bower/require-handlebars-plugin/js/hbs.js |   653 -
 .../main/webapp/libs/bower/requirejs/js/require.js |  2146 ---
 .../libs/bower/select2/select2-bootstrap4.css      |   175 -
 .../webapp/libs/bower/select2/select2-spinner.gif  |   Bin 1849 -> 0 bytes
 .../src/main/webapp/libs/bower/select2/select2.css |   615 -
 .../src/main/webapp/libs/bower/select2/select2.js  |  3219 ----
 .../src/main/webapp/libs/bower/select2/select2.png |   Bin 613 -> 0 bytes
 .../main/webapp/libs/bower/select2/select2x2.png   |   Bin 845 -> 0 bytes
 .../webapp/libs/bower/tag-it/css/jquery.tagit.css  |    69 -
 .../src/main/webapp/libs/bower/tag-it/js/tag-it.js |   589 -
 .../main/webapp/libs/bower/tag-it/js/tag-it.min.js |    17 -
 .../webapp/libs/bower/underscore/js/underscore.js  |  2079 --
 .../bower/x-editable/css/bootstrap-editable.css    |   674 -
 .../webapp/libs/bower/x-editable/img/clear.png     |   Bin 509 -> 0 bytes
 .../webapp/libs/bower/x-editable/img/loading.gif   |   Bin 1849 -> 0 bytes
 .../libs/bower/x-editable/js/bootstrap-editable.js |  6636 -------
 .../main/webapp/libs/fsOverrides/BBFOverrides.js   |   370 -
 .../main/webapp/libs/other/backbone.fetch-cache.js |   326 -
 .../Backgrid.ColumnManager.css                     |   114 -
 .../Backgrid.ColumnManager.min.js                  |   971 -
 .../main/webapp/libs/other/backgrid/backgrid.css   |   258 -
 .../main/webapp/libs/other/backgrid/backgrid.js    |  2946 ---
 .../libs/other/datepicker/css/datepicker.css       |   224 -
 .../other/datepicker/js/bootstrap-datepicker.js    |   834 -
 .../libs/other/datepicker/less/datepicker.less     |   122 -
 .../other/daterangepicker/css/daterangepicker.css  |   410 -
 .../other/daterangepicker/js/daterangepicker.js    |  1578 --
 .../jquery-ui/css/images/animated-overlay.gif      |   Bin 1738 -> 0 bytes
 .../ui-bg_diagonals-thick_18_b81900_40x40.png      |   Bin 528 -> 0 bytes
 .../ui-bg_diagonals-thick_20_666666_40x40.png      |   Bin 436 -> 0 bytes
 .../css/images/ui-bg_flat_10_000000_40x100.png     |   Bin 205 -> 0 bytes
 .../css/images/ui-bg_glass_100_f6f6f6_1x400.png    |   Bin 376 -> 0 bytes
 .../css/images/ui-bg_glass_100_fdf5ce_1x400.png    |   Bin 458 -> 0 bytes
 .../css/images/ui-bg_glass_65_ffffff_1x400.png     |   Bin 317 -> 0 bytes
 .../images/ui-bg_gloss-wave_35_f6a828_500x100.png  |   Bin 5925 -> 0 bytes
 .../ui-bg_highlight-soft_100_eeeeee_1x100.png      |   Bin 394 -> 0 bytes
 .../ui-bg_highlight-soft_75_ffe45c_1x100.png       |   Bin 438 -> 0 bytes
 .../css/images/ui-icons_222222_256x240.png         |   Bin 7077 -> 0 bytes
 .../css/images/ui-icons_228ef1_256x240.png         |   Bin 4670 -> 0 bytes
 .../css/images/ui-icons_444444_256x240.png         |   Bin 6992 -> 0 bytes
 .../css/images/ui-icons_555555_256x240.png         |   Bin 6988 -> 0 bytes
 .../css/images/ui-icons_777620_256x240.png         |   Bin 4549 -> 0 bytes
 .../css/images/ui-icons_777777_256x240.png         |   Bin 6999 -> 0 bytes
 .../css/images/ui-icons_cc0000_256x240.png         |   Bin 4549 -> 0 bytes
 .../css/images/ui-icons_ef8c08_256x240.png         |   Bin 4670 -> 0 bytes
 .../css/images/ui-icons_ffd27a_256x240.png         |   Bin 4670 -> 0 bytes
 .../css/images/ui-icons_ffffff_256x240.png         |   Bin 6539 -> 0 bytes
 .../webapp/libs/other/jquery-ui/css/jquery-ui.css  |  1314 --
 .../libs/other/jquery-ui/css/jquery-ui.min.css     |     7 -
 .../other/jquery-ui/js/jquery-ui-1.13.1.custom.js  | 19062 -------------------
 .../libs/other/jquery-ui/js/jquery-ui.min.js       |     6 -
 .../webapp/libs/other/visualsearch/.bower.json     |    45 -
 .../webapp/libs/other/visualsearch/css/icons.css   |    19 -
 .../libs/other/visualsearch/css/workspace.css      |   290 -
 .../images/embed/icons/cancel_search.png           |   Bin 541 -> 0 bytes
 .../images/embed/icons/search_glyph.png            |   Bin 420 -> 0 bytes
 .../libs/other/visualsearch/js/visualsearch.js     |  1969 --
 security-admin/src/main/webapp/minify.build.js     |    27 -
 security-admin/src/main/webapp/package-lock.json   |    36 -
 security-admin/src/main/webapp/package.json        |    10 -
 .../react-webapp/src/views/SideBar/SideBarBody.jsx |    13 -
 security-admin/src/main/webapp/scripts/App.js      |    65 -
 security-admin/src/main/webapp/scripts/Init.js     |   155 -
 security-admin/src/main/webapp/scripts/Main.js     |    76 -
 .../src/main/webapp/scripts/RegionManager.js       |    65 -
 .../collection_bases/RangerPolicyListBase.js       |    60 -
 .../RangerPolicyResourceListBase.js                |    66 -
 .../collection_bases/RangerServiceDefListBase.js   |    65 -
 .../collection_bases/RangerServiceListBase.js      |    60 -
 .../scripts/collection_bases/RangerZoneListBase.js |    58 -
 .../collection_bases/UserPermissionListBase.js     |    64 -
 .../collection_bases/VXAccessAuditListBase.js      |    60 -
 .../scripts/collection_bases/VXAssetListBase.js    |    60 -
 .../scripts/collection_bases/VXAuditMapListBase.js |    59 -
 .../collection_bases/VXAuthSessionListBase.js      |    64 -
 .../scripts/collection_bases/VXGroupListBase.js    |   101 -
 .../scripts/collection_bases/VXKmsKeyListBase.js   |    68 -
 .../collection_bases/VXModuleDefListBase.js        |    64 -
 .../scripts/collection_bases/VXPermMapListBase.js  |    59 -
 .../VXPolicyExportAuditListBase.js                 |    61 -
 .../collection_bases/VXPortalUserListBase.js       |    59 -
 .../scripts/collection_bases/VXResourceListBase.js |    60 -
 .../scripts/collection_bases/VXRoleListBase.js     |    99 -
 .../scripts/collection_bases/VXTrxLogListBase.js   |    74 -
 .../scripts/collection_bases/VXUserListBase.js     |   110 -
 .../webapp/scripts/collections/RangerPolicyList.js |    34 -
 .../collections/RangerPolicyResourceList.js        |    34 -
 .../scripts/collections/RangerServiceDefList.js    |    36 -
 .../scripts/collections/RangerServiceList.js       |    36 -
 .../webapp/scripts/collections/RangerZoneList.js   |    34 -
 .../scripts/collections/UserPermissionList.js      |    34 -
 .../scripts/collections/VXAccessAuditList.js       |    36 -
 .../main/webapp/scripts/collections/VXAssetList.js |    36 -
 .../webapp/scripts/collections/VXAuditMapList.js   |    36 -
 .../scripts/collections/VXAuthSessionList.js       |    36 -
 .../main/webapp/scripts/collections/VXGroupList.js |    36 -
 .../webapp/scripts/collections/VXKmsKeyList.js     |    36 -
 .../webapp/scripts/collections/VXModuleDefList.js  |    34 -
 .../webapp/scripts/collections/VXPermMapList.js    |    36 -
 .../scripts/collections/VXPolicyExportAuditList.js |    36 -
 .../webapp/scripts/collections/VXPortalUserList.js |    36 -
 .../webapp/scripts/collections/VXResourceList.js   |    36 -
 .../main/webapp/scripts/collections/VXRoleList.js  |    34 -
 .../webapp/scripts/collections/VXTrxLogList.js     |    36 -
 .../main/webapp/scripts/collections/VXUserList.js  |    36 -
 .../webapp/scripts/collections/XABaseCollection.js |   147 -
 .../src/main/webapp/scripts/communicator.js        |    43 -
 .../main/webapp/scripts/controllers/Controller.js  |   650 -
 .../main/webapp/scripts/controllers/NController.js |   651 -
 .../src/main/webapp/scripts/mgrs/SessionMgr.js     |   151 -
 .../webapp/scripts/model_bases/RangerPolicyBase.js |    90 -
 .../model_bases/RangerPolicyResourceBase.js        |    90 -
 .../scripts/model_bases/RangerServiceBase.js       |   101 -
 .../scripts/model_bases/RangerServiceDefBase.js    |   105 -
 .../webapp/scripts/model_bases/RangerZoneBase.js   |    56 -
 .../scripts/model_bases/UserPermissionBase.js      |    59 -
 .../scripts/model_bases/VXAccessAuditBase.js       |   111 -
 .../main/webapp/scripts/model_bases/VXAssetBase.js |   131 -
 .../webapp/scripts/model_bases/VXAuditMapBase.js   |   100 -
 .../scripts/model_bases/VXAuthSessionBase.js       |    54 -
 .../main/webapp/scripts/model_bases/VXGroupBase.js |   108 -
 .../webapp/scripts/model_bases/VXKmsKeyBase.js     |   103 -
 .../webapp/scripts/model_bases/VXModuleDefBase.js  |    59 -
 .../scripts/model_bases/VXPasswordChangeBase.js    |    33 -
 .../webapp/scripts/model_bases/VXPermMapBase.js    |   105 -
 .../scripts/model_bases/VXPolicyExportAuditBase.js |    99 -
 .../webapp/scripts/model_bases/VXPortalUserBase.js |   135 -
 .../webapp/scripts/model_bases/VXResourceBase.js   |   125 -
 .../main/webapp/scripts/model_bases/VXRoleBase.js  |    62 -
 .../webapp/scripts/model_bases/VXTrxLogBase.js     |    99 -
 .../main/webapp/scripts/model_bases/VXUserBase.js  |    61 -
 .../webapp/scripts/models/BackboneFormDataType.js  |   297 -
 .../src/main/webapp/scripts/models/RangerPolicy.js |   213 -
 .../webapp/scripts/models/RangerPolicyResource.js  |    66 -
 .../main/webapp/scripts/models/RangerService.js    |    72 -
 .../main/webapp/scripts/models/RangerServiceDef.js |   162 -
 .../src/main/webapp/scripts/models/RangerZone.js   |   243 -
 .../main/webapp/scripts/models/UserPermission.js   |    70 -
 .../src/main/webapp/scripts/models/VAppState.js    |    43 -
 .../main/webapp/scripts/models/VXAccessAudit.js    |    52 -
 .../src/main/webapp/scripts/models/VXAsset.js      |   134 -
 .../src/main/webapp/scripts/models/VXAuditMap.js   |    53 -
 .../main/webapp/scripts/models/VXAuthSession.js    |    52 -
 .../src/main/webapp/scripts/models/VXGroup.js      |    95 -
 .../src/main/webapp/scripts/models/VXKmsKey.js     |    54 -
 .../src/main/webapp/scripts/models/VXModuleDef.js  |    70 -
 .../main/webapp/scripts/models/VXPasswordChange.js |    27 -
 .../src/main/webapp/scripts/models/VXPermMap.js    |    54 -
 .../webapp/scripts/models/VXPolicyExportAudit.js   |    59 -
 .../src/main/webapp/scripts/models/VXPortalUser.js |   121 -
 .../src/main/webapp/scripts/models/VXResource.js   |    53 -
 .../src/main/webapp/scripts/models/VXRole.js       |    92 -
 .../src/main/webapp/scripts/models/VXTrxLog.js     |    53 -
 .../src/main/webapp/scripts/models/VXUser.js       |    81 -
 .../src/main/webapp/scripts/models/XABaseModel.js  |   113 -
 .../src/main/webapp/scripts/modules/RestCsrf.js    |   114 -
 .../src/main/webapp/scripts/modules/Vent.js        |    26 -
 .../src/main/webapp/scripts/modules/XALinks.js     |   370 -
 .../src/main/webapp/scripts/modules/XAOverrides.js |  1731 --
 .../webapp/scripts/modules/globalize/message/en.js |   578 -
 .../src/main/webapp/scripts/routers/Router.js      |   131 -
 .../src/main/webapp/scripts/utils/XAEnums.js       |   399 -
 .../src/main/webapp/scripts/utils/XAGlobals.js     |    97 -
 .../src/main/webapp/scripts/utils/XALangSupport.js |    94 -
 .../src/main/webapp/scripts/utils/XAUtils.js       |  2041 --
 .../src/main/webapp/scripts/utils/XAViewUtils.js   |   151 -
 .../webapp/scripts/views/DownloadServicePolicy.js  |   172 -
 .../webapp/scripts/views/UploadServicePolicy.js    |   432 -
 .../main/webapp/scripts/views/common/AddGroup.js   |   212 -
 .../webapp/scripts/views/common/BreadCrumbs.js     |    67 -
 .../webapp/scripts/views/common/CustomSubgrid.js   |   199 -
 .../webapp/scripts/views/common/DashboardLayout.js |    80 -
 .../main/webapp/scripts/views/common/ErrorView.js  |   121 -
 .../src/main/webapp/scripts/views/common/Footer.js |    81 -
 .../main/webapp/scripts/views/common/ProfileBar.js |   172 -
 .../main/webapp/scripts/views/common/Spinner.js    |    90 -
 .../src/main/webapp/scripts/views/common/TopNav.js |   131 -
 .../scripts/views/common/UserPermissionList.js     |   393 -
 .../main/webapp/scripts/views/common/XABackgrid.js |   387 -
 .../webapp/scripts/views/common/XATableLayout.js   |   231 -
 .../webapp/scripts/views/kms/KMSTableLayout.js     |   413 -
 .../main/webapp/scripts/views/kms/KmsKeyCreate.js  |   185 -
 .../main/webapp/scripts/views/kms/KmsKeyForm.js    |   108 -
 .../views/permissions/ModulePermissionCreate.js    |   146 -
 .../views/permissions/ModulePermissionForm.js      |   380 -
 .../views/permissions/ModulePermsTableLayout.js    |   268 -
 .../views/policies/NRangerPolicyTableLayout.js     |   767 -
 .../scripts/views/policies/PermissionList.js       |  1146 --
 .../scripts/views/policies/PolicyTimeList.js       |   194 -
 .../views/policies/RangerPolicyConditions.js       |   114 -
 .../scripts/views/policies/RangerPolicyCreate.js   |   340 -
 .../scripts/views/policies/RangerPolicyForm.js     |   649 -
 .../scripts/views/policies/RangerPolicyRO.js       |   351 -
 .../views/policies/RangerPolicyTableLayout.js      |   586 -
 .../webapp/scripts/views/policies/ResourceList.js  |   171 -
 .../scripts/views/policymanager/NServiceLayout.js  |    88 -
 .../scripts/views/policymanager/ServiceLayout.js   |   406 -
 .../views/policymanager/ServiceLayoutSidebar.js    |   599 -
 .../views/reports/AuditAccessLogDetailView.js      |   141 -
 .../webapp/scripts/views/reports/AuditLayout.js    |  2340 ---
 .../scripts/views/reports/LoginSessionDetail.js    |   100 -
 .../scripts/views/reports/OperationDiffDetail.js   |   397 -
 .../views/reports/PlugableServiceDiffDetail.js     |   461 -
 .../scripts/views/reports/UserAccessLayout.js      |  1215 --
 .../scripts/views/security_zone/SecurityZone.js    |   343 -
 .../views/security_zone/ZoneAdministration.js      |    89 -
 .../scripts/views/security_zone/ZoneCreate.js      |   202 -
 .../scripts/views/security_zone/ZoneCreateForm.js  |   293 -
 .../views/security_zone/ZoneResourceForm.js        |   499 -
 .../scripts/views/security_zone/zoneResource.js    |   222 -
 .../scripts/views/service/AuditFilterConfig.js     |   568 -
 .../scripts/views/service/ConfigurationList.js     |   111 -
 .../views/service/RangerServiceViewDetail.js       |   106 -
 .../views/service/ServiceAuditFilterResources.js   |   483 -
 .../webapp/scripts/views/service/ServiceCreate.js  |   314 -
 .../webapp/scripts/views/service/ServiceForm.js    |   321 -
 .../main/webapp/scripts/views/user/UserProfile.js  |   218 -
 .../webapp/scripts/views/user/UserProfileForm.js   |   159 -
 .../scripts/views/users/AddUsersOrGroupsList.js    |   156 -
 .../main/webapp/scripts/views/users/GroupCreate.js |   161 -
 .../main/webapp/scripts/views/users/GroupForm.js   |    82 -
 .../main/webapp/scripts/views/users/RoleCreate.js  |   161 -
 .../main/webapp/scripts/views/users/RoleForm.js    |   140 -
 .../main/webapp/scripts/views/users/UserCreate.js  |   216 -
 .../main/webapp/scripts/views/users/UserForm.js    |   292 -
 .../main/webapp/scripts/views/users/UserInfo.js    |   107 -
 .../webapp/scripts/views/users/UserTableLayout.js  |  1205 --
 security-admin/src/main/webapp/styles/app-font.css |    64 -
 .../webapp/templates/common/AddGroup_tmpl.html     |    31 -
 .../webapp/templates/common/ErrorView_tmpl.html    |    36 -
 .../main/webapp/templates/common/Footer_tmpl.html  |    28 -
 .../webapp/templates/common/ProfileBar_tmpl.html   |    31 -
 .../common/ServiceManagerLayout_tmpl.html          |   101 -
 .../common/ServiceManagerSidebarLayout_tmpl.html   |   276 -
 .../templates/common/ServiceMappingItem.html       |    28 -
 .../main/webapp/templates/common/TopNav_tmpl.html  |   114 -
 .../templates/common/UserPermissionItem.html       |    51 -
 .../templates/common/UserPermissionList.html       |    41 -
 .../templates/common/XATableLayout_tmpl.html       |    22 -
 .../main/webapp/templates/common/breadcrumbs.html  |    29 -
 .../common/downloadservicepolicy_tmpl.html         |    34 -
 .../main/webapp/templates/common/loading_tmpl.html |    45 -
 .../templates/common/uploadservicepolicy_tmpl.html |    69 -
 .../templates/dashboard/DashboardLayout_tmpl.html  |    19 -
 .../src/main/webapp/templates/helpers/XAHelpers.js |   627 -
 .../webapp/templates/kms/KmsKeyCreate_tmpl.html    |    26 -
 .../main/webapp/templates/kms/KmsKeyForm_tmpl.html |    20 -
 .../webapp/templates/kms/KmsTableLayout_tmpl.html  |    42 -
 .../permissions/ModulePermissionCreate_tmpl.html   |    26 -
 .../permissions/ModulePermissionForm_tmpl.html     |    72 -
 .../permissions/ModulePermsTableLayout_tmpl.html   |    29 -
 .../webapp/templates/policies/PermissionItem.html  |    62 -
 .../webapp/templates/policies/PermissionList.html  |    41 -
 .../policies/PolicyConditionsItem_tmpl.html        |    20 -
 .../templates/policies/PolicyTimeItem_tmpl.html    |    46 -
 .../templates/policies/PolicyTimeList_tmpl.html    |    42 -
 .../policies/RangerPolicyCreate_tmpl.html          |    56 -
 .../templates/policies/RangerPolicyForm_tmpl.html  |   156 -
 .../templates/policies/RangerPolicyRO_tmpl.html    |   332 -
 .../policies/RangerPolicyTableLayout_tmpl.html     |    71 -
 .../templates/policies/ResourceItem_tmpl.html      |    26 -
 .../templates/policies/ResourceList_tmpl.html      |    37 -
 .../templates/reports/AssetOperationDiff_tmpl.html |   134 -
 .../reports/AssetUpdateOperationDiff_tmpl.html     |   112 -
 .../reports/AuditAccessLogDetail_tmpl.html         |   285 -
 .../webapp/templates/reports/AuditLayout_tmpl.html |    78 -
 .../templates/reports/GroupOperationDiff_tmpl.html |    79 -
 .../reports/GroupUpdateOperationDiff_tmpl.html     |    74 -
 .../templates/reports/LoginSessionDetail_tmpl.html |    47 -
 .../PlugableServicePolicyDeleteDiff_tmpl.html      |   417 -
 .../reports/PlugableServicePolicyDiff_tmpl.html    |   394 -
 .../PlugableServicePolicyUpdateDiff_tmpl.html      |   831 -
 .../templates/reports/RoleOperationDiff_tmpl.html  |   129 -
 .../reports/RoleUpdateOperationDiff_tmpl.html      |   133 -
 .../templates/reports/UserAccessLayout_tmpl.html   |   149 -
 .../templates/reports/UserOperationDiff_tmpl.html  |   102 -
 .../templates/reports/UserSyncInfo_tmpl.html       |    34 -
 .../reports/UserUpdateOperationDiff_tmpl.html      |   120 -
 .../templates/reports/ZoneOperationDiff_tmpl.html  |   135 -
 .../reports/ZoneUpdateOperationDiff_tmpl.html      |   125 -
 .../templates/security_zone/SecurityZone_tmpl.html |   106 -
 .../security_zone/ZoneAdministration_tmpl.html     |    90 -
 .../security_zone/ZoneCreateForm_tmpl.html         |    86 -
 .../templates/security_zone/ZoneCreate_tmpl.html   |    30 -
 .../security_zone/ZoneResourceForm_tmpl.html       |    17 -
 .../security_zone/ZoneResourceItem_tmpl.html       |    29 -
 .../security_zone/ZoneResourceList_tmpl.html       |    18 -
 .../security_zone/ZoneResourcesForm_tmpl.html      |    21 -
 .../security_zone/ZoneResources_tmpl.html          |    15 -
 .../templates/service/AuditFilterItem_tmpl.html    |    70 -
 .../templates/service/AuditFilterList_tmpl.html    |    50 -
 .../templates/service/ConfigurationItem_tmpl.html  |    23 -
 .../templates/service/ConfigurationList_tmpl.html  |    38 -
 .../service/RangerServiceViewDetail_tmpl.html      |   229 -
 .../ServiceAuditFilterResourcesForm_tmpl.html      |    17 -
 .../templates/service/ServiceCreate_tmpl.html      |    29 -
 .../webapp/templates/service/ServiceForm_tmpl.html |    62 -
 .../templates/service/ServiceTableLayout_tmpl.html |    26 -
 .../templates/user/UserProfileForm_tmpl.html       |    25 -
 .../webapp/templates/user/UserProfile_tmpl.html    |    40 -
 .../templates/users/AddUserOrGroupsItem_tmpl.html  |    27 -
 .../templates/users/AddUserOrGroupsList_tmpl.html  |    41 -
 .../webapp/templates/users/GroupCreate_tmpl.html   |    26 -
 .../webapp/templates/users/GroupForm_tmpl.html     |    45 -
 .../webapp/templates/users/RoleCreate_tmpl.html    |    26 -
 .../main/webapp/templates/users/RoleForm_tmpl.html |    44 -
 .../webapp/templates/users/UserCreate_tmpl.html    |    34 -
 .../main/webapp/templates/users/UserForm_tmpl.html |    55 -
 .../main/webapp/templates/users/UserInfo_tmpl.html |    98 -
 .../templates/users/UserTableLayout_tmpl.html      |    62 -
 .../src/test/javascript/karma-common.conf.js       |    98 -
 .../src/test/javascript/karma-dev.conf.js          |    25 -
 .../src/test/javascript/karma-prd.conf.js          |    26 -
 .../src/test/javascript/package-lock.json          |  3595 ----
 security-admin/src/test/javascript/package.json    |    14 -
 security-admin/src/test/javascript/test-main.js    |    45 -
 .../src/test/javascript/tests/main-test.js         |    37 -
 360 files changed, 7 insertions(+), 127218 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 711794b08..8c1fbdfa6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,7 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
 sudo: false
 dist: bionic
 language: generic
@@ -42,7 +41,7 @@ jobs:
       group: edge
       env:
         - JDK_VERSION=11
-        - MAVEN_ARGS="-DskipJSTests=true -P!all"
+        - MAVEN_ARGS=" -P!all"
 
 before_install:
   - export MAVEN_OPTS="-Xmx1200M -XX:MaxPermSize=768m -Xms512m"
diff --git a/README.md b/README.md
index 0566da892..bbc76b58f 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
+
 # Apache Ranger
 
 [![License](https://img.shields.io/:license-Apache%202-green.svg)](https://www.apache.org/licenses/LICENSE-2.0.txt)
@@ -21,13 +22,12 @@ under the License.
 [![Documentation](https://img.shields.io/badge/docs-apache.org-blue.svg)](https://ranger.apache.org)
 [![Wiki](https://img.shields.io/badge/ranger-wiki-orange)](https://cwiki.apache.org/confluence/display/RANGER/Index)
 
-
 #### NOTE
+
 Apache Ranger allows contributions via pull requests (PRs) on GitHub.  
 Alternatively, use [this](https://reviews.apache.org) to submit changes for review using the Review Board.
 Also create a [ranger jira](https://issues.apache.org/jira/browse/RANGER) to go along with the review and mention it in the review board review.
 
-
 ## Building Ranger in Docker (Sandbox Install)
 
 Ranger is built using [Apache Maven](https://maven.apache.org/). To run Ranger:
@@ -45,6 +45,7 @@ Ranger is built using [Apache Maven](https://maven.apache.org/). To run Ranger:
    `./ranger_in_docker up`
 
 6. After successful completion of the above command, you should be able to view Ranger Admin Console by using URL:
+
    ```
     http://<hostname-of-system>:6080/
 
@@ -62,10 +63,6 @@ Ranger is built using [Apache Maven](https://maven.apache.org/). To run Ranger:
 
    `mvn eclipse:eclipse`
 
-   Ranger Admin UI tests depend on PhantomJS. If the build fails with npm or Karma errors you can either:
-   - install PhantomJS dependencies for your platform (bzip2 and fontconfig)
-   - skip JavaScript test execution: mvn -DskipJSTests ...
-
 3. After the above build command execution, you should see the following TAR files in the target folder:
    ```
    ranger-<version>-admin.tar.gz
@@ -95,12 +92,11 @@ Ranger is built using [Apache Maven](https://maven.apache.org/). To run Ranger:
 
 2. Import maven project from the root directory where ranger source code is downloaded (and build)
 
-
 ## Deployment Process
 
-
 ### Installation Host Information
-1. Ranger Admin Tool Component  (ranger-<version-number>-admin.tar.gz) should be installed on a host where Policy Admin Tool web application runs on port 6080 (default).
+
+1. Ranger Admin Tool Component (ranger-<version-number>-admin.tar.gz) should be installed on a host where Policy Admin Tool web application runs on port 6080 (default).
 2. Ranger User Synchronization Component (ranger-<version-number>-usersync.tar.gz) should be installed on a host to synchronize the external user/group information into Ranger database via Ranger Admin Tool.
 3. Ranger Component plugin should be installed on the component boxes:
    - HDFS Plugin needs to be installed on Name Node hosts.
@@ -122,8 +118,7 @@ Ranger is built using [Apache Maven](https://maven.apache.org/). To run Ranger:
 
 3. Go to the component name under the expanded folder (e.g. /usr/lib/ranger/ranger-<version-number>-admin/)
 
-4. Modify the install.properties file with appropriate variables 
+4. Modify the install.properties file with appropriate variables
 
 5. - If the module has setup.sh, execute ./setup.sh
    - If the install.sh file does not exists, execute ./enable-<component>-plugin.sh
-
diff --git a/security-admin/pom.xml b/security-admin/pom.xml
index 3929423c5..bfaf5b531 100644
--- a/security-admin/pom.xml
+++ b/security-admin/pom.xml
@@ -29,7 +29,6 @@
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <skipJSCoverage>true</skipJSCoverage>
-        <skipJSTests>false</skipJSTests>
     </properties>
     <dependencies>
         <dependency>
@@ -183,7 +182,6 @@
                 </exclusion>
             </exclusions>
         </dependency>
-
         <dependency>
             <groupId>com.webcohesion.enunciate</groupId>
             <artifactId>enunciate-core-annotations</artifactId>
@@ -892,40 +890,6 @@
                     </execution>
                 </executions>
             </plugin>
-            <plugin>
-                <groupId>com.google.code.maven-replacer-plugin</groupId>
-                <artifactId>replacer</artifactId>
-                <version>1.5.3</version>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>replace</goal>
-                        </goals>
-                        <phase>prepare-package</phase>
-                        <configuration>
-                            <basedir>${project.build.directory}/${project.build.finalName}</basedir>
-                            <includes>
-                                <include>backbone-index.html</include>
-                                <include>scripts/Init.js</include>
-                            </includes>
-                            <replacements>
-                                <replacement>
-                                    <token>build.version</token>
-                                    <value>${project.version}</value>
-                                </replacement>
-                                <replacement>
-                                    <token>(?m)\&lt;\!-- *dev *--\&gt;(.*)$</token>
-                                    <value>\&lt;\!-- dev $1 --\&gt;</value>
-                                </replacement>
-                                <replacement>
-                                    <token>\&lt;\!-- *prod *(.*) *--\&gt;</token>
-                                    <value>\&lt;\!-- prod --\&gt;$1</value>
-                                </replacement>
-                            </replacements>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
             <plugin>
                 <groupId>com.webcohesion.enunciate</groupId>
                 <artifactId>enunciate-maven-plugin</artifactId>
@@ -951,44 +915,6 @@
                 <artifactId>maven-resources-plugin</artifactId>
                 <version>2.7</version>
                 <executions>
-                    <execution>
-                        <id>copy-resources</id>
-                        <goals>
-                            <goal>copy-resources</goal>
-                        </goals>
-                        <phase>validate</phase>
-                        <configuration>
-                            <outputDirectory>${project.build.directory}/jsmain</outputDirectory>
-                            <resources>
-                                <resource>
-                                    <directory>${basedir}/src/main/webapp</directory>
-                                    <includes>
-                                        <include>package.json</include>
-                                        <include>package-lock.json</include>
-                                    </includes>
-                                </resource>
-                            </resources>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>copy-js-test-resources</id>
-                        <goals>
-                            <goal>copy-resources</goal>
-                        </goals>
-                        <phase>validate</phase>
-                        <configuration>
-                            <outputDirectory>${project.build.directory}/jstest</outputDirectory>
-                            <resources>
-                                <resource>
-                                    <directory>${basedir}/src/test/javascript</directory>
-                                    <includes>
-                                        <include>package.json</include>
-                                        <include>package-lock.json</include>
-                                    </includes>
-                                </resource>
-                            </resources>
-                        </configuration>
-                    </execution>
                     <!-- react-webapp copy-resources execution start -->
                     <execution>
                         <id>copy-resources-react-webapp</id>
@@ -1091,82 +1017,6 @@
                     <installDirectory>${project.build.directory}</installDirectory>
                 </configuration>
                 <executions>
-                    <execution>
-                        <id>install node and npm</id>
-                        <goals>
-                            <goal>install-node-and-npm</goal>
-                        </goals>
-                        <phase>process-resources</phase>
-                        <configuration>
-                            <nodeVersion>v8.12.0</nodeVersion>
-                            <npmVersion>6.4.1</npmVersion>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>npm install for packaging</id>
-                        <goals>
-                            <goal>npm</goal>
-                        </goals>
-                        <phase>prepare-package</phase>
-                        <configuration>
-                            <workingDirectory>${project.build.directory}/jsmain</workingDirectory>
-                            <arguments>install</arguments>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>npm run r.js</id>
-                        <goals>
-                            <goal>npm</goal>
-                        </goals>
-                        <phase>prepare-package</phase>
-                        <configuration>
-                            <workingDirectory>${project.build.directory}/jsmain</workingDirectory>
-                            <arguments>run r.js -- -o ../${project.build.finalName}/minify.build.js</arguments>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>npm install for tests</id>
-                        <goals>
-                            <goal>npm</goal>
-                        </goals>
-                        <phase>test</phase>
-                        <configuration>
-                            <skip>${skipJSTests}</skip>
-                            <workingDirectory>${project.build.directory}/jstest</workingDirectory>
-                            <arguments>install</arguments>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>karma dev</id>
-                        <goals>
-                            <goal>karma</goal>
-                        </goals>
-                        <phase>test</phase>
-                        <configuration>
-                            <environmentVariables>
-                                <OPENSSL_CONF>/etc/ssl/</OPENSSL_CONF>
-                            </environmentVariables>
-                            <skip>${skipJSTests}</skip>
-                            <workingDirectory>${project.build.directory}/jstest</workingDirectory>
-                            <karmaConfPath>../../src/test/javascript/karma-dev.conf.js</karmaConfPath>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>karma prd</id>
-                        <goals>
-                            <goal>karma</goal>
-                        </goals>
-                        <phase>integration-test</phase>
-                        <configuration>
-                            <environmentVariables>
-                                <buildDir>${project.build.finalName}</buildDir>
-                                <OPENSSL_CONF>/etc/ssl/</OPENSSL_CONF>
-                            </environmentVariables>
-                            <skip>${skipJSTests}</skip>
-                            <workingDirectory>${project.build.directory}/jstest</workingDirectory>
-                            <karmaConfPath>../../src/test/javascript/karma-prd.conf.js</karmaConfPath>
-                        </configuration>
-                    </execution>
                     <!-- react-webapp frontend-maven-plugin start -->
                     <execution>
                         <id>install node and npm for react-webapp</id>
diff --git a/security-admin/src/main/webapp/backbone-index.html b/security-admin/src/main/webapp/backbone-index.html
deleted file mode 100644
index bc006cd75..000000000
--- a/security-admin/src/main/webapp/backbone-index.html
+++ /dev/null
@@ -1,139 +0,0 @@
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one or more
-  contributor license agreements.  See the NOTICE file distributed with
-  this work for additional information regarding copyright ownership.
-  The ASF licenses this file to You under the Apache License, Version 2.0
-  (the "License"); you may not use this file except in compliance with
-  the License.  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
--->
-<!doctype html>
-<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
-<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
-<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
-<!--[if gt IE 8]> 	   <html class="ie"> <![endif]-->
-<html class="no-js">
-    <!--<![endif]-->
-    <head>
-        <meta charset="utf-8">
-        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
-        <title>Ranger</title>
-        <meta name="description" content="">
-        <meta name="viewport" content="width=device-width">
-        <!-- Place favicon.ico and apple-touch-icon.png in the root directory -->
-        <link rel="shortcut icon" href="images/favicon.ico">
-        <link rel="stylesheet" href="styles/app-font.css">
-        <link rel="stylesheet" href="styles/font-awesome.min.css">
-        <link href="styles/bootstrap.min.css" media="all" rel="stylesheet" type="text/css" id="bootstrap-css">
-        <link href="libs/other/jquery-ui/css/jquery-ui.min.css" media="all" rel="stylesheet" type="text/css">
-        <link href="libs/other/backgrid/backgrid.css" media="all" rel="stylesheet" type="text/css">
-        <link href="libs/other/backgrid-column-manager/Backgrid.ColumnManager.css" media="all" rel="stylesheet" type="text/css">
-        <link href="libs/bower/backgrid-paginator/css/backgrid-paginator.css" media="all" rel="stylesheet" type="text/css">
-        <link href="libs/bower/backgrid-filter/css/backgrid-filter.css" media="all" rel="stylesheet" type="text/css">
-        <link href="libs/bower/select2/select2.css" media="all" rel="stylesheet" type="text/css">
-        <link href="libs/bower/select2/select2-bootstrap4.css" media="all" rel="stylesheet" type="text/css">
-        <link href="libs/bower/bootstrap-notify/css/bootstrap-notify.css" rel="stylesheet">
-        <link href="libs/bower/tag-it/css/jquery.tagit.css" rel="stylesheet">
-        <link href="libs/other/datepicker/css/datepicker.css" media="all" rel="stylesheet" type="text/css">
-        <link href="libs/bower/x-editable/css/bootstrap-editable.css" media="all" rel="stylesheet" type="text/css">
-        <link href="libs/other/daterangepicker/css/daterangepicker.css" media="all" rel="stylesheet" type="text/css">
-        <link href="libs/other/visualsearch/css/workspace.css" rel="stylesheet">
-        <link href="libs/other/visualsearch/css/icons.css" rel="stylesheet">
-        <link href="styles/xa.css" media="all" rel="stylesheet" type="text/css">
-    </head>
-
-    <body class="container-fluid service-layout" id="contentBody">
-        <!-- Main navigation bar
-        ================================================== -->
-        <header class="navbar fixed-top navbar-expand-lg ranger-nav" id="top-navbar">
-            <div class="navbar-inner">
-                <div class="container-fluid">
-                    <a class="navbar-brand logo" href="#"><img alt="Af_logo" src="images/ranger_logo.png"></a>
-                    <a class="btn nav-button collapsed" data-toggle="collapse" data-target=".navbar-collapse"> <span class="fa fw fa fa-reorder"></span> </a>
-                    <div id="r_topNav" style="margin-right: auto;"></div>
-                    <div id="r_topProfileBar"></div>
-                </div>
-            </div>
-        </header>
-        <!-- / Main navigation bar -->
-        <!-- Page content
-        ================================================== -->
-        <section id="r_sidebar"></section>
-        <section class="container-fluid">
-            <div class="headerBreadcrumbs">
-                <section id="r_breadcrumbs" class="r_breadcrumbs"></section>
-                <div class="latestResponse"></div>
-            </div>
-            <div class="notifications top-right ranger-notifications"></div>
-            <section id="r_content" style="min-height: 450px;">
-                <div class="loading-img">
-                    <div id="center">
-                        <div class="letter_container_1">
-                            <span>L</span>
-                        </div>
-                        <div class="letter_container_2">
-                            <span>O</span>
-                        </div>
-                        <div class="letter_container_3">
-                            <span>A</span>
-                        </div>
-                        <div class="letter_container_4">
-                            <span>D</span>
-                        </div>
-                        <div class="letter_container_5">
-                            <span>I</span>
-                        </div>
-                        <div class="letter_container_6">
-                            <span>N</span>
-                        </div>
-                        <div class="letter_container_7">
-                            <span>G</span>
-                        </div>
-                        <div class="letter_container_8">
-                            <span>..</span>
-                        </div>
-                    </div>
-                </div>
-            </section><!-- r_content -->
-
-            <!-- Page footer
-            ================================================== -->
-            <footer class="clearBoth" id="r_footer">
-
-            </footer>
-            <!-- / Page footer -->
-        </section>
-        <!-- Page content ends
-        ================================================== -->
-
-        <a href="#" class="btn-top _allowNav" id="back-top" title="Scroll to top">
-            <i class="fa fa-arrow-up bigger-120 _allowNav"></i>
-        </a>
-        <script src="libs/bower/requirejs/js/require.js"></script>
-
-        <!--
-        the script tags below are commented/uncommented during the packaging phase.
-        (see the replacer configuration in POM)
-        -->
-        <!-- dev --><script src="scripts/Init.js?ver=build.version"></script>
-        <!-- prod <script src="scripts/Main.min.js?ver=build.version"></script> -->
-
-        <script type="text/javascript">
-            require.config({
-                waitSeconds : 0
-            });
-            if (!window.console) window.console = {};
-            if (!window.console.log) window.console.log = function () { };
-            require(['Main'], function(){
-                //nothing to do, loading Main already triggers the app
-            });
-        </script>
-    </body>
-</html>
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/libs/bower/backbone-forms/css/bootstrap.css b/security-admin/src/main/webapp/libs/bower/backbone-forms/css/bootstrap.css
deleted file mode 100644
index 667c6f40a..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone-forms/css/bootstrap.css
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Date */
-.bbf-date .bbf-date {
-  width: 4em
-}
-
-.bbf-date .bbf-month {
-  width: 9em;
-}
-
-.bbf-date .bbf-year {
-  width: 5em;
-}
-
-
-/* DateTime */
-.bbf-datetime select {
-  width: 4em;
-}
-
-
-/* List */
-.bbf-list .bbf-add {
-  margin-top: -10px
-}
-
-.bbf-list li {
-  margin-bottom: 5px
-}
-
-.bbf-list .bbf-del {
-  margin-left: 4px
-}
-
-
-/* List.Modal */
-.bbf-list-modal {
-  cursor: pointer;
-  border: 1px solid #ccc;
-  width: 208px;
-  border-radius: 3px;
-  padding: 4px;
-  color: #555;
-}
diff --git a/security-admin/src/main/webapp/libs/bower/backbone-forms/css/old.css b/security-admin/src/main/webapp/libs/bower/backbone-forms/css/old.css
deleted file mode 100644
index 79261ea54..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone-forms/css/old.css
+++ /dev/null
@@ -1,140 +0,0 @@
-/* Form */
-.bbf-form {
-  margin: 0;
-  padding: 0;
-  border: none;
-}
-
-
-/* Field */
-.bbf-field {
-  margin: 1em 0;
-  list-style-type: none;
-  position: relative;
-  clear: both;
-}
-
-  .bbf-field label {
-    float: left;
-    width: 25%;
-  }
-  
-  .bbf-field .bbf-editor {
-    margin-left: 25%;
-    width: 74%;
-  }
-      
-    .bbf-field input, .bbf-field textarea, .bbf-field select {
-      width: 100%;
-    }
-  
-  .bbf-field .bbf-help {
-    margin-left: 25%;
-    width: 74%;
-    color: #999;
-  }
-
-  .bbf-field .bbf-error {
-    margin-left: 25%;
-    width: 74%;
-    color: red;
-  }
-
-  .bbf-field.bbf-error .bbf-editor {
-    outline: 1px solid red;
-  }
-
-
-/* Radio */
-.bbf-radio {
-  list-style-type: none;
-}
-
-  .bbf-radio input {
-    width: auto;
-  }
-
-  .bbf-radio label {
-    float: none;
-  }
-
-
-/* Checkboxes */
-.bbf-checkboxes {
-  list-style-type: none;
-}
-
-  .bbf-checkboxes input {
-    width: auto;
-  }
-
-  .bbf-checkboxes label {
-    float: none;
-  }
-
-
-/* List */
-.bbf-list ul {
-  list-style-type: none;
-  margin: 0;
-  padding: 0;
-}
-
-  .bbf-list .bbf-error {
-    border: 1px solid red;
-  }
-
-  .bbf-list li {
-    clear: both;
-    width: 100%;
-  }
-
-    .bbf-list li .bbf-editor-container {
-      margin-right: 2em;
-    }
-
-    .bbf-list li .bbf-remove {
-      float: right;
-      width: 2em;
-    }
-
-.bbf-list .bbf-actions {
-  text-align: center;
-  clear: both;
-}
-
-/* List.Modal */
-.bbf-list-modal {
-  cursor: pointer;
-  border: 1px solid #ccc;
-  width: 208px;
-  border-radius: 3px;
-  padding: 4px;
-  color: #555;
-}
-
-
-
-/* Date */
-.bbf-date .bbf-date {
-  width: 4em;
-}
-
-.bbf-date .bbf-month {
-  width: 9em;
-}
-
-.bbf-date .bbf-year {
-  width: 6em;
-}
-
-
-/* DateTime */
-.bbf-datetime .bbf-date-container {
-  float: left;
-  margin-right: 1em;
-}
-
-.bbf-datetime select {
-  width: 4em;
-}
diff --git a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/backbone-forms.js b/security-admin/src/main/webapp/libs/bower/backbone-forms/js/backbone-forms.js
deleted file mode 100644
index bb16c684a..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/backbone-forms.js
+++ /dev/null
@@ -1,2527 +0,0 @@
-/**
- * Backbone Forms v0.14.1
- *
- * NOTE:
- * This version is for use with RequireJS
- * If using regular <script> tags to include your files, use backbone-forms.min.js
- *
- * Copyright (c) 2013 Charles Davison, Pow Media Ltd
- * 
- * License and more information at:
- * http://github.com/powmedia/backbone-forms
- */
-define(['jquery', 'underscore', 'backbone'], function($, _, Backbone) {
-
-  //==================================================================================================
-//FORM
-//==================================================================================================
-
-var Form = Backbone.View.extend({
-
-  events: {
-    'submit': function(event) {
-      this.trigger('submit', event);
-    }
-  },
-
-  /**
-   * Constructor
-   * 
-   * @param {Object} [options.schema]
-   * @param {Backbone.Model} [options.model]
-   * @param {Object} [options.data]
-   * @param {String[]|Object[]} [options.fieldsets]
-   * @param {String[]} [options.fields]
-   * @param {String} [options.idPrefix]
-   * @param {Form.Field} [options.Field]
-   * @param {Form.Fieldset} [options.Fieldset]
-   * @param {Function} [options.template]
-   * @param {Boolean|String} [options.submitButton]
-   */
-  initialize: function(options) {
-    var self = this;
-
-    //Merge default options
-    options = this.options = _.extend({
-      submitButton: false
-    }, options);
-
-    //Find the schema to use
-    var schema = this.schema = (function() {
-      //Prefer schema from options
-      if (options.schema) return _.result(options, 'schema');
-
-      //Then schema on model
-      var model = options.model;
-      if (model && model.schema) return _.result(model, 'schema');
-
-      //Then built-in schema
-      if (self.schema) return _.result(self, 'schema');
-
-      //Fallback to empty schema
-      return {};
-    })();
-
-    //Store important data
-    _.extend(this, _.pick(options, 'model', 'data', 'idPrefix', 'templateData'));
-
-    //Override defaults
-    var constructor = this.constructor;
-    this.template = options.template || this.template || constructor.template;
-    this.Fieldset = options.Fieldset || this.Fieldset || constructor.Fieldset;
-    this.Field = options.Field || this.Field || constructor.Field;
-    this.NestedField = options.NestedField || this.NestedField || constructor.NestedField;
-
-    //Check which fields will be included (defaults to all)
-    var selectedFields = this.selectedFields = options.fields || _.keys(schema);
-
-    //Create fields
-    var fields = this.fields = {};
-
-    _.each(selectedFields, function(key) {
-      var fieldSchema = schema[key];
-      fields[key] = this.createField(key, fieldSchema);
-    }, this);
-
-    //Create fieldsets
-    var fieldsetSchema = options.fieldsets || _.result(this, 'fieldsets') || [selectedFields],
-        fieldsets = this.fieldsets = [];
-
-    _.each(fieldsetSchema, function(itemSchema) {
-      this.fieldsets.push(this.createFieldset(itemSchema));
-    }, this);
-  },
-
-  /**
-   * Creates a Fieldset instance
-   *
-   * @param {String[]|Object[]} schema       Fieldset schema
-   *
-   * @return {Form.Fieldset}
-   */
-  createFieldset: function(schema) {
-    var options = {
-      schema: schema,
-      fields: this.fields
-    };
-
-    return new this.Fieldset(options);
-  },
-
-  /**
-   * Creates a Field instance
-   *
-   * @param {String} key
-   * @param {Object} schema       Field schema
-   *
-   * @return {Form.Field}
-   */
-  createField: function(key, schema) {
-    var options = {
-      form: this,
-      key: key,
-      schema: schema,
-      idPrefix: this.idPrefix
-    };
-
-    if (this.model) {
-      options.model = this.model;
-    } else if (this.data) {
-      options.value = this.data[key];
-    } else {
-      options.value = null;
-    }
-
-    var field = new this.Field(options);
-
-    this.listenTo(field.editor, 'all', this.handleEditorEvent);
-
-    return field;
-  },
-
-  /**
-   * Callback for when an editor event is fired.
-   * Re-triggers events on the form as key:event and triggers additional form-level events
-   *
-   * @param {String} event
-   * @param {Editor} editor
-   */
-  handleEditorEvent: function(event, editor) {
-    //Re-trigger editor events on the form
-    var formEvent = editor.key+':'+event;
-
-    this.trigger.call(this, formEvent, this, editor, Array.prototype.slice.call(arguments, 2));
-
-    //Trigger additional events
-    switch (event) {
-      case 'change':
-        this.trigger('change', this);
-        break;
-
-      case 'focus':
-        if (!this.hasFocus) this.trigger('focus', this);
-        break;
-
-      case 'blur':
-        if (this.hasFocus) {
-          //TODO: Is the timeout etc needed?
-          var self = this;
-          setTimeout(function() {
-            var focusedField = _.find(self.fields, function(field) {
-              return field.editor.hasFocus;
-            });
-
-            if (!focusedField) self.trigger('blur', self);
-          }, 0);
-        }
-        break;
-    }
-  },
-
-  templateData: function() {
-    var options = this.options;
-
-    return {
-      submitButton: options.submitButton
-    }
-  },
-
-  render: function() {
-    var self = this,
-        fields = this.fields,
-        $ = Backbone.$;
-
-    //Render form
-    var $form = $($.trim(this.template(_.result(this, 'templateData'))));
-
-    //Render standalone editors
-    $form.find('[data-editors]').add($form).each(function(i, el) {
-      var $container = $(el),
-          selection = $container.attr('data-editors');
-
-      if (_.isUndefined(selection)) return;
-
-      //Work out which fields to include
-      var keys = (selection == '*')
-        ? self.selectedFields || _.keys(fields)
-        : selection.split(',');
-
-      //Add them
-      _.each(keys, function(key) {
-        var field = fields[key];
-
-        $container.append(field.editor.render().el);
-      });
-    });
-
-    //Render standalone fields
-    $form.find('[data-fields]').add($form).each(function(i, el) {
-      var $container = $(el),
-          selection = $container.attr('data-fields');
-
-      if (_.isUndefined(selection)) return;
-
-      //Work out which fields to include
-      var keys = (selection == '*')
-        ? self.selectedFields || _.keys(fields)
-        : selection.split(',');
-
-      //Add them
-      _.each(keys, function(key) {
-        var field = fields[key];
-
-        $container.append(field.render().el);
-      });
-    });
-
-    //Render fieldsets
-    $form.find('[data-fieldsets]').add($form).each(function(i, el) {
-      var $container = $(el),
-          selection = $container.attr('data-fieldsets');
-
-      if (_.isUndefined(selection)) return;
-
-      _.each(self.fieldsets, function(fieldset) {
-        $container.append(fieldset.render().el);
-      });
-    });
-
-    //Set the main element
-    this.setElement($form);
-    
-    //Set class
-    $form.addClass(this.className);
-
-    return this;
-  },
-
-  /**
-   * Validate the data
-   *
-   * @return {Object}       Validation errors
-   */
-  validate: function(options) {
-    var self = this,
-        fields = this.fields,
-        model = this.model,
-        errors = {};
-
-    options = options || {};
-
-    //Collect errors from schema validation
-    _.each(fields, function(field) {
-      var error = field.validate();
-      if (error) {
-        errors[field.key] = error;
-      }
-    });
-
-    //Get errors from default Backbone model validator
-    if (!options.skipModelValidate && model && model.validate) {
-      var modelErrors = model.validate(this.getValue());
-
-      if (modelErrors) {
-        var isDictionary = _.isObject(modelErrors) && !_.isArray(modelErrors);
-
-        //If errors are not in object form then just store on the error object
-        if (!isDictionary) {
-          errors._others = errors._others || [];
-          errors._others.push(modelErrors);
-        }
-
-        //Merge programmatic errors (requires model.validate() to return an object e.g. { fieldKey: 'error' })
-        if (isDictionary) {
-          _.each(modelErrors, function(val, key) {
-            //Set error on field if there isn't one already
-            if (fields[key] && !errors[key]) {
-              fields[key].setError(val);
-              errors[key] = val;
-            }
-
-            else {
-              //Otherwise add to '_others' key
-              errors._others = errors._others || [];
-              var tmpErr = {};
-              tmpErr[key] = val;
-              errors._others.push(tmpErr);
-            }
-          });
-        }
-      }
-    }
-
-    return _.isEmpty(errors) ? null : errors;
-  },
-
-  /**
-   * Update the model with all latest values.
-   *
-   * @param {Object} [options]  Options to pass to Model#set (e.g. { silent: true })
-   *
-   * @return {Object}  Validation errors
-   */
-  commit: function(options) {
-    //Validate
-    options = options || {};
-
-    var validateOptions = {
-        skipModelValidate: !options.validate
-    };
-
-    var errors = this.validate(validateOptions);
-    //custom property
-    if (errors){
-      var vFirstField = this.fields[_.keys(errors)[0]];
-      if(vFirstField){
-        $("html, body").animate({
-        scrollTop: vFirstField.$el.position().top-100
-      }, 1100, function(){
-        if(options.focusFirstField) vFirstField.editor.$el.focus();
-      });
-      }
-      return errors;
-    }
-
-    //Commit
-    var modelError;
-
-    var setOptions = _.extend({
-      error: function(model, e) {
-        modelError = e;
-      }
-    }, options);
-
-    this.model.set(this.getValue(), setOptions);
-    
-    if (modelError) return modelError;
-  },
-
-  /**
-   * Get all the field values as an object.
-   * Use this method when passing data instead of objects
-   *
-   * @param {String} [key]    Specific field value to get
-   */
-  getValue: function(key) {
-    //Return only given key if specified
-    if (key) return this.fields[key].getValue();
-
-    //Otherwise return entire form
-    var values = {};
-    _.each(this.fields, function(field) {
-      values[field.key] = field.getValue();
-    });
-
-    return values;
-  },
-
-  /**
-   * Update field values, referenced by key
-   *
-   * @param {Object|String} key     New values to set, or property to set
-   * @param val                     Value to set
-   */
-  setValue: function(prop, val) {
-    var data = {};
-    if (typeof prop === 'string') {
-      data[prop] = val;
-    } else {
-      data = prop;
-    }
-
-    var key;
-    for (key in this.schema) {
-      if (data[key] !== undefined) {
-        this.fields[key].setValue(data[key]);
-      }
-    }
-  },
-
-  /**
-   * Returns the editor for a given field key
-   *
-   * @param {String} key
-   *
-   * @return {Editor}
-   */
-  getEditor: function(key) {
-    var field = this.fields[key];
-    if (!field) throw new Error('Field not found: '+key);
-
-    return field.editor;
-  },
-
-  /**
-   * Gives the first editor in the form focus
-   */
-  focus: function() {
-    if (this.hasFocus) return;
-
-    //Get the first field
-    var fieldset = this.fieldsets[0],
-        field = fieldset.getFieldAt(0);
-
-    if (!field) return;
-
-    //Set focus
-    field.editor.focus();
-  },
-
-  /**
-   * Removes focus from the currently focused editor
-   */
-  blur: function() {
-    if (!this.hasFocus) return;
-
-    var focusedField = _.find(this.fields, function(field) {
-      return field.editor.hasFocus;
-    });
-
-    if (focusedField) focusedField.editor.blur();
-  },
-
-  /**
-   * Manages the hasFocus property
-   *
-   * @param {String} event
-   */
-  trigger: function(event) {
-    if (event === 'focus') {
-      this.hasFocus = true;
-    }
-    else if (event === 'blur') {
-      this.hasFocus = false;
-    }
-
-    return Backbone.View.prototype.trigger.apply(this, arguments);
-  },
-
-  /**
-   * Override default remove function in order to remove embedded views
-   *
-   * TODO: If editors are included directly with data-editors="x", they need to be removed
-   * May be best to use XView to manage adding/removing views
-   */
-  remove: function() {
-    _.each(this.fieldsets, function(fieldset) {
-      fieldset.remove();
-    });
-
-    _.each(this.fields, function(field) {
-      field.remove();
-    });
-
-    return Backbone.View.prototype.remove.apply(this, arguments);
-  }
-
-}, {
-
-  //STATICS
-  template: _.template('\
-    <form>\
-     <div data-fieldsets></div>\
-      <% if (submitButton) { %>\
-        <button type="submit"><%= submitButton %></button>\
-      <% } %>\
-    </form>\
-  ', null, this.templateSettings),
-
-  templateSettings: {
-    evaluate: /<%([\s\S]+?)%>/g, 
-    interpolate: /<%=([\s\S]+?)%>/g, 
-    escape: /<%-([\s\S]+?)%>/g
-  },
-
-  editors: {}
-
-});
-
-  
-//==================================================================================================
-//VALIDATORS
-//==================================================================================================
-
-Form.validators = (function() {
-
-  var validators = {};
-
-  validators.errMessages = {
-    required: 'Required',
-    regexp: 'Invalid',
-    number: 'Must be a number',
-    email: 'Invalid email address',
-    url: 'Invalid URL',
-    match: _.template('Must match field "<%= field %>"', null, Form.templateSettings)
-  };
-  
-  validators.required = function(options) {
-    options = _.extend({
-      type: 'required',
-      message: this.errMessages.required
-    }, options);
-     
-    return function required(value) {
-      options.value = value;
-      
-      var err = {
-        type: options.type,
-        message: _.isFunction(options.message) ? options.message(options) : options.message
-      };
-      
-      if (value === null || value === undefined || value === false || value === '') return err;
-    };
-  };
-  
-  validators.regexp = function(options) {
-    if (!options.regexp) throw new Error('Missing required "regexp" option for "regexp" validator');
-  
-    options = _.extend({
-      type: 'regexp',
-      match: true,
-      message: this.errMessages.regexp
-    }, options);
-    
-    return function regexp(value) {
-      options.value = value;
-      
-      var err = {
-        type: options.type,
-        message: _.isFunction(options.message) ? options.message(options) : options.message
-      };
-      
-      //Don't check empty values (add a 'required' validator for this)
-      if (value === null || value === undefined || value === '') return;
-
-      //Create RegExp from string if it's valid
-      if ('string' === typeof options.regexp) options.regexp = new RegExp(options.regexp, options.flags);
-
-      if ((options.match) ? !options.regexp.test(value) : options.regexp.test(value)) return err;
-    };
-  };
-
-  validators.number = function(options) {
-    options = _.extend({
-      type: 'number',
-      message: this.errMessages.number,
-      regexp: /^[0-9]*\.?[0-9]*?$/
-    }, options);
-    
-    return validators.regexp(options);
-  };
-  
-  validators.email = function(options) {
-    options = _.extend({
-      type: 'email',
-      message: this.errMessages.email,
-      regexp: /^[\w\-]{1,}([\w\-\+.]{1,1}[\w\-]{1,}){0,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/
-    }, options);
-    
-    return validators.regexp(options);
-  };
-  
-  validators.url = function(options) {
-    options = _.extend({
-      type: 'url',
-      message: this.errMessages.url,
-      regexp: /^(http|https):\/\/(([A-Z0-9][A-Z0-9_\-]*)(\.[A-Z0-9][A-Z0-9_\-]*)+)(:(\d+))?\/?/i
-    }, options);
-    
-    return validators.regexp(options);
-  };
-  
-  validators.match = function(options) {
-    if (!options.field) throw new Error('Missing required "field" options for "match" validator');
-    
-    options = _.extend({
-      type: 'match',
-      message: this.errMessages.match
-    }, options);
-    
-    return function match(value, attrs) {
-      options.value = value;
-      
-      var err = {
-        type: options.type,
-        message: _.isFunction(options.message) ? options.message(options) : options.message
-      };
-      
-      //Don't check empty values (add a 'required' validator for this)
-      if (value === null || value === undefined || value === '') return;
-      
-      if (value !== attrs[options.field]) return err;
-    };
-  };
-
-
-  return validators;
-
-})();
-
-
-//==================================================================================================
-//FIELDSET
-//==================================================================================================
-
-Form.Fieldset = Backbone.View.extend({
-
-  /**
-   * Constructor
-   *
-   * Valid fieldset schemas:
-   *   ['field1', 'field2']
-   *   { legend: 'Some Fieldset', fields: ['field1', 'field2'] }
-   *
-   * @param {String[]|Object[]} options.schema      Fieldset schema
-   * @param {Object} options.fields           Form fields
-   */
-  initialize: function(options) {
-    options = options || {};
-
-    //Create the full fieldset schema, merging defaults etc.
-    var schema = this.schema = this.createSchema(options.schema);
-
-    //Store the fields for this fieldset
-    this.fields = _.pick(options.fields, schema.fields);
-    
-    //Override defaults
-    this.template = options.template || schema.template || this.template || this.constructor.template;
-  },
-
-  /**
-   * Creates the full fieldset schema, normalising, merging defaults etc.
-   *
-   * @param {String[]|Object[]} schema
-   *
-   * @return {Object}
-   */
-  createSchema: function(schema) {
-    //Normalise to object
-    if (_.isArray(schema)) {
-      schema = { fields: schema };
-    }
-
-    //Add null legend to prevent template error
-    schema.legend = schema.legend || null;
-
-    return schema;
-  },
-
-  /**
-   * Returns the field for a given index
-   *
-   * @param {Number} index
-   *
-   * @return {Field}
-   */
-  getFieldAt: function(index) {
-    var key = this.schema.fields[index];
-
-    return this.fields[key];
-  },
-
-  /**
-   * Returns data to pass to template
-   *
-   * @return {Object}
-   */
-  templateData: function() {
-    return this.schema;
-  },
-
-  /**
-   * Renders the fieldset and fields
-   *
-   * @return {Fieldset} this
-   */
-  render: function() {
-    var schema = this.schema,
-        fields = this.fields,
-        $ = Backbone.$;
-
-    //Render fieldset
-    var $fieldset = $($.trim(this.template(_.result(this, 'templateData'))));
-
-    //Render fields
-    $fieldset.find('[data-fields]').add($fieldset).each(function(i, el) {
-      var $container = $(el),
-          selection = $container.attr('data-fields');
-
-      if (_.isUndefined(selection)) return;
-
-      _.each(fields, function(field) {
-        $container.append(field.render().el);
-      });
-    });
-
-    this.setElement($fieldset);
-
-    return this;
-  },
-
-  /**
-   * Remove embedded views then self
-   */
-  remove: function() {
-    _.each(this.fields, function(field) {
-      field.remove();
-    });
-
-    Backbone.View.prototype.remove.call(this);
-  }
-  
-}, {
-  //STATICS
-
-  template: _.template('\
-    <fieldset data-fields>\
-      <% if (legend) { %>\
-        <legend><%= legend %></legend>\
-      <% } %>\
-    </fieldset>\
-  ', null, Form.templateSettings)
-
-});
-
-
-//==================================================================================================
-//FIELD
-//==================================================================================================
-
-Form.Field = Backbone.View.extend({
-
-  /**
-   * Constructor
-   * 
-   * @param {Object} options.key
-   * @param {Object} options.form
-   * @param {Object} [options.schema]
-   * @param {Function} [options.schema.template]
-   * @param {Backbone.Model} [options.model]
-   * @param {Object} [options.value]
-   * @param {String} [options.idPrefix]
-   * @param {Function} [options.template]
-   * @param {Function} [options.errorClassName]
-   */
-  initialize: function(options) {
-    options = options || {};
-
-    //Store important data
-    _.extend(this, _.pick(options, 'form', 'key', 'model', 'value', 'idPrefix'));
-
-    //Create the full field schema, merging defaults etc.
-    var schema = this.schema = this.createSchema(options.schema);
-
-    //Override defaults
-    this.template = options.template || schema.template || this.template || this.constructor.template;
-    this.errorClassName = options.errorClassName || this.errorClassName || this.constructor.errorClassName;
-
-    //Create editor
-    this.editor = this.createEditor();
-  },
-
-  /**
-   * Creates the full field schema, merging defaults etc.
-   *
-   * @param {Object|String} schema
-   *
-   * @return {Object}
-   */
-  createSchema: function(schema) {
-    if (_.isString(schema)) schema = { type: schema };
-
-    //Set defaults
-    schema = _.extend({
-      type: 'Text',
-      title: this.createTitle()
-    }, schema);
-
-    //Get the real constructor function i.e. if type is a string such as 'Text'
-    schema.type = (_.isString(schema.type)) ? Form.editors[schema.type] : schema.type;
-
-    return schema;
-  },
-
-  /**
-   * Creates the editor specified in the schema; either an editor string name or
-   * a constructor function
-   *
-   * @return {View}
-   */
-  createEditor: function() {
-    var options = _.extend(
-      _.pick(this, 'schema', 'form', 'key', 'model', 'value'),
-      { id: this.createEditorId() }
-    );
-
-    var constructorFn = this.schema.type;
-
-    return new constructorFn(options);
-  },
-
-  /**
-   * Creates the ID that will be assigned to the editor
-   *
-   * @return {String}
-   */
-  createEditorId: function() {
-    var prefix = this.idPrefix,
-        id = this.key;
-
-    //Replace periods with underscores (e.g. for when using paths)
-    id = id.replace(/\./g, '_');
-
-    //If a specific ID prefix is set, use it
-    if (_.isString(prefix) || _.isNumber(prefix)) return prefix + id;
-    if (_.isNull(prefix)) return id;
-
-    //Otherwise, if there is a model use it's CID to avoid conflicts when multiple forms are on the page
-    if (this.model) return this.model.cid + '_' + id;
-
-    return id;
-  },
-
-  /**
-   * Create the default field title (label text) from the key name.
-   * (Converts 'camelCase' to 'Camel Case')
-   *
-   * @return {String}
-   */
-  createTitle: function() {
-    var str = this.key;
-
-    //Add spaces
-    str = str.replace(/([A-Z])/g, ' $1');
-
-    //Uppercase first character
-    str = str.replace(/^./, function(str) { return str.toUpperCase(); });
-
-    return str;
-  },
-
-  /**
-   * Returns the data to be passed to the template
-   *
-   * @return {Object}
-   */
-  templateData: function() {
-    var schema = this.schema;
-
-    return {
-      help: schema.help || '',
-      title: schema.title,
-      fieldAttrs: schema.fieldAttrs,
-      editorAttrs: schema.editorAttrs,
-      key: this.key,
-      editorId: this.editor.id
-    };
-  },
-
-  /**
-   * Render the field and editor
-   *
-   * @return {Field} self
-   */
-  render: function() {
-    var schema = this.schema,
-        editor = this.editor,
-        $ = Backbone.$;
-
-    //Only render the editor if Hidden
-    if (schema.type == Form.editors.Hidden) {
-      return this.setElement(editor.render().el);
-    }
-
-    //Render field
-    var $field = $($.trim(this.template(_.result(this, 'templateData'))));
-
-    if (schema.fieldClass) $field.addClass(schema.fieldClass);
-    if (schema.fieldAttrs) $field.attr(schema.fieldAttrs);
-
-    //Render editor
-    $field.find('[data-editor]').add($field).each(function(i, el) {
-      var $container = $(el),
-          selection = $container.attr('data-editor');
-
-      if (_.isUndefined(selection)) return;
-
-      $container.append(editor.render().el);
-    });
-
-    this.setElement($field);
-
-    return this;
-  },
-
-  /**
-   * Check the validity of the field
-   *
-   * @return {String}
-   */
-  validate: function() {
-    var error = this.editor.validate();
-
-    if (error) {
-      this.setError(error.message);
-    } else {
-      this.clearError();
-    }
-
-    return error;
-  },
-
-  /**
-   * Set the field into an error state, adding the error class and setting the error message
-   *
-   * @param {String} msg     Error message
-   */
-  setError: function(msg) {
-    //Nested form editors (e.g. Object) set their errors internally
-    if (this.editor.hasNestedForm) return;
-
-    //Add error CSS class
-    this.$el.addClass(this.errorClassName);
-
-    //Set error message
-    this.$('[data-error]').html(msg);
-  },
-
-  /**
-   * Clear the error state and reset the help message
-   */
-  clearError: function() {
-    //Remove error CSS class
-    this.$el.removeClass(this.errorClassName);
-
-    //Clear error message
-    this.$('[data-error]').empty();
-  },
-
-  /**
-   * Update the model with the new value from the editor
-   *
-   * @return {Mixed}
-   */
-  commit: function() {
-    return this.editor.commit();
-  },
-
-  /**
-   * Get the value from the editor
-   *
-   * @return {Mixed}
-   */
-  getValue: function() {
-    return this.editor.getValue();
-  },
-
-  /**
-   * Set/change the value of the editor
-   *
-   * @param {Mixed} value
-   */
-  setValue: function(value) {
-    this.editor.setValue(value);
-  },
-
-  /**
-   * Give the editor focus
-   */
-  focus: function() {
-    this.editor.focus();
-  },
-
-  /**
-   * Remove focus from the editor
-   */
-  blur: function() {
-    this.editor.blur();
-  },
-
-  /**
-   * Remove the field and editor views
-   */
-  remove: function() {
-    this.editor.remove();
-
-    Backbone.View.prototype.remove.call(this);
-  }
-
-}, {
-  //STATICS
-
-  template: _.template('\
-    <div>\
-      <label for="<%= editorId %>"><%= title %></label>\
-      <div>\
-        <span data-editor></span>\
-        <div data-error></div>\
-        <div><%= help %></div>\
-      </div>\
-    </div>\
-  ', null, Form.templateSettings),
-
-  /**
-   * CSS class name added to the field when there is a validation error
-   */
-  errorClassName: 'error'
-
-});
-
-
-//==================================================================================================
-//NESTEDFIELD
-//==================================================================================================
-
-Form.NestedField = Form.Field.extend({
-
-  template: _.template('\
-    <div>\
-      <span data-editor></span>\
-      <% if (help) { %>\
-        <div><%= help %></div>\
-      <% } %>\
-      <div data-error></div>\
-    </div>\
-  ', null, Form.templateSettings)
-
-});
-
-/**
- * Base editor (interface). To be extended, not used directly
- *
- * @param {Object} options
- * @param {String} [options.id]         Editor ID
- * @param {Model} [options.model]       Use instead of value, and use commit()
- * @param {String} [options.key]        The model attribute key. Required when using 'model'
- * @param {Mixed} [options.value]       When not using a model. If neither provided, defaultValue will be used
- * @param {Object} [options.schema]     Field schema; may be required by some editors
- * @param {Object} [options.validators] Validators; falls back to those stored on schema
- * @param {Object} [options.form]       The form
- */
-Form.Editor = Form.editors.Base = Backbone.View.extend({
-
-  defaultValue: null,
-
-  hasFocus: false,
-
-  initialize: function(options) {
-    var options = options || {};
-
-    //Set initial value
-    if (options.model) {
-      if (!options.key) throw new Error("Missing option: 'key'");
-
-      this.model = options.model;
-
-      this.value = this.model.get(options.key);
-    }
-    else if (options.value !== undefined) {
-      this.value = options.value;
-    }
-
-    if (this.value === undefined) this.value = this.defaultValue;
-
-    //Store important data
-    _.extend(this, _.pick(options, 'key', 'form'));
-
-    var schema = this.schema = options.schema || {};
-
-    this.validators = options.validators || schema.validators;
-
-    //Main attributes
-    this.$el.attr('id', this.id);
-    this.$el.attr('name', this.getName());
-    if (schema.editorClass) this.$el.addClass(schema.editorClass);
-    if (schema.editorAttrs) this.$el.attr(schema.editorAttrs);
-  },
-
-  /**
-   * Get the value for the form input 'name' attribute
-   *
-   * @return {String}
-   *
-   * @api private
-   */
-  getName: function() {
-    var key = this.key || '';
-
-    //Replace periods with underscores (e.g. for when using paths)
-    return key.replace(/\./g, '_');
-  },
-
-  /**
-   * Get editor value
-   * Extend and override this method to reflect changes in the DOM
-   *
-   * @return {Mixed}
-   */
-  getValue: function() {
-    return this.value;
-  },
-
-  /**
-   * Set editor value
-   * Extend and override this method to reflect changes in the DOM
-   *
-   * @param {Mixed} value
-   */
-  setValue: function(value) {
-    this.value = value;
-  },
-
-  /**
-   * Give the editor focus
-   * Extend and override this method
-   */
-  focus: function() {
-    throw new Error('Not implemented');
-  },
-  
-  /**
-   * Remove focus from the editor
-   * Extend and override this method
-   */
-  blur: function() {
-    throw new Error('Not implemented');
-  },
-
-  /**
-   * Update the model with the current value
-   *
-   * @param {Object} [options]              Options to pass to model.set()
-   * @param {Boolean} [options.validate]    Set to true to trigger built-in model validation
-   *
-   * @return {Mixed} error
-   */
-  commit: function(options) {
-    var error = this.validate();
-    if (error) return error;
-
-    this.listenTo(this.model, 'invalid', function(model, e) {
-      error = e;
-    });
-    this.model.set(this.key, this.getValue(), options);
-
-    if (error) return error;
-  },
-
-  /**
-   * Check validity
-   *
-   * @return {Object|Undefined}
-   */
-  validate: function() {
-    var $el = this.$el,
-        error = null,
-        value = this.getValue(),
-        formValues = this.form ? this.form.getValue() : {},
-        validators = this.validators,
-        getValidator = this.getValidator;
-
-    if (validators) {
-      //Run through validators until an error is found
-      _.every(validators, function(validator) {
-        error = getValidator(validator)(value, formValues);
-
-        return error ? false : true;
-      });
-    }
-
-    return error;
-  },
-
-  /**
-   * Set this.hasFocus, or call parent trigger()
-   *
-   * @param {String} event
-   */
-  trigger: function(event) {
-    if (event === 'focus') {
-      this.hasFocus = true;
-    }
-    else if (event === 'blur') {
-      this.hasFocus = false;
-    }
-
-    return Backbone.View.prototype.trigger.apply(this, arguments);
-  },
-
-  /**
-   * Returns a validation function based on the type defined in the schema
-   *
-   * @param {RegExp|String|Function} validator
-   * @return {Function}
-   */
-  getValidator: function(validator) {
-    var validators = Form.validators;
-
-    //Convert regular expressions to validators
-    if (_.isRegExp(validator)) {
-      return validators.regexp({ regexp: validator });
-    }
-    
-    //Use a built-in validator if given a string
-    if (_.isString(validator)) {
-      if (!validators[validator]) throw new Error('Validator "'+validator+'" not found');
-      
-      return validators[validator]();
-    }
-
-    //Functions can be used directly
-    if (_.isFunction(validator)) return validator;
-
-    //Use a customised built-in validator if given an object
-    if (_.isObject(validator) && validator.type) {
-      var config = validator;
-      
-      return validators[config.type](config);
-    }
-    
-    //Unkown validator type
-    throw new Error('Invalid validator: ' + validator);
-  }
-});
-
-/**
- * Text
- * 
- * Text input with focus, blur and change events
- */
-Form.editors.Text = Form.Editor.extend({
-
-  tagName: 'input',
-
-  defaultValue: '',
-
-  previousValue: '',
-
-  events: {
-    'keyup':    'determineChange',
-    'keypress': function(event) {
-      var self = this;
-      setTimeout(function() {
-        self.determineChange();
-      }, 0);
-    },
-    'select':   function(event) {
-      this.trigger('select', this);
-    },
-    'focus':    function(event) {
-      this.trigger('focus', this);
-    },
-    'blur':     function(event) {
-      var trimmedVal = $.trim(this.$el.val());
-      this.$el.val(trimmedVal);
-      this.trigger('blur', this);
-    }
-  },
-
-  initialize: function(options) {
-    Form.editors.Base.prototype.initialize.call(this, options);
-
-    var schema = this.schema;
-
-    //Allow customising text type (email, phone etc.) for HTML5 browsers
-    var type = 'text';
-
-    if (schema && schema.editorAttrs && schema.editorAttrs.type) type = schema.editorAttrs.type;
-    if (schema && schema.dataType) type = schema.dataType;
-
-    this.$el.attr('type', type);
-  },
-
-  /**
-   * Adds the editor to the DOM
-   */
-  render: function() {
-    this.setValue(this.value);
-
-    return this;
-  },
-
-  determineChange: function(event) {
-    var currentValue = this.$el.val();
-    var changed = (currentValue !== this.previousValue);
-
-    if (changed) {
-      this.previousValue = currentValue;
-
-      this.trigger('change', this);
-    }
-  },
-
-  /**
-   * Returns the current editor value
-   * @return {String}
-   */
-  getValue: function() {
-    return this.$el.val();
-  },
-
-  /**
-   * Sets the value of the form element
-   * @param {String}
-   */
-  setValue: function(value) {
-    this.$el.val(value);
-  },
-
-  focus: function() {
-    if (this.hasFocus) return;
-
-    this.$el.focus();
-  },
-
-  blur: function() {
-    if (!this.hasFocus) return;
-
-    this.$el.blur();
-  },
-
-  select: function() {
-    this.$el.select();
-  }
-
-});
-
-/**
- * TextArea editor
- */
-Form.editors.TextArea = Form.editors.Text.extend({
-
-  tagName: 'textarea',
-
-  /**
-   * Override Text constructor so type property isn't set (issue #261)
-   */
-  initialize: function(options) {
-    Form.editors.Base.prototype.initialize.call(this, options);
-  }
-
-});
-
-/**
- * Password editor
- */
-Form.editors.Password = Form.editors.Text.extend({
-
-  initialize: function(options) {
-    Form.editors.Text.prototype.initialize.call(this, options);
-
-    this.$el.attr('type', 'password');
-  }
-
-});
-
-/**
- * NUMBER
- * 
- * Normal text input that only allows a number. Letters etc. are not entered.
- */
-Form.editors.Number = Form.editors.Text.extend({
-
-  defaultValue: 0,
-
-  events: _.extend({}, Form.editors.Text.prototype.events, {
-    'keypress': 'onKeyPress',
-    'change': 'onKeyPress'
-  }),
-
-  initialize: function(options) {
-    Form.editors.Text.prototype.initialize.call(this, options);
-
-    var schema = this.schema;
-
-    this.$el.attr('type', 'number');
-
-    if (!schema || !schema.editorAttrs || !schema.editorAttrs.step) {
-      // provide a default for `step` attr,
-      // but don't overwrite if already specified
-      this.$el.attr('step', 'any');
-    }
-  },
-
-  /**
-   * Check value is numeric
-   */
-  onKeyPress: function(event) {
-    var self = this,
-        delayedDetermineChange = function() {
-          setTimeout(function() {
-            self.determineChange();
-          }, 0);
-        };
-
-    //Allow backspace
-    if (event.charCode === 0) {
-      delayedDetermineChange();
-      return;
-    }
-
-    //Get the whole new value so that we can prevent things like double decimals points etc.
-    var newVal = this.$el.val()
-    if( event.charCode != undefined ) {
-      newVal = newVal + String.fromCharCode(event.charCode);
-    }
-
-    var numeric = /^[0-9]*\.?[0-9]*?$/.test(newVal);
-
-    if (numeric) {
-      delayedDetermineChange();
-    }
-    else {
-      event.preventDefault();
-    }
-  },
-
-  getValue: function() {
-    var value = this.$el.val();
-
-    return value === "" ? null : parseFloat(value, 10);
-  },
-
-  setValue: function(value) {
-    value = (function() {
-      if (_.isNumber(value)) return value;
-
-      if (_.isString(value) && value !== '') return parseFloat(value, 10);
-
-      return null;
-    })();
-
-    if (_.isNaN(value)) value = null;
-
-    Form.editors.Text.prototype.setValue.call(this, value);
-  }
-
-});
-
-/**
- * Hidden editor
- */
-Form.editors.Hidden = Form.editors.Text.extend({
-
-  defaultValue: '',
-
-  initialize: function(options) {
-    Form.editors.Text.prototype.initialize.call(this, options);
-
-    this.$el.attr('type', 'hidden');
-  },
-
-  focus: function() {
-
-  },
-
-  blur: function() {
-
-  }
-
-});
-
-/**
- * Checkbox editor
- *
- * Creates a single checkbox, i.e. boolean value
- */
-Form.editors.Checkbox = Form.editors.Base.extend({
-
-  defaultValue: false,
-
-  tagName: 'input',
-
-  events: {
-    'click':  function(event) {
-      this.trigger('change', this);
-    },
-    'focus':  function(event) {
-      this.trigger('focus', this);
-    },
-    'blur':   function(event) {
-      this.trigger('blur', this);
-    }
-  },
-
-  initialize: function(options) {
-    Form.editors.Base.prototype.initialize.call(this, options);
-
-    this.$el.attr('type', 'checkbox');
-  },
-
-  /**
-   * Adds the editor to the DOM
-   */
-  render: function() {
-    this.setValue(this.value);
-
-    return this;
-  },
-
-  getValue: function() {
-    return this.$el.prop('checked');
-  },
-
-  setValue: function(value) {
-    if (value) {
-      this.$el.prop('checked', true);
-    }else{
-      this.$el.prop('checked', false);
-    }
-  },
-
-  focus: function() {
-    if (this.hasFocus) return;
-
-    this.$el.focus();
-  },
-
-  blur: function() {
-    if (!this.hasFocus) return;
-
-    this.$el.blur();
-  }
-
-});
-
-/**
- * Select editor
- *
- * Renders a <select> with given options
- *
- * Requires an 'options' value on the schema.
- *  Can be an array of options, a function that calls back with the array of options, a string of HTML
- *  or a Backbone collection. If a collection, the models must implement a toString() method
- */
-Form.editors.Select = Form.editors.Base.extend({
-
-  tagName: 'select',
-
-  previousValue: '',
-
-  events: {
-    'keyup':    'determineChange',
-    'keypress': function(event) {
-      var self = this;
-      setTimeout(function() {
-        self.determineChange();
-      }, 0);
-    },
-    'change': function(event) {
-      this.trigger('change', this);
-    },
-    'focus':  function(event) {
-      this.trigger('focus', this);
-    },
-    'blur':   function(event) {
-      this.trigger('blur', this);
-    }
-  },
-
-  initialize: function(options) {
-    Form.editors.Base.prototype.initialize.call(this, options);
-
-    if (!this.schema || !this.schema.options) throw new Error("Missing required 'schema.options'");
-  },
-
-  render: function() {
-    this.setOptions(this.schema.options);
-
-    return this;
-  },
-
-  /**
-   * Sets the options that populate the <select>
-   *
-   * @param {Mixed} options
-   */
-  setOptions: function(options) {
-    var self = this;
-
-    //If a collection was passed, check if it needs fetching
-    if (options instanceof Backbone.Collection) {
-      var collection = options;
-
-      //Don't do the fetch if it's already populated
-      if (collection.length > 0) {
-        this.renderOptions(options);
-      } else {
-        collection.fetch({
-          success: function(collection) {
-            self.renderOptions(options);
-          }
-        });
-      }
-    }
-
-    //If a function was passed, run it to get the options
-    else if (_.isFunction(options)) {
-      options(function(result) {
-        self.renderOptions(result);
-      }, self);
-    }
-
-    //Otherwise, ready to go straight to renderOptions
-    else {
-      this.renderOptions(options);
-    }
-  },
-
-  /**
-   * Adds the <option> html to the DOM
-   * @param {Mixed}   Options as a simple array e.g. ['option1', 'option2']
-   *                      or as an array of objects e.g. [{val: 543, label: 'Title for object 543'}]
-   *                      or as a string of <option> HTML to insert into the <select>
-   *                      or any object
-   */
-  renderOptions: function(options) {
-    var $select = this.$el,
-        html;
-
-    html = this._getOptionsHtml(options);
-
-    //Insert options
-    $select.html(html);
-
-    //Select correct option
-    this.setValue(this.value);
-  },
-
-  _getOptionsHtml: function(options) {
-    var html;
-    //Accept string of HTML
-    if (_.isString(options)) {
-      html = options;
-    }
-
-    //Or array
-    else if (_.isArray(options)) {
-      html = this._arrayToHtml(options);
-    }
-
-    //Or Backbone collection
-    else if (options instanceof Backbone.Collection) {
-      html = this._collectionToHtml(options);
-    }
-
-    else if (_.isFunction(options)) {
-      var newOptions;
-
-      options(function(opts) {
-        newOptions = opts;
-      }, this);
-
-      html = this._getOptionsHtml(newOptions);
-    //Or any object
-    }else{
-      html=this._objectToHtml(options);
-    }
-
-    return html;
-  },
-
-  determineChange: function(event) {
-    var currentValue = this.getValue();
-    var changed = (currentValue !== this.previousValue);
-
-    if (changed) {
-      this.previousValue = currentValue;
-
-      this.trigger('change', this);
-    }
-  },
-
-  getValue: function() {
-    return this.$el.val();
-  },
-
-  setValue: function(value) {
-    this.$el.val(value);
-  },
-
-  focus: function() {
-    if (this.hasFocus) return;
-
-    this.$el.focus();
-  },
-
-  blur: function() {
-    if (!this.hasFocus) return;
-
-    this.$el.blur();
-  },
-
-  /**
-   * Transforms a collection into HTML ready to use in the renderOptions method
-   * @param {Backbone.Collection}
-   * @return {String}
-   */
-  _collectionToHtml: function(collection) {
-    //Convert collection to array first
-    var array = [];
-    collection.each(function(model) {
-      array.push({ val: model.id, label: model.toString() });
-    });
-
-    //Now convert to HTML
-    var html = this._arrayToHtml(array);
-
-    return html;
-  },
-  /**
-   * Transforms an object into HTML ready to use in the renderOptions method
-   * @param {Object}
-   * @return {String}
-   */
-  _objectToHtml: function(obj) {
-    //Convert object to array first
-    var array = [];
-    for(var key in obj){
-      if( obj.hasOwnProperty( key ) ) {
-        array.push({ val: key, label: obj[key] });
-      }
-    }
-
-    //Now convert to HTML
-    var html = this._arrayToHtml(array);
-
-    return html;
-  },
-
-
-
-  /**
-   * Create the <option> HTML
-   * @param {Array}   Options as a simple array e.g. ['option1', 'option2']
-   *                      or as an array of objects e.g. [{val: 543, label: 'Title for object 543'}]
-   * @return {String} HTML
-   */
-  _arrayToHtml: function(array) {
-    var html = [];
-
-    //Generate HTML
-    _.each(array, function(option) {
-      if (_.isObject(option)) {
-        if (option.group) {
-          html.push('<optgroup label="'+option.group+'">');
-          html.push(this._getOptionsHtml(option.options))
-          html.push('</optgroup>');
-        } else {
-          var val = (option.val || option.val === 0) ? option.val : '';
-          html.push('<option value="'+val+'">'+option.label+'</option>');
-        }
-      }
-      else {
-        html.push('<option>'+option+'</option>');
-      }
-    }, this);
-
-    return html.join('');
-  }
-
-});
-
-/**
- * Radio editor
- *
- * Renders a <ul> with given options represented as <li> objects containing radio buttons
- *
- * Requires an 'options' value on the schema.
- *  Can be an array of options, a function that calls back with the array of options, a string of HTML
- *  or a Backbone collection. If a collection, the models must implement a toString() method
- */
-Form.editors.Radio = Form.editors.Select.extend({
-
-  tagName: 'div',
-
-  events: {
-    'change input[type=radio]': function() {
-      this.trigger('change', this);
-    },
-    'focus input[type=radio]': function() {
-      if (this.hasFocus) return;
-      this.trigger('focus', this);
-    },
-    'blur input[type=radio]': function() {
-      if (!this.hasFocus) return;
-      var self = this;
-      setTimeout(function() {
-        if (self.$('input[type=radio]:focus')[0]) return;
-        self.trigger('blur', self);
-      }, 0);
-    }
-  },
-
-  /**
-   * Returns the template. Override for custom templates
-   *
-   * @return {Function}       Compiled template
-   */
-  getTemplate: function() {
-    return this.schema.template || this.constructor.template;
-  },
-
-  getValue: function() {
-    return this.$('input[type=radio]:checked').val();
-  },
-
-  setValue: function(value) {
-    this.$('input[type=radio]').val([value]);
-  },
-
-  focus: function() {
-    if (this.hasFocus) return;
-
-    var checked = this.$('input[type=radio]:checked');
-    if (checked[0]) {
-      checked.focus();
-      return;
-    }
-
-    this.$('input[type=radio]').first().focus();
-  },
-
-  blur: function() {
-    if (!this.hasFocus) return;
-
-    this.$('input[type=radio]:focus').blur();
-  },
-
-  /**
-   * Create the radio list HTML
-   * @param {Array}   Options as a simple array e.g. ['option1', 'option2']
-   *                      or as an array of objects e.g. [{val: 543, label: 'Title for object 543'}]
-   * @return {String} HTML
-   */
-  _arrayToHtml: function (array) {
-    var self = this;
-
-    var template = this.getTemplate(),
-        name = self.getName(),
-        id = self.id;
-
-    var items = _.map(array, function(option, index) {
-      var item = {
-        name: name,
-        id: id + '-' + index
-      }
-
-      if (_.isObject(option)) {
-        item.value = (option.val || option.val === 0) ? option.val : '';
-        item.label = option.label;
-      } else {
-        item.value = option;
-        item.label = option;
-      }
-
-      return item;
-    });
-
-    return template({ items: items });
-  }
-
-}, {
-
-  //STATICS
-  template: _.template('\
-    <% _.each(items, function(item) { %>\
-      <div class="form-check form-check-inline">\
-        <input class="form-check-input" type="radio" name="<%= item.name %>" value="<%= item.value %>" id="<%= item.id %>" />\
-        <label class="form-check-label" for="<%= item.id %>"><%= item.label %></label>\
-      </div>\
-    <% }); %>\
-  ', null, Form.templateSettings)
-
-});
-
-/**
- * Checkboxes editor
- *
- * Renders a <ul> with given options represented as <li> objects containing checkboxes
- *
- * Requires an 'options' value on the schema.
- *  Can be an array of options, a function that calls back with the array of options, a string of HTML
- *  or a Backbone collection. If a collection, the models must implement a toString() method
- */
-Form.editors.Checkboxes = Form.editors.Select.extend({
-
-  tagName: 'ul',
-
-  groupNumber: 0,
-
-  events: {
-    'click input[type=checkbox]': function() {
-      this.trigger('change', this);
-    },
-    'focus input[type=checkbox]': function() {
-      if (this.hasFocus) return;
-      this.trigger('focus', this);
-    },
-    'blur input[type=checkbox]':  function() {
-      if (!this.hasFocus) return;
-      var self = this;
-      setTimeout(function() {
-        if (self.$('input[type=checkbox]:focus')[0]) return;
-        self.trigger('blur', self);
-      }, 0);
-    }
-  },
-
-  getValue: function() {
-    var values = [];
-    this.$('input[type=checkbox]:checked').each(function() {
-      values.push($(this).val());
-    });
-    return values;
-  },
-
-  setValue: function(values) {
-    if (!_.isArray(values)) values = [values];
-    this.$('input[type=checkbox]').val(values);
-  },
-
-  focus: function() {
-    if (this.hasFocus) return;
-
-    this.$('input[type=checkbox]').first().focus();
-  },
-
-  blur: function() {
-    if (!this.hasFocus) return;
-
-    this.$('input[type=checkbox]:focus').blur();
-  },
-
-  /**
-   * Create the checkbox list HTML
-   * @param {Array}   Options as a simple array e.g. ['option1', 'option2']
-   *                      or as an array of objects e.g. [{val: 543, label: 'Title for object 543'}]
-   * @return {String} HTML
-   */
-  _arrayToHtml: function (array) {
-    var html = [];
-    var self = this;
-
-    _.each(array, function(option, index) {
-      var itemHtml = '<li>';
-      var close = true;
-      if (_.isObject(option)) {
-        if (option.group) {
-          var originalId = self.id;
-          self.id += "-" + self.groupNumber++; 
-          itemHtml = ('<fieldset class="group"> <legend>'+option.group+'</legend>');
-          itemHtml += (self._arrayToHtml(option.options));
-          itemHtml += ('</fieldset>');
-          self.id = originalId;
-          close = false;
-        }else{
-          var val = (option.val || option.val === 0) ? option.val : '';
-          itemHtml += ('<input type="checkbox" name="'+self.getName()+'" value="'+val+'" id="'+self.id+'-'+index+'" />');
-          itemHtml += ('<label for="'+self.id+'-'+index+'">'+option.label+'</label>');
-        }
-      }
-      else {
-        itemHtml += ('<input type="checkbox" name="'+self.getName()+'" value="'+option+'" id="'+self.id+'-'+index+'" />');
-        itemHtml += ('<label for="'+self.id+'-'+index+'">'+option+'</label>');
-      }
-      if(close){
-        itemHtml += '</li>';
-      }
-      html.push(itemHtml);
-    });
-
-    return html.join('');
-  }
-
-});
-
-/**
- * Object editor
- *
- * Creates a child form. For editing Javascript objects
- *
- * @param {Object} options
- * @param {Form} options.form                 The form this editor belongs to; used to determine the constructor for the nested form
- * @param {Object} options.schema             The schema for the object
- * @param {Object} options.schema.subSchema   The schema for the nested form
- */
-Form.editors.Object = Form.editors.Base.extend({
-  //Prevent error classes being set on the main control; they are internally on the individual fields
-  hasNestedForm: true,
-
-  initialize: function(options) {
-    //Set default value for the instance so it's not a shared object
-    this.value = {};
-
-    //Init
-    Form.editors.Base.prototype.initialize.call(this, options);
-
-    //Check required options
-    if (!this.form) throw new Error('Missing required option "form"');
-    if (!this.schema.subSchema) throw new Error("Missing required 'schema.subSchema' option for Object editor");
-  },
-
-  render: function() {
-    //Get the constructor for creating the nested form; i.e. the same constructor as used by the parent form
-    var NestedForm = this.form.constructor;
-
-    //Create the nested form
-    this.nestedForm = new NestedForm({
-      schema: this.schema.subSchema,
-      data: this.value,
-      idPrefix: this.id + '_',
-      Field: NestedForm.NestedField
-    });
-
-    this._observeFormEvents();
-
-    this.$el.html(this.nestedForm.render().el);
-
-    if (this.hasFocus) this.trigger('blur', this);
-
-    return this;
-  },
-
-  getValue: function() {
-    if (this.nestedForm) return this.nestedForm.getValue();
-
-    return this.value;
-  },
-
-  setValue: function(value) {
-    this.value = value;
-
-    this.render();
-  },
-
-  focus: function() {
-    if (this.hasFocus) return;
-
-    this.nestedForm.focus();
-  },
-
-  blur: function() {
-    if (!this.hasFocus) return;
-
-    this.nestedForm.blur();
-  },
-
-  remove: function() {
-    this.nestedForm.remove();
-
-    Backbone.View.prototype.remove.call(this);
-  },
-
-  validate: function() {
-    return this.nestedForm.validate();
-  },
-
-  _observeFormEvents: function() {
-    if (!this.nestedForm) return;
-    
-    this.nestedForm.on('all', function() {
-      // args = ["key:change", form, fieldEditor]
-      var args = _.toArray(arguments);
-      args[1] = this;
-      // args = ["key:change", this=objectEditor, fieldEditor]
-
-      this.trigger.apply(this, args);
-    }, this);
-  }
-
-});
-
-/**
- * NestedModel editor
- *
- * Creates a child form. For editing nested Backbone models
- *
- * Special options:
- *   schema.model:   Embedded model constructor
- */
-Form.editors.NestedModel = Form.editors.Object.extend({
-  initialize: function(options) {
-    Form.editors.Base.prototype.initialize.call(this, options);
-
-    if (!this.form) throw new Error('Missing required option "form"');
-    if (!options.schema.model) throw new Error('Missing required "schema.model" option for NestedModel editor');
-  },
-
-  render: function() {
-    //Get the constructor for creating the nested form; i.e. the same constructor as used by the parent form
-    var NestedForm = this.form.constructor;
-
-    var data = this.value || {},
-        key = this.key,
-        nestedModel = this.schema.model;
-
-    //Wrap the data in a model if it isn't already a model instance
-    var modelInstance = (data.constructor === nestedModel) ? data : new nestedModel(data);
-
-    this.nestedForm = new NestedForm({
-      model: modelInstance,
-      idPrefix: this.id + '_',
-      fieldTemplate: 'nestedField'
-    });
-
-    this._observeFormEvents();
-
-    //Render form
-    this.$el.html(this.nestedForm.render().el);
-
-    if (this.hasFocus) this.trigger('blur', this);
-
-    return this;
-  },
-
-  /**
-   * Update the embedded model, checking for nested validation errors and pass them up
-   * Then update the main model if all OK
-   *
-   * @return {Error|null} Validation error or null
-   */
-  commit: function() {
-    var error = this.nestedForm.commit();
-    if (error) {
-      this.$el.addClass('error');
-      return error;
-    }
-
-    return Form.editors.Object.prototype.commit.call(this);
-  }
-
-});
-
-/**
- * Date editor
- *
- * Schema options
- * @param {Number|String} [options.schema.yearStart]  First year in list. Default: 100 years ago
- * @param {Number|String} [options.schema.yearEnd]    Last year in list. Default: current year
- *
- * Config options (if not set, defaults to options stored on the main Date class)
- * @param {Boolean} [options.showMonthNames]  Use month names instead of numbers. Default: true
- * @param {String[]} [options.monthNames]     Month names. Default: Full English names
- */
-Form.editors.Date = Form.editors.Base.extend({
-
-  events: {
-    'change select':  function() {
-      this.updateHidden();
-      this.trigger('change', this);
-    },
-    'focus select':   function() {
-      if (this.hasFocus) return;
-      this.trigger('focus', this);
-    },
-    'blur select':    function() {
-      if (!this.hasFocus) return;
-      var self = this;
-      setTimeout(function() {
-        if (self.$('select:focus')[0]) return;
-        self.trigger('blur', self);
-      }, 0);
-    }
-  },
-
-  initialize: function(options) {
-    options = options || {};
-
-    Form.editors.Base.prototype.initialize.call(this, options);
-
-    var Self = Form.editors.Date,
-        today = new Date();
-
-    //Option defaults
-    this.options = _.extend({
-      monthNames: Self.monthNames,
-      showMonthNames: Self.showMonthNames
-    }, options);
-
-    //Schema defaults
-    this.schema = _.extend({
-      yearStart: today.getFullYear() - 100,
-      yearEnd: today.getFullYear()
-    }, options.schema || {});
-
-    //Cast to Date
-    if (this.value && !_.isDate(this.value)) {
-      this.value = new Date(this.value);
-    }
-
-    //Set default date
-    if (!this.value) {
-      var date = new Date();
-      date.setSeconds(0);
-      date.setMilliseconds(0);
-
-      this.value = date;
-    }
-
-    //Template
-    this.template = options.template || this.constructor.template;
-  },
-
-  render: function() {
-    var options = this.options,
-        schema = this.schema,
-        $ = Backbone.$;
-
-    var datesOptions = _.map(_.range(1, 32), function(date) {
-      return '<option value="'+date+'">' + date + '</option>';
-    });
-
-    var monthsOptions = _.map(_.range(0, 12), function(month) {
-      var value = (options.showMonthNames)
-          ? options.monthNames[month]
-          : (month + 1);
-
-      return '<option value="'+month+'">' + value + '</option>';
-    });
-
-    var yearRange = (schema.yearStart < schema.yearEnd)
-      ? _.range(schema.yearStart, schema.yearEnd + 1)
-      : _.range(schema.yearStart, schema.yearEnd - 1, -1);
-
-    var yearsOptions = _.map(yearRange, function(year) {
-      return '<option value="'+year+'">' + year + '</option>';
-    });
-
-    //Render the selects
-    var $el = $($.trim(this.template({
-      dates: datesOptions.join(''),
-      months: monthsOptions.join(''),
-      years: yearsOptions.join('')
-    })));
-
-    //Store references to selects
-    this.$date = $el.find('[data-type="date"]');
-    this.$month = $el.find('[data-type="month"]');
-    this.$year = $el.find('[data-type="year"]');
-
-    //Create the hidden field to store values in case POSTed to server
-    this.$hidden = $('<input type="hidden" name="'+this.key+'" />');
-    $el.append(this.$hidden);
-
-    //Set value on this and hidden field
-    this.setValue(this.value);
-
-    //Remove the wrapper tag
-    this.setElement($el);
-    this.$el.attr('id', this.id);
-    this.$el.attr('name', this.getName());
-
-    if (this.hasFocus) this.trigger('blur', this);
-
-    return this;
-  },
-
-  /**
-   * @return {Date}   Selected date
-   */
-  getValue: function() {
-    var year = this.$year.val(),
-        month = this.$month.val(),
-        date = this.$date.val();
-
-    if (!year || !month || !date) return null;
-
-    return new Date(year, month, date);
-  },
-
-  /**
-   * @param {Date} date
-   */
-  setValue: function(date) {
-    this.$date.val(date.getDate());
-    this.$month.val(date.getMonth());
-    this.$year.val(date.getFullYear());
-
-    this.updateHidden();
-  },
-
-  focus: function() {
-    if (this.hasFocus) return;
-
-    this.$('select').first().focus();
-  },
-
-  blur: function() {
-    if (!this.hasFocus) return;
-
-    this.$('select:focus').blur();
-  },
-
-  /**
-   * Update the hidden input which is maintained for when submitting a form
-   * via a normal browser POST
-   */
-  updateHidden: function() {
-    var val = this.getValue();
-
-    if (_.isDate(val)) val = val.toISOString();
-
-    this.$hidden.val(val);
-  }
-
-}, {
-  //STATICS
-  template: _.template('\
-    <div>\
-      <select data-type="date"><%= dates %></select>\
-      <select data-type="month"><%= months %></select>\
-      <select data-type="year"><%= years %></select>\
-    </div>\
-  ', null, Form.templateSettings),
-
-  //Whether to show month names instead of numbers
-  showMonthNames: true,
-
-  //Month names to use if showMonthNames is true
-  //Replace for localisation, e.g. Form.editors.Date.monthNames = ['Janvier', 'Fevrier'...]
-  monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
-});
-
-/**
- * DateTime editor
- *
- * @param {Editor} [options.DateEditor]           Date editor view to use (not definition)
- * @param {Number} [options.schema.minsInterval]  Interval between minutes. Default: 15
- */
-Form.editors.DateTime = Form.editors.Base.extend({
-
-  events: {
-    'change select':  function() {
-      this.updateHidden();
-      this.trigger('change', this);
-    },
-    'focus select':   function() {
-      if (this.hasFocus) return;
-      this.trigger('focus', this);
-    },
-    'blur select':    function() {
-      if (!this.hasFocus) return;
-      var self = this;
-      setTimeout(function() {
-        if (self.$('select:focus')[0]) return;
-        self.trigger('blur', self);
-      }, 0);
-    }
-  },
-
-  initialize: function(options) {
-    options = options || {};
-
-    Form.editors.Base.prototype.initialize.call(this, options);
-
-    //Option defaults
-    this.options = _.extend({
-      DateEditor: Form.editors.DateTime.DateEditor
-    }, options);
-
-    //Schema defaults
-    this.schema = _.extend({
-      minsInterval: 15
-    }, options.schema || {});
-
-    //Create embedded date editor
-    this.dateEditor = new this.options.DateEditor(options);
-
-    this.value = this.dateEditor.value;
-
-    //Template
-    this.template = options.template || this.constructor.template;
-  },
-
-  render: function() {
-    function pad(n) {
-      return n < 10 ? '0' + n : n;
-    }
-
-    var schema = this.schema,
-        $ = Backbone.$;
-
-    //Create options
-    var hoursOptions = _.map(_.range(0, 24), function(hour) {
-      return '<option value="'+hour+'">' + pad(hour) + '</option>';
-    });
-
-    var minsOptions = _.map(_.range(0, 60, schema.minsInterval), function(min) {
-      return '<option value="'+min+'">' + pad(min) + '</option>';
-    });
-
-    //Render time selects
-    var $el = $($.trim(this.template({
-      hours: hoursOptions.join(),
-      mins: minsOptions.join()
-    })));
-
-    //Include the date editor
-    $el.find('[data-date]').append(this.dateEditor.render().el);
-
-    //Store references to selects
-    this.$hour = $el.find('select[data-type="hour"]');
-    this.$min = $el.find('select[data-type="min"]');
-
-    //Get the hidden date field to store values in case POSTed to server
-    this.$hidden = $el.find('input[type="hidden"]');
-
-    //Set time
-    this.setValue(this.value);
-
-    this.setElement($el);
-    this.$el.attr('id', this.id);
-    this.$el.attr('name', this.getName());
-
-    if (this.hasFocus) this.trigger('blur', this);
-
-    return this;
-  },
-
-  /**
-   * @return {Date}   Selected datetime
-   */
-  getValue: function() {
-    var date = this.dateEditor.getValue();
-
-    var hour = this.$hour.val(),
-        min = this.$min.val();
-
-    if (!date || !hour || !min) return null;
-
-    date.setHours(hour);
-    date.setMinutes(min);
-
-    return date;
-  },
-
-  /**
-   * @param {Date}
-   */
-  setValue: function(date) {
-    if (!_.isDate(date)) date = new Date(date);
-
-    this.dateEditor.setValue(date);
-
-    this.$hour.val(date.getHours());
-    this.$min.val(date.getMinutes());
-
-    this.updateHidden();
-  },
-
-  focus: function() {
-    if (this.hasFocus) return;
-
-    this.$('select').first().focus();
-  },
-
-  blur: function() {
-    if (!this.hasFocus) return;
-
-    this.$('select:focus').blur();
-  },
-
-  /**
-   * Update the hidden input which is maintained for when submitting a form
-   * via a normal browser POST
-   */
-  updateHidden: function() {
-    var val = this.getValue();
-    if (_.isDate(val)) val = val.toISOString();
-
-    this.$hidden.val(val);
-  },
-
-  /**
-   * Remove the Date editor before removing self
-   */
-  remove: function() {
-    this.dateEditor.remove();
-
-    Form.editors.Base.prototype.remove.call(this);
-  }
-
-}, {
-  //STATICS
-  template: _.template('\
-    <div class="bbf-datetime">\
-      <div class="bbf-date-container" data-date></div>\
-      <select data-type="hour"><%= hours %></select>\
-      :\
-      <select data-type="min"><%= mins %></select>\
-    </div>\
-  ', null, Form.templateSettings),
-
-  //The date editor to use (constructor function, not instance)
-  DateEditor: Form.editors.Date
-});
-
-
-
-  //Metadata
-  Form.VERSION = '0.14.1';
-
-  //Exports
-  Backbone.Form = Form;
-
-  return Form;
-});
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/backbone-forms.min.js b/security-admin/src/main/webapp/libs/bower/backbone-forms/js/backbone-forms.min.js
deleted file mode 100644
index 40c9b0129..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/backbone-forms.min.js
+++ /dev/null
@@ -1 +0,0 @@
-define(["jquery","underscore","backbone"],function(e,t,n){var r=n.View.extend({events:{submit:function(e){this.trigger("submit",e)}},initialize:function(e){var n=this;e=this.options=t.extend({submitButton:!1},e);var r=this.schema=function(){if(e.schema)return t.result(e,"schema");var r=e.model;return r&&r.schema?t.result(r,"schema"):n.schema?t.result(n,"schema"):{}}();t.extend(this,t.pick(e,"model","data","idPrefix","templateData"));var i=this.constructor;this.template=e.template||this.t [...]
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/bootstrap.js b/security-admin/src/main/webapp/libs/bower/backbone-forms/js/bootstrap.js
deleted file mode 100644
index 7e14fdeb3..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/bootstrap.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/** 
- * Include this template file after backbone-forms.amd.js to override the default templates
- *
- * 'data-*' attributes control where elements are placed
- */
-define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Backbone) {
-  var Form = Backbone.Form;
-
-  
-  /**
-   * Bootstrap 3 templates
-   */
-  Form.template = _.template('\
-    <form class="form-horizontal" role="form">\
-      <div data-fieldsets></div>\
-      <% if (submitButton) { %>\
-        <button type="submit" class="btn"><%= submitButton %></button>\
-      <% } %>\
-    </form>\
-  ');
-
-
-  Form.Fieldset.template = _.template('\
-    <fieldset data-fields>\
-      <% if (legend) { %>\
-        <legend><%= legend %></legend>\
-      <% } %>\
-    </fieldset>\
-  ');
-
-
-  Form.Field.template = _.template('\
-    <div class="form-group field-<%= key %>">\
-      <label class="col-sm-3 control-label" for="<%= editorId %>"><%= title %></label>\
-      <div class="col-sm-4">\
-        <span data-editor></span>\
-        <p class="help-block" data-error></p>\
-        <p class="help-block"><%= help %></p>\
-      </div>\
-    </div>\
-  ');
-
-
-  Form.NestedField.template = _.template('\
-    <div class="field-<%= key %>">\
-      <div title="<%= title %>" class="input-xlarge">\
-        <span data-editor></span>\
-        <div class="help-inline" data-error></div>\
-      </div>\
-      <div class="help-block"><%= help %></div>\
-    </div>\
-  ');
-
-  Form.editors.Base.prototype.className = 'form-control';
-  Form.Field.errorClassName = 'has-error';
-
-
-  if (Form.editors.List) {
-
-    Form.editors.List.template = _.template('\
-      <div class="bbf-list">\
-        <ul class="list-unstyled clearfix" data-items></ul>\
-        <button type="button" class="btn bbf-add" data-action="add">Add</button>\
-      </div>\
-    ');
-
-
-    Form.editors.List.Item.template = _.template('\
-      <li class="clearfix">\
-        <div class="pull-left" data-editor></div>\
-        <button type="button" class="btn bbf-del" data-action="remove">&times;</button>\
-      </li>\
-    ');
-    
-
-    Form.editors.List.Object.template = Form.editors.List.NestedModel.template = _.template('\
-      <div class="bbf-list-modal"><%= summary %></div>\
-    ');
-
-  }
-
-
-});
diff --git a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/list.js b/security-admin/src/main/webapp/libs/bower/backbone-forms/js/list.js
deleted file mode 100644
index 48439c0d7..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/list.js
+++ /dev/null
@@ -1,658 +0,0 @@
-define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Backbone) {
-
-  ;(function(Form) {
-
-  /**
-   * List editor
-   * 
-   * An array editor. Creates a list of other editor items.
-   *
-   * Special options:
-   * @param {String} [options.schema.itemType]          The editor type for each item in the list. Default: 'Text'
-   * @param {String} [options.schema.confirmDelete]     Text to display in a delete confirmation dialog. If falsey, will not ask for confirmation.
-   */
-  Form.editors.List = Form.editors.Base.extend({
-
-    events: {
-      'click [data-action="add"]': function(event) {
-        event.preventDefault();
-        this.addItem(null, true);
-      }
-    },
-
-    initialize: function(options) {
-      options = options || {};
-
-      var editors = Form.editors;
-
-      editors.Base.prototype.initialize.call(this, options);
-
-      var schema = this.schema;
-      if (!schema) throw new Error("Missing required option 'schema'");
-
-      this.template = options.template || this.constructor.template;
-
-      //Determine the editor to use
-      this.Editor = (function() {
-        var type = schema.itemType;
-
-        //Default to Text
-        if (!type) return editors.Text;
-
-        //Use List-specific version if available
-        if (editors.List[type]) return editors.List[type];
-
-        //Or whichever was passed
-        return editors[type];
-      })();
-
-      this.items = [];
-    },
-
-    render: function() {
-      var self = this,
-          value = this.value || [],
-          $ = Backbone.$;
-
-      //Create main element
-      var $el = $($.trim(this.template()));
-
-      //Store a reference to the list (item container)
-      this.$list = $el.is('[data-items]') ? $el : $el.find('[data-items]');
-
-      //Add existing items
-      if (value.length) {
-        _.each(value, function(itemValue) {
-          self.addItem(itemValue);
-        });
-      }
-
-      //If no existing items create an empty one, unless the editor specifies otherwise
-      else {
-        if (!this.Editor.isAsync) this.addItem();
-      }
-
-      this.setElement($el);
-      this.$el.attr('id', this.id);
-      this.$el.attr('name', this.key);
-            
-      if (this.hasFocus) this.trigger('blur', this);
-      
-      return this;
-    },
-
-    /**
-     * Add a new item to the list
-     * @param {Mixed} [value]           Value for the new item editor
-     * @param {Boolean} [userInitiated] If the item was added by the user clicking 'add'
-     */
-    addItem: function(value, userInitiated) {
-      var self = this,
-          editors = Form.editors;
-
-      //Create the item
-      var item = new editors.List.Item({
-        list: this,
-        form: this.form,
-        schema: this.schema,
-        value: value,
-        Editor: this.Editor,
-        key: this.key
-      }).render();
-      
-      var _addItem = function() {
-        self.items.push(item);
-        self.$list.append(item.el);
-        
-        item.editor.on('all', function(event) {
-          if (event === 'change') return;
-
-          // args = ["key:change", itemEditor, fieldEditor]
-          var args = _.toArray(arguments);
-          args[0] = 'item:' + event;
-          args.splice(1, 0, self);
-          // args = ["item:key:change", this=listEditor, itemEditor, fieldEditor]
-
-          editors.List.prototype.trigger.apply(this, args);
-        }, self);
-
-        item.editor.on('change', function() {
-          if (!item.addEventTriggered) {
-            item.addEventTriggered = true;
-            this.trigger('add', this, item.editor);
-          }
-          this.trigger('item:change', this, item.editor);
-          this.trigger('change', this);
-        }, self);
-
-        item.editor.on('focus', function() {
-          if (this.hasFocus) return;
-          this.trigger('focus', this);
-        }, self);
-        item.editor.on('blur', function() {
-          if (!this.hasFocus) return;
-          var self = this;
-          setTimeout(function() {
-            if (_.find(self.items, function(item) { return item.editor.hasFocus; })) return;
-            self.trigger('blur', self);
-          }, 0);
-        }, self);
-        
-        if (userInitiated || value) {
-          item.addEventTriggered = true;
-        }
-        
-        if (userInitiated) {
-          self.trigger('add', self, item.editor);
-          self.trigger('change', self);
-        }
-      };
-
-      //Check if we need to wait for the item to complete before adding to the list
-      if (this.Editor.isAsync) {
-        item.editor.on('readyToAdd', _addItem, this);
-      }
-
-      //Most editors can be added automatically
-      else {
-        _addItem();
-        item.editor.focus();
-      }
-      
-      return item;
-    },
-
-    /**
-     * Remove an item from the list
-     * @param {List.Item} item
-     */
-    removeItem: function(item) {
-      //Confirm delete
-      var confirmMsg = this.schema.confirmDelete;
-      if (confirmMsg && !confirm(confirmMsg)) return;
-
-      var index = _.indexOf(this.items, item);
-
-      this.items[index].remove();
-      this.items.splice(index, 1);
-      
-      if (item.addEventTriggered) {
-        this.trigger('remove', this, item.editor);
-        this.trigger('change', this);
-      }
-
-      if (!this.items.length && !this.Editor.isAsync) this.addItem();
-    },
-
-    getValue: function() {
-      var values = _.map(this.items, function(item) {
-        return item.getValue();
-      });
-
-      //Filter empty items
-      return _.without(values, undefined, '');
-    },
-
-    setValue: function(value) {
-      this.value = value;
-      this.render();
-    },
-    
-    focus: function() {
-      if (this.hasFocus) return;
-
-      if (this.items[0]) this.items[0].editor.focus();
-    },
-    
-    blur: function() {
-      if (!this.hasFocus) return;
-
-      var focusedItem = _.find(this.items, function(item) { return item.editor.hasFocus; });
-      
-      if (focusedItem) focusedItem.editor.blur();
-    },
-
-    /**
-     * Override default remove function in order to remove item views
-     */
-    remove: function() {
-      _.invoke(this.items, 'remove');
-
-      Form.editors.Base.prototype.remove.call(this);
-    },
-    
-    /**
-     * Run validation
-     * 
-     * @return {Object|Null}
-     */
-    validate: function() {
-      if (!this.validators) return null;
-
-      //Collect errors
-      var errors = _.map(this.items, function(item) {
-        return item.validate();
-      });
-
-      //Check if any item has errors
-      var hasErrors = _.compact(errors).length ? true : false;
-      if (!hasErrors) return null;
-
-      //If so create a shared error
-      var fieldError = {
-        type: 'list',
-        message: 'Some of the items in the list failed validation',
-        errors: errors
-      };
-
-      return fieldError;
-    }
-  }, {
-
-    //STATICS
-    template: _.template('\
-      <div>\
-        <div data-items></div>\
-        <button type="button" data-action="add">Add</button>\
-      </div>\
-    ', null, Form.templateSettings)
-
-  });
-
-
-  /**
-   * A single item in the list
-   *
-   * @param {editors.List} options.list The List editor instance this item belongs to
-   * @param {Function} options.Editor   Editor constructor function
-   * @param {String} options.key        Model key
-   * @param {Mixed} options.value       Value
-   * @param {Object} options.schema     Field schema
-   */
-  Form.editors.List.Item = Form.editors.Base.extend({
-
-    events: {
-      'click [data-action="remove"]': function(event) {
-        event.preventDefault();
-        this.list.removeItem(this);
-      },
-      'keydown input[type=text]': function(event) {
-        if(event.keyCode !== 13) return;
-        event.preventDefault();
-        this.list.addItem();
-        this.list.$list.find("> li:last input").focus();
-      }
-    },
-
-    initialize: function(options) {
-      this.list = options.list;
-      this.schema = options.schema || this.list.schema;
-      this.value = options.value;
-      this.Editor = options.Editor || Form.editors.Text;
-      this.key = options.key;
-      this.template = options.template || this.schema.itemTemplate || this.constructor.template;
-      this.errorClassName = options.errorClassName || this.constructor.errorClassName;
-      this.form = options.form;
-    },
-
-    render: function() {
-      var $ = Backbone.$;
-      
-      //Create editor
-      this.editor = new this.Editor({
-        key: this.key,
-        schema: this.schema,
-        value: this.value,
-        list: this.list,
-        item: this,
-        form: this.form
-      }).render();
-
-      //Create main element
-      var $el = $($.trim(this.template()));
-
-      $el.find('[data-editor]').append(this.editor.el);
-
-      //Replace the entire element so there isn't a wrapper tag
-      this.setElement($el);
-        
-      return this;
-    },
-
-    getValue: function() {
-      return this.editor.getValue();
-    },
-
-    setValue: function(value) {
-      this.editor.setValue(value);
-    },
-    
-    focus: function() {
-      this.editor.focus();
-    },
-    
-    blur: function() {
-      this.editor.blur();
-    },
-
-    remove: function() {
-      this.editor.remove();
-
-      Backbone.View.prototype.remove.call(this);
-    },
-
-    validate: function() {
-      var value = this.getValue(),
-          formValues = this.list.form ? this.list.form.getValue() : {},
-          validators = this.schema.validators,
-          getValidator = this.getValidator;
-
-      if (!validators) return null;
-
-      //Run through validators until an error is found
-      var error = null;
-      _.every(validators, function(validator) {
-        error = getValidator(validator)(value, formValues);
-
-        return error ? false : true;
-      });
-
-      //Show/hide error
-      if (error){
-        this.setError(error);
-      } else {
-        this.clearError();
-      }
-
-      //Return error to be aggregated by list
-      return error ? error : null;
-    },
-
-    /**
-     * Show a validation error
-     */
-    setError: function(err) {
-      this.$el.addClass(this.errorClassName);
-      this.$el.attr('title', err.message);
-    },
-
-    /**
-     * Hide validation errors
-     */
-    clearError: function() {
-      this.$el.removeClass(this.errorClassName);
-      this.$el.attr('title', null);
-    }
-  }, {
-
-    //STATICS
-    template: _.template('\
-      <div>\
-        <span data-editor></span>\
-        <button type="button" data-action="remove">&times;</button>\
-      </div>\
-    ', null, Form.templateSettings),
-
-    errorClassName: 'error'
-
-  });
-
-
-  /**
-   * Base modal object editor for use with the List editor; used by Object 
-   * and NestedModal list types
-   */
-  Form.editors.List.Modal = Form.editors.Base.extend({
-
-    events: {
-      'click': 'openEditor'
-    },
-
-    /**
-     * @param {Object} options
-     * @param {Form} options.form                       The main form
-     * @param {Function} [options.schema.itemToString]  Function to transform the value for display in the list.
-     * @param {String} [options.schema.itemType]        Editor type e.g. 'Text', 'Object'.
-     * @param {Object} [options.schema.subSchema]       Schema for nested form,. Required when itemType is 'Object'
-     * @param {Function} [options.schema.model]         Model constructor function. Required when itemType is 'NestedModel'
-     */
-    initialize: function(options) {
-      options = options || {};
-      
-      Form.editors.Base.prototype.initialize.call(this, options);
-      
-      //Dependencies
-      if (!Form.editors.List.Modal.ModalAdapter) throw new Error('A ModalAdapter is required');
-
-      this.form = options.form;
-      if (!options.form) throw new Error('Missing required option: "form"');
-
-      //Template
-      this.template = options.template || this.constructor.template;
-    },
-
-    /**
-     * Render the list item representation
-     */
-    render: function() {
-      var self = this;
-
-      //New items in the list are only rendered when the editor has been OK'd
-      if (_.isEmpty(this.value)) {
-        this.openEditor();
-      }
-
-      //But items with values are added automatically
-      else {
-        this.renderSummary();
-
-        setTimeout(function() {
-          self.trigger('readyToAdd');
-        }, 0);
-      }
-
-      if (this.hasFocus) this.trigger('blur', this);
-
-      return this;
-    },
-
-    /**
-     * Renders the list item representation
-     */
-    renderSummary: function() {
-      this.$el.html($.trim(this.template({
-        summary: this.getStringValue()
-      })));
-    },
-
-    /**
-     * Function which returns a generic string representation of an object
-     *
-     * @param {Object} value
-     * 
-     * @return {String}
-     */
-    itemToString: function(value) {
-      var createTitle = function(key) {
-        var context = { key: key };
-
-        return Form.Field.prototype.createTitle.call(context);
-      };
-
-      value = value || {};
-
-      //Pretty print the object keys and values
-      var parts = [];
-      _.each(this.nestedSchema, function(schema, key) {
-        var desc = schema.title ? schema.title : createTitle(key),
-            val = value[key];
-
-        if (_.isUndefined(val) || _.isNull(val)) val = '';
-
-        parts.push(desc + ': ' + val);
-      });
-
-      return parts.join('<br />');
-    },
-
-    /**
-     * Returns the string representation of the object value
-     */
-    getStringValue: function() {
-      var schema = this.schema,
-          value = this.getValue();
-
-      if (_.isEmpty(value)) return '[Empty]';
-
-      //If there's a specified toString use that
-      if (schema.itemToString) return schema.itemToString(value);
-      
-      //Otherwise use the generic method or custom overridden method
-      return this.itemToString(value);
-    },
-
-    openEditor: function() {
-      var self = this,
-          ModalForm = this.form.constructor;
-
-      var form = this.modalForm = new ModalForm({
-        schema: this.nestedSchema,
-        data: this.value
-      });
-
-      var modal = this.modal = new Form.editors.List.Modal.ModalAdapter({
-        content: form,
-        animate: true
-      });
-
-      modal.open();
-
-      this.trigger('open', this);
-      this.trigger('focus', this);
-
-      modal.on('cancel', this.onModalClosed, this);
-      
-      modal.on('ok', _.bind(this.onModalSubmitted, this));
-    },
-
-    /**
-     * Called when the user clicks 'OK'.
-     * Runs validation and tells the list when ready to add the item
-     */
-    onModalSubmitted: function() {
-      var modal = this.modal,
-          form = this.modalForm,
-          isNew = !this.value;
-
-      //Stop if there are validation errors
-      var error = form.validate();
-      if (error) return modal.preventClose();
-
-      //Store form value
-      this.value = form.getValue();
-
-      //Render item
-      this.renderSummary();
-
-      if (isNew) this.trigger('readyToAdd');
-      
-      this.trigger('change', this);
-
-      this.onModalClosed();
-    },
-
-    /**
-     * Cleans up references, triggers events. To be called whenever the modal closes
-     */
-    onModalClosed: function() {
-      this.modal = null;
-      this.modalForm = null;
-
-      this.trigger('close', this);
-      this.trigger('blur', this);
-    },
-
-    getValue: function() {
-      return this.value;
-    },
-
-    setValue: function(value) {
-      this.value = value;
-    },
-    
-    focus: function() {
-      if (this.hasFocus) return;
-
-      this.openEditor();
-    },
-    
-    blur: function() {
-      if (!this.hasFocus) return;
-      
-      if (this.modal) {
-        this.modal.trigger('cancel');
-      }
-    }
-  }, {
-    //STATICS
-    template: _.template('\
-      <div><%= summary %></div>\
-    ', null, Form.templateSettings),
-
-    //The modal adapter that creates and manages the modal dialog.
-    //Defaults to BootstrapModal (http://github.com/powmedia/backbone.bootstrap-modal)
-    //Can be replaced with another adapter that implements the same interface.
-    ModalAdapter: Backbone.BootstrapModal,
-    
-    //Make the wait list for the 'ready' event before adding the item to the list
-    isAsync: true
-  });
-
-
-  Form.editors.List.Object = Form.editors.List.Modal.extend({
-    initialize: function () {
-      Form.editors.List.Modal.prototype.initialize.apply(this, arguments);
-
-      var schema = this.schema;
-
-      if (!schema.subSchema) throw new Error('Missing required option "schema.subSchema"');
-
-      this.nestedSchema = schema.subSchema;
-    }
-  });
-
-
-  Form.editors.List.NestedModel = Form.editors.List.Modal.extend({
-    initialize: function() {
-      Form.editors.List.Modal.prototype.initialize.apply(this, arguments);
-
-      var schema = this.schema;
-
-      if (!schema.model) throw new Error('Missing required option "schema.model"');
-
-      var nestedSchema = schema.model.prototype.schema;
-
-      this.nestedSchema = (_.isFunction(nestedSchema)) ? nestedSchema() : nestedSchema;
-    },
-
-    /**
-     * Returns the string representation of the object value
-     */
-    getStringValue: function() {
-      var schema = this.schema,
-          value = this.getValue();
-
-      if (_.isEmpty(value)) return null;
-
-      //If there's a specified toString use that
-      if (schema.itemToString) return schema.itemToString(value);
-      
-      //Otherwise use the model
-      return new (schema.model)(value).toString();
-    }
-  });
-
-})(Backbone.Form);
-
-
-});
diff --git a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/list.min.js b/security-admin/src/main/webapp/libs/bower/backbone-forms/js/list.min.js
deleted file mode 100644
index 7068cb2b3..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/list.min.js
+++ /dev/null
@@ -1 +0,0 @@
-define(["jquery","underscore","backbone","backbone-forms"],function(e,t,n){(function(r){r.editors.List=r.editors.Base.extend({events:{'click [data-action="add"]':function(e){e.preventDefault(),this.addItem(null,!0)}},initialize:function(e){e=e||{};var t=r.editors;t.Base.prototype.initialize.call(this,e);var n=this.schema;if(!n)throw new Error("Missing required option 'schema'");this.template=e.template||this.constructor.template,this.Editor=function(){var e=n.itemType;return e?t.List[e]? [...]
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/old.js b/security-admin/src/main/webapp/libs/bower/backbone-forms/js/old.js
deleted file mode 100644
index 67ccb98a8..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone-forms/js/old.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/** 
- * Include this template file after backbone-forms.amd.js to override the default templates
- *
- * 'data-*' attributes control where elements are placed
- */
-define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Backbone) {
-  var Form = Backbone.Form;
-
-    
-  /**
-   * Templates to match those used previous versions of Backbone Form, i.e. <= 0.11.0.
-   * NOTE: These templates are deprecated.
-   */
-  Form.template = _.template('\
-    <form class="bbf-form">\
-      <div data-fieldsets></div>\
-      <% if (submitButton) { %>\
-        <button type="submit"><%= submitButton %></button>\
-      <% } %>\
-    </form>\
-  ');
-
-
-  Form.Fieldset.template = _.template('\
-    <fieldset>\
-      <% if (legend) { %>\
-        <legend><%= legend %></legend>\
-      <% } %>\
-      <ul data-fields></ul>\
-    </fieldset>\
-  ');
-
-
-  Form.Field.template = _.template('\
-    <li class="bbf-field field-<%= key %>">\
-      <label for="<%= editorId %>"><%= title %></label>\
-      <div class="bbf-editor" data-editor></div>\
-      <div class="bbf-help"><%= help %></div>\
-      <div class="bbf-error" data-error></div>\
-    </li>\
-  ');
-
-
-  Form.NestedField.template = _.template('\
-    <li class="bbf-field bbf-nested-field field-<%= key %>">\
-      <label for="<%= editorId %>"><%= title %></label>\
-      <div class="bbf-editor" data-editor></div>\
-      <div class="bbf-help"><%= help %></div>\
-      <div class="bbf-error" data-error></div>\
-    </li>\
-  ');
-
-
-  Form.editors.Date.template = _.template('\
-    <div class="bbf-date">\
-      <select class="bbf-date" data-type="date"><%= dates %></select>\
-      <select class="bbf-month" data-type="month"><%= months %></select>\
-      <select class="bbf-year" data-type="year"><%= years %></select>\
-    </div>\
-  ');
-
-
-  Form.editors.DateTime.template = _.template('\
-    <div class="bbf-datetime">\
-      <div class="bbf-date-container" data-date></div>\
-      <select data-type="hour"><%= hours %></select>\
-      :\
-      <select data-type="min"><%= mins %></select>\
-    </div>\
-  ');
-
-
-  if (Form.editors.List) {
-  
-    Form.editors.List.template = _.template('\
-      <div class="bbf-list">\
-        <ul data-items></ul>\
-        <div class="bbf-actions"><button type="button" data-action="add">Add</div>\
-      </div>\
-    ');
-   
-   
-    Form.editors.List.Item.template = _.template('\
-      <li>\
-        <button type="button" data-action="remove" class="bbf-remove">&times;</button>\
-        <div class="bbf-editor-container" data-editor></div>\
-      </li>\
-    ');
-    
-   
-    Form.editors.List.Object.template = Form.editors.List.NestedModel.template = _.template('\
-      <div class="bbf-list-modal"><%= summary %></div>\
-    ');
-
-  }
-
-
-
-});
diff --git a/security-admin/src/main/webapp/libs/bower/backbone-pageable/js/backbone-pageable.js b/security-admin/src/main/webapp/libs/bower/backbone-pageable/js/backbone-pageable.js
deleted file mode 100644
index 9accadd1b..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone-pageable/js/backbone-pageable.js
+++ /dev/null
@@ -1,1327 +0,0 @@
-/*
-  backbone-pageable 1.3.2
-  http://github.com/wyuenho/backbone-pageable
-
-  Copyright (c) 2013 Jimmy Yuen Ho Wong
-  Licensed under the MIT @license.
-*/
-
-(function (factory) {
-
-  // CommonJS
-  if (typeof exports == "object") {
-    module.exports = factory(require("underscore"), require("backbone"));
-  }
-  // AMD
-  else if (typeof define == "function" && define.amd) {
-    define(["underscore", "backbone"], factory);
-  }
-  // Browser
-  else if (typeof _ !== "undefined" && typeof Backbone !== "undefined") {
-    var oldPageableCollection = Backbone.PageableCollection;
-    var PageableCollection = factory(_, Backbone);
-
-    /**
-       __BROWSER ONLY__
-
-       If you already have an object named `PageableCollection` attached to the
-       `Backbone` module, you can use this to return a local reference to this
-       Backbone.PageableCollection class and reset the name
-       Backbone.PageableCollection to its previous definition.
-
-           // The left hand side gives you a reference to this
-           // Backbone.PageableCollection implementation, the right hand side
-           // resets Backbone.PageableCollection to your other
-           // Backbone.PageableCollection.
-           var PageableCollection = Backbone.PageableCollection.noConflict();
-
-       @static
-       @member Backbone.PageableCollection
-       @return {Backbone.PageableCollection}
-    */
-    Backbone.PageableCollection.noConflict = function () {
-      Backbone.PageableCollection = oldPageableCollection;
-      return PageableCollection;
-    };
-  }
-
-}(function (_, Backbone) {
-
-  "use strict";
-
-  var _extend = _.extend;
-  var _omit = _.omit;
-  var _clone = _.clone;
-  var _each = _.each;
-  var _pick = _.pick;
-  var _contains = _.contains;
-  var _isEmpty = _.isEmpty;
-  var _pairs = _.pairs;
-  var _invert = _.invert;
-  var _isArray = _.isArray;
-  var _isFunction = _.isFunction;
-  var _isObject = _.isObject;
-  var _keys = _.keys;
-  var _isUndefined = _.isUndefined;
-  var _result = _.result;
-  var ceil = Math.ceil;
-  var floor = Math.floor;
-  var max = Math.max;
-
-  var BBColProto = Backbone.Collection.prototype;
-
-  function finiteInt (val, name) {
-    if (!_.isNumber(val) || _.isNaN(val) || !_.isFinite(val) || ~~val !== val) {
-      throw new TypeError("`" + name + "` must be a finite integer");
-    }
-    return val;
-  }
-
-  function queryStringToParams (qs) {
-    var kvp, k, v, ls, params = {}, decode = decodeURIComponent;
-    var kvps = qs.split('&');
-    for (var i = 0, l = kvps.length; i < l; i++) {
-      var param = kvps[i];
-      kvp = param.split('='), k = kvp[0], v = kvp[1] || true;
-      k = decode(k), ls = params[k];
-      if (_isArray(ls)) ls.push(v);
-      else if (ls) params[k] = [ls, v];
-      else params[k] = v;
-    }
-    return params;
-  }
-
-  var PARAM_TRIM_RE = /[\s'"]/g;
-  var URL_TRIM_RE = /[<>\s'"]/g;
-
-  /**
-     Drop-in replacement for Backbone.Collection. Supports server-side and
-     client-side pagination and sorting. Client-side mode also support fully
-     multi-directional synchronization of changes between pages.
-
-     @class Backbone.PageableCollection
-     @extends Backbone.Collection
-  */
-  var PageableCollection = Backbone.PageableCollection = Backbone.Collection.extend({
-
-    /**
-       The container object to store all pagination states.
-
-       You can override the default state by extending this class or specifying
-       them in an `options` hash to the constructor.
-
-       @property {Object} state
-
-       @property {0|1} [state.firstPage=1] The first page index. Set to 0 if
-       your server API uses 0-based indices. You should only override this value
-       during extension, initialization or reset by the server after
-       fetching. This value should be read only at other times.
-
-       @property {number} [state.lastPage=null] The last page index. This value
-       is __read only__ and it's calculated based on whether `firstPage` is 0 or
-       1, during bootstrapping, fetching and resetting. Please don't change this
-       value under any circumstances.
-
-       @property {number} [state.currentPage=null] The current page index. You
-       should only override this value during extension, initialization or reset
-       by the server after fetching. This value should be read only at other
-       times. Can be a 0-based or 1-based index, depending on whether
-       `firstPage` is 0 or 1. If left as default, it will be set to `firstPage`
-       on initialization.
-
-       @property {number} [state.pageSize=25] How many records to show per
-       page. This value is __read only__ after initialization, if you want to
-       change the page size after initialization, you must call #setPageSize.
-
-       @property {number} [state.totalPages=null] How many pages there are. This
-       value is __read only__ and it is calculated from `totalRecords`.
-
-       @property {number} [state.totalRecords=null] How many records there
-       are. This value is __required__ under server mode. This value is optional
-       for client mode as the number will be the same as the number of models
-       during bootstrapping and during fetching, either supplied by the server
-       in the metadata, or calculated from the size of the response.
-
-       @property {string} [state.sortKey=null] The model attribute to use for
-       sorting.
-
-       @property {-1|0|1} [state.order=-1] The order to use for sorting. Specify
-       -1 for ascending order or 1 for descending order. If 0, no client side
-       sorting will be done and the order query parameter will not be sent to
-       the server during a fetch.
-    */
-    state: {
-      firstPage: 1,
-      lastPage: null,
-      currentPage: null,
-      pageSize: 25,
-      totalPages: null,
-      totalRecords: null,
-      sortKey: null,
-      order: -1
-    },
-
-    /**
-       @property {"server"|"client"|"infinite"} [mode="server"] The mode of
-       operations for this collection. `"server"` paginates on the server-side,
-       `"client"` paginates on the client-side and `"infinite"` paginates on the
-       server-side for APIs that do not support `totalRecords`.
-    */
-    mode: "server",
-
-    /**
-       A translation map to convert Backbone.PageableCollection state attributes
-       to the query parameters accepted by your server API.
-
-       You can override the default state by extending this class or specifying
-       them in `options.queryParams` object hash to the constructor.
-
-       @property {Object} queryParams
-       @property {string} [queryParams.currentPage="page"]
-       @property {string} [queryParams.pageSize="per_page"]
-       @property {string} [queryParams.totalPages="total_pages"]
-       @property {string} [queryParams.totalRecords="total_entries"]
-       @property {string} [queryParams.sortKey="sort_by"]
-       @property {string} [queryParams.order="order"]
-       @property {string} [queryParams.directions={"-1": "asc", "1": "desc"}] A
-       map for translating a Backbone.PageableCollection#state.order constant to
-       the ones your server API accepts.
-    */
-    queryParams: {
-      currentPage: "page",
-      pageSize: "per_page",
-      totalPages: "total_pages",
-      totalRecords: "total_entries",
-      sortKey: "sort_by",
-      order: "order",
-      directions: {
-        "-1": "asc",
-        "1": "desc"
-      }
-    },
-
-    /**
-       __CLIENT MODE ONLY__
-
-       This collection is the internal storage for the bootstrapped or fetched
-       models. You can use this if you want to operate on all the pages.
-
-       @property {Backbone.Collection} fullCollection
-    */
-
-    /**
-       Given a list of models or model attributues, bootstraps the full
-       collection in client mode or infinite mode, or just the page you want in
-       server mode.
-
-       If you want to initialize a collection to a different state than the
-       default, you can specify them in `options.state`. Any state parameters
-       supplied will be merged with the default. If you want to change the
-       default mapping from #state keys to your server API's query parameter
-       names, you can specifiy an object hash in `option.queryParams`. Likewise,
-       any mapping provided will be merged with the default. Lastly, all
-       Backbone.Collection constructor options are also accepted.
-
-       See:
-
-       - Backbone.PageableCollection#state
-       - Backbone.PageableCollection#queryParams
-       - [Backbone.Collection#initialize](http://backbonejs.org/#Collection-constructor)
-
-       @param {Array.<Object>} [models]
-
-       @param {Object} [options]
-
-       @param {function(*, *): number} [options.comparator] If specified, this
-       comparator is set to the current page under server mode, or the #fullCollection
-       otherwise.
-
-       @param {boolean} [options.full] If `false` and either a
-       `options.comparator` or `sortKey` is defined, the comparator is attached
-       to the current page. Default is `true` under client or infinite mode and
-       the comparator will be attached to the #fullCollection.
-
-       @param {Object} [options.state] The state attributes overriding the defaults.
-
-       @param {string} [options.state.sortKey] The model attribute to use for
-       sorting. If specified instead of `options.comparator`, a comparator will
-       be automatically created using this value, and optionally a sorting order
-       specified in `options.state.order`. The comparator is then attached to
-       the new collection instance.
-
-       @param {-1|1} [options.state.order] The order to use for sorting. Specify
-       -1 for ascending order and 1 for descending order.
-
-       @param {Object} [options.queryParam]
-    */
-    constructor: function (models, options) {
-
-      Backbone.Collection.apply(this, arguments);
-
-      options = options || {};
-
-      var mode = this.mode = options.mode || this.mode || PageableProto.mode;
-
-      var queryParams = _extend({}, PageableProto.queryParams, this.queryParams,
-                                options.queryParams || {});
-
-      queryParams.directions = _extend({},
-                                       PageableProto.queryParams.directions,
-                                       this.queryParams.directions,
-                                       queryParams.directions || {});
-
-      this.queryParams = queryParams;
-
-      var state = this.state = _extend({}, PageableProto.state, this.state,
-                                       options.state || {});
-
-      state.currentPage = state.currentPage == null ?
-        state.firstPage :
-        state.currentPage;
-
-      if (!_isArray(models)) models = models ? [models] : [];
-
-      if (mode != "server" && state.totalRecords == null && !_isEmpty(models)) {
-        state.totalRecords = models.length;
-      }
-
-      this.switchMode(mode, _extend({fetch: false,
-                                     resetState: false,
-                                     models: models}, options));
-
-      var comparator = options.comparator;
-
-      if (state.sortKey && !comparator) {
-        this.setSorting(state.sortKey, state.order, options);
-      }
-
-      if (mode != "server") {
-        var fullCollection = this.fullCollection;
-
-        if (comparator && options.full) {
-          delete this.comparator;
-          fullCollection.comparator = comparator;
-        }
-
-        if (options.full) fullCollection.sort();
-
-        // make sure the models in the current page and full collection have the
-        // same references
-        if (models && !_isEmpty(models)) {
-          this.getPage(state.currentPage);
-          models.splice.apply(models, [0, models.length].concat(this.models));
-        }
-      }
-
-      this._initState = _clone(this.state);
-    },
-
-    /**
-       Makes a Backbone.Collection that contains all the pages.
-
-       @private
-       @param {Array.<Object|Backbone.Model>} models
-       @param {Object} options Options for Backbone.Collection constructor.
-       @return {Backbone.Collection}
-    */
-    _makeFullCollection: function (models, options) {
-
-      var properties = ["url", "model", "sync", "comparator"];
-      var thisProto = this.constructor.prototype;
-      var i, length, prop;
-
-      var proto = {};
-      for (i = 0, length = properties.length; i < length; i++) {
-        prop = properties[i];
-        if (!_isUndefined(thisProto[prop])) {
-          proto[prop] = thisProto[prop];
-        }
-      }
-
-      var fullCollection = new (Backbone.Collection.extend(proto))(models, options);
-
-      for (i = 0, length = properties.length; i < length; i++) {
-        prop = properties[i];
-        if (this[prop] !== thisProto[prop]) {
-          fullCollection[prop] = this[prop];
-        }
-      }
-
-      return fullCollection;
-    },
-
-    /**
-       Factory method that returns a Backbone event handler that responses to
-       the `add`, `remove`, `reset`, and the `sort` events. The returned event
-       handler will synchronize the current page collection and the full
-       collection's models.
-
-       @private
-
-       @param {Backbone.PageableCollection} pageCol
-       @param {Backbone.Collection} fullCol
-
-       @return {function(string, Backbone.Model, Backbone.Collection, Object)}
-       Collection event handler
-    */
-    _makeCollectionEventHandler: function (pageCol, fullCol) {
-
-      return function collectionEventHandler (event, model, collection, options) {
-
-        var handlers = pageCol._handlers;
-        _each(_keys(handlers), function (event) {
-          var handler = handlers[event];
-          pageCol.off(event, handler);
-          fullCol.off(event, handler);
-        });
-
-        var state = _clone(pageCol.state);
-        var firstPage = state.firstPage;
-        var currentPage = firstPage === 0 ?
-          state.currentPage :
-          state.currentPage - 1;
-        var pageSize = state.pageSize;
-        var pageStart = currentPage * pageSize, pageEnd = pageStart + pageSize;
-
-        if (event == "add") {
-          var pageIndex, fullIndex, addAt, colToAdd, options = options || {};
-          if (collection == fullCol) {
-            fullIndex = fullCol.indexOf(model);
-            if (fullIndex >= pageStart && fullIndex < pageEnd) {
-              colToAdd = pageCol;
-              pageIndex = addAt = fullIndex - pageStart;
-            }
-          }
-          else {
-            pageIndex = pageCol.indexOf(model);
-            fullIndex = pageStart + pageIndex;
-            colToAdd = fullCol;
-            var addAt = !_isUndefined(options.at) ?
-              options.at + pageStart :
-              fullIndex;
-          }
-
-          ++state.totalRecords;
-          pageCol.state = pageCol._checkState(state);
-
-          if (colToAdd) {
-            colToAdd.add(model, _extend({}, options || {}, {at: addAt}));
-            var modelToRemove = pageIndex >= pageSize ?
-              model :
-              !_isUndefined(options.at) && addAt < pageEnd && pageCol.length > pageSize ?
-              pageCol.at(pageSize) :
-              null;
-            if (modelToRemove) {
-              var addHandlers = collection._events.add || [],
-              popOptions = {onAdd: true};
-              if (addHandlers.length) {
-                var lastAddHandler = addHandlers[addHandlers.length - 1];
-                var oldCallback = lastAddHandler.callback;
-                lastAddHandler.callback = function () {
-                  try {
-                    oldCallback.apply(this, arguments);
-                    pageCol.remove(modelToRemove, popOptions);
-                  }
-                  finally {
-                    lastAddHandler.callback = oldCallback;
-                  }
-                };
-              }
-              else pageCol.remove(modelToRemove, popOptions);
-            }
-          }
-        }
-
-        // remove the model from the other collection as well
-        if (event == "remove") {
-          if (!options.onAdd) {
-            // decrement totalRecords and update totalPages and lastPage
-            if (!--state.totalRecords) {
-              state.totalRecords = null;
-              state.totalPages = null;
-            }
-            else {
-              var totalPages = state.totalPages = ceil(state.totalRecords / pageSize);
-              state.lastPage = firstPage === 0 ? totalPages - 1 : totalPages;
-              if (state.currentPage > totalPages) state.currentPage = state.lastPage;
-            }
-            pageCol.state = pageCol._checkState(state);
-
-            var nextModel, removedIndex = options.index;
-            if (collection == pageCol) {
-              if (nextModel = fullCol.at(pageEnd)) pageCol.push(nextModel);
-              fullCol.remove(model);
-            }
-            else if (removedIndex >= pageStart && removedIndex < pageEnd) {
-              pageCol.remove(model);
-              nextModel = fullCol.at(currentPage * (pageSize + removedIndex));
-              if (nextModel) pageCol.push(nextModel);
-            }
-          }
-          else delete options.onAdd;
-        }
-
-        if (event == "reset") {
-          options = collection;
-          collection = model;
-
-          // Reset that's not a result of getPage
-          if (collection === pageCol && options.from == null &&
-              options.to == null) {
-            var head = fullCol.models.slice(0, pageStart);
-            var tail = fullCol.models.slice(pageStart + pageCol.models.length);
-            fullCol.reset(head.concat(pageCol.models).concat(tail), options);
-          }
-          else if (collection === fullCol) {
-            if (!(state.totalRecords = fullCol.models.length)) {
-              state.totalRecords = null;
-              state.totalPages = null;
-            }
-            if (pageCol.mode == "client") {
-              state.lastPage = state.currentPage = state.firstPage;
-            }
-            pageCol.state = pageCol._checkState(state);
-            pageCol.reset(fullCol.models.slice(pageStart, pageEnd),
-                          _extend({}, options, {parse: false}));
-          }
-        }
-
-        if (event == "sort") {
-          options = collection;
-          collection = model;
-          if (collection === fullCol) {
-            pageCol.reset(fullCol.models.slice(pageStart, pageEnd),
-                          _extend({}, options, {parse: false}));
-          }
-        }
-
-        _each(_keys(handlers), function (event) {
-          var handler = handlers[event];
-          _each([pageCol, fullCol], function (col) {
-            col.on(event, handler);
-            var callbacks = col._events[event] || [];
-            callbacks.unshift(callbacks.pop());
-          });
-        });
-      };
-    },
-
-    /**
-       Sanity check this collection's pagination states. Only perform checks
-       when all the required pagination state values are defined and not null.
-       If `totalPages` is undefined or null, it is set to `totalRecords` /
-       `pageSize`. `lastPage` is set according to whether `firstPage` is 0 or 1
-       when no error occurs.
-
-       @private
-
-       @throws {TypeError} If `totalRecords`, `pageSize`, `currentPage` or
-       `firstPage` is not a finite integer.
-
-       @throws {RangeError} If `pageSize`, `currentPage` or `firstPage` is out
-       of bounds.
-
-       @return {Object} Returns the `state` object if no error was found.
-    */
-    _checkState: function (state) {
-
-      var mode = this.mode;
-      var links = this.links;
-      var totalRecords = state.totalRecords;
-      var pageSize = state.pageSize;
-      var currentPage = state.currentPage;
-      var firstPage = state.firstPage;
-      var totalPages = state.totalPages;
-
-      if (totalRecords != null && pageSize != null && currentPage != null &&
-          firstPage != null && (mode == "infinite" ? links : true)) {
-
-        totalRecords = finiteInt(totalRecords, "totalRecords");
-        pageSize = finiteInt(pageSize, "pageSize");
-        currentPage = finiteInt(currentPage, "currentPage");
-        firstPage = finiteInt(firstPage, "firstPage");
-
-        if (pageSize < 1) {
-          throw new RangeError("`pageSize` must be >= 1");
-        }
-
-        totalPages = state.totalPages = ceil(totalRecords / pageSize);
-
-        if (firstPage < 0 || firstPage > 1) {
-          throw new RangeError("`firstPage must be 0 or 1`");
-        }
-
-        state.lastPage = firstPage === 0 ? max(0, totalPages - 1) : totalPages;
-
-        if (mode == "infinite") {
-          if (!links[currentPage + '']) {
-            throw new RangeError("No link found for page " + currentPage);
-          }
-        }
-        else if (currentPage < firstPage ||
-                 (totalPages > 0 &&
-                  (firstPage ? currentPage > totalPages : currentPage >= totalPages))) {
-          throw new RangeError("`currentPage` must be firstPage <= currentPage " +
-                               (firstPage ? ">" : ">=") +
-                               " totalPages if " + firstPage + "-based. Got " +
-                               currentPage + '.');
-        }
-      }
-
-      return state;
-    },
-
-    /**
-       Change the page size of this collection.
-
-       Under most if not all circumstances, you should call this method to
-       change the page size of a pageable collection because it will keep the
-       pagination state sane. By default, the method will recalculate the
-       current page number to one that will retain the current page's models
-       when increasing the page size. When decreasing the page size, this method
-       will retain the last models to the current page that will fit into the
-       smaller page size.
-
-       If `options.first` is true, changing the page size will also reset the
-       current page back to the first page instead of trying to be smart.
-
-       For server mode operations, changing the page size will trigger a #fetch
-       and subsequently a `reset` event.
-
-       For client mode operations, changing the page size will `reset` the
-       current page by recalculating the current page boundary on the client
-       side.
-
-       If `options.fetch` is true, a fetch can be forced if the collection is in
-       client mode.
-
-       @param {number} pageSize The new page size to set to #state.
-       @param {Object} [options] {@link #fetch} options.
-       @param {boolean} [options.first=false] Reset the current page number to
-       the first page if `true`.
-       @param {boolean} [options.fetch] If `true`, force a fetch in client mode.
-
-       @throws {TypeError} If `pageSize` is not a finite integer.
-       @throws {RangeError} If `pageSize` is less than 1.
-
-       @chainable
-       @return {XMLHttpRequest|Backbone.PageableCollection} The XMLHttpRequest
-       from fetch or this.
-    */
-    setPageSize: function (pageSize, options) {
-      pageSize = finiteInt(pageSize, "pageSize");
-
-      options = options || {first: false};
-
-      var state = this.state;
-      var totalPages = ceil(state.totalRecords / pageSize);
-      var currentPage = totalPages ?
-        max(state.firstPage,
-            floor(totalPages *
-                  (state.firstPage ?
-                   state.currentPage :
-                   state.currentPage + 1) /
-                  state.totalPages)) :
-        state.firstPage;
-
-      state = this.state = this._checkState(_extend({}, state, {
-        pageSize: pageSize,
-        currentPage: options.first ? state.firstPage : currentPage,
-        totalPages: totalPages
-      }));
-
-      if(!options.fetch)
-    	  return;
-      return this.getPage(state.currentPage, _omit(options, ["first"]));
-    },
-
-    /**
-       Switching between client, server and infinite mode.
-
-       If switching from client to server mode, the #fullCollection is emptied
-       first and then deleted and a fetch is immediately issued for the current
-       page from the server. Pass `false` to `options.fetch` to skip fetching.
-
-       If switching to infinite mode, and if `options.models` is given for an
-       array of models, #links will be populated with a URL per page, using the
-       default URL for this collection.
-
-       If switching from server to client mode, all of the pages are immediately
-       refetched. If you have too many pages, you can pass `false` to
-       `options.fetch` to skip fetching.
-
-       If switching to any mode from infinite mode, the #links will be deleted.
-
-       @param {"server"|"client"|"infinite"} [mode] The mode to switch to.
-
-       @param {Object} [options]
-
-       @param {boolean} [options.fetch=true] If `false`, no fetching is done.
-
-       @param {boolean} [options.resetState=true] If 'false', the state is not
-       reset, but checked for sanity instead.
-
-       @chainable
-       @return {XMLHttpRequest|Backbone.PageableCollection} The XMLHttpRequest
-       from fetch or this if `options.fetch` is `false`.
-    */
-    switchMode: function (mode, options) {
-
-      if (!_contains(["server", "client", "infinite"], mode)) {
-        throw new TypeError('`mode` must be one of "server", "client" or "infinite"');
-      }
-
-      options = options || {fetch: true, resetState: true};
-
-      var state = this.state = options.resetState ?
-        _clone(this._initState) :
-        this._checkState(_extend({}, this.state));
-
-      this.mode = mode;
-
-      var self = this;
-      var fullCollection = this.fullCollection;
-      var handlers = this._handlers = this._handlers || {}, handler;
-      if (mode != "server" && !fullCollection) {
-        fullCollection = this._makeFullCollection(options.models || []);
-        fullCollection.pageableCollection = this;
-        this.fullCollection = fullCollection;
-        var allHandler = this._makeCollectionEventHandler(this, fullCollection);
-        _each(["add", "remove", "reset", "sort"], function (event) {
-          handlers[event] = handler = _.bind(allHandler, {}, event);
-          self.on(event, handler);
-          fullCollection.on(event, handler);
-        });
-        fullCollection.comparator = this._fullComparator;
-      }
-      else if (mode == "server" && fullCollection) {
-        _each(_keys(handlers), function (event) {
-          handler = handlers[event];
-          self.off(event, handler);
-          fullCollection.off(event, handler);
-        });
-        delete this._handlers;
-        this._fullComparator = fullCollection.comparator;
-        delete this.fullCollection;
-      }
-
-      if (mode == "infinite") {
-        var links = this.links = {};
-        var firstPage = state.firstPage;
-        var totalPages = ceil(state.totalRecords / state.pageSize);
-        var lastPage = firstPage === 0 ? max(0, totalPages - 1) : totalPages || firstPage;
-        for (var i = state.firstPage; i <= lastPage; i++) {
-          links[i] = this.url;
-        }
-      }
-      else if (this.links) delete this.links;
-
-      return options.fetch ?
-        this.fetch(_omit(options, "fetch", "resetState")) :
-        this;
-    },
-
-    /**
-       @return {boolean} `true` if this collection can page backward, `false`
-       otherwise.
-    */
-    hasPrevious: function () {
-      var state = this.state;
-      var currentPage = state.currentPage;
-      if (this.mode != "infinite") return currentPage > state.firstPage;
-      return !!this.links[currentPage - 1];
-    },
-
-    /**
-       @return {boolean} `true` if this collection can page forward, `false`
-       otherwise.
-    */
-    hasNext: function () {
-      var state = this.state;
-      var currentPage = this.state.currentPage;
-      if (this.mode != "infinite") return currentPage < state.lastPage;
-      return !!this.links[currentPage + 1];
-    },
-
-    /**
-       Fetch the first page in server mode, or reset the current page of this
-       collection to the first page in client or infinite mode.
-
-       @param {Object} options {@link #getPage} options.
-
-       @chainable
-       @return {XMLHttpRequest|Backbone.PageableCollection} The XMLHttpRequest
-       from fetch or this.
-    */
-    getFirstPage: function (options) {
-      return this.getPage("first", options);
-    },
-
-    /**
-       Fetch the previous page in server mode, or reset the current page of this
-       collection to the previous page in client or infinite mode.
-
-       @param {Object} options {@link #getPage} options.
-
-       @chainable
-       @return {XMLHttpRequest|Backbone.PageableCollection} The XMLHttpRequest
-       from fetch or this.
-    */
-    getPreviousPage: function (options) {
-      return this.getPage("prev", options);
-    },
-
-    /**
-       Fetch the next page in server mode, or reset the current page of this
-       collection to the next page in client mode.
-
-       @param {Object} options {@link #getPage} options.
-
-       @chainable
-       @return {XMLHttpRequest|Backbone.PageableCollection} The XMLHttpRequest
-       from fetch or this.
-    */
-    getNextPage: function (options) {
-      return this.getPage("next", options);
-    },
-
-    /**
-       Fetch the last page in server mode, or reset the current page of this
-       collection to the last page in client mode.
-
-       @param {Object} options {@link #getPage} options.
-
-       @chainable
-       @return {XMLHttpRequest|Backbone.PageableCollection} The XMLHttpRequest
-       from fetch or this.
-    */
-    getLastPage: function (options) {
-      return this.getPage("last", options);
-    },
-
-    /**
-       Given a page index, set #state.currentPage to that index. If this
-       collection is in server mode, fetch the page using the updated state,
-       otherwise, reset the current page of this collection to the page
-       specified by `index` in client mode. If `options.fetch` is true, a fetch
-       can be forced in client mode before resetting the current page. Under
-       infinite mode, if the index is less than the current page, a reset is
-       done as in client mode. If the index is greater than the current page
-       number, a fetch is made with the results **appended** to #fullCollection.
-       The current page will then be reset after fetching.
-
-       @param {number|string} index The page index to go to, or the page name to
-       look up from #links in infinite mode.
-       @param {Object} [options] {@link #fetch} options or
-       [reset](http://backbonejs.org/#Collection-reset) options for client mode
-       when `options.fetch` is `false`.
-       @param {boolean} [options.fetch=false] If true, force a {@link #fetch} in
-       client mode.
-
-       @throws {TypeError} If `index` is not a finite integer under server or
-       client mode, or does not yield a URL from #links under infinite mode.
-
-       @throws {RangeError} If `index` is out of bounds.
-
-       @chainable
-       @return {XMLHttpRequest|Backbone.PageableCollection} The XMLHttpRequest
-       from fetch or this.
-    */
-    getPage: function (index, options) {
-
-      var mode = this.mode, fullCollection = this.fullCollection;
-
-      options = options || {fetch: false};
-
-      var state = this.state,
-      firstPage = state.firstPage,
-      currentPage = state.currentPage,
-      lastPage = state.lastPage,
-      pageSize = state.pageSize;
-
-      var pageNum = index;
-      switch (index) {
-        case "first": pageNum = firstPage; break;
-        case "prev": pageNum = currentPage - 1; break;
-        case "next": pageNum = currentPage + 1; break;
-        case "last": pageNum = lastPage; break;
-        default: pageNum = finiteInt(index, "index");
-      }
-
-      this.state = this._checkState(_extend({}, state, {currentPage: pageNum}));
-
-      options.from = currentPage, options.to = pageNum;
-
-      var pageStart = (firstPage === 0 ? pageNum : pageNum - 1) * pageSize;
-      var pageModels = fullCollection && fullCollection.length ?
-        fullCollection.models.slice(pageStart, pageStart + pageSize) :
-        [];
-      if ((mode == "client" || (mode == "infinite" && !_isEmpty(pageModels))) &&
-          !options.fetch) {
-        return this.reset(pageModels, _omit(options, "fetch"));
-      }
-
-      if (mode == "infinite") options.url = this.links[pageNum];
-
-      return this.fetch(_omit(options, "fetch"));
-    },
-
-    /**
-       Fetch the page for the provided item offset in server mode, or reset the current page of this
-       collection to the page for the provided item offset in client mode.
-
-       @param {Object} options {@link #getPage} options.
-
-       @chainable
-       @return {XMLHttpRequest|Backbone.PageableCollection} The XMLHttpRequest
-       from fetch or this.
-    */
-    getPageByOffset: function (offset, options) {
-      if (offset < 0) {
-        throw new RangeError("`offset must be > 0`");
-      }
-      offset = finiteInt(offset);
-
-      var page = floor(offset / this.state.pageSize);
-      if (this.state.firstPage !== 0) page++;
-      if (page > this.state.lastPage) page = this.state.lastPage;
-      return this.getPage(page, options);
-    },
-
-    /**
-       Overidden to make `getPage` compatible with Zepto.
-
-       @param {string} method
-       @param {Backbone.Model|Backbone.Collection} model
-       @param {Object} [options]
-
-       @return {XMLHttpRequest}
-    */
-    sync: function (method, model, options) {
-      var self = this;
-      if (self.mode == "infinite") {
-        var success = options.success;
-        var currentPage = self.state.currentPage;
-        options.success = function (resp, status, xhr) {
-          var links = self.links;
-          var newLinks = self.parseLinks(resp, _extend({xhr: xhr}, options));
-          if (newLinks.first) links[self.state.firstPage] = newLinks.first;
-          if (newLinks.prev) links[currentPage - 1] = newLinks.prev;
-          if (newLinks.next) links[currentPage + 1] = newLinks.next;
-          if (success) success(resp, status, xhr);
-        };
-      }
-
-      return (BBColProto.sync || Backbone.sync).call(self, method, model, options);
-    },
-
-    /**
-       Parse pagination links from the server response. Only valid under
-       infinite mode.
-
-       Given a response body and a XMLHttpRequest object, extract pagination
-       links from them for infinite paging.
-
-       This default implementation parses the RFC 5988 `Link` header and extract
-       3 links from it - `first`, `prev`, `next`. If a `previous` link is found,
-       it will be found in the `prev` key in the returned object hash. Any
-       subclasses overriding this method __must__ return an object hash having
-       only the keys above. If `first` is missing, the collection's default URL
-       is assumed to be the `first` URL. If `prev` or `next` is missing, it is
-       assumed to be `null`. An empty object hash must be returned if there are
-       no links found. If either the response or the header contains information
-       pertaining to the total number of records on the server, #state.totalRecords
-       must be set to that number. The default implementation uses the `last`
-       link from the header to calculate it.
-
-       @param {*} resp The deserialized response body.
-       @param {Object} [options]
-       @param {XMLHttpRequest} [options.xhr] The XMLHttpRequest object for this
-       response.
-       @return {Object}
-    */
-    parseLinks: function (resp, options) {
-      var links = {};
-      var linkHeader = options.xhr.getResponseHeader("Link");
-      if (linkHeader) {
-        var relations = ["first", "prev", "previous", "next", "last"];
-        _each(linkHeader.split(","), function (linkValue) {
-          var linkParts = linkValue.split(";");
-          var url = linkParts[0].replace(URL_TRIM_RE, '');
-          var params = linkParts.slice(1);
-          _each(params, function (param) {
-            var paramParts = param.split("=");
-            var key = paramParts[0].replace(PARAM_TRIM_RE, '');
-            var value = paramParts[1].replace(PARAM_TRIM_RE, '');
-            if (key == "rel" && _contains(relations, value)) {
-              if (value == "previous") links.prev = url;
-              else links[value] = url;
-            }
-          });
-        });
-
-        var last = links.last || '', qsi, qs;
-        if (qs = (qsi = last.indexOf('?')) ? last.slice(qsi + 1) : '') {
-          var params = queryStringToParams(qs);
-
-          var state = _clone(this.state);
-          var queryParams = this.queryParams;
-          var pageSize = state.pageSize;
-
-          var totalRecords = params[queryParams.totalRecords] * 1;
-          var pageNum = params[queryParams.currentPage] * 1;
-          var totalPages = params[queryParams.totalPages];
-
-          if (!totalRecords) {
-            if (pageNum) totalRecords = (state.firstPage === 0 ?
-                                         pageNum + 1 :
-                                         pageNum) * pageSize;
-            else if (totalPages) totalRecords = totalPages * pageSize;
-          }
-
-          if (totalRecords) state.totalRecords = totalRecords;
-
-          this.state = this._checkState(state);
-        }
-      }
-
-      delete links.last;
-
-      return links;
-    },
-
-    /**
-       Parse server response data.
-
-       This default implementation assumes the response data is in one of two
-       structures:
-
-           [
-             {}, // Your new pagination state
-             [{}, ...] // An array of JSON objects
-           ]
-
-       Or,
-
-           [{}] // An array of JSON objects
-
-       The first structure is the preferred form because the pagination states
-       may have been updated on the server side, sending them down again allows
-       this collection to update its states. If the response has a pagination
-       state object, it is checked for errors.
-
-       The second structure is the
-       [Backbone.Collection#parse](http://backbonejs.org/#Collection-parse)
-       default.
-
-       **Note:** this method has been further simplified since 1.1.7. While
-       existing #parse implementations will continue to work, new code is
-       encouraged to override #parseState and #parseRecords instead.
-
-       @param {Object} resp The deserialized response data from the server.
-       @param {Object} the options for the ajax request
-
-       @return {Array.<Object>} An array of model objects
-    */
-    parse: function (resp, options) {
-      var newState = this.parseState(resp, _clone(this.queryParams), _clone(this.state), options);
-      if (newState) this.state = this._checkState(_extend({}, this.state, newState));
-      return this.parseRecords(resp, options);
-    },
-
-    /**
-       Parse server response for server pagination state updates.
-
-       This default implementation first checks whether the response has any
-       state object as documented in #parse. If it exists, a state object is
-       returned by mapping the server state keys to this pageable collection
-       instance's query parameter keys using `queryParams`.
-
-       It is __NOT__ neccessary to return a full state object complete with all
-       the mappings defined in #queryParams. Any state object resulted is merged
-       with a copy of the current pageable collection state and checked for
-       sanity before actually updating. Most of the time, simply providing a new
-       `totalRecords` value is enough to trigger a full pagination state
-       recalculation.
-
-           parseState: function (resp, queryParams, state, options) {
-             return {totalRecords: resp.total_entries};
-           }
-
-       If you want to use header fields use:
-
-           parseState: function (resp, queryParams, state, options) {
-               return {totalRecords: options.xhr.getResponseHeader("X-total")};
-           }
-
-       This method __MUST__ return a new state object instead of directly
-       modifying the #state object. The behavior of directly modifying #state is
-       undefined.
-
-       @param {Object} resp The deserialized response data from the server.
-       @param {Object} queryParams A copy of #queryParams.
-       @param {Object} state A copy of #state.
-       @param {Object} [options] The options passed through from
-       `parse`. (backbone >= 0.9.10 only)
-
-       @return {Object} A new (partial) state object.
-     */
-    parseState: function (resp, queryParams, state, options) {
-      if (resp && resp.length === 2 && _isObject(resp[0]) && _isArray(resp[1])) {
-
-        var newState = _clone(state);
-        var serverState = resp[0];
-
-        _each(_pairs(_omit(queryParams, "directions")), function (kvp) {
-          var k = kvp[0], v = kvp[1];
-          var serverVal = serverState[v];
-          if (!_isUndefined(serverVal) && !_.isNull(serverVal)) newState[k] = serverState[v];
-        });
-
-        if (serverState.order) {
-          newState.order = _invert(queryParams.directions)[serverState.order] * 1;
-        }
-
-        return newState;
-      }
-    },
-
-    /**
-       Parse server response for an array of model objects.
-
-       This default implementation first checks whether the response has any
-       state object as documented in #parse. If it exists, the array of model
-       objects is assumed to be the second element, otherwise the entire
-       response is returned directly.
-
-       @param {Object} resp The deserialized response data from the server.
-       @param {Object} [options] The options passed through from the
-       `parse`. (backbone >= 0.9.10 only)
-
-       @return {Array.<Object>} An array of model objects
-     */
-    parseRecords: function (resp, options) {
-      if (resp && resp.length === 2 && _isObject(resp[0]) && _isArray(resp[1])) {
-        return resp[1];
-      }
-
-      return resp;
-    },
-
-    /**
-       Fetch a page from the server in server mode, or all the pages in client
-       mode. Under infinite mode, the current page is refetched by default and
-       then reset.
-
-       The query string is constructed by translating the current pagination
-       state to your server API query parameter using #queryParams.  The current
-       page will reset after fetch.
-
-       @param {Object} [options] Accepts all
-       [Backbone.Collection#fetch](http://backbonejs.org/#Collection-fetch)
-       options.
-
-       @return {XMLHttpRequest}
-    */
-    fetch: function (options) {
-
-      options = options || {};
-
-      var state = this._checkState(this.state);
-
-      var mode = this.mode;
-
-      if (mode == "infinite" && !options.url) {
-        options.url = this.links[state.currentPage];
-      }
-
-      var data = options.data || {};
-
-      // dedup query params
-      var url = _result(options, "url") || _result(this, "url") || '';
-      var qsi = url.indexOf('?');
-      if (qsi != -1) {
-        _extend(data, queryStringToParams(url.slice(qsi + 1)));
-        url = url.slice(0, qsi);
-      }
-
-      options.url = url;
-      options.data = data;
-
-      // map params except directions
-      var queryParams = this.mode == "client" ?
-        _pick(this.queryParams, "sortKey", "order") :
-        _omit(_pick(this.queryParams, _keys(PageableProto.queryParams)),
-              "directions");
-
-      var i, kvp, k, v, kvps = _pairs(queryParams), thisCopy = _clone(this);
-      for (i = 0; i < kvps.length; i++) {
-        kvp = kvps[i], k = kvp[0], v = kvp[1];
-        v = _isFunction(v) ? v.call(thisCopy) : v;
-        if (state[k] != null && v != null) {
-          data[v] = state[k];
-        }
-      }
-
-      // fix up sorting parameters
-      if (state.sortKey && state.order) {
-        data[queryParams.order] = this.queryParams.directions[state.order + ""];
-      }
-      else if (!state.sortKey) delete data[queryParams.order];
-
-      // map extra query parameters
-      var extraKvps = _pairs(_omit(this.queryParams,
-                                   _keys(PageableProto.queryParams)));
-      for (i = 0; i < extraKvps.length; i++) {
-        kvp = extraKvps[i];
-        v = kvp[1];
-        v = _isFunction(v) ? v.call(thisCopy) : v;
-        if (v != null) data[kvp[0]] = v;
-      }
-
-      if (mode != "server") {
-        var self = this, fullCol = this.fullCollection;
-        var success = options.success;
-        options.success = function (col, resp, opts) {
-
-          // make sure the caller's intent is obeyed
-          opts = opts || {};
-          if (_isUndefined(options.silent)) delete opts.silent;
-          else opts.silent = options.silent;
-
-          var models = col.models;
-          if (mode == "client") fullCol.reset(models, opts);
-          else fullCol.add(models, _extend({at: fullCol.length}, opts));
-
-          if (success) success(col, resp, opts);
-        };
-
-        // silent the first reset from backbone
-        return BBColProto.fetch.call(self, _extend({}, options, {silent: true}));
-      }
-
-      return BBColProto.fetch.call(this, options);
-    },
-
-    /**
-       Convenient method for making a `comparator` sorted by a model attribute
-       identified by `sortKey` and ordered by `order`.
-
-       Like a Backbone.Collection, a Backbone.PageableCollection will maintain
-       the __current page__ in sorted order on the client side if a `comparator`
-       is attached to it. If the collection is in client mode, you can attach a
-       comparator to #fullCollection to have all the pages reflect the global
-       sorting order by specifying an option `full` to `true`. You __must__ call
-       `sort` manually or #fullCollection.sort after calling this method to
-       force a resort.
-
-       While you can use this method to sort the current page in server mode,
-       the sorting order may not reflect the global sorting order due to the
-       additions or removals of the records on the server since the last
-       fetch. If you want the most updated page in a global sorting order, it is
-       recommended that you set #state.sortKey and optionally #state.order, and
-       then call #fetch.
-
-       @protected
-
-       @param {string} [sortKey=this.state.sortKey] See `state.sortKey`.
-       @param {number} [order=this.state.order] See `state.order`.
-       @param {(function(Backbone.Model, string): Object) | string} [sortValue] See #setSorting.
-
-       See [Backbone.Collection.comparator](http://backbonejs.org/#Collection-comparator).
-    */
-    _makeComparator: function (sortKey, order, sortValue) {
-      var state = this.state;
-
-      sortKey = sortKey || state.sortKey;
-      order = order || state.order;
-
-      if (!sortKey || !order) return;
-
-      if (!sortValue) sortValue = function (model, attr) {
-        return model.get(attr);
-      };
-
-      return function (left, right) {
-        var l = sortValue(left, sortKey), r = sortValue(right, sortKey), t;
-        if (order === 1) t = l, l = r, r = t;
-        if (l === r) return 0;
-        else if (l < r) return -1;
-        return 1;
-      };
-    },
-
-    /**
-       Adjusts the sorting for this pageable collection.
-
-       Given a `sortKey` and an `order`, sets `state.sortKey` and
-       `state.order`. A comparator can be applied on the client side to sort in
-       the order defined if `options.side` is `"client"`. By default the
-       comparator is applied to the #fullCollection. Set `options.full` to
-       `false` to apply a comparator to the current page under any mode. Setting
-       `sortKey` to `null` removes the comparator from both the current page and
-       the full collection.
-
-       If a `sortValue` function is given, it will be passed the `(model,
-       sortKey)` arguments and is used to extract a value from the model during
-       comparison sorts. If `sortValue` is not given, `model.get(sortKey)` is
-       used for sorting.
-
-       @chainable
-
-       @param {string} sortKey See `state.sortKey`.
-       @param {number} [order=this.state.order] See `state.order`.
-       @param {Object} [options]
-       @param {"server"|"client"} [options.side] By default, `"client"` if
-       `mode` is `"client"`, `"server"` otherwise.
-       @param {boolean} [options.full=true]
-       @param {(function(Backbone.Model, string): Object) | string} [options.sortValue]
-    */
-    setSorting: function (sortKey, order, options) {
-
-      var state = this.state;
-
-      state.sortKey = sortKey;
-      state.order = order = order || state.order;
-
-      var fullCollection = this.fullCollection;
-
-      var delComp = false, delFullComp = false;
-
-      if (!sortKey) delComp = delFullComp = true;
-
-      var mode = this.mode;
-      options = _extend({side: mode == "client" ? mode : "server", full: true},
-                        options);
-
-      var comparator = this._makeComparator(sortKey, order, options.sortValue);
-
-      var full = options.full, side = options.side;
-
-      if (side == "client") {
-        if (full) {
-          if (fullCollection) fullCollection.comparator = comparator;
-          delComp = true;
-        }
-        else {
-          this.comparator = comparator;
-          delFullComp = true;
-        }
-      }
-      else if (side == "server" && !full) {
-        this.comparator = comparator;
-      }
-
-      if (delComp) delete this.comparator;
-      if (delFullComp && fullCollection) delete fullCollection.comparator;
-
-      return this;
-    }
-
-  });
-
-  var PageableProto = PageableCollection.prototype;
-
-  return PageableCollection;
-
-}));
diff --git a/security-admin/src/main/webapp/libs/bower/backbone-pageable/js/backbone-pageable.min.js b/security-admin/src/main/webapp/libs/bower/backbone-pageable/js/backbone-pageable.min.js
deleted file mode 100644
index 78f32fd91..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone-pageable/js/backbone-pageable.min.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
-  backbone-pageable 1.3.2
-  http://github.com/wyuenho/backbone-pageable
-
-  Copyright (c) 2013 Jimmy Yuen Ho Wong
-  Licensed under the MIT @license.
-*/
-!function(a){if("object"==typeof exports)module.exports=a(require("underscore"),require("backbone"));else if("function"==typeof define&&define.amd)define(["underscore","backbone"],a);else if("undefined"!=typeof _&&"undefined"!=typeof Backbone){var b=Backbone.PageableCollection,c=a(_,Backbone);Backbone.PageableCollection.noConflict=function(){return Backbone.PageableCollection=b,c}}}(function(a,b){"use strict";function c(b,c){if(!a.isNumber(b)||a.isNaN(b)||!a.isFinite(b)||~~b!==b)throw ne [...]
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/libs/bower/backbone.babysitter/js/backbone.babysitter.js b/security-admin/src/main/webapp/libs/bower/backbone.babysitter/js/backbone.babysitter.js
deleted file mode 100644
index a182eda6a..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone.babysitter/js/backbone.babysitter.js
+++ /dev/null
@@ -1,178 +0,0 @@
-// Backbone.BabySitter
-// -------------------
-// v0.0.6
-//
-// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
-// Distributed under MIT license
-//
-// http://github.com/babysitterjs/backbone.babysitter
-
-(function (root, factory) {
-  if (typeof exports === 'object') {
-
-    var underscore = require('underscore');
-    var backbone = require('backbone');
-
-    module.exports = factory(underscore, backbone);
-
-  } else if (typeof define === 'function' && define.amd) {
-
-    define(['underscore', 'backbone'], factory);
-
-  } 
-}(this, function (_, Backbone) {
-  "option strict";
-
-  // Backbone.ChildViewContainer
-// ---------------------------
-//
-// Provide a container to store, retrieve and
-// shut down child views.
-
-Backbone.ChildViewContainer = (function(Backbone, _){
-  
-  // Container Constructor
-  // ---------------------
-
-  var Container = function(views){
-    this._views = {};
-    this._indexByModel = {};
-    this._indexByCustom = {};
-    this._updateLength();
-
-    _.each(views, this.add, this);
-  };
-
-  // Container Methods
-  // -----------------
-
-  _.extend(Container.prototype, {
-
-    // Add a view to this container. Stores the view
-    // by `cid` and makes it searchable by the model
-    // cid (and model itself). Optionally specify
-    // a custom key to store an retrieve the view.
-    add: function(view, customIndex){
-      var viewCid = view.cid;
-
-      // store the view
-      this._views[viewCid] = view;
-
-      // index it by model
-      if (view.model){
-        this._indexByModel[view.model.cid] = viewCid;
-      }
-
-      // index by custom
-      if (customIndex){
-        this._indexByCustom[customIndex] = viewCid;
-      }
-
-      this._updateLength();
-    },
-
-    // Find a view by the model that was attached to
-    // it. Uses the model's `cid` to find it.
-    findByModel: function(model){
-      return this.findByModelCid(model.cid);
-    },
-
-    // Find a view by the `cid` of the model that was attached to
-    // it. Uses the model's `cid` to find the view `cid` and
-    // retrieve the view using it.
-    findByModelCid: function(modelCid){
-      var viewCid = this._indexByModel[modelCid];
-      return this.findByCid(viewCid);
-    },
-
-    // Find a view by a custom indexer.
-    findByCustom: function(index){
-      var viewCid = this._indexByCustom[index];
-      return this.findByCid(viewCid);
-    },
-
-    // Find by index. This is not guaranteed to be a
-    // stable index.
-    findByIndex: function(index){
-      return _.values(this._views)[index];
-    },
-
-    // retrieve a view by it's `cid` directly
-    findByCid: function(cid){
-      return this._views[cid];
-    },
-
-    // Remove a view
-    remove: function(view){
-      var viewCid = view.cid;
-
-      // delete model index
-      if (view.model){
-        delete this._indexByModel[view.model.cid];
-      }
-
-      // delete custom index
-      _.any(this._indexByCustom, function(cid, key) {
-        if (cid === viewCid) {
-          delete this._indexByCustom[key];
-          return true;
-        }
-      }, this);
-
-      // remove the view from the container
-      delete this._views[viewCid];
-
-      // update the length
-      this._updateLength();
-    },
-
-    // Call a method on every view in the container,
-    // passing parameters to the call method one at a
-    // time, like `function.call`.
-    call: function(method){
-      this.apply(method, _.tail(arguments));
-    },
-
-    // Apply a method on every view in the container,
-    // passing parameters to the call method one at a
-    // time, like `function.apply`.
-    apply: function(method, args){
-      _.each(this._views, function(view){
-        if (_.isFunction(view[method])){
-          view[method].apply(view, args || []);
-        }
-      });
-    },
-
-    // Update the `.length` attribute on this container
-    _updateLength: function(){
-      this.length = _.size(this._views);
-    }
-  });
-
-  // Borrowing this code from Backbone.Collection:
-  // http://backbonejs.org/docs/backbone.html#section-106
-  //
-  // Mix in methods from Underscore, for iteration, and other
-  // collection related features.
-  var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter', 
-    'select', 'reject', 'every', 'all', 'some', 'any', 'include', 
-    'contains', 'invoke', 'toArray', 'first', 'initial', 'rest', 
-    'last', 'without', 'isEmpty', 'pluck'];
-
-  _.each(methods, function(method) {
-    Container.prototype[method] = function() {
-      var views = _.values(this._views);
-      var args = [views].concat(_.toArray(arguments));
-      return _[method].apply(_, args);
-    };
-  });
-
-  // return the public API
-  return Container;
-})(Backbone, _);
-
-  return Backbone.ChildViewContainer; 
-
-}));
-
diff --git a/security-admin/src/main/webapp/libs/bower/backbone.babysitter/js/backbone.babysitter.min.js b/security-admin/src/main/webapp/libs/bower/backbone.babysitter/js/backbone.babysitter.min.js
deleted file mode 100644
index 78355c8d7..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone.babysitter/js/backbone.babysitter.min.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// Backbone.BabySitter
-// -------------------
-// v0.0.6
-//
-// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
-// Distributed under MIT license
-//
-// http://github.com/babysitterjs/backbone.babysitter
-
-(function(i,e){if("object"==typeof exports){var t=require("underscore"),n=require("backbone");module.exports=e(t,n)}else"function"==typeof define&&define.amd&&define(["underscore","backbone"],e)})(this,function(i,e){"option strict";return e.ChildViewContainer=function(i,e){var t=function(i){this._views={},this._indexByModel={},this._indexByCustom={},this._updateLength(),e.each(i,this.add,this)};e.extend(t.prototype,{add:function(i,e){var t=i.cid;this._views[t]=i,i.model&&(this._indexByMo [...]
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/libs/bower/backbone.bootstrap-modal/js/backbone.bootstrap-modal.js b/security-admin/src/main/webapp/libs/bower/backbone.bootstrap-modal/js/backbone.bootstrap-modal.js
deleted file mode 100644
index c2fa0452f..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone.bootstrap-modal/js/backbone.bootstrap-modal.js
+++ /dev/null
@@ -1,291 +0,0 @@
-/**
- * Bootstrap Modal wrapper for use with Backbone.
- *
- * Takes care of instantiation, manages multiple modals,
- * adds several options and removes the element from the DOM when closed
- *
- * @author Charles Davison <ch...@powmedia.co.uk>
- *
- * Events:
- * shown: Fired when the modal has finished animating in
- * hidden: Fired when the modal has finished animating out
- * cancel: The user dismissed the modal
- * ok: The user clicked OK
- */
-(function($, _, Backbone) {
-
-  //Set custom template settings
-  var _interpolateBackup = _.templateSettings;
-  _.templateSettings = {
-    interpolate: /\{\{(.+?)\}\}/g,
-    evaluate: /<%([\s\S]+?)%>/g
-  };
-
-  var template = _.template('\
-    <div class="modal-dialog modal-lg"><div class="modal-content">\
-    <% if (title) { %>\
-      <div class="modal-header">\
-        <h4 class="modal-title">{{title}}</h4>\
-        <% if (allowCancel) { %>\
-          <a class="close">&times;</a>\
-        <% } %>\
-      </div>\
-    <% } %>\
-    <div class="modal-body">{{content}}</div>\
-    <% if (showFooter) { %>\
-      <div class="modal-footer">\
-        <% if (allowCancel) { %>\
-          <% if (cancelText) { %>\
-            <a href="#" class="btn cancel btn-sm">{{cancelText}}</a>\
-          <% } %>\
-        <% } %>\
-        <a href="#" class="btn ok btn-primary btn-sm">{{okText}}</a>\
-      </div>\
-    <% } %>\
-    </div></div>\
-  ');
-
-  //Reset to users' template settings
-  _.templateSettings = _interpolateBackup;
-
-
-  var Modal = Backbone.View.extend({
-
-    className: 'modal',
-
-    events: {
-      'click .close': function(event) {
-        event.preventDefault();
-
-        this.trigger('cancel');
-
-        if (this.options.content && this.options.content.trigger) {
-          this.options.content.trigger('cancel', this);
-        }
-      },
-      'click .cancel': function(event) {
-        event.preventDefault();
-
-        this.trigger('cancel');
-
-        if (this.options.content && this.options.content.trigger) {
-          this.options.content.trigger('cancel', this);
-        }
-      },
-      'click .ok': function(event) {
-        event.preventDefault();
-
-        this.trigger('ok');
-
-        if (this.options.content && this.options.content.trigger) {
-          this.options.content.trigger('ok', this);
-        }
-
-        if (this.options.okCloses) {
-          this.close();
-        }
-      },
-      'keypress': function(event) {
-        if (this.options.enterTriggersOk && event.which == 13) {
-          event.preventDefault();
-
-          this.trigger('ok');
-
-          if (this.options.content && this.options.content.trigger) {
-            this.options.content.trigger('ok', this);
-          }
-
-          if (this.options.okCloses) {
-            this.close();
-          }
-        }
-      }
-    },
-
-    /**
-     * Creates an instance of a Bootstrap Modal
-     *
-     * @see http://twitter.github.com/bootstrap/javascript.html#modals
-     *
-     * @param {Object} options
-     * @param {String|View} [options.content]     Modal content. Default: none
-     * @param {String} [options.title]            Title. Default: none
-     * @param {String} [options.okText]           Text for the OK button. Default: 'OK'
-     * @param {String} [options.cancelText]       Text for the cancel button. Default: 'Cancel'. If passed a falsey value, the button will be removed
-     * @param {Boolean} [options.allowCancel      Whether the modal can be closed, other than by pressing OK. Default: true
-     * @param {Boolean} [options.escape]          Whether the 'esc' key can dismiss the modal. Default: true, but false if options.cancellable is true
-     * @param {Boolean} [options.animate]         Whether to animate in/out. Default: false
-     * @param {Function} [options.template]       Compiled underscore template to override the default one
-     * @param {Boolean} [options.enterTriggersOk] Whether the 'enter' key will trigger OK. Default: false
-     */
-    initialize: function(options) {
-      this.options = _.extend({
-        title: null,
-        okText: 'OK',
-        focusOk: true,
-        okCloses: true,
-        cancelText: 'Cancel',
-        showFooter: true,
-        allowCancel: true,
-        escape: true,
-        animate: false,
-        template: template,
-        enterTriggersOk: false
-      }, options);
-    },
-
-    /**
-     * Creates the DOM element
-     *
-     * @api private
-     */
-    render: function() {
-      var $el = this.$el,
-          options = this.options,
-          content = options.content;
-
-      //Create the modal container
-      $el.html(options.template(options));
-
-      var $content = this.$content = $el.find('.modal-body')
-
-      //Insert the main content if it's a view
-      if (content && content.$el) {
-        content.render();
-        $el.find('.modal-body').html(content.$el);
-      }
-
-      if (options.animate) $el.addClass('fade');
-
-      this.isRendered = true;
-
-      return this;
-    },
-
-    /**
-     * Renders and shows the modal
-     *
-     * @param {Function} [cb]     Optional callback that runs only when OK is pressed.
-     */
-    open: function(cb) {
-      if (!this.isRendered) this.render();
-
-      var self = this,
-          $el = this.$el;
-
-      //Create it
-      $el.modal(_.extend({
-        keyboard: this.options.allowCancel,
-        backdrop: this.options.allowCancel ? true : 'static'
-      }, this.options.modalOptions));
-
-      //Focus OK button
-      $el.one('shown.bs.modal', function() {
-        if (self.options.focusOk) {
-          $el.find('.btn.ok').focus();
-        }
-
-        if (self.options.content && self.options.content.trigger) {
-          self.options.content.trigger('shown', self);
-        }
-
-        self.trigger('shown');
-      });
-
-      //Adjust the modal and backdrop z-index; for dealing with multiple modals
-      var numModals = Modal.count,
-          $backdrop = $('.modal-backdrop:eq('+numModals+')'),
-          backdropIndex = parseInt($backdrop.css('z-index'),10),
-          elIndex = parseInt($backdrop.css('z-index'), 10);
-
-      $backdrop.css('z-index', backdropIndex + numModals);
-      this.$el.css('z-index', elIndex + numModals);
-
-      if (this.options.allowCancel) {
-        $backdrop.one('click', function() {
-          if (self.options.content && self.options.content.trigger) {
-            self.options.content.trigger('cancel', self);
-          }
-
-          self.trigger('cancel');
-        });
-
-        $(document).one('keyup.dismiss.modal', function (e) {
-          e.which == 27 && self.trigger('cancel');
-
-          if (self.options.content && self.options.content.trigger) {
-            e.which == 27 && self.options.content.trigger('shown', self);
-          }
-        });
-      }
-
-      this.on('cancel', function() {
-        self.close();
-      });
-
-      Modal.count++;
-
-      //Run callback on OK if provided
-      if (cb) {
-        self.on('ok', cb);
-      }
-
-      return this;
-    },
-
-    /**
-     * Closes the modal
-     */
-    close: function() {
-      var self = this,
-          $el = this.$el;
-
-      //Check if the modal should stay open
-      if (this._preventClose) {
-        this._preventClose = false;
-        return;
-      }
-
-      $el.one('hidden.bs.modal', function onHidden(e) {
-        // Ignore events propagated from interior objects, like bootstrap tooltips
-        if(e.target !== e.currentTarget){
-          return $el.one('hidden', onHidden);
-        }
-        self.remove();
-
-        if (self.options.content && self.options.content.trigger) {
-          self.options.content.trigger('hidden', self);
-        }
-
-        self.trigger('hidden');
-      });
-
-      $el.modal('hide');
-
-      Modal.count--;
-    },
-
-    /**
-     * Stop the modal from closing.
-     * Can be called from within a 'close' or 'ok' event listener.
-     */
-    preventClose: function() {
-      this._preventClose = true;
-    }
-  }, {
-    //STATICS
-
-    //The number of modals on display
-    count: 0
-  });
-
-
-  //EXPORTS
-  //CommonJS
-  if (typeof require == 'function' && typeof module !== 'undefined' && exports) {
-    module.exports = Modal;
-  }
-  //Regular; add to Backbone.Bootstrap.Modal
-  Backbone.BootstrapModal = Modal;
-
-})(jQuery, _, Backbone);
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/libs/bower/backbone.localstorage/backbone.localStorage.js b/security-admin/src/main/webapp/libs/bower/backbone.localstorage/backbone.localStorage.js
deleted file mode 100644
index 4446d4ac7..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone.localstorage/backbone.localStorage.js
+++ /dev/null
@@ -1,222 +0,0 @@
-/**
- * Backbone localStorage Adapter
- * Version 1.1.7
- *
- * https://github.com/jeromegn/Backbone.localStorage
- */
-(function (root, factory) {
-   if (typeof exports === 'object' && typeof require === 'function') {
-     module.exports = factory(require("underscore"), require("backbone"));
-   } else if (typeof define === "function" && define.amd) {
-      // AMD. Register as an anonymous module.
-      define(["underscore","backbone"], function(_, Backbone) {
-        // Use global variables if the locals are undefined.
-        return factory(_ || root._, Backbone || root.Backbone);
-      });
-   } else {
-      // RequireJS isn't being used. Assume underscore and backbone are loaded in <script> tags
-      factory(_, Backbone);
-   }
-}(this, function(_, Backbone) {
-// A simple module to replace `Backbone.sync` with *localStorage*-based
-// persistence. Models are given GUIDS, and saved into a JSON object. Simple
-// as that.
-
-// Hold reference to Underscore.js and Backbone.js in the closure in order
-// to make things work even if they are removed from the global namespace
-
-// Generate four random hex digits.
-function S4() {
-   return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
-};
-
-// Generate a pseudo-GUID by concatenating random hexadecimal.
-function guid() {
-   return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
-};
-
-// Our Store is represented by a single JS object in *localStorage*. Create it
-// with a meaningful name, like the name you'd give a table.
-// window.Store is deprectated, use Backbone.LocalStorage instead
-Backbone.LocalStorage = window.Store = function(name) {
-  if( !this.localStorage ) {
-    throw "Backbone.localStorage: Environment does not support localStorage."
-  }
-  this.name = name;
-  var store = this.localStorage().getItem(this.name);
-  this.records = (store && store.split(",")) || [];
-};
-
-_.extend(Backbone.LocalStorage.prototype, {
-
-  // Save the current state of the **Store** to *localStorage*.
-  save: function() {
-    this.localStorage().setItem(this.name, this.records.join(","));
-  },
-
-  // Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
-  // have an id of it's own.
-  create: function(model) {
-    if (!model.id) {
-      model.id = guid();
-      model.set(model.idAttribute, model.id);
-    }
-    this.localStorage().setItem(this.name+"-"+model.id, JSON.stringify(model));
-    this.records.push(model.id.toString());
-    this.save();
-    return this.find(model);
-  },
-
-  // Update a model by replacing its copy in `this.data`.
-  update: function(model) {
-    this.localStorage().setItem(this.name+"-"+model.id, JSON.stringify(model));
-    if (!_.include(this.records, model.id.toString()))
-      this.records.push(model.id.toString()); this.save();
-    return this.find(model);
-  },
-
-  // Retrieve a model from `this.data` by id.
-  find: function(model) {
-    return this.jsonData(this.localStorage().getItem(this.name+"-"+model.id));
-  },
-
-  // Return the array of all models currently in storage.
-  findAll: function() {
-    // Lodash removed _#chain in v1.0.0-rc.1
-    return (_.chain || _)(this.records)
-      .map(function(id){
-        return this.jsonData(this.localStorage().getItem(this.name+"-"+id));
-      }, this)
-      .compact()
-      .value();
-  },
-
-  // Delete a model from `this.data`, returning it.
-  destroy: function(model) {
-    if (model.isNew())
-      return false
-    this.localStorage().removeItem(this.name+"-"+model.id);
-    this.records = _.reject(this.records, function(id){
-      return id === model.id.toString();
-    });
-    this.save();
-    return model;
-  },
-
-  localStorage: function() {
-    return localStorage;
-  },
-
-  // fix for "illegal access" error on Android when JSON.parse is passed null
-  jsonData: function (data) {
-      return data && JSON.parse(data);
-  },
-
-  // Clear localStorage for specific collection.
-  _clear: function() {
-    var local = this.localStorage(),
-      itemRe = new RegExp("^" + this.name + "-");
-
-    // Remove id-tracking item (e.g., "foo").
-    local.removeItem(this.name);
-
-    // Lodash removed _#chain in v1.0.0-rc.1
-    // Match all data items (e.g., "foo-ID") and remove.
-    (_.chain || _)(local).keys()
-      .filter(function (k) { return itemRe.test(k); })
-      .each(function (k) { local.removeItem(k); });
-
-    this.records.length = 0;
-  },
-
-  // Size of localStorage.
-  _storageSize: function() {
-    return this.localStorage().length;
-  }
-
-});
-
-// localSync delegate to the model or collection's
-// *localStorage* property, which should be an instance of `Store`.
-// window.Store.sync and Backbone.localSync is deprecated, use Backbone.LocalStorage.sync instead
-Backbone.LocalStorage.sync = window.Store.sync = Backbone.localSync = function(method, model, options) {
-  var store = model.localStorage || model.collection.localStorage;
-
-  var resp, errorMessage, syncDfd = Backbone.$.Deferred && Backbone.$.Deferred(); //If $ is having Deferred - use it.
-
-  try {
-
-    switch (method) {
-      case "read":
-        resp = model.id != undefined ? store.find(model) : store.findAll();
-        break;
-      case "create":
-        resp = store.create(model);
-        break;
-      case "update":
-        resp = store.update(model);
-        break;
-      case "delete":
-        resp = store.destroy(model);
-        break;
-    }
-
-  } catch(error) {
-    if (error.code === 22 && store._storageSize() === 0)
-      errorMessage = "Private browsing is unsupported";
-    else
-      errorMessage = error.message;
-  }
-
-  if (resp) {
-    if (options && options.success) {
-      if (Backbone.VERSION === "0.9.10") {
-        options.success(model, resp, options);
-      } else {
-        options.success(resp);
-      }
-    }
-    if (syncDfd) {
-      syncDfd.resolve(resp);
-    }
-
-  } else {
-    errorMessage = errorMessage ? errorMessage
-                                : "Record Not Found";
-
-    if (options && options.error)
-      if (Backbone.VERSION === "0.9.10") {
-        options.error(model, errorMessage, options);
-      } else {
-        options.error(errorMessage);
-      }
-
-    if (syncDfd)
-      syncDfd.reject(errorMessage);
-  }
-
-  // add compatibility with $.ajax
-  // always execute callback for success and error
-  if (options && options.complete) options.complete(resp);
-
-  return syncDfd && syncDfd.promise();
-};
-
-Backbone.ajaxSync = Backbone.sync;
-
-Backbone.getSyncMethod = function(model) {
-  if(model.localStorage || (model.collection && model.collection.localStorage)) {
-    return Backbone.localSync;
-  }
-
-  return Backbone.ajaxSync;
-};
-
-// Override 'Backbone.sync' to default to localSync,
-// the original 'Backbone.sync' is still available in 'Backbone.ajaxSync'
-Backbone.sync = function(method, model, options) {
-  return Backbone.getSyncMethod(model).apply(this, [method, model, options]);
-};
-
-return Backbone.LocalStorage;
-}));
diff --git a/security-admin/src/main/webapp/libs/bower/backbone.marionette/js/backbone.marionette.js b/security-admin/src/main/webapp/libs/bower/backbone.marionette/js/backbone.marionette.js
deleted file mode 100644
index dee18607d..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone.marionette/js/backbone.marionette.js
+++ /dev/null
@@ -1,1959 +0,0 @@
-// MarionetteJS (Backbone.Marionette)
-// ----------------------------------
-// v1.1.0
-//
-// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
-// Distributed under MIT license
-//
-// http://marionettejs.com
-
-
-
-/*!
- * Includes BabySitter
- * https://github.com/marionettejs/backbone.babysitter/
- *
- * Includes Wreqr
- * https://github.com/marionettejs/backbone.wreqr/
- */
-
-(function (root, factory) {
-  if (typeof exports === 'object') {
-
-    var underscore = require('underscore');
-    var backbone = require('backbone');
-    var wreqr = require('backbone.wreqr');
-    var babysitter = require('backbone.babysitter');
-
-    module.exports = factory(underscore, backbone, wreqr, babysitter);
-
-  } else if (typeof define === 'function' && define.amd) {
-
-    define(['underscore', 'backbone', 'backbone.wreqr', 'backbone.babysitter'], factory);
-
-  } 
-}(this, function (_, Backbone) {
-
-  var Marionette = (function(global, Backbone, _){
-  "use strict";
-
-  // Define and export the Marionette namespace
-  var Marionette = {};
-  Backbone.Marionette = Marionette;
-
-  // Get the DOM manipulator for later use
-  Marionette.$ = Backbone.$;
-
-// Helpers
-// -------
-
-// For slicing `arguments` in functions
-var protoSlice = Array.prototype.slice;
-function slice(args) {
-  return protoSlice.call(args);
-}
-
-function throwError(message, name) {
-  var error = new Error(message);
-  error.name = name || 'Error';
-  throw error;
-}
-
-// Marionette.extend
-// -----------------
-
-// Borrow the Backbone `extend` method so we can use it as needed
-Marionette.extend = Backbone.Model.extend;
-
-// Marionette.getOption
-// --------------------
-
-// Retrieve an object, function or other value from a target
-// object or its `options`, with `options` taking precedence.
-Marionette.getOption = function(target, optionName){
-  if (!target || !optionName){ return; }
-  var value;
-
-  if (target.options && (optionName in target.options) && (target.options[optionName] !== undefined)){
-    value = target.options[optionName];
-  } else {
-    value = target[optionName];
-  }
-
-  return value;
-};
-
-// Trigger an event and/or a corresponding method name. Examples:
-//
-// `this.triggerMethod("foo")` will trigger the "foo" event and
-// call the "onFoo" method.
-//
-// `this.triggerMethod("foo:bar") will trigger the "foo:bar" event and
-// call the "onFooBar" method.
-Marionette.triggerMethod = (function(){
-
-  // split the event name on the :
-  var splitter = /(^|:)(\w)/gi;
-
-  // take the event section ("section1:section2:section3")
-  // and turn it in to uppercase name
-  function getEventName(match, prefix, eventName) {
-    return eventName.toUpperCase();
-  }
-
-  // actual triggerMethod name
-  var triggerMethod = function(event) {
-    // get the method name from the event name
-    var methodName = 'on' + event.replace(splitter, getEventName);
-    var method = this[methodName];
-
-    // trigger the event, if a trigger method exists
-    if(_.isFunction(this.trigger)) {
-      this.trigger.apply(this, arguments);
-    }
-
-    // call the onMethodName if it exists
-    if (_.isFunction(method)) {
-      // pass all arguments, except the event name
-      return method.apply(this, _.tail(arguments));
-    }
-  };
-
-  return triggerMethod;
-})();
-
-// DOMRefresh
-// ----------
-//
-// Monitor a view's state, and after it has been rendered and shown
-// in the DOM, trigger a "dom:refresh" event every time it is
-// re-rendered.
-
-Marionette.MonitorDOMRefresh = (function(){
-  // track when the view has been shown in the DOM,
-  // using a Marionette.Region (or by other means of triggering "show")
-  function handleShow(view){
-    view._isShown = true;
-    triggerDOMRefresh(view);
-  }
-
-  // track when the view has been rendered
-  function handleRender(view){
-    view._isRendered = true;
-    triggerDOMRefresh(view);
-  }
-
-  // Trigger the "dom:refresh" event and corresponding "onDomRefresh" method
-  function triggerDOMRefresh(view){
-    if (view._isShown && view._isRendered){
-      if (_.isFunction(view.triggerMethod)){
-        view.triggerMethod("dom:refresh");
-      }
-    }
-  }
-
-  // Export public API
-  return function(view){
-    view.listenTo(view, "show", function(){
-      handleShow(view);
-    });
-
-    view.listenTo(view, "render", function(){
-      handleRender(view);
-    });
-  };
-})();
-
-
-// Marionette.bindEntityEvents & unbindEntityEvents
-// ---------------------------
-//
-// These methods are used to bind/unbind a backbone "entity" (collection/model) 
-// to methods on a target object. 
-//
-// The first parameter, `target`, must have a `listenTo` method from the
-// EventBinder object.
-//
-// The second parameter is the entity (Backbone.Model or Backbone.Collection)
-// to bind the events from.
-//
-// The third parameter is a hash of { "event:name": "eventHandler" }
-// configuration. Multiple handlers can be separated by a space. A
-// function can be supplied instead of a string handler name. 
-
-(function(Marionette){
-  "use strict";
-
-  // Bind the event to handlers specified as a string of
-  // handler names on the target object
-  function bindFromStrings(target, entity, evt, methods){
-    var methodNames = methods.split(/\s+/);
-
-    _.each(methodNames,function(methodName) {
-
-      var method = target[methodName];
-      if(!method) {
-        throwError("Method '"+ methodName +"' was configured as an event handler, but does not exist.");
-      }
-
-      target.listenTo(entity, evt, method, target);
-    });
-  }
-
-  // Bind the event to a supplied callback function
-  function bindToFunction(target, entity, evt, method){
-      target.listenTo(entity, evt, method, target);
-  }
-
-  // Bind the event to handlers specified as a string of
-  // handler names on the target object
-  function unbindFromStrings(target, entity, evt, methods){
-    var methodNames = methods.split(/\s+/);
-
-    _.each(methodNames,function(methodName) {
-      var method = target[methodName];
-      target.stopListening(entity, evt, method, target);
-    });
-  }
-
-  // Bind the event to a supplied callback function
-  function unbindToFunction(target, entity, evt, method){
-      target.stopListening(entity, evt, method, target);
-  }
-
-  
-  // generic looping function
-  function iterateEvents(target, entity, bindings, functionCallback, stringCallback){
-    if (!entity || !bindings) { return; }
-
-    // allow the bindings to be a function
-    if (_.isFunction(bindings)){
-      bindings = bindings.call(target);
-    }
-
-    // iterate the bindings and bind them
-    _.each(bindings, function(methods, evt){
-
-      // allow for a function as the handler, 
-      // or a list of event names as a string
-      if (_.isFunction(methods)){
-        functionCallback(target, entity, evt, methods);
-      } else {
-        stringCallback(target, entity, evt, methods);
-      }
-
-    });
-  }
- 
-  // Export Public API
-  Marionette.bindEntityEvents = function(target, entity, bindings){
-    iterateEvents(target, entity, bindings, bindToFunction, bindFromStrings);
-  };
-
-  Marionette.unbindEntityEvents = function(target, entity, bindings){
-    iterateEvents(target, entity, bindings, unbindToFunction, unbindFromStrings);
-  };
-
-})(Marionette);
-
-
-// Callbacks
-// ---------
-
-// A simple way of managing a collection of callbacks
-// and executing them at a later point in time, using jQuery's
-// `Deferred` object.
-Marionette.Callbacks = function(){
-  this._deferred = Marionette.$.Deferred();
-  this._callbacks = [];
-};
-
-_.extend(Marionette.Callbacks.prototype, {
-
-  // Add a callback to be executed. Callbacks added here are
-  // guaranteed to execute, even if they are added after the 
-  // `run` method is called.
-  add: function(callback, contextOverride){
-    this._callbacks.push({cb: callback, ctx: contextOverride});
-
-    this._deferred.done(function(context, options){
-      if (contextOverride){ context = contextOverride; }
-      callback.call(context, options);
-    });
-  },
-
-  // Run all registered callbacks with the context specified. 
-  // Additional callbacks can be added after this has been run 
-  // and they will still be executed.
-  run: function(options, context){
-    this._deferred.resolve(context, options);
-  },
-
-  // Resets the list of callbacks to be run, allowing the same list
-  // to be run multiple times - whenever the `run` method is called.
-  reset: function(){
-    var callbacks = this._callbacks;
-    this._deferred = Marionette.$.Deferred();
-    this._callbacks = [];
-    
-    _.each(callbacks, function(cb){
-      this.add(cb.cb, cb.ctx);
-    }, this);
-  }
-});
-
-
-// Marionette Controller
-// ---------------------
-//
-// A multi-purpose object to use as a controller for
-// modules and routers, and as a mediator for workflow
-// and coordination of other objects, views, and more.
-Marionette.Controller = function(options){
-  this.triggerMethod = Marionette.triggerMethod;
-  this.options = options || {};
-
-  if (_.isFunction(this.initialize)){
-    this.initialize(this.options);
-  }
-};
-
-Marionette.Controller.extend = Marionette.extend;
-
-// Controller Methods
-// --------------
-
-// Ensure it can trigger events with Backbone.Events
-_.extend(Marionette.Controller.prototype, Backbone.Events, {
-  close: function(){
-    this.stopListening();
-    this.triggerMethod("close");
-    this.unbind();
-  }
-});
-
-// Region 
-// ------
-//
-// Manage the visual regions of your composite application. See
-// http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/
-
-Marionette.Region = function(options){
-  this.options = options || {};
-
-  this.el = Marionette.getOption(this, "el");
-
-  if (!this.el){
-    var err = new Error("An 'el' must be specified for a region.");
-    err.name = "NoElError";
-    throw err;
-  }
-
-  if (this.initialize){
-    var args = Array.prototype.slice.apply(arguments);
-    this.initialize.apply(this, args);
-  }
-};
-
-
-// Region Type methods
-// -------------------
-
-_.extend(Marionette.Region, {
-
-  // Build an instance of a region by passing in a configuration object
-  // and a default region type to use if none is specified in the config.
-  //
-  // The config object should either be a string as a jQuery DOM selector,
-  // a Region type directly, or an object literal that specifies both
-  // a selector and regionType:
-  //
-  // ```js
-  // {
-  //   selector: "#foo",
-  //   regionType: MyCustomRegion
-  // }
-  // ```
-  //
-  buildRegion: function(regionConfig, defaultRegionType){
-
-    var regionIsString = (typeof regionConfig === "string");
-    var regionSelectorIsString = (typeof regionConfig.selector === "string");
-    var regionTypeIsUndefined = (typeof regionConfig.regionType === "undefined");
-    var regionIsType = (typeof regionConfig === "function");
-
-    if (!regionIsType && !regionIsString && !regionSelectorIsString) {
-      throw new Error("Region must be specified as a Region type, a selector string or an object with selector property");
-    }
-
-    var selector, RegionType;
-   
-    // get the selector for the region
-    
-    if (regionIsString) {
-      selector = regionConfig;
-    } 
-
-    if (regionConfig.selector) {
-      selector = regionConfig.selector;
-    }
-
-    // get the type for the region
-    
-    if (regionIsType){
-      RegionType = regionConfig;
-    }
-
-    if (!regionIsType && regionTypeIsUndefined) {
-      RegionType = defaultRegionType;
-    }
-
-    if (regionConfig.regionType) {
-      RegionType = regionConfig.regionType;
-    }
-    
-    // build the region instance
-    var region = new RegionType({
-      el: selector
-    });
-
-    // override the `getEl` function if we have a parentEl
-    // this must be overridden to ensure the selector is found
-    // on the first use of the region. if we try to assign the
-    // region's `el` to `parentEl.find(selector)` in the object
-    // literal to build the region, the element will not be
-    // guaranteed to be in the DOM already, and will cause problems
-    if (regionConfig.parentEl){
-
-      region.getEl = function(selector) {
-        var parentEl = regionConfig.parentEl;
-        if (_.isFunction(parentEl)){
-          parentEl = parentEl();
-        }
-        return parentEl.find(selector);
-      };
-    }
-
-    return region;
-  }
-
-});
-
-// Region Instance Methods
-// -----------------------
-
-_.extend(Marionette.Region.prototype, Backbone.Events, {
-
-  // Displays a backbone view instance inside of the region.
-  // Handles calling the `render` method for you. Reads content
-  // directly from the `el` attribute. Also calls an optional
-  // `onShow` and `close` method on your view, just after showing
-  // or just before closing the view, respectively.
-  show: function(view){
-
-    this.ensureEl();
-
-    var isViewClosed = view.isClosed || _.isUndefined(view.$el);
-
-    var isDifferentView = view !== this.currentView;
-
-    if (isDifferentView) {
-      this.close();
-    }
-
-    view.render();
-
-    if (isDifferentView || isViewClosed) {
-      this.open(view);
-    }
-    
-    this.currentView = view;
-
-    Marionette.triggerMethod.call(this, "show", view);
-    Marionette.triggerMethod.call(view, "show");
-  },
-
-  ensureEl: function(){
-    if (!this.$el || this.$el.length === 0){
-      this.$el = this.getEl(this.el);
-    }
-  },
-
-  // Override this method to change how the region finds the
-  // DOM element that it manages. Return a jQuery selector object.
-  getEl: function(selector){
-    return Marionette.$(selector);
-  },
-
-  // Override this method to change how the new view is
-  // appended to the `$el` that the region is managing
-  open: function(view){
-    this.$el.empty().append(view.el);
-  },
-
-  // Close the current view, if there is one. If there is no
-  // current view, it does nothing and returns immediately.
-  close: function(){
-    var view = this.currentView;
-    if (!view || view.isClosed){ return; }
-
-    // call 'close' or 'remove', depending on which is found
-    if (view.close) { view.close(); }
-    else if (view.remove) { view.remove(); }
-
-    Marionette.triggerMethod.call(this, "close");
-
-    delete this.currentView;
-  },
-
-  // Attach an existing view to the region. This 
-  // will not call `render` or `onShow` for the new view, 
-  // and will not replace the current HTML for the `el`
-  // of the region.
-  attachView: function(view){
-    this.currentView = view;
-  },
-
-  // Reset the region by closing any existing view and
-  // clearing out the cached `$el`. The next time a view
-  // is shown via this region, the region will re-query the
-  // DOM for the region's `el`.
-  reset: function(){
-    this.close();
-    delete this.$el;
-  }
-});
-
-// Copy the `extend` function used by Backbone's classes
-Marionette.Region.extend = Marionette.extend;
-
-// Marionette.RegionManager
-// ------------------------
-//
-// Manage one or more related `Marionette.Region` objects.
-Marionette.RegionManager = (function(Marionette){
-
-  var RegionManager = Marionette.Controller.extend({
-    constructor: function(options){
-      this._regions = {};
-      Marionette.Controller.prototype.constructor.call(this, options);
-    },
-
-    // Add multiple regions using an object literal, where
-    // each key becomes the region name, and each value is
-    // the region definition.
-    addRegions: function(regionDefinitions, defaults){
-      var regions = {};
-
-      _.each(regionDefinitions, function(definition, name){
-        if (typeof definition === "string"){
-          definition = { selector: definition };
-        }
-
-        if (definition.selector){
-          definition = _.defaults({}, definition, defaults);
-        }
-
-        var region = this.addRegion(name, definition);
-        regions[name] = region;
-      }, this);
-
-      return regions;
-    },
-
-    // Add an individual region to the region manager,
-    // and return the region instance
-    addRegion: function(name, definition){
-      var region;
-
-      var isObject = _.isObject(definition);
-      var isString = _.isString(definition);
-      var hasSelector = !!definition.selector;
-
-      if (isString || (isObject && hasSelector)){
-        region = Marionette.Region.buildRegion(definition, Marionette.Region);
-      } else if (_.isFunction(definition)){
-        region = Marionette.Region.buildRegion(definition, Marionette.Region);
-      } else {
-        region = definition;
-      }
-
-      this._store(name, region);
-      this.triggerMethod("region:add", name, region);
-      return region;
-    },
-
-    // Get a region by name
-    get: function(name){
-      return this._regions[name];
-    },
-
-    // Remove a region by name
-    removeRegion: function(name){
-      var region = this._regions[name];
-      this._remove(name, region);
-    },
-
-    // Close all regions in the region manager, and
-    // remove them
-    removeRegions: function(){
-      _.each(this._regions, function(region, name){
-        this._remove(name, region);
-      }, this);
-    },
-
-    // Close all regions in the region manager, but
-    // leave them attached
-    closeRegions: function(){
-      _.each(this._regions, function(region, name){
-        region.close();
-      }, this);
-    },
-
-    // Close all regions and shut down the region
-    // manager entirely
-    close: function(){
-      this.removeRegions();
-      var args = Array.prototype.slice.call(arguments);
-      Marionette.Controller.prototype.close.apply(this, args);
-    },
-
-    // internal method to store regions
-    _store: function(name, region){
-      this._regions[name] = region;
-      this._setLength();
-    },
-
-    // internal method to remove a region
-    _remove: function(name, region){
-      region.close();
-      delete this._regions[name];
-      this._setLength();
-      this.triggerMethod("region:remove", name, region);
-    },
-
-    // set the number of regions current held
-    _setLength: function(){
-      this.length = _.size(this._regions);
-    }
-
-  });
-
-  // Borrowing this code from Backbone.Collection:
-  // http://backbonejs.org/docs/backbone.html#section-106
-  //
-  // Mix in methods from Underscore, for iteration, and other
-  // collection related features.
-  var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter', 
-    'select', 'reject', 'every', 'all', 'some', 'any', 'include', 
-    'contains', 'invoke', 'toArray', 'first', 'initial', 'rest', 
-    'last', 'without', 'isEmpty', 'pluck'];
-
-  _.each(methods, function(method) {
-    RegionManager.prototype[method] = function() {
-      var regions = _.values(this._regions);
-      var args = [regions].concat(_.toArray(arguments));
-      return _[method].apply(_, args);
-    };
-  });
-
-  return RegionManager;
-})(Marionette);
-
-
-// Template Cache
-// --------------
-
-// Manage templates stored in `<script>` blocks,
-// caching them for faster access.
-Marionette.TemplateCache = function(templateId){
-  this.templateId = templateId;
-};
-
-// TemplateCache object-level methods. Manage the template
-// caches from these method calls instead of creating 
-// your own TemplateCache instances
-_.extend(Marionette.TemplateCache, {
-  templateCaches: {},
-
-  // Get the specified template by id. Either
-  // retrieves the cached version, or loads it
-  // from the DOM.
-  get: function(templateId){
-    var cachedTemplate = this.templateCaches[templateId];
-
-    if (!cachedTemplate){
-      cachedTemplate = new Marionette.TemplateCache(templateId);
-      this.templateCaches[templateId] = cachedTemplate;
-    }
-
-    return cachedTemplate.load();
-  },
-
-  // Clear templates from the cache. If no arguments
-  // are specified, clears all templates:
-  // `clear()`
-  //
-  // If arguments are specified, clears each of the 
-  // specified templates from the cache:
-  // `clear("#t1", "#t2", "...")`
-  clear: function(){
-    var i;
-    var args = slice(arguments);
-    var length = args.length;
-
-    if (length > 0){
-      for(i=0; i<length; i++){
-        delete this.templateCaches[args[i]];
-      }
-    } else {
-      this.templateCaches = {};
-    }
-  }
-});
-
-// TemplateCache instance methods, allowing each
-// template cache object to manage its own state
-// and know whether or not it has been loaded
-_.extend(Marionette.TemplateCache.prototype, {
-
-  // Internal method to load the template
-  load: function(){
-    // Guard clause to prevent loading this template more than once
-    if (this.compiledTemplate){
-      return this.compiledTemplate;
-    }
-
-    // Load the template and compile it
-    var template = this.loadTemplate(this.templateId);
-    this.compiledTemplate = this.compileTemplate(template);
-
-    return this.compiledTemplate;
-  },
-
-  // Load a template from the DOM, by default. Override
-  // this method to provide your own template retrieval
-  // For asynchronous loading with AMD/RequireJS, consider
-  // using a template-loader plugin as described here: 
-  // https://github.com/marionettejs/backbone.marionette/wiki/Using-marionette-with-requirejs
-  loadTemplate: function(templateId){
-    var template = Marionette.$(templateId).html();
-
-    if (!template || template.length === 0){
-      throwError("Could not find template: '" + templateId + "'", "NoTemplateError");
-    }
-
-    return template;
-  },
-
-  // Pre-compile the template before caching it. Override
-  // this method if you do not need to pre-compile a template
-  // (JST / RequireJS for example) or if you want to change
-  // the template engine used (Handebars, etc).
-  compileTemplate: function(rawTemplate){
-    return _.template(rawTemplate);
-  }
-});
-
-
-// Renderer
-// --------
-
-// Render a template with data by passing in the template
-// selector and the data to render.
-Marionette.Renderer = {
-
-  // Render a template with data. The `template` parameter is
-  // passed to the `TemplateCache` object to retrieve the
-  // template function. Override this method to provide your own
-  // custom rendering and template handling for all of Marionette.
-  render: function(template, data){
-
-    if (!template) {
-      var error = new Error("Cannot render the template since it's false, null or undefined.");
-      error.name = "TemplateNotFoundError";
-      throw error;
-    }
-
-    var templateFunc;
-    if (typeof template === "function"){
-      templateFunc = template;
-    } else {
-      templateFunc = Marionette.TemplateCache.get(template);
-    }
-
-    return templateFunc(data);
-  }
-};
-
-
-
-// Marionette.View
-// ---------------
-
-// The core view type that other Marionette views extend from.
-Marionette.View = Backbone.View.extend({
-
-  constructor: function(){
-    _.bindAll(this, "render");
-
-    var args = Array.prototype.slice.apply(arguments);
-    Backbone.View.prototype.constructor.apply(this, args);
-
-    Marionette.MonitorDOMRefresh(this);
-    this.listenTo(this, "show", this.onShowCalled, this);
-  },
-
-  // import the "triggerMethod" to trigger events with corresponding
-  // methods if the method exists 
-  triggerMethod: Marionette.triggerMethod,
-
-  // Get the template for this view
-  // instance. You can set a `template` attribute in the view
-  // definition or pass a `template: "whatever"` parameter in
-  // to the constructor options.
-  getTemplate: function(){
-    return Marionette.getOption(this, "template");
-  },
-
-  // Mix in template helper methods. Looks for a
-  // `templateHelpers` attribute, which can either be an
-  // object literal, or a function that returns an object
-  // literal. All methods and attributes from this object
-  // are copies to the object passed in.
-  mixinTemplateHelpers: function(target){
-    target = target || {};
-    var templateHelpers = Marionette.getOption(this, "templateHelpers");
-    if (_.isFunction(templateHelpers)){
-      templateHelpers = templateHelpers.call(this);
-    }
-    return _.extend(target, templateHelpers);
-  },
-
-  // Configure `triggers` to forward DOM events to view
-  // events. `triggers: {"click .foo": "do:foo"}`
-  configureTriggers: function(){
-    if (!this.triggers) { return; }
-
-    var triggerEvents = {};
-
-    // Allow `triggers` to be configured as a function
-    var triggers = _.result(this, "triggers");
-
-    // Configure the triggers, prevent default
-    // action and stop propagation of DOM events
-    _.each(triggers, function(value, key){
-
-      // build the event handler function for the DOM event
-      triggerEvents[key] = function(e){
-
-        // stop the event in its tracks
-        if (e && e.preventDefault){ e.preventDefault(); }
-        if (e && e.stopPropagation){ e.stopPropagation(); }
-
-        // build the args for the event
-        var args = {
-          view: this,
-          model: this.model,
-          collection: this.collection
-        };
-
-        // trigger the event
-        this.triggerMethod(value, args);
-      };
-
-    }, this);
-
-    return triggerEvents;
-  },
-
-  // Overriding Backbone.View's delegateEvents to handle 
-  // the `triggers`, `modelEvents`, and `collectionEvents` configuration
-  delegateEvents: function(events){
-    this._delegateDOMEvents(events);
-    Marionette.bindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
-    Marionette.bindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
-  },
-
-  // internal method to delegate DOM events and triggers
-  _delegateDOMEvents: function(events){
-    events = events || this.events;
-    if (_.isFunction(events)){ events = events.call(this); }
-
-    var combinedEvents = {};
-    var triggers = this.configureTriggers();
-    _.extend(combinedEvents, events, triggers);
-
-    Backbone.View.prototype.delegateEvents.call(this, combinedEvents);
-  },
-
-  // Overriding Backbone.View's undelegateEvents to handle unbinding
-  // the `triggers`, `modelEvents`, and `collectionEvents` config
-  undelegateEvents: function(){
-    var args = Array.prototype.slice.call(arguments);
-    Backbone.View.prototype.undelegateEvents.apply(this, args);
-
-    Marionette.unbindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
-    Marionette.unbindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
-  },
-
-  // Internal method, handles the `show` event.
-  onShowCalled: function(){},
-
-  // Default `close` implementation, for removing a view from the
-  // DOM and unbinding it. Regions will call this method
-  // for you. You can specify an `onClose` method in your view to
-  // add custom code that is called after the view is closed.
-  close: function(){
-    if (this.isClosed) { return; }
-
-    // allow the close to be stopped by returning `false`
-    // from the `onBeforeClose` method
-    var shouldClose = this.triggerMethod("before:close");
-    if (shouldClose === false){
-      return;
-    }
-
-    // mark as closed before doing the actual close, to
-    // prevent infinite loops within "close" event handlers
-    // that are trying to close other views
-    this.isClosed = true;
-    this.triggerMethod("close");
-
-    // unbind UI elements
-    this.unbindUIElements();
-
-    // remove the view from the DOM
-    this.remove();
-  },
-
-  // This method binds the elements specified in the "ui" hash inside the view's code with
-  // the associated jQuery selectors.
-  bindUIElements: function(){
-    if (!this.ui) { return; }
-
-    // store the ui hash in _uiBindings so they can be reset later
-    // and so re-rendering the view will be able to find the bindings
-    if (!this._uiBindings){
-      this._uiBindings = this.ui;
-    }
-
-    // get the bindings result, as a function or otherwise
-    var bindings = _.result(this, "_uiBindings");
-
-    // empty the ui so we don't have anything to start with
-    this.ui = {};
-
-    // bind each of the selectors
-    _.each(_.keys(bindings), function(key) {
-      var selector = bindings[key];
-      this.ui[key] = this.$(selector);
-    }, this);
-  },
-
-  // This method unbinds the elements specified in the "ui" hash
-  unbindUIElements: function(){
-    if (!this.ui || !this._uiBindings){ return; }
-
-    // delete all of the existing ui bindings
-    _.each(this.ui, function($el, name){
-      delete this.ui[name];
-    }, this);
-
-    // reset the ui element to the original bindings configuration
-    this.ui = this._uiBindings;
-    delete this._uiBindings;
-  }
-});
-
-// Item View
-// ---------
-
-// A single item view implementation that contains code for rendering
-// with underscore.js templates, serializing the view's model or collection,
-// and calling several methods on extended views, such as `onRender`.
-Marionette.ItemView = Marionette.View.extend({
-  
-  // Setting up the inheritance chain which allows changes to 
-  // Marionette.View.prototype.constructor which allows overriding
-  constructor: function(){
-    Marionette.View.prototype.constructor.apply(this, slice(arguments));
-  },
-
-  // Serialize the model or collection for the view. If a model is
-  // found, `.toJSON()` is called. If a collection is found, `.toJSON()`
-  // is also called, but is used to populate an `items` array in the
-  // resulting data. If both are found, defaults to the model.
-  // You can override the `serializeData` method in your own view
-  // definition, to provide custom serialization for your view's data.
-  serializeData: function(){
-    var data = {};
-
-    if (this.model) {
-      data = this.model.toJSON();
-    }
-    else if (this.collection) {
-      data = { items: this.collection.toJSON() };
-    }
-
-    return data;
-  },
-
-  // Render the view, defaulting to underscore.js templates.
-  // You can override this in your view definition to provide
-  // a very specific rendering for your view. In general, though,
-  // you should override the `Marionette.Renderer` object to
-  // change how Marionette renders views.
-  render: function(){
-    this.isClosed = false;
-
-    this.triggerMethod("before:render", this);
-    this.triggerMethod("item:before:render", this);
-
-    var data = this.serializeData();
-    data = this.mixinTemplateHelpers(data);
-
-    var template = this.getTemplate();
-    var html = Marionette.Renderer.render(template, data);
-
-    this.$el.html(html);
-    this.bindUIElements();
-
-    this.triggerMethod("render", this);
-    this.triggerMethod("item:rendered", this);
-
-    return this;
-  },
-
-  // Override the default close event to add a few
-  // more events that are triggered.
-  close: function(){
-    if (this.isClosed){ return; }
-
-    this.triggerMethod('item:before:close');
-
-    Marionette.View.prototype.close.apply(this, slice(arguments));
-
-    this.triggerMethod('item:closed');
-  }
-});
-
-// Collection View
-// ---------------
-
-// A view that iterates over a Backbone.Collection
-// and renders an individual ItemView for each model.
-Marionette.CollectionView = Marionette.View.extend({
-  // used as the prefix for item view events
-  // that are forwarded through the collectionview
-  itemViewEventPrefix: "itemview",
-
-  // constructor
-  constructor: function(options){
-    this._initChildViewStorage();
-
-    Marionette.View.prototype.constructor.apply(this, slice(arguments));
-
-    this._initialEvents();
-  },
-
-  // Configured the initial events that the collection view
-  // binds to. Override this method to prevent the initial
-  // events, or to add your own initial events.
-  _initialEvents: function(){
-    if (this.collection){
-      this.listenTo(this.collection, "add", this.addChildView, this);
-      this.listenTo(this.collection, "remove", this.removeItemView, this);
-      this.listenTo(this.collection, "reset", this.render, this);
-    }
-  },
-
-  // Handle a child item added to the collection
-  addChildView: function(item, collection, options){
-    this.closeEmptyView();
-    var ItemView = this.getItemView(item);
-    var index = this.collection.indexOf(item);
-    this.addItemView(item, ItemView, index);
-  },
-
-  // Override from `Marionette.View` to guarantee the `onShow` method
-  // of child views is called.
-  onShowCalled: function(){
-    this.children.each(function(child){
-      Marionette.triggerMethod.call(child, "show");
-    });
-  },
-
-  // Internal method to trigger the before render callbacks
-  // and events
-  triggerBeforeRender: function(){
-    this.triggerMethod("before:render", this);
-    this.triggerMethod("collection:before:render", this);
-  },
-
-  // Internal method to trigger the rendered callbacks and
-  // events
-  triggerRendered: function(){
-    this.triggerMethod("render", this);
-    this.triggerMethod("collection:rendered", this);
-  },
-
-  // Render the collection of items. Override this method to
-  // provide your own implementation of a render function for
-  // the collection view.
-  render: function(){
-    this.isClosed = false;
-    this.triggerBeforeRender();
-    this._renderChildren();
-    this.triggerRendered();
-    return this;
-  },
-
-  // Internal method. Separated so that CompositeView can have
-  // more control over events being triggered, around the rendering
-  // process
-  _renderChildren: function(){
-    this.closeEmptyView();
-    this.closeChildren();
-
-    if (this.collection && this.collection.length > 0) {
-      this.showCollection();
-    } else {
-      this.showEmptyView();
-    }
-  },
-
-  // Internal method to loop through each item in the
-  // collection view and show it
-  showCollection: function(){
-    var ItemView;
-    this.collection.each(function(item, index){
-      ItemView = this.getItemView(item);
-      this.addItemView(item, ItemView, index);
-    }, this);
-  },
-
-  // Internal method to show an empty view in place of
-  // a collection of item views, when the collection is
-  // empty
-  showEmptyView: function(){
-    var EmptyView = Marionette.getOption(this, "emptyView");
-
-    if (EmptyView && !this._showingEmptyView){
-      this._showingEmptyView = true;
-      var model = new Backbone.Model();
-      this.addItemView(model, EmptyView, 0);
-    }
-  },
-
-  // Internal method to close an existing emptyView instance
-  // if one exists. Called when a collection view has been
-  // rendered empty, and then an item is added to the collection.
-  closeEmptyView: function(){
-    if (this._showingEmptyView){
-      this.closeChildren();
-      delete this._showingEmptyView;
-    }
-  },
-
-  // Retrieve the itemView type, either from `this.options.itemView`
-  // or from the `itemView` in the object definition. The "options"
-  // takes precedence.
-  getItemView: function(item){
-    var itemView = Marionette.getOption(this, "itemView");
-
-    if (!itemView){
-      throwError("An `itemView` must be specified", "NoItemViewError");
-    }
-
-    return itemView;
-  },
-
-  // Render the child item's view and add it to the
-  // HTML for the collection view.
-  addItemView: function(item, ItemView, index){
-    // get the itemViewOptions if any were specified
-    var itemViewOptions = Marionette.getOption(this, "itemViewOptions");
-    if (_.isFunction(itemViewOptions)){
-      itemViewOptions = itemViewOptions.call(this, item, index);
-    }
-
-    // build the view 
-    var view = this.buildItemView(item, ItemView, itemViewOptions);
-    
-    // set up the child view event forwarding
-    this.addChildViewEventForwarding(view);
-
-    // this view is about to be added
-    this.triggerMethod("before:item:added", view);
-
-    // Store the child view itself so we can properly
-    // remove and/or close it later
-    this.children.add(view);
-
-    // Render it and show it
-    this.renderItemView(view, index);
-
-    // call the "show" method if the collection view
-    // has already been shown
-    if (this._isShown){
-      Marionette.triggerMethod.call(view, "show");
-    }
-
-    // this view was added
-    this.triggerMethod("after:item:added", view);
-  },
-
-  // Set up the child view event forwarding. Uses an "itemview:"
-  // prefix in front of all forwarded events.
-  addChildViewEventForwarding: function(view){
-    var prefix = Marionette.getOption(this, "itemViewEventPrefix");
-
-    // Forward all child item view events through the parent,
-    // prepending "itemview:" to the event name
-    this.listenTo(view, "all", function(){
-      var args = slice(arguments);
-      args[0] = prefix + ":" + args[0];
-      args.splice(1, 0, view);
-
-      Marionette.triggerMethod.apply(this, args);
-    }, this);
-  },
-
-  // render the item view
-  renderItemView: function(view, index) {
-    view.render();
-    this.appendHtml(this, view, index);
-  },
-
-  // Build an `itemView` for every model in the collection.
-  buildItemView: function(item, ItemViewType, itemViewOptions){
-    var options = _.extend({model: item}, itemViewOptions);
-    return new ItemViewType(options);
-  },
-
-  // get the child view by item it holds, and remove it
-  removeItemView: function(item){
-    var view = this.children.findByModel(item);
-    this.removeChildView(view);
-    this.checkEmpty();
-  },
-
-  // Remove the child view and close it
-  removeChildView: function(view){
-
-    // shut down the child view properly,
-    // including events that the collection has from it
-    if (view){
-      this.stopListening(view);
-
-      // call 'close' or 'remove', depending on which is found
-      if (view.close) { view.close(); }
-      else if (view.remove) { view.remove(); }
-
-      this.children.remove(view);
-    }
-
-    this.triggerMethod("item:removed", view);
-  },
-
-  // helper to show the empty view if the collection is empty
-  checkEmpty: function() {
-    // check if we're empty now, and if we are, show the
-    // empty view
-    if (!this.collection || this.collection.length === 0){
-      this.showEmptyView();
-    }
-  },
-
-  // Append the HTML to the collection's `el`.
-  // Override this method to do something other
-  // then `.append`.
-  appendHtml: function(collectionView, itemView, index){
-    collectionView.$el.append(itemView.el);
-  },
-
-  // Internal method to set up the `children` object for
-  // storing all of the child views
-  _initChildViewStorage: function(){
-    this.children = new Backbone.ChildViewContainer();
-  },
-
-  // Handle cleanup and other closing needs for
-  // the collection of views.
-  close: function(){
-    if (this.isClosed){ return; }
-
-    this.triggerMethod("collection:before:close");
-    this.closeChildren();
-    this.triggerMethod("collection:closed");
-
-    Marionette.View.prototype.close.apply(this, slice(arguments));
-  },
-
-  // Close the child views that this collection view
-  // is holding on to, if any
-  closeChildren: function(){
-    this.children.each(function(child){
-      this.removeChildView(child);
-    }, this);
-    this.checkEmpty();
-  }
-});
-
-
-// Composite View
-// --------------
-
-// Used for rendering a branch-leaf, hierarchical structure.
-// Extends directly from CollectionView and also renders an
-// an item view as `modelView`, for the top leaf
-Marionette.CompositeView = Marionette.CollectionView.extend({
-
-  // Setting up the inheritance chain which allows changes to
-  // Marionette.CollectionView.prototype.constructor which allows overriding
-  constructor: function(){
-    Marionette.CollectionView.prototype.constructor.apply(this, slice(arguments));
-  },
-
-  // Configured the initial events that the composite view
-  // binds to. Override this method to prevent the initial
-  // events, or to add your own initial events.
-  _initialEvents: function(){
-    if (this.collection){
-      this.listenTo(this.collection, "add", this.addChildView, this);
-      this.listenTo(this.collection, "remove", this.removeItemView, this);
-      this.listenTo(this.collection, "reset", this._renderChildren, this);
-    }
-  },
-
-  // Retrieve the `itemView` to be used when rendering each of
-  // the items in the collection. The default is to return
-  // `this.itemView` or Marionette.CompositeView if no `itemView`
-  // has been defined
-  getItemView: function(item){
-    var itemView = Marionette.getOption(this, "itemView") || this.constructor;
-
-    if (!itemView){
-      throwError("An `itemView` must be specified", "NoItemViewError");
-    }
-
-    return itemView;
-  },
-
-  // Serialize the collection for the view.
-  // You can override the `serializeData` method in your own view
-  // definition, to provide custom serialization for your view's data.
-  serializeData: function(){
-    var data = {};
-
-    if (this.model){
-      data = this.model.toJSON();
-    }
-
-    return data;
-  },
-
-  // Renders the model once, and the collection once. Calling
-  // this again will tell the model's view to re-render itself
-  // but the collection will not re-render.
-  render: function(){
-    this.isRendered = true;
-    this.isClosed = false;
-    this.resetItemViewContainer();
-
-    this.triggerBeforeRender();
-    var html = this.renderModel();
-    this.$el.html(html);
-    // the ui bindings is done here and not at the end of render since they
-    // will not be available until after the model is rendered, but should be
-    // available before the collection is rendered.
-    this.bindUIElements();
-    this.triggerMethod("composite:model:rendered");
-
-    this._renderChildren();
-
-    this.triggerMethod("composite:rendered");
-    this.triggerRendered();
-    return this;
-  },
-
-  _renderChildren: function(){
-    if (this.isRendered){
-      Marionette.CollectionView.prototype._renderChildren.call(this);
-      this.triggerMethod("composite:collection:rendered");
-    }
-  },
-
-  // Render an individual model, if we have one, as
-  // part of a composite view (branch / leaf). For example:
-  // a treeview.
-  renderModel: function(){
-    var data = {};
-    data = this.serializeData();
-    data = this.mixinTemplateHelpers(data);
-
-    var template = this.getTemplate();
-    return Marionette.Renderer.render(template, data);
-  },
-
-  // Appends the `el` of itemView instances to the specified
-  // `itemViewContainer` (a jQuery selector). Override this method to
-  // provide custom logic of how the child item view instances have their
-  // HTML appended to the composite view instance.
-  appendHtml: function(cv, iv, index){
-    var $container = this.getItemViewContainer(cv);
-    $container.append(iv.el);
-  },
-
-  // Internal method to ensure an `$itemViewContainer` exists, for the
-  // `appendHtml` method to use.
-  getItemViewContainer: function(containerView){
-    if ("$itemViewContainer" in containerView){
-      return containerView.$itemViewContainer;
-    }
-
-    var container;
-    var itemViewContainer = Marionette.getOption(containerView, "itemViewContainer");
-    if (itemViewContainer){
-
-      var selector = _.isFunction(itemViewContainer) ? itemViewContainer() : itemViewContainer;
-      container = containerView.$(selector);
-      if (container.length <= 0) {
-        throwError("The specified `itemViewContainer` was not found: " + containerView.itemViewContainer, "ItemViewContainerMissingError");
-      }
-
-    } else {
-      container = containerView.$el;
-    }
-
-    containerView.$itemViewContainer = container;
-    return container;
-  },
-
-  // Internal method to reset the `$itemViewContainer` on render
-  resetItemViewContainer: function(){
-    if (this.$itemViewContainer){
-      delete this.$itemViewContainer;
-    }
-  }
-});
-
-
-// Layout
-// ------
-
-// Used for managing application layouts, nested layouts and
-// multiple regions within an application or sub-application.
-//
-// A specialized view type that renders an area of HTML and then
-// attaches `Region` instances to the specified `regions`.
-// Used for composite view management and sub-application areas.
-Marionette.Layout = Marionette.ItemView.extend({
-  regionType: Marionette.Region,
-  
-  // Ensure the regions are available when the `initialize` method
-  // is called.
-  constructor: function (options) {
-    options = options || {};
-
-    this._firstRender = true;
-    this._initializeRegions(options);
-    
-    Marionette.ItemView.prototype.constructor.call(this, options);
-  },
-
-  // Layout's render will use the existing region objects the
-  // first time it is called. Subsequent calls will close the
-  // views that the regions are showing and then reset the `el`
-  // for the regions to the newly rendered DOM elements.
-  render: function(){
-
-    if (this.isClosed){
-      // a previously closed layout means we need to 
-      // completely re-initialize the regions
-      this._initializeRegions();
-    }
-    if (this._firstRender) {
-      // if this is the first render, don't do anything to
-      // reset the regions
-      this._firstRender = false;
-    } else if (!this.isClosed){
-      // If this is not the first render call, then we need to 
-      // re-initializing the `el` for each region
-      this._reInitializeRegions();
-    }
-
-    var args = Array.prototype.slice.apply(arguments);
-    var result = Marionette.ItemView.prototype.render.apply(this, args);
-
-    return result;
-  },
-
-  // Handle closing regions, and then close the view itself.
-  close: function () {
-    if (this.isClosed){ return; }
-    this.regionManager.close();
-    var args = Array.prototype.slice.apply(arguments);
-    Marionette.ItemView.prototype.close.apply(this, args);
-  },
-
-  // Add a single region, by name, to the layout
-  addRegion: function(name, definition){
-    var regions = {};
-    regions[name] = definition;
-    return this._buildRegions(regions)[name];
-  },
-
-  // Add multiple regions as a {name: definition, name2: def2} object literal
-  addRegions: function(regions){
-    this.regions = _.extend({}, this.regions, regions);
-    return this._buildRegions(regions);
-  },
-
-  // Remove a single region from the Layout, by name
-  removeRegion: function(name){
-    delete this.regions[name];
-    return this.regionManager.removeRegion(name);
-  },
-
-  // internal method to build regions
-  _buildRegions: function(regions){
-    var that = this;
-
-    var defaults = {
-      regionType: Marionette.getOption(this, "regionType"),
-      parentEl: function(){ return that.$el; }
-    };
-
-    return this.regionManager.addRegions(regions, defaults);
-  },
-
-  // Internal method to initialize the regions that have been defined in a
-  // `regions` attribute on this layout. 
-  _initializeRegions: function (options) {
-    var regions;
-    this._initRegionManager();
-
-    if (_.isFunction(this.regions)) {
-      regions = this.regions(options);
-    } else {
-      regions = this.regions || {};
-    }
-
-    this.addRegions(regions);
-  },
-
-  // Internal method to re-initialize all of the regions by updating the `el` that
-  // they point to
-  _reInitializeRegions: function(){
-    this.regionManager.closeRegions();
-    this.regionManager.each(function(region){
-      region.reset();
-    });
-  },
-
-  // Internal method to initialize the region manager
-  // and all regions in it
-  _initRegionManager: function(){
-    this.regionManager = new Marionette.RegionManager();
-
-    this.listenTo(this.regionManager, "region:add", function(name, region){
-      this[name] = region;
-      this.trigger("region:add", name, region);
-    });
-
-    this.listenTo(this.regionManager, "region:remove", function(name, region){
-      delete this[name];
-      this.trigger("region:remove", name, region);
-    });
-  }
-});
-
-
-// AppRouter
-// ---------
-
-// Reduce the boilerplate code of handling route events
-// and then calling a single method on another object.
-// Have your routers configured to call the method on
-// your object, directly.
-//
-// Configure an AppRouter with `appRoutes`.
-//
-// App routers can only take one `controller` object. 
-// It is recommended that you divide your controller
-// objects in to smaller pieces of related functionality
-// and have multiple routers / controllers, instead of
-// just one giant router and controller.
-//
-// You can also add standard routes to an AppRouter.
-
-Marionette.AppRouter = Backbone.Router.extend({
-
-  constructor: function(options){
-    Backbone.Router.prototype.constructor.apply(this, slice(arguments));
-	
-    this.options = options || {};
-
-    var appRoutes = Marionette.getOption(this, "appRoutes");
-    var controller = this._getController();
-    this.processAppRoutes(controller, appRoutes);
-  },
-
-  // Similar to route method on a Backbone Router but
-  // method is called on the controller
-  appRoute: function(route, methodName) {
-    var controller = this._getController();
-    this._addAppRoute(controller, route, methodName);
-  },
-
-  // Internal method to process the `appRoutes` for the
-  // router, and turn them in to routes that trigger the
-  // specified method on the specified `controller`.
-  processAppRoutes: function(controller, appRoutes) {
-    if (!appRoutes){ return; }
-
-    var routeNames = _.keys(appRoutes).reverse(); // Backbone requires reverted order of routes
-
-    _.each(routeNames, function(route) {
-      this._addAppRoute(controller, route, appRoutes[route]);
-    }, this);
-  },
-
-  _getController: function(){
-    return Marionette.getOption(this, "controller");
-  },
-
-  _addAppRoute: function(controller, route, methodName){
-    var method = controller[methodName];
-
-    if (!method) {
-      throw new Error("Method '" + methodName + "' was not found on the controller");
-    }
-
-    this.route(route, methodName, _.bind(method, controller));
-  }
-});
-
-
-// Application
-// -----------
-
-// Contain and manage the composite application as a whole.
-// Stores and starts up `Region` objects, includes an
-// event aggregator as `app.vent`
-Marionette.Application = function(options){
-  this._initRegionManager();
-  this._initCallbacks = new Marionette.Callbacks();
-  this.vent = new Backbone.Wreqr.EventAggregator();
-  this.commands = new Backbone.Wreqr.Commands();
-  this.reqres = new Backbone.Wreqr.RequestResponse();
-  this.submodules = {};
-
-  _.extend(this, options);
-
-  this.triggerMethod = Marionette.triggerMethod;
-};
-
-_.extend(Marionette.Application.prototype, Backbone.Events, {
-  // Command execution, facilitated by Backbone.Wreqr.Commands
-  execute: function(){
-    var args = Array.prototype.slice.apply(arguments);
-    this.commands.execute.apply(this.commands, args);
-  },
-
-  // Request/response, facilitated by Backbone.Wreqr.RequestResponse
-  request: function(){
-    var args = Array.prototype.slice.apply(arguments);
-    return this.reqres.request.apply(this.reqres, args);
-  },
-
-  // Add an initializer that is either run at when the `start`
-  // method is called, or run immediately if added after `start`
-  // has already been called.
-  addInitializer: function(initializer){
-    this._initCallbacks.add(initializer);
-  },
-
-  // kick off all of the application's processes.
-  // initializes all of the regions that have been added
-  // to the app, and runs all of the initializer functions
-  start: function(options){
-    this.triggerMethod("initialize:before", options);
-    this._initCallbacks.run(options, this);
-    this.triggerMethod("initialize:after", options);
-
-    this.triggerMethod("start", options);
-  },
-
-  // Add regions to your app. 
-  // Accepts a hash of named strings or Region objects
-  // addRegions({something: "#someRegion"})
-  // addRegions({something: Region.extend({el: "#someRegion"}) });
-  addRegions: function(regions){
-    return this._regionManager.addRegions(regions);
-  },
-
-  // Close all regions in the app, without removing them
-  closeRegions: function(){
-    this._regionManager.closeRegions();
-  },
-
-  // Removes a region from your app, by name
-  // Accepts the regions name
-  // removeRegion('myRegion')
-  removeRegion: function(region) {
-    this._regionManager.removeRegion(region);
-  },
-  
-  // Provides alternative access to regions
-  // Accepts the region name
-  // getRegion('main')
-  getRegion: function(region) {
-    return this._regionManager.get(region);
-  },
-
-  // Create a module, attached to the application
-  module: function(moduleNames, moduleDefinition){
-    // slice the args, and add this application object as the
-    // first argument of the array
-    var args = slice(arguments);
-    args.unshift(this);
-
-    // see the Marionette.Module object for more information
-    return Marionette.Module.create.apply(Marionette.Module, args);
-  },
-
-  // Internal method to set up the region manager
-  _initRegionManager: function(){
-    this._regionManager = new Marionette.RegionManager();
-
-    this.listenTo(this._regionManager, "region:add", function(name, region){
-      this[name] = region;
-    });
-
-    this.listenTo(this._regionManager, "region:remove", function(name, region){
-      delete this[name];
-    });
-  }
-});
-
-// Copy the `extend` function used by Backbone's classes
-Marionette.Application.extend = Marionette.extend;
-
-// Module
-// ------
-
-// A simple module system, used to create privacy and encapsulation in
-// Marionette applications
-Marionette.Module = function(moduleName, app){
-  this.moduleName = moduleName;
-
-  // store sub-modules
-  this.submodules = {};
-
-  this._setupInitializersAndFinalizers();
-
-  // store the configuration for this module
-  this.app = app;
-  this.startWithParent = true;
-
-  this.triggerMethod = Marionette.triggerMethod;
-};
-
-// Extend the Module prototype with events / listenTo, so that the module
-// can be used as an event aggregator or pub/sub.
-_.extend(Marionette.Module.prototype, Backbone.Events, {
-
-  // Initializer for a specific module. Initializers are run when the
-  // module's `start` method is called.
-  addInitializer: function(callback){
-    this._initializerCallbacks.add(callback);
-  },
-
-  // Finalizers are run when a module is stopped. They are used to teardown
-  // and finalize any variables, references, events and other code that the
-  // module had set up.
-  addFinalizer: function(callback){
-    this._finalizerCallbacks.add(callback);
-  },
-
-  // Start the module, and run all of its initializers
-  start: function(options){
-    // Prevent re-starting a module that is already started
-    if (this._isInitialized){ return; }
-
-    // start the sub-modules (depth-first hierarchy)
-    _.each(this.submodules, function(mod){
-      // check to see if we should start the sub-module with this parent
-      if (mod.startWithParent){
-        mod.start(options);
-      }
-    });
-
-    // run the callbacks to "start" the current module
-    this.triggerMethod("before:start", options);
-
-    this._initializerCallbacks.run(options, this);
-    this._isInitialized = true;
-
-    this.triggerMethod("start", options);
-  },
-
-  // Stop this module by running its finalizers and then stop all of
-  // the sub-modules for this module
-  stop: function(){
-    // if we are not initialized, don't bother finalizing
-    if (!this._isInitialized){ return; }
-    this._isInitialized = false;
-
-    Marionette.triggerMethod.call(this, "before:stop");
-
-    // stop the sub-modules; depth-first, to make sure the
-    // sub-modules are stopped / finalized before parents
-    _.each(this.submodules, function(mod){ mod.stop(); });
-
-    // run the finalizers
-    this._finalizerCallbacks.run(undefined,this);
-
-    // reset the initializers and finalizers
-    this._initializerCallbacks.reset();
-    this._finalizerCallbacks.reset();
-
-    Marionette.triggerMethod.call(this, "stop");
-  },
-
-  // Configure the module with a definition function and any custom args
-  // that are to be passed in to the definition function
-  addDefinition: function(moduleDefinition, customArgs){
-    this._runModuleDefinition(moduleDefinition, customArgs);
-  },
-
-  // Internal method: run the module definition function with the correct
-  // arguments
-  _runModuleDefinition: function(definition, customArgs){
-    if (!definition){ return; }
-
-    // build the correct list of arguments for the module definition
-    var args = _.flatten([
-      this,
-      this.app,
-      Backbone,
-      Marionette,
-      Marionette.$, _,
-      customArgs
-    ]);
-
-    definition.apply(this, args);
-  },
-
-  // Internal method: set up new copies of initializers and finalizers.
-  // Calling this method will wipe out all existing initializers and
-  // finalizers.
-  _setupInitializersAndFinalizers: function(){
-    this._initializerCallbacks = new Marionette.Callbacks();
-    this._finalizerCallbacks = new Marionette.Callbacks();
-  }
-});
-
-// Type methods to create modules
-_.extend(Marionette.Module, {
-
-  // Create a module, hanging off the app parameter as the parent object.
-  create: function(app, moduleNames, moduleDefinition){
-    var module = app;
-
-    // get the custom args passed in after the module definition and
-    // get rid of the module name and definition function
-    var customArgs = slice(arguments);
-    customArgs.splice(0, 3);
-
-    // split the module names and get the length
-    moduleNames = moduleNames.split(".");
-    var length = moduleNames.length;
-
-    // store the module definition for the last module in the chain
-    var moduleDefinitions = [];
-    moduleDefinitions[length-1] = moduleDefinition;
-
-    // Loop through all the parts of the module definition
-    _.each(moduleNames, function(moduleName, i){
-      var parentModule = module;
-      module = this._getModule(parentModule, moduleName, app);
-      this._addModuleDefinition(parentModule, module, moduleDefinitions[i], customArgs);
-    }, this);
-
-    // Return the last module in the definition chain
-    return module;
-  },
-
-  _getModule: function(parentModule, moduleName, app, def, args){
-    // Get an existing module of this name if we have one
-    var module = parentModule[moduleName];
-
-    if (!module){
-      // Create a new module if we don't have one
-      module = new Marionette.Module(moduleName, app);
-      parentModule[moduleName] = module;
-      // store the module on the parent
-      parentModule.submodules[moduleName] = module;
-    }
-
-    return module;
-  },
-
-  _addModuleDefinition: function(parentModule, module, def, args){
-    var fn; 
-    var startWithParent;
-
-    if (_.isFunction(def)){
-      // if a function is supplied for the module definition
-      fn = def;
-      startWithParent = true;
-
-    } else if (_.isObject(def)){
-      // if an object is supplied
-      fn = def.define;
-      startWithParent = def.startWithParent;
-      
-    } else {
-      // if nothing is supplied
-      startWithParent = true;
-    }
-
-    // add module definition if needed
-    if (fn){
-      module.addDefinition(fn, args);
-    }
-
-    // `and` the two together, ensuring a single `false` will prevent it
-    // from starting with the parent
-    module.startWithParent = module.startWithParent && startWithParent;
-
-    // setup auto-start if needed
-    if (module.startWithParent && !module.startWithParentIsConfigured){
-
-      // only configure this once
-      module.startWithParentIsConfigured = true;
-
-      // add the module initializer config
-      parentModule.addInitializer(function(options){
-        if (module.startWithParent){
-          module.start(options);
-        }
-      });
-
-    }
-
-  }
-});
-
-
-
-  return Marionette;
-})(this, Backbone, _);
-
-  return Backbone.Marionette; 
-
-}));
diff --git a/security-admin/src/main/webapp/libs/bower/backbone.marionette/js/backbone.marionette.min.js b/security-admin/src/main/webapp/libs/bower/backbone.marionette/js/backbone.marionette.min.js
deleted file mode 100644
index e2ebd3e98..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone.marionette/js/backbone.marionette.min.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// MarionetteJS (Backbone.Marionette)
-// ----------------------------------
-// v1.1.0
-//
-// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
-// Distributed under MIT license
-//
-// http://marionettejs.com
-
-
-
-/*!
- * Includes BabySitter
- * https://github.com/marionettejs/backbone.babysitter/
- *
- * Includes Wreqr
- * https://github.com/marionettejs/backbone.wreqr/
- */
-
-(function(e,t){if("object"==typeof exports){var i=require("underscore"),n=require("backbone"),r=require("backbone.wreqr"),o=require("backbone.babysitter");module.exports=t(i,n,r,o)}else"function"==typeof define&&define.amd&&define(["underscore","backbone","backbone.wreqr","backbone.babysitter"],t)})(this,function(e,t){return function(e,t,i){"use strict";function n(e){return s.call(e)}function r(e,t){var i=Error(e);throw i.name=t||"Error",i}var o={};t.Marionette=o,o.$=t.$;var s=Array.prot [...]
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/libs/bower/backbone.wreqr/js/backbone.wreqr.js b/security-admin/src/main/webapp/libs/bower/backbone.wreqr/js/backbone.wreqr.js
deleted file mode 100644
index b3e784ab3..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone.wreqr/js/backbone.wreqr.js
+++ /dev/null
@@ -1,277 +0,0 @@
-(function (root, factory) {
-  if (typeof exports === 'object') {
-
-    var underscore = require('underscore');
-    var backbone = require('backbone');
-
-    module.exports = factory(underscore, backbone);
-
-  } else if (typeof define === 'function' && define.amd) {
-
-    define(['underscore', 'backbone'], factory);
-
-  } 
-}(this, function (_, Backbone) {
-  "use strict";
-
-  Backbone.Wreqr = (function(Backbone, Marionette, _){
-  "use strict";
-  var Wreqr = {};
-
-  // Handlers
-// --------
-// A registry of functions to call, given a name
-
-Wreqr.Handlers = (function(Backbone, _){
-  "use strict";
-  
-  // Constructor
-  // -----------
-
-  var Handlers = function(options){
-    this.options = options;
-    this._wreqrHandlers = {};
-    
-    if (_.isFunction(this.initialize)){
-      this.initialize(options);
-    }
-  };
-
-  Handlers.extend = Backbone.Model.extend;
-
-  // Instance Members
-  // ----------------
-
-  _.extend(Handlers.prototype, Backbone.Events, {
-
-    // Add multiple handlers using an object literal configuration
-    setHandlers: function(handlers){
-      _.each(handlers, function(handler, name){
-        var context = null;
-
-        if (_.isObject(handler) && !_.isFunction(handler)){
-          context = handler.context;
-          handler = handler.callback;
-        }
-
-        this.setHandler(name, handler, context);
-      }, this);
-    },
-
-    // Add a handler for the given name, with an
-    // optional context to run the handler within
-    setHandler: function(name, handler, context){
-      var config = {
-        callback: handler,
-        context: context
-      };
-
-      this._wreqrHandlers[name] = config;
-
-      this.trigger("handler:add", name, handler, context);
-    },
-
-    // Determine whether or not a handler is registered
-    hasHandler: function(name){
-      return !! this._wreqrHandlers[name];
-    },
-
-    // Get the currently registered handler for
-    // the specified name. Throws an exception if
-    // no handler is found.
-    getHandler: function(name){
-      var config = this._wreqrHandlers[name];
-
-      if (!config){
-        throw new Error("Handler not found for '" + name + "'");
-      }
-
-      return function(){
-        var args = Array.prototype.slice.apply(arguments);
-        return config.callback.apply(config.context, args);
-      };
-    },
-
-    // Remove a handler for the specified name
-    removeHandler: function(name){
-      delete this._wreqrHandlers[name];
-    },
-
-    // Remove all handlers from this registry
-    removeAllHandlers: function(){
-      this._wreqrHandlers = {};
-    }
-  });
-
-  return Handlers;
-})(Backbone, _);
-
-  // Wreqr.CommandStorage
-// --------------------
-//
-// Store and retrieve commands for execution.
-Wreqr.CommandStorage = (function(){
-  "use strict";
-
-  // Constructor function
-  var CommandStorage = function(options){
-    this.options = options;
-    this._commands = {};
-
-    if (_.isFunction(this.initialize)){
-      this.initialize(options);
-    }
-  };
-
-  // Instance methods
-  _.extend(CommandStorage.prototype, Backbone.Events, {
-
-    // Get an object literal by command name, that contains
-    // the `commandName` and the `instances` of all commands
-    // represented as an array of arguments to process
-    getCommands: function(commandName){
-      var commands = this._commands[commandName];
-
-      // we don't have it, so add it
-      if (!commands){
-
-        // build the configuration
-        commands = {
-          command: commandName, 
-          instances: []
-        };
-
-        // store it
-        this._commands[commandName] = commands;
-      }
-
-      return commands;
-    },
-
-    // Add a command by name, to the storage and store the
-    // args for the command
-    addCommand: function(commandName, args){
-      var command = this.getCommands(commandName);
-      command.instances.push(args);
-    },
-
-    // Clear all commands for the given `commandName`
-    clearCommands: function(commandName){
-      var command = this.getCommands(commandName);
-      command.instances = [];
-    }
-  });
-
-  return CommandStorage;
-})();
-
-  // Wreqr.Commands
-// --------------
-//
-// A simple command pattern implementation. Register a command
-// handler and execute it.
-Wreqr.Commands = (function(Wreqr){
-  "use strict";
-
-  return Wreqr.Handlers.extend({
-    // default storage type
-    storageType: Wreqr.CommandStorage,
-
-    constructor: function(options){
-      this.options = options || {};
-
-      this._initializeStorage(this.options);
-      this.on("handler:add", this._executeCommands, this);
-
-      var args = Array.prototype.slice.call(arguments);
-      Wreqr.Handlers.prototype.constructor.apply(this, args);
-    },
-
-    // Execute a named command with the supplied args
-    execute: function(name, args){
-      name = arguments[0];
-      args = Array.prototype.slice.call(arguments, 1);
-
-      if (this.hasHandler(name)){
-        this.getHandler(name).apply(this, args);
-      } else {
-        this.storage.addCommand(name, args);
-      }
-
-    },
-
-    // Internal method to handle bulk execution of stored commands
-    _executeCommands: function(name, handler, context){
-      var command = this.storage.getCommands(name);
-
-      // loop through and execute all the stored command instances
-      _.each(command.instances, function(args){
-        handler.apply(context, args);
-      });
-
-      this.storage.clearCommands(name);
-    },
-
-    // Internal method to initialize storage either from the type's
-    // `storageType` or the instance `options.storageType`.
-    _initializeStorage: function(options){
-      var storage;
-
-      var StorageType = options.storageType || this.storageType;
-      if (_.isFunction(StorageType)){
-        storage = new StorageType();
-      } else {
-        storage = StorageType;
-      }
-
-      this.storage = storage;
-    }
-  });
-
-})(Wreqr);
-
-  // Wreqr.RequestResponse
-// ---------------------
-//
-// A simple request/response implementation. Register a
-// request handler, and return a response from it
-Wreqr.RequestResponse = (function(Wreqr){
-  "use strict";
-
-  return Wreqr.Handlers.extend({
-    request: function(){
-      var name = arguments[0];
-      var args = Array.prototype.slice.call(arguments, 1);
-
-      return this.getHandler(name).apply(this, args);
-    }
-  });
-
-})(Wreqr);
-
-  // Event Aggregator
-// ----------------
-// A pub-sub object that can be used to decouple various parts
-// of an application through event-driven architecture.
-
-Wreqr.EventAggregator = (function(Backbone, _){
-  "use strict";
-  var EA = function(){};
-
-  // Copy the `extend` function used by Backbone's classes
-  EA.extend = Backbone.Model.extend;
-
-  // Copy the basic Backbone.Events on to the event aggregator
-  _.extend(EA.prototype, Backbone.Events);
-
-  return EA;
-})(Backbone, _);
-
-
-  return Wreqr;
-})(Backbone, Backbone.Marionette, _);
-
-  return Backbone.Wreqr; 
-
-}));
-
diff --git a/security-admin/src/main/webapp/libs/bower/backbone.wreqr/js/backbone.wreqr.min.js b/security-admin/src/main/webapp/libs/bower/backbone.wreqr/js/backbone.wreqr.min.js
deleted file mode 100644
index 65141500d..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone.wreqr/js/backbone.wreqr.min.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Backbone.Wreqr (Backbone.Marionette)
-// ----------------------------------
-// v0.2.0
-//
-// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
-// Distributed under MIT license
-//
-// http://github.com/marionettejs/backbone.wreqr
-
-
-(function(t,e){if("object"==typeof exports){var n=require("underscore"),r=require("backbone");module.exports=e(n,r)}else"function"==typeof define&&define.amd&&define(["underscore","backbone"],e)})(this,function(t,e){"use strict";return e.Wreqr=function(t,e,n){var r={};return r.Handlers=function(t,e){var n=function(t){this.options=t,this._wreqrHandlers={},e.isFunction(this.initialize)&&this.initialize(t)};return n.extend=t.Model.extend,e.extend(n.prototype,t.Events,{setHandlers:function(t [...]
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/libs/bower/backbone/js/backbone-min.js b/security-admin/src/main/webapp/libs/bower/backbone/js/backbone-min.js
deleted file mode 100644
index c8c33e0d7..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone/js/backbone-min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-(function(t){var e=typeof self=="object"&&self.self===self&&self||typeof global=="object"&&global.global===global&&global;if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,n,r){e.Backbone=t(e,r,i,n)})}else if(typeof exports!=="undefined"){var i=require("underscore"),n;try{n=require("jquery")}catch(r){}t(e,exports,i,n)}else{e.Backbone=t(e,{},e._,e.jQuery||e.Zepto||e.ender||e.$)}})(function(t,e,i,n){var r=t.Backbone;var s=Array.prototype.slice;e [...]
-//# sourceMappingURL=backbone-min.map
\ No newline at end of file
diff --git a/security-admin/src/main/webapp/libs/bower/backbone/js/backbone.js b/security-admin/src/main/webapp/libs/bower/backbone/js/backbone.js
deleted file mode 100644
index 3e09d0dcb..000000000
--- a/security-admin/src/main/webapp/libs/bower/backbone/js/backbone.js
+++ /dev/null
@@ -1,2096 +0,0 @@
-//     Backbone.js 1.4.0
-
-//     (c) 2010-2019 Jeremy Ashkenas and DocumentCloud
-//     Backbone may be freely distributed under the MIT license.
-//     For all details and documentation:
-//     http://backbonejs.org
-
-(function(factory) {
-
-  // Establish the root object, `window` (`self`) in the browser, or `global` on the server.
-  // We use `self` instead of `window` for `WebWorker` support.
-  var root = typeof self == 'object' && self.self === self && self ||
-            typeof global == 'object' && global.global === global && global;
-
-  // Set up Backbone appropriately for the environment. Start with AMD.
-  if (typeof define === 'function' && define.amd) {
-    define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
-      // Export global even in AMD case in case this script is loaded with
-      // others that may still expect a global Backbone.
-      root.Backbone = factory(root, exports, _, $);
-    });
-
-  // Next for Node.js or CommonJS. jQuery may not be needed as a module.
-  } else if (typeof exports !== 'undefined') {
-    var _ = require('underscore'), $;
-    try { $ = require('jquery'); } catch (e) {}
-    factory(root, exports, _, $);
-
-  // Finally, as a browser global.
-  } else {
-    root.Backbone = factory(root, {}, root._, root.jQuery || root.Zepto || root.ender || root.$);
-  }
-
-})(function(root, Backbone, _, $) {
-
-  // Initial Setup
-  // -------------
-
-  // Save the previous value of the `Backbone` variable, so that it can be
-  // restored later on, if `noConflict` is used.
-  var previousBackbone = root.Backbone;
-
-  // Create a local reference to a common array method we'll want to use later.
-  var slice = Array.prototype.slice;
-
-  // Current version of the library. Keep in sync with `package.json`.
-  Backbone.VERSION = '1.4.0';
-
-  // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
-  // the `$` variable.
-  Backbone.$ = $;
-
-  // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
-  // to its previous owner. Returns a reference to this Backbone object.
-  Backbone.noConflict = function() {
-    root.Backbone = previousBackbone;
-    return this;
-  };
-
-  // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
-  // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and
-  // set a `X-Http-Method-Override` header.
-  Backbone.emulateHTTP = false;
-
-  // Turn on `emulateJSON` to support legacy servers that can't deal with direct
-  // `application/json` requests ... this will encode the body as
-  // `application/x-www-form-urlencoded` instead and will send the model in a
-  // form param named `model`.
-  Backbone.emulateJSON = false;
-
-  // Backbone.Events
-  // ---------------
-
-  // A module that can be mixed in to *any object* in order to provide it with
-  // a custom event channel. You may bind a callback to an event with `on` or
-  // remove with `off`; `trigger`-ing an event fires all callbacks in
-  // succession.
-  //
-  //     var object = {};
-  //     _.extend(object, Backbone.Events);
-  //     object.on('expand', function(){ alert('expanded'); });
-  //     object.trigger('expand');
-  //
-  var Events = Backbone.Events = {};
-
-  // Regular expression used to split event strings.
-  var eventSplitter = /\s+/;
-
-  // A private global variable to share between listeners and listenees.
-  var _listening;
-
-  // Iterates over the standard `event, callback` (as well as the fancy multiple
-  // space-separated events `"change blur", callback` and jQuery-style event
-  // maps `{event: callback}`).
-  var eventsApi = function(iteratee, events, name, callback, opts) {
-    var i = 0, names;
-    if (name && typeof name === 'object') {
-      // Handle event maps.
-      if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback;
-      for (names = _.keys(name); i < names.length ; i++) {
-        events = eventsApi(iteratee, events, names[i], name[names[i]], opts);
-      }
-    } else if (name && eventSplitter.test(name)) {
-      // Handle space-separated event names by delegating them individually.
-      for (names = name.split(eventSplitter); i < names.length; i++) {
-        events = iteratee(events, names[i], callback, opts);
-      }
-    } else {
-      // Finally, standard events.
-      events = iteratee(events, name, callback, opts);
-    }
-    return events;
-  };
-
-  // Bind an event to a `callback` function. Passing `"all"` will bind
-  // the callback to all events fired.
-  Events.on = function(name, callback, context) {
-    this._events = eventsApi(onApi, this._events || {}, name, callback, {
-      context: context,
-      ctx: this,
-      listening: _listening
-    });
-
-    if (_listening) {
-      var listeners = this._listeners || (this._listeners = {});
-      listeners[_listening.id] = _listening;
-      // Allow the listening to use a counter, instead of tracking
-      // callbacks for library interop
-      _listening.interop = false;
-    }
-
-    return this;
-  };
-
-  // Inversion-of-control versions of `on`. Tell *this* object to listen to
-  // an event in another object... keeping track of what it's listening to
-  // for easier unbinding later.
-  Events.listenTo = function(obj, name, callback) {
-    if (!obj) return this;
-    var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
-    var listeningTo = this._listeningTo || (this._listeningTo = {});
-    var listening = _listening = listeningTo[id];
-
-    // This object is not listening to any other events on `obj` yet.
-    // Setup the necessary references to track the listening callbacks.
-    if (!listening) {
-      this._listenId || (this._listenId = _.uniqueId('l'));
-      listening = _listening = listeningTo[id] = new Listening(this, obj);
-    }
-
-    // Bind callbacks on obj.
-    var error = tryCatchOn(obj, name, callback, this);
-    _listening = void 0;
-
-    if (error) throw error;
-    // If the target obj is not Backbone.Events, track events manually.
-    if (listening.interop) listening.on(name, callback);
-
-    return this;
-  };
-
-  // The reducing API that adds a callback to the `events` object.
-  var onApi = function(events, name, callback, options) {
-    if (callback) {
-      var handlers = events[name] || (events[name] = []);
-      var context = options.context, ctx = options.ctx, listening = options.listening;
-      if (listening) listening.count++;
-
-      handlers.push({callback: callback, context: context, ctx: context || ctx, listening: listening});
-    }
-    return events;
-  };
-
-  // An try-catch guarded #on function, to prevent poisoning the global
-  // `_listening` variable.
-  var tryCatchOn = function(obj, name, callback, context) {
-    try {
-      obj.on(name, callback, context);
-    } catch (e) {
-      return e;
-    }
-  };
-
-  // Remove one or many callbacks. If `context` is null, removes all
-  // callbacks with that function. If `callback` is null, removes all
-  // callbacks for the event. If `name` is null, removes all bound
-  // callbacks for all events.
-  Events.off = function(name, callback, context) {
-    if (!this._events) return this;
-    this._events = eventsApi(offApi, this._events, name, callback, {
-      context: context,
-      listeners: this._listeners
-    });
-
-    return this;
-  };
-
-  // Tell this object to stop listening to either specific events ... or
-  // to every object it's currently listening to.
-  Events.stopListening = function(obj, name, callback) {
-    var listeningTo = this._listeningTo;
-    if (!listeningTo) return this;
-
-    var ids = obj ? [obj._listenId] : _.keys(listeningTo);
-    for (var i = 0; i < ids.length; i++) {
-      var listening = listeningTo[ids[i]];
-
-      // If listening doesn't exist, this object is not currently
-      // listening to obj. Break out early.
-      if (!listening) break;
-
-      listening.obj.off(name, callback, this);
-      if (listening.interop) listening.off(name, callback);
-    }
-    if (_.isEmpty(listeningTo)) this._listeningTo = void 0;
-
-    return this;
-  };
-
-  // The reducing API that removes a callback from the `events` object.
-  var offApi = function(events, name, callback, options) {
-    if (!events) return;
-
-    var context = options.context, listeners = options.listeners;
-    var i = 0, names;
-
-    // Delete all event listeners and "drop" events.
-    if (!name && !context && !callback) {
-      for (names = _.keys(listeners); i < names.length; i++) {
-        listeners[names[i]].cleanup();
-      }
-      return;
-    }
-
-    names = name ? [name] : _.keys(events);
-    for (; i < names.length; i++) {
-      name = names[i];
-      var handlers = events[name];
-
-      // Bail out if there are no events stored.
-      if (!handlers) break;
-
-      // Find any remaining events.
-      var remaining = [];
-      for (var j = 0; j < handlers.length; j++) {
-        var handler = handlers[j];
-        if (
-          callback && callback !== handler.callback &&
-            callback !== handler.callback._callback ||
-              context && context !== handler.context
-        ) {
-          remaining.push(handler);
-        } else {
-          var listening = handler.listening;
-          if (listening) listening.off(name, callback);
-        }
-      }
-
-      // Replace events if there are any remaining.  Otherwise, clean up.
-      if (remaining.length) {
-        events[name] = remaining;
-      } else {
-        delete events[name];
-      }
-    }
-
-    return events;
-  };
-
-  // Bind an event to only be triggered a single time. After the first time
-  // the callback is invoked, its listener will be removed. If multiple events
-  // are passed in using the space-separated syntax, the handler will fire
-  // once for each event, not once for a combination of all events.
-  Events.once = function(name, callback, context) {
-    // Map the event into a `{event: once}` object.
-    var events = eventsApi(onceMap, {}, name, callback, this.off.bind(this));
-    if (typeof name === 'string' && context == null) callback = void 0;
-    return this.on(events, callback, context);
-  };
-
-  // Inversion-of-control versions of `once`.
-  Events.listenToOnce = function(obj, name, callback) {
-    // Map the event into a `{event: once}` object.
-    var events = eventsApi(onceMap, {}, name, callback, this.stopListening.bind(this, obj));
-    return this.listenTo(obj, events);
-  };
-
-  // Reduces the event callbacks into a map of `{event: onceWrapper}`.
-  // `offer` unbinds the `onceWrapper` after it has been called.
-  var onceMap = function(map, name, callback, offer) {
-    if (callback) {
-      var once = map[name] = _.once(function() {
-        offer(name, once);
-        callback.apply(this, arguments);
-      });
-      once._callback = callback;
-    }
-    return map;
-  };
-
-  // Trigger one or many events, firing all bound callbacks. Callbacks are
-  // passed the same arguments as `trigger` is, apart from the event name
-  // (unless you're listening on `"all"`, which will cause your callback to
-  // receive the true name of the event as the first argument).
-  Events.trigger = function(name) {
-    if (!this._events) return this;
-
-    var length = Math.max(0, arguments.length - 1);
-    var args = Array(length);
-    for (var i = 0; i < length; i++) args[i] = arguments[i + 1];
-
-    eventsApi(triggerApi, this._events, name, void 0, args);
-    return this;
-  };
-
-  // Handles triggering the appropriate event callbacks.
-  var triggerApi = function(objEvents, name, callback, args) {
-    if (objEvents) {
-      var events = objEvents[name];
-      var allEvents = objEvents.all;
-      if (events && allEvents) allEvents = allEvents.slice();
-      if (events) triggerEvents(events, args);
-      if (allEvents) triggerEvents(allEvents, [name].concat(args));
-    }
-    return objEvents;
-  };
-
-  // A difficult-to-believe, but optimized internal dispatch function for
-  // triggering events. Tries to keep the usual cases speedy (most internal
-  // Backbone events have 3 arguments).
-  var triggerEvents = function(events, args) {
-    var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
-    switch (args.length) {
-      case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
-      case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
-      case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
-      case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
-      default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
-    }
-  };
-
-  // A listening class that tracks and cleans up memory bindings
-  // when all callbacks have been offed.
-  var Listening = function(listener, obj) {
-    this.id = listener._listenId;
-    this.listener = listener;
-    this.obj = obj;
-    this.interop = true;
-    this.count = 0;
-    this._events = void 0;
-  };
-
-  Listening.prototype.on = Events.on;
-
-  // Offs a callback (or several).
-  // Uses an optimized counter if the listenee uses Backbone.Events.
-  // Otherwise, falls back to manual tracking to support events
-  // library interop.
-  Listening.prototype.off = function(name, callback) {
-    var cleanup;
-    if (this.interop) {
-      this._events = eventsApi(offApi, this._events, name, callback, {
-        context: void 0,
-        listeners: void 0
-      });
-      cleanup = !this._events;
-    } else {
-      this.count--;
-      cleanup = this.count === 0;
-    }
-    if (cleanup) this.cleanup();
-  };
-
-  // Cleans up memory bindings between the listener and the listenee.
-  Listening.prototype.cleanup = function() {
-    delete this.listener._listeningTo[this.obj._listenId];
-    if (!this.interop) delete this.obj._listeners[this.id];
-  };
-
-  // Aliases for backwards compatibility.
-  Events.bind   = Events.on;
-  Events.unbind = Events.off;
-
-  // Allow the `Backbone` object to serve as a global event bus, for folks who
-  // want global "pubsub" in a convenient place.
-  _.extend(Backbone, Events);
-
-  // Backbone.Model
-  // --------------
-
-  // Backbone **Models** are the basic data object in the framework --
-  // frequently representing a row in a table in a database on your server.
-  // A discrete chunk of data and a bunch of useful, related methods for
-  // performing computations and transformations on that data.
-
-  // Create a new model with the specified attributes. A client id (`cid`)
-  // is automatically generated and assigned for you.
-  var Model = Backbone.Model = function(attributes, options) {
-    var attrs = attributes || {};
-    options || (options = {});
-    this.preinitialize.apply(this, arguments);
-    this.cid = _.uniqueId(this.cidPrefix);
-    this.attributes = {};
-    if (options.collection) this.collection = options.collection;
-    if (options.parse) attrs = this.parse(attrs, options) || {};
-    var defaults = _.result(this, 'defaults');
-    attrs = _.defaults(_.extend({}, defaults, attrs), defaults);
-    this.set(attrs, options);
-    this.changed = {};
-    this.initialize.apply(this, arguments);
-  };
-
-  // Attach all inheritable methods to the Model prototype.
-  _.extend(Model.prototype, Events, {
-
-    // A hash of attributes whose current and previous value differ.
-    changed: null,
-
-    // The value returned during the last failed validation.
-    validationError: null,
-
-    // The default name for the JSON `id` attribute is `"id"`. MongoDB and
-    // CouchDB users may want to set this to `"_id"`.
-    idAttribute: 'id',
-
-    // The prefix is used to create the client id which is used to identify models locally.
-    // You may want to override this if you're experiencing name clashes with model ids.
-    cidPrefix: 'c',
-
-    // preinitialize is an empty function by default. You can override it with a function
-    // or object.  preinitialize will run before any instantiation logic is run in the Model.
-    preinitialize: function(){},
-
-    // Initialize is an empty function by default. Override it with your own
-    // initialization logic.
-    initialize: function(){},
-
-    // Return a copy of the model's `attributes` object.
-    toJSON: function(options) {
-      return _.clone(this.attributes);
-    },
-
-    // Proxy `Backbone.sync` by default -- but override this if you need
-    // custom syncing semantics for *this* particular model.
-    sync: function() {
-      return Backbone.sync.apply(this, arguments);
-    },
-
-    // Get the value of an attribute.
-    get: function(attr) {
-      return this.attributes[attr];
-    },
-
-    // Get the HTML-escaped value of an attribute.
-    escape: function(attr) {
-      return _.escape(this.get(attr));
-    },
-
-    // Returns `true` if the attribute contains a value that is not null
-    // or undefined.
-    has: function(attr) {
-      return this.get(attr) != null;
-    },
-
-    // Special-cased proxy to underscore's `_.matches` method.
-    matches: function(attrs) {
-      return !!_.iteratee(attrs, this)(this.attributes);
-    },
-
-    // Set a hash of model attributes on the object, firing `"change"`. This is
-    // the core primitive operation of a model, updating the data and notifying
-    // anyone who needs to know about the change in state. The heart of the beast.
-    set: function(key, val, options) {
-      if (key == null) return this;
-
-      // Handle both `"key", value` and `{key: value}` -style arguments.
-      var attrs;
-      if (typeof key === 'object') {
-        attrs = key;
-        options = val;
-      } else {
-        (attrs = {})[key] = val;
-      }
-
-      options || (options = {});
-
-      // Run validation.
-      if (!this._validate(attrs, options)) return false;
-
-      // Extract attributes and options.
-      var unset      = options.unset;
-      var silent     = options.silent;
-      var changes    = [];
-      var changing   = this._changing;
-      this._changing = true;
-
-      if (!changing) {
-        this._previousAttributes = _.clone(this.attributes);
-        this.changed = {};
-      }
-
-      var current = this.attributes;
-      var changed = this.changed;
-      var prev    = this._previousAttributes;
-
-      // For each `set` attribute, update or delete the current value.
-      for (var attr in attrs) {
-        val = attrs[attr];
-        if (!_.isEqual(current[attr], val)) changes.push(attr);
-        if (!_.isEqual(prev[attr], val)) {
-          changed[attr] = val;
-        } else {
-          delete changed[attr];
-        }
-        unset ? delete current[attr] : current[attr] = val;
-      }
-
-      // Update the `id`.
-      if (this.idAttribute in attrs) this.id = this.get(this.idAttribute);
-
-      // Trigger all relevant attribute changes.
-      if (!silent) {
-        if (changes.length) this._pending = options;
-        for (var i = 0; i < changes.length; i++) {
-          this.trigger('change:' + changes[i], this, current[changes[i]], options);
-        }
-      }
-
-      // You might be wondering why there's a `while` loop here. Changes can
-      // be recursively nested within `"change"` events.
-      if (changing) return this;
-      if (!silent) {
-        while (this._pending) {
-          options = this._pending;
-          this._pending = false;
-          this.trigger('change', this, options);
-        }
-      }
-      this._pending = false;
-      this._changing = false;
-      return this;
-    },
-
-    // Remove an attribute from the model, firing `"change"`. `unset` is a noop
-    // if the attribute doesn't exist.
-    unset: function(attr, options) {
-      return this.set(attr, void 0, _.extend({}, options, {unset: true}));
-    },
-
-    // Clear all attributes on the model, firing `"change"`.
-    clear: function(options) {
-      var attrs = {};
-      for (var key in this.attributes) attrs[key] = void 0;
-      return this.set(attrs, _.extend({}, options, {unset: true}));
-    },
-
-    // Determine if the model has changed since the last `"change"` event.
-    // If you specify an attribute name, determine if that attribute has changed.
-    hasChanged: function(attr) {
-      if (attr == null) return !_.isEmpty(this.changed);
-      return _.has(this.changed, attr);
-    },
-
-    // Return an object containing all the attributes that have changed, or
-    // false if there are no changed attributes. Useful for determining what
-    // parts of a view need to be updated and/or what attributes need to be
-    // persisted to the server. Unset attributes will be set to undefined.
-    // You can also pass an attributes object to diff against the model,
-    // determining if there *would be* a change.
-    changedAttributes: function(diff) {
-      if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
-      var old = this._changing ? this._previousAttributes : this.attributes;
-      var changed = {};
-      var hasChanged;
-      for (var attr in diff) {
-        var val = diff[attr];
-        if (_.isEqual(old[attr], val)) continue;
-        changed[attr] = val;
-        hasChanged = true;
-      }
-      return hasChanged ? changed : false;
-    },
-
-    // Get the previous value of an attribute, recorded at the time the last
-    // `"change"` event was fired.
-    previous: function(attr) {
-      if (attr == null || !this._previousAttributes) return null;
-      return this._previousAttributes[attr];
-    },
-
-    // Get all of the attributes of the model at the time of the previous
-    // `"change"` event.
-    previousAttributes: function() {
-      return _.clone(this._previousAttributes);
-    },
-
-    // Fetch the model from the server, merging the response with the model's
-    // local attributes. Any changed attributes will trigger a "change" event.
-    fetch: function(options) {
-      options = _.extend({parse: true}, options);
-      var model = this;
-      var success = options.success;
-      options.success = function(resp) {
-        var serverAttrs = options.parse ? model.parse(resp, options) : resp;
-        if (!model.set(serverAttrs, options)) return false;
-        if (success) success.call(options.context, model, resp, options);
-        model.trigger('sync', model, resp, options);
-      };
-      wrapError(this, options);
-      return this.sync('read', this, options);
-    },
-
-    // Set a hash of model attributes, and sync the model to the server.
-    // If the server returns an attributes hash that differs, the model's
-    // state will be `set` again.
-    save: function(key, val, options) {
-      // Handle both `"key", value` and `{key: value}` -style arguments.
-      var attrs;
-      if (key == null || typeof key === 'object') {
-        attrs = key;
-        options = val;
-      } else {
-        (attrs = {})[key] = val;
-      }
-
-      options = _.extend({validate: true, parse: true}, options);
-      var wait = options.wait;
-
-      // If we're not waiting and attributes exist, save acts as
-      // `set(attr).save(null, opts)` with validation. Otherwise, check if
-      // the model will be valid when the attributes, if any, are set.
-      if (attrs && !wait) {
-        if (!this.set(attrs, options)) return false;
-      } else if (!this._validate(attrs, options)) {
-        return false;
-      }
-
-      // After a successful server-side save, the client is (optionally)
-      // updated with the server-side state.
-      var model = this;
-      var success = options.success;
-      var attributes = this.attributes;
-      options.success = function(resp) {
-        // Ensure attributes are restored during synchronous saves.
-        model.attributes = attributes;
-        var serverAttrs = options.parse ? model.parse(resp, options) : resp;
-        if (wait) serverAttrs = _.extend({}, attrs, serverAttrs);
-        if (serverAttrs && !model.set(serverAttrs, options)) return false;
-        if (success) success.call(options.context, model, resp, options);
-        model.trigger('sync', model, resp, options);
-      };
-      wrapError(this, options);
-
-      // Set temporary attributes if `{wait: true}` to properly find new ids.
-      if (attrs && wait) this.attributes = _.extend({}, attributes, attrs);
-
-      var method = this.isNew() ? 'create' : options.patch ? 'patch' : 'update';
-      if (method === 'patch' && !options.attrs) options.attrs = attrs;
-      var xhr = this.sync(method, this, options);
-
-      // Restore attributes.
-      this.attributes = attributes;
-
-      return xhr;
-    },
-
-    // Destroy this model on the server if it was already persisted.
-    // Optimistically removes the model from its collection, if it has one.
-    // If `wait: true` is passed, waits for the server to respond before removal.
-    destroy: function(options) {
-      options = options ? _.clone(options) : {};
-      var model = this;
-      var success = options.success;
-      var wait = options.wait;
-
-      var destroy = function() {
-        model.stopListening();
-        model.trigger('destroy', model, model.collection, options);
-      };
-
-      options.success = function(resp) {
-        if (wait) destroy();
-        if (success) success.call(options.context, model, resp, options);
-        if (!model.isNew()) model.trigger('sync', model, resp, options);
-      };
-
-      var xhr = false;
-      if (this.isNew()) {
-        _.defer(options.success);
-      } else {
-        wrapError(this, options);
-        xhr = this.sync('delete', this, options);
-      }
-      if (!wait) destroy();
-      return xhr;
-    },
-
-    // Default URL for the model's representation on the server -- if you're
-    // using Backbone's restful methods, override this to change the endpoint
-    // that will be called.
-    url: function() {
-      var base =
-        _.result(this, 'urlRoot') ||
-        _.result(this.collection, 'url') ||
-        urlError();
-      if (this.isNew()) return base;
-      var id = this.get(this.idAttribute);
-      return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id);
-    },
-
-    // **parse** converts a response into the hash of attributes to be `set` on
-    // the model. The default implementation is just to pass the response along.
-    parse: function(resp, options) {
-      return resp;
-    },
-
-    // Create a new model with identical attributes to this one.
-    clone: function() {
-      return new this.constructor(this.attributes);
-    },
-
-    // A model is new if it has never been saved to the server, and lacks an id.
-    isNew: function() {
-      return !this.has(this.idAttribute);
-    },
-
-    // Check if the model is currently in a valid state.
-    isValid: function(options) {
-      return this._validate({}, _.extend({}, options, {validate: true}));
-    },
-
-    // Run validation against the next complete set of model attributes,
-    // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
-    _validate: function(attrs, options) {
-      if (!options.validate || !this.validate) return true;
-      attrs = _.extend({}, this.attributes, attrs);
-      var error = this.validationError = this.validate(attrs, options) || null;
-      if (!error) return true;
-      this.trigger('invalid', this, error, _.extend(options, {validationError: error}));
-      return false;
-    }
-
-  });
-
-  // Backbone.Collection
-  // -------------------
-
-  // If models tend to represent a single row of data, a Backbone Collection is
-  // more analogous to a table full of data ... or a small slice or page of that
-  // table, or a collection of rows that belong together for a particular reason
-  // -- all of the messages in this particular folder, all of the documents
-  // belonging to this particular author, and so on. Collections maintain
-  // indexes of their models, both in order, and for lookup by `id`.
-
-  // Create a new **Collection**, perhaps to contain a specific type of `model`.
-  // If a `comparator` is specified, the Collection will maintain
-  // its models in sort order, as they're added and removed.
-  var Collection = Backbone.Collection = function(models, options) {
-    options || (options = {});
-    this.preinitialize.apply(this, arguments);
-    if (options.model) this.model = options.model;
-    if (options.comparator !== void 0) this.comparator = options.comparator;
-    this._reset();
-    this.initialize.apply(this, arguments);
-    if (models) this.reset(models, _.extend({silent: true}, options));
-  };
-
-  // Default options for `Collection#set`.
-  var setOptions = {add: true, remove: true, merge: true};
-  var addOptions = {add: true, remove: false};
-
-  // Splices `insert` into `array` at index `at`.
-  var splice = function(array, insert, at) {
-    at = Math.min(Math.max(at, 0), array.length);
-    var tail = Array(array.length - at);
-    var length = insert.length;
-    var i;
-    for (i = 0; i < tail.length; i++) tail[i] = array[i + at];
-    for (i = 0; i < length; i++) array[i + at] = insert[i];
-    for (i = 0; i < tail.length; i++) array[i + length + at] = tail[i];
-  };
-
-  // Define the Collection's inheritable methods.
-  _.extend(Collection.prototype, Events, {
-
-    // The default model for a collection is just a **Backbone.Model**.
-    // This should be overridden in most cases.
-    model: Model,
-
-
-    // preinitialize is an empty function by default. You can override it with a function
-    // or object.  preinitialize will run before any instantiation logic is run in the Collection.
-    preinitialize: function(){},
-
-    // Initialize is an empty function by default. Override it with your own
-    // initialization logic.
-    initialize: function(){},
-
-    // The JSON representation of a Collection is an array of the
-    // models' attributes.
-    toJSON: function(options) {
-      return this.map(function(model) { return model.toJSON(options); });
-    },
-
-    // Proxy `Backbone.sync` by default.
-    sync: function() {
-      return Backbone.sync.apply(this, arguments);
-    },
-
-    // Add a model, or list of models to the set. `models` may be Backbone
-    // Models or raw JavaScript objects to be converted to Models, or any
-    // combination of the two.
-    add: function(models, options) {
-      return this.set(models, _.extend({merge: false}, options, addOptions));
-    },
-
-    // Remove a model, or a list of models from the set.
-    remove: function(models, options) {
-      options = _.extend({}, options);
-      var singular = !_.isArray(models);
-      models = singular ? [models] : models.slice();
-      var removed = this._removeModels(models, options);
-      if (!options.silent && removed.length) {
-        options.changes = {added: [], merged: [], removed: removed};
-        this.trigger('update', this, options);
-      }
-      return singular ? removed[0] : removed;
-    },
-
-    // Update a collection by `set`-ing a new list of models, adding new ones,
-    // removing models that are no longer present, and merging models that
-    // already exist in the collection, as necessary. Similar to **Model#set**,
-    // the core operation for updating the data contained by the collection.
-    set: function(models, options) {
-      if (models == null) return;
-
-      options = _.extend({}, setOptions, options);
-      if (options.parse && !this._isModel(models)) {
-        models = this.parse(models, options) || [];
-      }
-
-      var singular = !_.isArray(models);
-      models = singular ? [models] : models.slice();
-
-      var at = options.at;
-      if (at != null) at = +at;
-      if (at > this.length) at = this.length;
-      if (at < 0) at += this.length + 1;
-
-      var set = [];
-      var toAdd = [];
-      var toMerge = [];
-      var toRemove = [];
-      var modelMap = {};
-
-      var add = options.add;
-      var merge = options.merge;
-      var remove = options.remove;
-
-      var sort = false;
-      var sortable = this.comparator && at == null && options.sort !== false;
-      var sortAttr = _.isString(this.comparator) ? this.comparator : null;
-
-      // Turn bare objects into model references, and prevent invalid models
-      // from being added.
-      var model, i;
-      for (i = 0; i < models.length; i++) {
-        model = models[i];
-
-        // If a duplicate is found, prevent it from being added and
-        // optionally merge it into the existing model.
-        var existing = this.get(model);
-        if (existing) {
-          if (merge && model !== existing) {
-            var attrs = this._isModel(model) ? model.attributes : model;
-            if (options.parse) attrs = existing.parse(attrs, options);
-            existing.set(attrs, options);
-            toMerge.push(existing);
-            if (sortable && !sort) sort = existing.hasChanged(sortAttr);
-          }
-          if (!modelMap[existing.cid]) {
-            modelMap[existing.cid] = true;
-            set.push(existing);
-          }
-          models[i] = existing;
-
-        // If this is a new, valid model, push it to the `toAdd` list.
-        } else if (add) {
-          model = models[i] = this._prepareModel(model, options);
-          if (model) {
-            toAdd.push(model);
-            this._addReference(model, options);
-            modelMap[model.cid] = true;
-            set.push(model);
-          }
-        }
-      }
-
-      // Remove stale models.
-      if (remove) {
-        for (i = 0; i < this.length; i++) {
-          model = this.models[i];
-          if (!modelMap[model.cid]) toRemove.push(model);
-        }
-        if (toRemove.length) this._removeModels(toRemove, options);
-      }
-
-      // See if sorting is needed, update `length` and splice in new models.
-      var orderChanged = false;
-      var replace = !sortable && add && remove;
-      if (set.length && replace) {
-        orderChanged = this.length !== set.length || _.some(this.models, function(m, index) {
-          return m !== set[index];
-        });
-        this.models.length = 0;
-        splice(this.models, set, 0);
-        this.length = this.models.length;
-      } else if (toAdd.length) {
-        if (sortable) sort = true;
-        splice(this.models, toAdd, at == null ? this.length : at);
-        this.length = this.models.length;
-      }
-
-      // Silently sort the collection if appropriate.
-      if (sort) this.sort({silent: true});
-
-      // Unless silenced, it's time to fire all appropriate add/sort/update events.
-      if (!options.silent) {
-        for (i = 0; i < toAdd.length; i++) {
-          if (at != null) options.index = at + i;
-          model = toAdd[i];
-          model.trigger('add', model, this, options);
-        }
-        if (sort || orderChanged) this.trigger('sort', this, options);
-        if (toAdd.length || toRemove.length || toMerge.length) {
-          options.changes = {
-            added: toAdd,
-            removed: toRemove,
-            merged: toMerge
-          };
-          this.trigger('update', this, options);
-        }
-      }
-
-      // Return the added (or merged) model (or models).
-      return singular ? models[0] : models;
-    },
-
-    // When you have more items than you want to add or remove individually,
-    // you can reset the entire set with a new list of models, without firing
-    // any granular `add` or `remove` events. Fires `reset` when finished.
-    // Useful for bulk operations and optimizations.
-    reset: function(models, options) {
-      options = options ? _.clone(options) : {};
-      for (var i = 0; i < this.models.length; i++) {
-        this._removeReference(this.models[i], options);
-      }
-      options.previousModels = this.models;
-      this._reset();
-      models = this.add(models, _.extend({silent: true}, options));
-      if (!options.silent) this.trigger('reset', this, options);
-      return models;
-    },
-
-    // Add a model to the end of the collection.
-    push: function(model, options) {
-      return this.add(model, _.extend({at: this.length}, options));
-    },
-
-    // Remove a model from the end of the collection.
-    pop: function(options) {
-      var model = this.at(this.length - 1);
-      return this.remove(model, options);
-    },
-
-    // Add a model to the beginning of the collection.
-    unshift: function(model, options) {
-      return this.add(model, _.extend({at: 0}, options));
-    },
-
-    // Remove a model from the beginning of the collection.
-    shift: function(options) {
-      var model = this.at(0);
-      return this.remove(model, options);
-    },
-
-    // Slice out a sub-array of models from the collection.
-    slice: function() {
-      return slice.apply(this.models, arguments);
-    },
-
-    // Get a model from the set by id, cid, model object with id or cid
-    // properties, or an attributes object that is transformed through modelId.
-    get: function(obj) {
-      if (obj == null) return void 0;
-      return this._byId[obj] ||
-        this._byId[this.modelId(this._isModel(obj) ? obj.attributes : obj)] ||
-        obj.cid && this._byId[obj.cid];
-    },
-
-    // Returns `true` if the model is in the collection.
-    has: function(obj) {
-      return this.get(obj) != null;
-    },
-
-    // Get the model at the given index.
-    at: function(index) {
-      if (index < 0) index += this.length;
-      return this.models[index];
-    },
-
-    // Return models with matching attributes. Useful for simple cases of
-    // `filter`.
-    where: function(attrs, first) {
-      return this[first ? 'find' : 'filter'](attrs);
-    },
-
-    // Return the first model with matching attributes. Useful for simple cases
-    // of `find`.
-    findWhere: function(attrs) {
-      return this.where(attrs, true);
-    },
-
-    // Force the collection to re-sort itself. You don't need to call this under
-    // normal circumstances, as the set will maintain sort order as each item
-    // is added.
-    sort: function(options) {
-      var comparator = this.comparator;
-      if (!comparator) throw new Error('Cannot sort a set without a comparator');
-      options || (options = {});
-
-      var length = comparator.length;
-      if (_.isFunction(comparator)) comparator = comparator.bind(this);
-
-      // Run sort based on type of `comparator`.
-      if (length === 1 || _.isString(comparator)) {
-        this.models = this.sortBy(comparator);
-      } else {
-        this.models.sort(comparator);
-      }
-      if (!options.silent) this.trigger('sort', this, options);
-      return this;
-    },
-
-    // Pluck an attribute from each model in the collection.
-    pluck: function(attr) {
-      return this.map(attr + '');
-    },
-
-    // Fetch the default set of models for this collection, resetting the
-    // collection when they arrive. If `reset: true` is passed, the response
-    // data will be passed through the `reset` method instead of `set`.
-    fetch: function(options) {
-      options = _.extend({parse: true}, options);
-      var success = options.success;
-      var collection = this;
-      options.success = function(resp) {
-        var method = options.reset ? 'reset' : 'set';
-        collection[method](resp, options);
-        if (success) success.call(options.context, collection, resp, options);
-        collection.trigger('sync', collection, resp, options);
-      };
-      wrapError(this, options);
-      return this.sync('read', this, options);
-    },
-
-    // Create a new instance of a model in this collection. Add the model to the
-    // collection immediately, unless `wait: true` is passed, in which case we
-    // wait for the server to agree.
-    create: function(model, options) {
-      options = options ? _.clone(options) : {};
-      var wait = options.wait;
-      model = this._prepareModel(model, options);
-      if (!model) return false;
-      if (!wait) this.add(model, options);
-      var collection = this;
-      var success = options.success;
-      options.success = function(m, resp, callbackOpts) {
-        if (wait) collection.add(m, callbackOpts);
-        if (success) success.call(callbackOpts.context, m, resp, callbackOpts);
-      };
-      model.save(null, options);
-      return model;
-    },
-
-    // **parse** converts a response into a list of models to be added to the
-    // collection. The default implementation is just to pass it through.
-    parse: function(resp, options) {
-      return resp;
-    },
-
-    // Create a new collection with an identical list of models as this one.
-    clone: function() {
-      return new this.constructor(this.models, {
-        model: this.model,
-        comparator: this.comparator
-      });
-    },
-
-    // Define how to uniquely identify models in the collection.
-    modelId: function(attrs) {
-      return attrs[this.model.prototype.idAttribute || 'id'];
-    },
-
-    // Get an iterator of all models in this collection.
-    values: function() {
-      return new CollectionIterator(this, ITERATOR_VALUES);
-    },
-
-    // Get an iterator of all model IDs in this collection.
-    keys: function() {
-      return new CollectionIterator(this, ITERATOR_KEYS);
-    },
-
-    // Get an iterator of all [ID, model] tuples in this collection.
-    entries: function() {
-      return new CollectionIterator(this, ITERATOR_KEYSVALUES);
-    },
-
-    // Private method to reset all internal state. Called when the collection
-    // is first initialized or reset.
-    _reset: function() {
-      this.length = 0;
-      this.models = [];
-      this._byId  = {};
-    },
-
-    // Prepare a hash of attributes (or other model) to be added to this
-    // collection.
-    _prepareModel: function(attrs, options) {
-      if (this._isModel(attrs)) {
-        if (!attrs.collection) attrs.collection = this;
-        return attrs;
-      }
-      options = options ? _.clone(options) : {};
-      options.collection = this;
-      var model = new this.model(attrs, options);
-      if (!model.validationError) return model;
-      this.trigger('invalid', this, model.validationError, options);
-      return false;
-    },
-
-    // Internal method called by both remove and set.
-    _removeModels: function(models, options) {
-      var removed = [];
-      for (var i = 0; i < models.length; i++) {
-        var model = this.get(models[i]);
-        if (!model) continue;
-
-        var index = this.indexOf(model);
-        this.models.splice(index, 1);
-        this.length--;
-
-        // Remove references before triggering 'remove' event to prevent an
-        // infinite loop. #3693
-        delete this._byId[model.cid];
-        var id = this.modelId(model.attributes);
-        if (id != null) delete this._byId[id];
-
-        if (!options.silent) {
-          options.index = index;
-          model.trigger('remove', model, this, options);
-        }
-
-        removed.push(model);
-        this._removeReference(model, options);
-      }
-      return removed;
-    },
-
-    // Method for checking whether an object should be considered a model for
-    // the purposes of adding to the collection.
-    _isModel: function(model) {
-      return model instanceof Model;
-    },
-
-    // Internal method to create a model's ties to a collection.
-    _addReference: function(model, options) {
-      this._byId[model.cid] = model;
-      var id = this.modelId(model.attributes);
-      if (id != null) this._byId[id] = model;
-      model.on('all', this._onModelEvent, this);
-    },
-
-    // Internal method to sever a model's ties to a collection.
-    _removeReference: function(model, options) {
-      delete this._byId[model.cid];
-      var id = this.modelId(model.attributes);
-      if (id != null) delete this._byId[id];
-      if (this === model.collection) delete model.collection;
-      model.off('all', this._onModelEvent, this);
-    },
-
-    // Internal method called every time a model in the set fires an event.
-    // Sets need to update their indexes when models change ids. All other
-    // events simply proxy through. "add" and "remove" events that originate
-    // in other collections are ignored.
-    _onModelEvent: function(event, model, collection, options) {
-      if (model) {
-        if ((event === 'add' || event === 'remove') && collection !== this) return;
-        if (event === 'destroy') this.remove(model, options);
-        if (event === 'change') {
-          var prevId = this.modelId(model.previousAttributes());
-          var id = this.modelId(model.attributes);
-          if (prevId !== id) {
-            if (prevId != null) delete this._byId[prevId];
-            if (id != null) this._byId[id] = model;
-          }
-        }
-      }
-      this.trigger.apply(this, arguments);
-    }
-
-  });
-
-  // Defining an @@iterator method implements JavaScript's Iterable protocol.
-  // In modern ES2015 browsers, this value is found at Symbol.iterator.
-  /* global Symbol */
-  var $$iterator = typeof Symbol === 'function' && Symbol.iterator;
... 119933 lines suppressed ...